Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
7d69837bd2
110 changed files with 1956 additions and 720 deletions
17
doc/rust.md
17
doc/rust.md
|
|
@ -3168,7 +3168,7 @@ Raw pointers (`*`)
|
|||
: Raw pointers are pointers without safety or liveness guarantees.
|
||||
Raw pointers are written `*content`,
|
||||
for example `*int` means a raw pointer to an integer.
|
||||
Copying or dropping a raw pointer is has no effect on the lifecycle of any other value.
|
||||
Copying or dropping a raw pointer has no effect on the lifecycle of any other value.
|
||||
Dereferencing a raw pointer or converting it to any other pointer type is an [`unsafe` operation](#unsafe-functions).
|
||||
Raw pointers are generally discouraged in Rust code;
|
||||
they exist to support interoperability with foreign code,
|
||||
|
|
@ -3395,16 +3395,23 @@ a [temporary](#lvalues-rvalues-and-temporaries), or a local variable.
|
|||
A _local variable_ (or *stack-local* allocation) holds a value directly,
|
||||
allocated within the stack's memory. The value is a part of the stack frame.
|
||||
|
||||
Local variables are immutable unless declared with `let mut`. The
|
||||
`mut` keyword applies to all local variables declared within that
|
||||
declaration (so `let mut (x, y) = ...` declares two mutable variables, `x` and
|
||||
`y`).
|
||||
Local variables are immutable unless declared otherwise like: `let mut x = ...`.
|
||||
|
||||
Function parameters are immutable unless declared with `mut`. The
|
||||
`mut` keyword applies only to the following parameter (so `|mut x, y|`
|
||||
and `fn f(mut x: ~int, y: ~int)` declare one mutable variable `x` and
|
||||
one immutable variable `y`).
|
||||
|
||||
Methods that take either `self` or `~self` can optionally place them in a
|
||||
mutable slot by prefixing them with `mut` (similar to regular arguments):
|
||||
|
||||
~~~
|
||||
trait Changer {
|
||||
fn change(mut self) -> Self;
|
||||
fn modify(mut ~self) -> ~Self;
|
||||
}
|
||||
~~~
|
||||
|
||||
Local variables are not initialized when allocated; the entire frame worth of
|
||||
local variables are allocated at once, on frame-entry, in an uninitialized
|
||||
state. Subsequent statements within a function may or may not initialize the
|
||||
|
|
|
|||
|
|
@ -151,22 +151,6 @@ declaration to appear at the top level of the file: all statements must
|
|||
live inside a function. Rust programs can also be compiled as
|
||||
libraries, and included in other programs.
|
||||
|
||||
## Using the rust tool
|
||||
|
||||
While using `rustc` directly to generate your executables, and then
|
||||
running them manually is a perfectly valid way to test your code,
|
||||
for smaller projects, prototypes, or if you're a beginner, it might be
|
||||
more convenient to use the `rust` tool.
|
||||
|
||||
The `rust` tool provides central access to the other rust tools,
|
||||
as well as handy shortcuts for directly running source files.
|
||||
For example, if you have a file `foo.rs` in your current directory,
|
||||
`rust run foo.rs` would attempt to compile it and, if successful,
|
||||
directly run the resulting binary.
|
||||
|
||||
To get a list of all available commands, simply call `rust` without any
|
||||
argument.
|
||||
|
||||
## Editing Rust code
|
||||
|
||||
There are vim highlighting and indentation scripts in the Rust source
|
||||
|
|
|
|||
|
|
@ -370,6 +370,7 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \
|
|||
$$(SREQ$(1)_T_$(2)_H_$(3)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2)) \
|
||||
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(2)) \
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$$(X_$(2)) \
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(2))
|
||||
@$$(call E, compile_and_link: $$@)
|
||||
|
|
|
|||
|
|
@ -521,15 +521,15 @@ fn borrow_rwlock<T:Freeze + Send>(state: *mut RWArcInner<T>) -> *RWLock {
|
|||
|
||||
/// The "write permission" token used for RWArc.write_downgrade().
|
||||
pub struct RWWriteMode<'self, T> {
|
||||
data: &'self mut T,
|
||||
token: sync::RWLockWriteMode<'self>,
|
||||
poison: PoisonOnFail,
|
||||
priv data: &'self mut T,
|
||||
priv token: sync::RWLockWriteMode<'self>,
|
||||
priv poison: PoisonOnFail,
|
||||
}
|
||||
|
||||
/// The "read permission" token used for RWArc.write_downgrade().
|
||||
pub struct RWReadMode<'self, T> {
|
||||
data: &'self T,
|
||||
token: sync::RWLockReadMode<'self>,
|
||||
priv data: &'self T,
|
||||
priv token: sync::RWLockReadMode<'self>,
|
||||
}
|
||||
|
||||
impl<'self, T:Freeze + Send> RWWriteMode<'self, T> {
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ pub enum CharacterSet {
|
|||
/// Contains configuration parameters for `to_base64`.
|
||||
pub struct Config {
|
||||
/// Character set to use
|
||||
char_set: CharacterSet,
|
||||
priv char_set: CharacterSet,
|
||||
/// True to pad output with `=` characters
|
||||
pad: bool,
|
||||
priv pad: bool,
|
||||
/// `Some(len)` to wrap lines at `len`, `None` to disable line wrapping
|
||||
line_length: Option<uint>
|
||||
priv line_length: Option<uint>
|
||||
}
|
||||
|
||||
/// Configuration for RFC 4648 standard base64 encoding
|
||||
|
|
@ -318,7 +318,7 @@ mod test {
|
|||
use std::vec;
|
||||
|
||||
do 1000.times {
|
||||
let times = task_rng().gen_integer_range(1u, 100);
|
||||
let times = task_rng().gen_range(1u, 100);
|
||||
let v = vec::from_fn(times, |_| random::<u8>());
|
||||
assert_eq!(v.to_base64(STANDARD).from_base64().unwrap(), v);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,9 +226,9 @@ enum Op {Union, Intersect, Assign, Difference}
|
|||
#[deriving(Clone)]
|
||||
pub struct Bitv {
|
||||
/// Internal representation of the bit vector (small or large)
|
||||
rep: BitvVariant,
|
||||
priv rep: BitvVariant,
|
||||
/// The number of valid bits in the internal representation
|
||||
nbits: uint
|
||||
priv nbits: uint
|
||||
}
|
||||
|
||||
fn die() -> ! {
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ pub mod test {
|
|||
digest.reset();
|
||||
|
||||
while count < total_size {
|
||||
let next: uint = rng.gen_integer_range(0, 2 * blocksize + 1);
|
||||
let next: uint = rng.gen_range(0, 2 * blocksize + 1);
|
||||
let remaining = total_size - count;
|
||||
let size = if next > remaining { remaining } else { next };
|
||||
digest.input(buffer.slice_to(size));
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ impl Doc {
|
|||
}
|
||||
|
||||
pub struct TaggedDoc {
|
||||
tag: uint,
|
||||
priv tag: uint,
|
||||
doc: Doc,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ struct FileInput_ {
|
|||
// "self.fi" -> "self." and renaming FileInput_. Documentation above
|
||||
// will likely have to be updated to use `let mut in = ...`.
|
||||
pub struct FileInput {
|
||||
fi: @mut FileInput_
|
||||
priv fi: @mut FileInput_
|
||||
}
|
||||
|
||||
impl FileInput {
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ mod tests {
|
|||
let mut r = rand::rng();
|
||||
let mut words = ~[];
|
||||
do 20.times {
|
||||
let range = r.gen_integer_range(1u, 10);
|
||||
let range = r.gen_range(1u, 10);
|
||||
words.push(r.gen_vec::<u8>(range));
|
||||
}
|
||||
do 20.times {
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ pub struct Opt {
|
|||
/// How often it can occur
|
||||
occur: Occur,
|
||||
/// Which options it aliases
|
||||
aliases: ~[Opt],
|
||||
priv aliases: ~[Opt],
|
||||
}
|
||||
|
||||
/// Describes wether an option is given at all or has a value.
|
||||
|
|
@ -134,9 +134,9 @@ enum Optval {
|
|||
#[deriving(Clone, Eq)]
|
||||
pub struct Matches {
|
||||
/// Options that matched
|
||||
opts: ~[Opt],
|
||||
priv opts: ~[Opt],
|
||||
/// Values of the Options that matched
|
||||
vals: ~[~[Optval]],
|
||||
priv vals: ~[~[Optval]],
|
||||
/// Free string fragments
|
||||
free: ~[~str]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -480,13 +480,13 @@ pub struct MatchOptions {
|
|||
* currently only considers upper/lower case relationships between ASCII characters,
|
||||
* but in future this might be extended to work with Unicode.
|
||||
*/
|
||||
case_sensitive: bool,
|
||||
priv case_sensitive: bool,
|
||||
|
||||
/**
|
||||
* If this is true then path-component separator characters (e.g. `/` on Posix)
|
||||
* must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
|
||||
*/
|
||||
require_literal_separator: bool,
|
||||
priv require_literal_separator: bool,
|
||||
|
||||
/**
|
||||
* If this is true then paths that contain components that start with a `.` will
|
||||
|
|
@ -494,7 +494,7 @@ pub struct MatchOptions {
|
|||
* will not match. This is useful because such files are conventionally considered
|
||||
* hidden on Unix systems and it might be desirable to skip them when listing files.
|
||||
*/
|
||||
require_literal_leading_dot: bool
|
||||
priv require_literal_leading_dot: bool
|
||||
}
|
||||
|
||||
impl MatchOptions {
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ use std::cast;
|
|||
/// An implementation of the io::Reader interface which reads a buffer of bytes
|
||||
pub struct BufReader {
|
||||
/// The buffer of bytes to read
|
||||
buf: ~[u8],
|
||||
priv buf: ~[u8],
|
||||
/// The current position in the buffer of bytes
|
||||
pos: @mut uint
|
||||
priv pos: @mut uint
|
||||
}
|
||||
|
||||
impl BufReader {
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ pub type Object = TreeMap<~str, Json>;
|
|||
/// returned
|
||||
pub struct Error {
|
||||
/// The line number at which the error occurred
|
||||
line: uint,
|
||||
priv line: uint,
|
||||
/// The column number at which the error occurred
|
||||
col: uint,
|
||||
priv col: uint,
|
||||
/// A message describing the type of the error
|
||||
msg: @~str,
|
||||
priv msg: @~str,
|
||||
}
|
||||
|
||||
fn escape_str(s: &str) -> ~str {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ use super::bigint::BigInt;
|
|||
#[deriving(Clone)]
|
||||
#[allow(missing_doc)]
|
||||
pub struct Ratio<T> {
|
||||
numer: T,
|
||||
denom: T
|
||||
priv numer: T,
|
||||
priv denom: T
|
||||
}
|
||||
|
||||
/// Alias for a `Ratio` of machine-sized integers.
|
||||
|
|
|
|||
|
|
@ -71,17 +71,17 @@ impl ToStr for Identifier {
|
|||
#[deriving(Clone, Eq)]
|
||||
pub struct Version {
|
||||
/// The major version, to be incremented on incompatible changes.
|
||||
major: uint,
|
||||
priv major: uint,
|
||||
/// The minor version, to be incremented when functionality is added in a
|
||||
/// backwards-compatible manner.
|
||||
minor: uint,
|
||||
priv minor: uint,
|
||||
/// The patch version, to be incremented when backwards-compatible bug
|
||||
/// fixes are made.
|
||||
patch: uint,
|
||||
priv patch: uint,
|
||||
/// The pre-release version identifier, if one exists.
|
||||
pre: ~[Identifier],
|
||||
priv pre: ~[Identifier],
|
||||
/// The build metadata, ignored when determining version precedence.
|
||||
build: ~[Identifier],
|
||||
priv build: ~[Identifier],
|
||||
}
|
||||
|
||||
impl ToStr for Version {
|
||||
|
|
|
|||
|
|
@ -1069,8 +1069,8 @@ mod big_tests {
|
|||
isSorted(arr);
|
||||
|
||||
do 3.times {
|
||||
let i1 = rng.gen_integer_range(0u, n);
|
||||
let i2 = rng.gen_integer_range(0u, n);
|
||||
let i1 = rng.gen_range(0u, n);
|
||||
let i2 = rng.gen_range(0u, n);
|
||||
arr.swap(i1, i2);
|
||||
}
|
||||
tim_sort(arr); // 3sort
|
||||
|
|
@ -1088,7 +1088,7 @@ mod big_tests {
|
|||
isSorted(arr);
|
||||
|
||||
do (n/100).times {
|
||||
let idx = rng.gen_integer_range(0u, n);
|
||||
let idx = rng.gen_range(0u, n);
|
||||
arr[idx] = rng.gen();
|
||||
}
|
||||
tim_sort(arr);
|
||||
|
|
@ -1141,8 +1141,8 @@ mod big_tests {
|
|||
isSorted(arr);
|
||||
|
||||
do 3.times {
|
||||
let i1 = rng.gen_integer_range(0u, n);
|
||||
let i2 = rng.gen_integer_range(0u, n);
|
||||
let i1 = rng.gen_range(0u, n);
|
||||
let i2 = rng.gen_range(0u, n);
|
||||
arr.swap(i1, i2);
|
||||
}
|
||||
tim_sort(arr); // 3sort
|
||||
|
|
@ -1160,7 +1160,7 @@ mod big_tests {
|
|||
isSorted(arr);
|
||||
|
||||
do (n/100).times {
|
||||
let idx = rng.gen_integer_range(0u, n);
|
||||
let idx = rng.gen_range(0u, n);
|
||||
arr[idx] = @rng.gen();
|
||||
}
|
||||
tim_sort(arr);
|
||||
|
|
|
|||
|
|
@ -105,18 +105,23 @@ pub trait Stats {
|
|||
#[deriving(Clone, Eq)]
|
||||
#[allow(missing_doc)]
|
||||
pub struct Summary {
|
||||
sum: f64,
|
||||
priv sum: f64,
|
||||
// public
|
||||
min: f64,
|
||||
// public
|
||||
max: f64,
|
||||
mean: f64,
|
||||
priv mean: f64,
|
||||
// public
|
||||
median: f64,
|
||||
var: f64,
|
||||
std_dev: f64,
|
||||
std_dev_pct: f64,
|
||||
priv var: f64,
|
||||
priv std_dev: f64,
|
||||
priv std_dev_pct: f64,
|
||||
// public
|
||||
median_abs_dev: f64,
|
||||
// public
|
||||
median_abs_dev_pct: f64,
|
||||
quartiles: (f64,f64,f64),
|
||||
iqr: f64,
|
||||
priv quartiles: (f64,f64,f64),
|
||||
priv iqr: f64,
|
||||
}
|
||||
|
||||
impl Summary {
|
||||
|
|
|
|||
|
|
@ -376,8 +376,8 @@ impl Semaphore {
|
|||
* A task which fails while holding a mutex will unlock the mutex as it
|
||||
* unwinds.
|
||||
*/
|
||||
pub struct Mutex { priv sem: Sem<~[WaitQueue]> }
|
||||
|
||||
pub struct Mutex { priv sem: Sem<~[WaitQueue]> }
|
||||
impl Clone for Mutex {
|
||||
/// Create a new handle to the mutex.
|
||||
fn clone(&self) -> Mutex { Mutex { sem: Sem((*self.sem).clone()) } }
|
||||
|
|
@ -663,8 +663,8 @@ impl RWLock {
|
|||
}
|
||||
|
||||
/// The "write permission" token used for rwlock.write_downgrade().
|
||||
pub struct RWLockWriteMode<'self> { priv lock: &'self RWLock, priv token: NonCopyable }
|
||||
|
||||
pub struct RWLockWriteMode<'self> { priv lock: &'self RWLock, priv token: NonCopyable }
|
||||
/// The "read permission" token used for rwlock.write_downgrade().
|
||||
pub struct RWLockReadMode<'self> { priv lock: &'self RWLock,
|
||||
priv token: NonCopyable }
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ enum Msg<T> {
|
|||
}
|
||||
|
||||
pub struct TaskPool<T> {
|
||||
channels: ~[Chan<Msg<T>>],
|
||||
next_index: uint,
|
||||
priv channels: ~[Chan<Msg<T>>],
|
||||
priv next_index: uint,
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
|
|
|
|||
|
|
@ -95,14 +95,14 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str {
|
|||
|
||||
#[cfg(not(target_os = "win32"))]
|
||||
pub struct Terminal {
|
||||
num_colors: u16,
|
||||
priv num_colors: u16,
|
||||
priv out: @io::Writer,
|
||||
priv ti: ~TermInfo
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
pub struct Terminal {
|
||||
num_colors: u16,
|
||||
priv num_colors: u16,
|
||||
priv out: @io::Writer,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ pub enum Param {
|
|||
/// Container for static and dynamic variable arrays
|
||||
pub struct Variables {
|
||||
/// Static variables A-Z
|
||||
sta: [Param, ..26],
|
||||
priv sta: [Param, ..26],
|
||||
/// Dynamic variables a-z
|
||||
dyn: [Param, ..26]
|
||||
priv dyn: [Param, ..26]
|
||||
}
|
||||
|
||||
impl Variables {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ use std::hashmap::HashMap;
|
|||
/// A parsed terminfo entry.
|
||||
pub struct TermInfo {
|
||||
/// Names for the terminal
|
||||
names: ~[~str],
|
||||
priv names: ~[~str],
|
||||
/// Map of capability name to boolean value
|
||||
bools: HashMap<~str, bool>,
|
||||
priv bools: HashMap<~str, bool>,
|
||||
/// Map of capability name to numeric value
|
||||
numbers: HashMap<~str, u16>,
|
||||
/// Map of capability name to raw (unexpanded) string
|
||||
|
|
|
|||
|
|
@ -102,9 +102,9 @@ impl TestFn {
|
|||
|
||||
// Structure passed to BenchFns
|
||||
pub struct BenchHarness {
|
||||
iterations: u64,
|
||||
ns_start: u64,
|
||||
ns_end: u64,
|
||||
priv iterations: u64,
|
||||
priv ns_start: u64,
|
||||
priv ns_end: u64,
|
||||
bytes: u64
|
||||
}
|
||||
|
||||
|
|
@ -124,8 +124,8 @@ pub struct TestDescAndFn {
|
|||
|
||||
#[deriving(Clone, Encodable, Decodable, Eq)]
|
||||
pub struct Metric {
|
||||
value: f64,
|
||||
noise: f64
|
||||
priv value: f64,
|
||||
priv noise: f64
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
|
|
@ -322,8 +322,8 @@ pub fn opt_shard(maybestr: Option<~str>) -> Option<(uint,uint)> {
|
|||
|
||||
#[deriving(Clone, Eq)]
|
||||
pub struct BenchSamples {
|
||||
ns_iter_summ: stats::Summary,
|
||||
mb_s: uint
|
||||
priv ns_iter_summ: stats::Summary,
|
||||
priv mb_s: uint
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq)]
|
||||
|
|
|
|||
|
|
@ -31,9 +31,10 @@ pub mod rustrt {
|
|||
}
|
||||
|
||||
/// A record specifying a time value in seconds and nanoseconds.
|
||||
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
|
||||
pub struct Timespec { sec: i64, nsec: i32 }
|
||||
|
||||
|
||||
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
|
||||
pub struct Timespec { priv sec: i64, priv nsec: i32 }
|
||||
/*
|
||||
* Timespec assumes that pre-epoch Timespecs have negative sec and positive
|
||||
* nsec fields. Darwin's and Linux's struct timespec functions handle pre-
|
||||
|
|
@ -105,18 +106,18 @@ pub fn tzset() {
|
|||
|
||||
#[deriving(Clone, DeepClone, Eq, Encodable, Decodable)]
|
||||
pub struct Tm {
|
||||
tm_sec: i32, // seconds after the minute ~[0-60]
|
||||
tm_min: i32, // minutes after the hour ~[0-59]
|
||||
tm_hour: i32, // hours after midnight ~[0-23]
|
||||
tm_mday: i32, // days of the month ~[1-31]
|
||||
tm_mon: i32, // months since January ~[0-11]
|
||||
tm_year: i32, // years since 1900
|
||||
tm_wday: i32, // days since Sunday ~[0-6]
|
||||
tm_yday: i32, // days since January 1 ~[0-365]
|
||||
tm_isdst: i32, // Daylight Savings Time flag
|
||||
tm_gmtoff: i32, // offset from UTC in seconds
|
||||
tm_zone: ~str, // timezone abbreviation
|
||||
tm_nsec: i32, // nanoseconds
|
||||
priv tm_sec: i32, // seconds after the minute ~[0-60]
|
||||
priv tm_min: i32, // minutes after the hour ~[0-59]
|
||||
priv tm_hour: i32, // hours after midnight ~[0-23]
|
||||
priv tm_mday: i32, // days of the month ~[1-31]
|
||||
priv tm_mon: i32, // months since January ~[0-11]
|
||||
priv tm_year: i32, // years since 1900
|
||||
priv tm_wday: i32, // days since Sunday ~[0-6]
|
||||
priv tm_yday: i32, // days since January 1 ~[0-365]
|
||||
priv tm_isdst: i32, // Daylight Savings Time flag
|
||||
priv tm_gmtoff: i32, // offset from UTC in seconds
|
||||
priv tm_zone: ~str, // timezone abbreviation
|
||||
priv tm_nsec: i32, // nanoseconds
|
||||
}
|
||||
|
||||
pub fn empty_tm() -> Tm {
|
||||
|
|
|
|||
|
|
@ -1028,7 +1028,7 @@ mod test_treemap {
|
|||
}
|
||||
|
||||
do 30.times {
|
||||
let r = rng.gen_integer_range(0, ctrl.len());
|
||||
let r = rng.gen_range(0, ctrl.len());
|
||||
let (key, _) = ctrl.remove(r);
|
||||
assert!(map.remove(&key));
|
||||
check_structure(&map);
|
||||
|
|
|
|||
|
|
@ -128,8 +128,8 @@ impl WorkMap {
|
|||
}
|
||||
|
||||
pub struct Database {
|
||||
db_filename: Path,
|
||||
db_cache: TreeMap<~str, ~str>,
|
||||
priv db_filename: Path,
|
||||
priv db_cache: TreeMap<~str, ~str>,
|
||||
db_dirty: bool
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ impl Drop for Database {
|
|||
|
||||
pub struct Logger {
|
||||
// FIXME #4432: Fill in
|
||||
a: ()
|
||||
priv a: ()
|
||||
}
|
||||
|
||||
impl Logger {
|
||||
|
|
@ -228,26 +228,26 @@ pub type FreshnessMap = TreeMap<~str,extern fn(&str,&str)->bool>;
|
|||
#[deriving(Clone)]
|
||||
pub struct Context {
|
||||
db: RWArc<Database>,
|
||||
logger: RWArc<Logger>,
|
||||
cfg: Arc<json::Object>,
|
||||
priv logger: RWArc<Logger>,
|
||||
priv cfg: Arc<json::Object>,
|
||||
/// Map from kinds (source, exe, url, etc.) to a freshness function.
|
||||
/// The freshness function takes a name (e.g. file path) and value
|
||||
/// (e.g. hash of file contents) and determines whether it's up-to-date.
|
||||
/// For example, in the file case, this would read the file off disk,
|
||||
/// hash it, and return the result of comparing the given hash and the
|
||||
/// read hash for equality.
|
||||
freshness: Arc<FreshnessMap>
|
||||
priv freshness: Arc<FreshnessMap>
|
||||
}
|
||||
|
||||
pub struct Prep<'self> {
|
||||
ctxt: &'self Context,
|
||||
fn_name: &'self str,
|
||||
declared_inputs: WorkMap,
|
||||
priv ctxt: &'self Context,
|
||||
priv fn_name: &'self str,
|
||||
priv declared_inputs: WorkMap,
|
||||
}
|
||||
|
||||
pub struct Exec {
|
||||
discovered_inputs: WorkMap,
|
||||
discovered_outputs: WorkMap
|
||||
priv discovered_inputs: WorkMap,
|
||||
priv discovered_outputs: WorkMap
|
||||
}
|
||||
|
||||
enum Work<'self, T> {
|
||||
|
|
|
|||
|
|
@ -975,9 +975,9 @@ fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ {
|
|||
let explicit_self_kind = string[0];
|
||||
match explicit_self_kind as char {
|
||||
's' => { return ast::sty_static; }
|
||||
'v' => { return ast::sty_value; }
|
||||
'v' => { return ast::sty_value(get_mutability(string[1])); }
|
||||
'@' => { return ast::sty_box(get_mutability(string[1])); }
|
||||
'~' => { return ast::sty_uniq; }
|
||||
'~' => { return ast::sty_uniq(get_mutability(string[1])); }
|
||||
'&' => {
|
||||
// FIXME(#4846) expl. region
|
||||
return ast::sty_region(None, get_mutability(string[1]));
|
||||
|
|
|
|||
|
|
@ -662,8 +662,9 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic
|
|||
sty_static => {
|
||||
ebml_w.writer.write(&[ 's' as u8 ]);
|
||||
}
|
||||
sty_value => {
|
||||
sty_value(m) => {
|
||||
ebml_w.writer.write(&[ 'v' as u8 ]);
|
||||
encode_mutability(ebml_w, m);
|
||||
}
|
||||
sty_region(_, m) => {
|
||||
// FIXME(#4846) encode custom lifetime
|
||||
|
|
@ -674,8 +675,9 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic
|
|||
ebml_w.writer.write(&[ '@' as u8 ]);
|
||||
encode_mutability(ebml_w, m);
|
||||
}
|
||||
sty_uniq => {
|
||||
sty_uniq(m) => {
|
||||
ebml_w.writer.write(&[ '~' as u8 ]);
|
||||
encode_mutability(ebml_w, m);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ impl tr for ast::Def {
|
|||
ast::DefMethod(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
|
||||
}
|
||||
ast::DefSelfTy(nid) => { ast::DefSelfTy(xcx.tr_id(nid)) }
|
||||
ast::DefSelf(nid) => { ast::DefSelf(xcx.tr_id(nid)) }
|
||||
ast::DefSelf(nid, m) => { ast::DefSelf(xcx.tr_id(nid), m) }
|
||||
ast::DefMod(did) => { ast::DefMod(did.tr(xcx)) }
|
||||
ast::DefForeignMod(did) => { ast::DefForeignMod(did.tr(xcx)) }
|
||||
ast::DefStatic(did, m) => { ast::DefStatic(did.tr(xcx), m) }
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ fn visit_fn(v: &mut LivenessVisitor,
|
|||
match *fk {
|
||||
visit::fk_method(_, _, method) => {
|
||||
match method.explicit_self.node {
|
||||
sty_value | sty_region(*) | sty_box(_) | sty_uniq => {
|
||||
sty_value(_) | sty_region(*) | sty_box(_) | sty_uniq(_) => {
|
||||
fn_maps.add_variable(Arg(method.self_id,
|
||||
special_idents::self_));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -488,12 +488,12 @@ impl mem_categorization_ctxt {
|
|||
}
|
||||
}
|
||||
|
||||
ast::DefSelf(self_id) => {
|
||||
ast::DefSelf(self_id, mutbl) => {
|
||||
@cmt_ {
|
||||
id:id,
|
||||
span:span,
|
||||
cat:cat_self(self_id),
|
||||
mutbl: McImmutable,
|
||||
mutbl: if mutbl { McDeclared } else { McImmutable },
|
||||
ty:expr_ty
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ pub fn moved_variable_node_id_from_def(def: Def) -> Option<NodeId> {
|
|||
DefBinding(nid, _) |
|
||||
DefArg(nid, _) |
|
||||
DefLocal(nid, _) |
|
||||
DefSelf(nid) => Some(nid),
|
||||
DefSelf(nid, _) => Some(nid),
|
||||
|
||||
_ => None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ enum Mutability {
|
|||
|
||||
enum SelfBinding {
|
||||
NoSelfBinding,
|
||||
HasSelfBinding(NodeId)
|
||||
HasSelfBinding(NodeId, explicit_self)
|
||||
}
|
||||
|
||||
impl Visitor<()> for Resolver {
|
||||
|
|
@ -3799,8 +3799,12 @@ impl Resolver {
|
|||
NoSelfBinding => {
|
||||
// Nothing to do.
|
||||
}
|
||||
HasSelfBinding(self_node_id) => {
|
||||
let def_like = DlDef(DefSelf(self_node_id));
|
||||
HasSelfBinding(self_node_id, explicit_self) => {
|
||||
let mutable = match explicit_self.node {
|
||||
sty_uniq(m) | sty_value(m) if m == MutMutable => true,
|
||||
_ => false
|
||||
};
|
||||
let def_like = DlDef(DefSelf(self_node_id, mutable));
|
||||
*function_value_rib.self_binding = Some(def_like);
|
||||
}
|
||||
}
|
||||
|
|
@ -3937,7 +3941,7 @@ impl Resolver {
|
|||
// we only have self ty if it is a non static method
|
||||
let self_binding = match method.explicit_self.node {
|
||||
sty_static => { NoSelfBinding }
|
||||
_ => { HasSelfBinding(method.self_id) }
|
||||
_ => { HasSelfBinding(method.self_id, method.explicit_self) }
|
||||
};
|
||||
|
||||
self.resolve_function(rib_kind,
|
||||
|
|
|
|||
|
|
@ -1099,7 +1099,7 @@ pub fn trans_local_var(bcx: @mut Block, def: ast::Def) -> Datum {
|
|||
ast::DefLocal(nid, _) | ast::DefBinding(nid, _) => {
|
||||
take_local(bcx, bcx.fcx.lllocals, nid)
|
||||
}
|
||||
ast::DefSelf(nid) => {
|
||||
ast::DefSelf(nid, _) => {
|
||||
let self_info: ValSelfData = match bcx.fcx.llself {
|
||||
Some(ref self_info) => *self_info,
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
|
|||
debug!("calling inline trans_fn with self_ty {}",
|
||||
ty_to_str(ccx.tcx, self_ty));
|
||||
match mth.explicit_self.node {
|
||||
ast::sty_value => impl_self(self_ty, ty::ByRef),
|
||||
ast::sty_value(_) => impl_self(self_ty, ty::ByRef),
|
||||
_ => impl_self(self_ty, ty::ByCopy),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ pub fn trans_method(ccx: @mut CrateContext,
|
|||
debug!("calling trans_fn with self_ty {}",
|
||||
self_ty.repr(ccx.tcx));
|
||||
match method.explicit_self.node {
|
||||
ast::sty_value => impl_self(self_ty, ty::ByRef),
|
||||
ast::sty_value(_) => impl_self(self_ty, ty::ByRef),
|
||||
_ => impl_self(self_ty, ty::ByCopy),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -672,7 +672,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
|||
{
|
||||
match self_info.explicit_self.node {
|
||||
ast::sty_static => None,
|
||||
ast::sty_value => {
|
||||
ast::sty_value(_) => {
|
||||
Some(self_info.untransformed_self_ty)
|
||||
}
|
||||
ast::sty_region(ref lifetime, mutability) => {
|
||||
|
|
@ -689,7 +689,7 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
|
|||
ty::mt {ty: self_info.untransformed_self_ty,
|
||||
mutbl: mutability}))
|
||||
}
|
||||
ast::sty_uniq => {
|
||||
ast::sty_uniq(_) => {
|
||||
Some(ty::mk_uniq(this.tcx(),
|
||||
ty::mt {ty: self_info.untransformed_self_ty,
|
||||
mutbl: ast::MutImmutable}))
|
||||
|
|
|
|||
|
|
@ -1082,7 +1082,7 @@ impl<'self> LookupContext<'self> {
|
|||
ast::sty_static => {
|
||||
self.bug(~"static method for object type receiver");
|
||||
}
|
||||
ast::sty_value => {
|
||||
ast::sty_value(_) => {
|
||||
ty::mk_err() // error reported in `enforce_object_limitations()`
|
||||
}
|
||||
ast::sty_region(*) | ast::sty_box(*) | ast::sty_uniq(*) => {
|
||||
|
|
@ -1141,7 +1141,7 @@ impl<'self> LookupContext<'self> {
|
|||
through an object");
|
||||
}
|
||||
|
||||
ast::sty_value => { // reason (a) above
|
||||
ast::sty_value(_) => { // reason (a) above
|
||||
self.tcx().sess.span_err(
|
||||
self.expr.span,
|
||||
"cannot call a method with a by-value receiver \
|
||||
|
|
@ -1198,7 +1198,7 @@ impl<'self> LookupContext<'self> {
|
|||
false
|
||||
}
|
||||
|
||||
sty_value => {
|
||||
sty_value(_) => {
|
||||
rcvr_matches_ty(self.fcx, rcvr_ty, candidate)
|
||||
}
|
||||
|
||||
|
|
@ -1236,7 +1236,7 @@ impl<'self> LookupContext<'self> {
|
|||
}
|
||||
}
|
||||
|
||||
sty_uniq => {
|
||||
sty_uniq(_) => {
|
||||
debug!("(is relevant?) explicit self is a unique pointer");
|
||||
match ty::get(rcvr_ty).sty {
|
||||
ty::ty_uniq(mt) => {
|
||||
|
|
@ -1369,7 +1369,7 @@ impl<'self> LookupContext<'self> {
|
|||
|
||||
pub fn get_mode_from_explicit_self(explicit_self: ast::explicit_self_) -> SelfMode {
|
||||
match explicit_self {
|
||||
sty_value => ty::ByRef,
|
||||
sty_value(_) => ty::ByRef,
|
||||
_ => ty::ByCopy,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3254,7 +3254,7 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
|
|||
defn: ast::Def)
|
||||
-> ty_param_bounds_and_ty {
|
||||
match defn {
|
||||
ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid) |
|
||||
ast::DefArg(nid, _) | ast::DefLocal(nid, _) | ast::DefSelf(nid, _) |
|
||||
ast::DefBinding(nid, _) => {
|
||||
let typ = fcx.local_ty(sp, nid);
|
||||
return no_params(typ);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::Def) -> ty::Region {
|
|||
let tcx = fcx.tcx();
|
||||
match def {
|
||||
DefLocal(node_id, _) | DefArg(node_id, _) |
|
||||
DefSelf(node_id) | DefBinding(node_id, _) => {
|
||||
DefSelf(node_id, _) | DefBinding(node_id, _) => {
|
||||
tcx.region_maps.encl_region(node_id)
|
||||
}
|
||||
DefUpvar(_, subdef, closure_id, body_id) => {
|
||||
|
|
|
|||
|
|
@ -388,8 +388,8 @@ impl Clean<SelfTy> for ast::explicit_self {
|
|||
fn clean(&self) -> SelfTy {
|
||||
match self.node {
|
||||
ast::sty_static => SelfStatic,
|
||||
ast::sty_value => SelfValue,
|
||||
ast::sty_uniq => SelfOwned,
|
||||
ast::sty_value(_) => SelfValue,
|
||||
ast::sty_uniq(_) => SelfOwned,
|
||||
ast::sty_region(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
|
||||
ast::sty_box(mt) => SelfManaged(mt.clean()),
|
||||
}
|
||||
|
|
@ -1171,7 +1171,7 @@ fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
|
|||
|
||||
let (def_id, kind) = match *d {
|
||||
ast::DefFn(i, _) => (i, TypeFunction),
|
||||
ast::DefSelf(i) | ast::DefSelfTy(i) => return Self(i),
|
||||
ast::DefSelf(i, _) | ast::DefSelfTy(i) => return Self(i),
|
||||
ast::DefTy(i) => (i, TypeEnum),
|
||||
ast::DefTrait(i) => {
|
||||
debug!("saw DefTrait in def_to_id");
|
||||
|
|
|
|||
|
|
@ -12,22 +12,35 @@ use context::*;
|
|||
use crate::*;
|
||||
use package_id::*;
|
||||
use package_source::*;
|
||||
use path_util::{platform_library_name, target_build_dir};
|
||||
use target::*;
|
||||
use version::Version;
|
||||
use workspace::pkg_parent_workspaces;
|
||||
use workcache_support::*;
|
||||
pub use path_util::default_workspace;
|
||||
|
||||
pub use source_control::{safe_git_clone, git_clone_url};
|
||||
|
||||
use std::os;
|
||||
use std::{os, run};
|
||||
use extra::arc::{Arc,RWArc};
|
||||
use extra::workcache;
|
||||
use extra::workcache::{Database, Logger, FreshnessMap};
|
||||
use extra::treemap::TreeMap;
|
||||
|
||||
// A little sad -- duplicated from rustc::back::*
|
||||
#[cfg(target_arch = "arm")]
|
||||
fn cc_args() -> ~[~str] { ~[~"-marm"] }
|
||||
#[cfg(target_arch = "mips")]
|
||||
fn cc_args() -> ~[~str] { ~[] }
|
||||
#[cfg(target_arch = "x86")]
|
||||
fn cc_args() -> ~[~str] { ~[~"-m32"] }
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn cc_args() -> ~[~str] { ~[~"-m64"] }
|
||||
|
||||
/// Convenience functions intended for calling from pkg.rs
|
||||
/// p is where to put the cache file for dependencies
|
||||
pub fn default_context(p: Path) -> BuildContext {
|
||||
new_default_context(new_workcache_context(&p), p)
|
||||
pub fn default_context(sysroot: Path, p: Path) -> BuildContext {
|
||||
new_default_context(new_workcache_context(&p), sysroot)
|
||||
}
|
||||
|
||||
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
|
||||
|
|
@ -68,7 +81,7 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
|
|||
|
||||
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||
lib: Path) {
|
||||
let cx = default_context(sysroot);
|
||||
let cx = default_context(sysroot, root.clone());
|
||||
let pkg_src = PkgSrc {
|
||||
source_workspace: root.clone(),
|
||||
build_in_destination: false,
|
||||
|
|
@ -81,12 +94,12 @@ pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
|||
tests: ~[],
|
||||
benchs: ~[]
|
||||
};
|
||||
pkg_src.build(&cx, ~[]);
|
||||
pkg_src.build(&cx, ~[], []);
|
||||
}
|
||||
|
||||
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||
main: Path) {
|
||||
let cx = default_context(sysroot);
|
||||
let cx = default_context(sysroot, root.clone());
|
||||
let pkg_src = PkgSrc {
|
||||
source_workspace: root.clone(),
|
||||
build_in_destination: false,
|
||||
|
|
@ -100,13 +113,76 @@ pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
|||
benchs: ~[]
|
||||
};
|
||||
|
||||
pkg_src.build(&cx, ~[]);
|
||||
pkg_src.build(&cx, ~[], []);
|
||||
}
|
||||
|
||||
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
|
||||
let cx = default_context(sysroot);
|
||||
pub fn install_pkg(cx: &BuildContext,
|
||||
workspace: Path,
|
||||
name: ~str,
|
||||
version: Version,
|
||||
// For now, these inputs are assumed to be inputs to each of the crates
|
||||
more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path
|
||||
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
|
||||
cx.install(PkgSrc::new(workspace.clone(), workspace, false, pkgid), &Everything);
|
||||
cx.install(PkgSrc::new(workspace.clone(), workspace, false, pkgid),
|
||||
&WhatToBuild{ build_type: Inferred,
|
||||
inputs_to_discover: more_inputs,
|
||||
sources: Everything });
|
||||
}
|
||||
|
||||
/// Builds an arbitrary library whose short name is `output`,
|
||||
/// by invoking `tool` with arguments `args` plus "-o %s", where %s
|
||||
/// is the platform-specific library name for `output`.
|
||||
/// Returns that platform-specific name.
|
||||
pub fn build_library_in_workspace(exec: &mut workcache::Exec,
|
||||
context: &mut Context,
|
||||
package_name: &str,
|
||||
tool: &str,
|
||||
flags: &[~str],
|
||||
paths: &[~str],
|
||||
output: &str) -> ~str {
|
||||
use command_failed = conditions::command_failed::cond;
|
||||
|
||||
let workspace = my_workspace(context, package_name);
|
||||
let workspace_build_dir = target_build_dir(&workspace);
|
||||
let out_name = workspace_build_dir.join_many([package_name.to_str(),
|
||||
platform_library_name(output)]);
|
||||
// make paths absolute
|
||||
let pkgid = PkgId::new(package_name);
|
||||
let absolute_paths = paths.map(|s| {
|
||||
let whatever = workspace.join_many([~"src",
|
||||
pkgid.to_str(),
|
||||
s.to_owned()]);
|
||||
whatever.as_str().unwrap().to_owned()
|
||||
});
|
||||
|
||||
let cc_args = cc_args();
|
||||
|
||||
let all_args = flags + absolute_paths + cc_args +
|
||||
~[~"-o", out_name.as_str().unwrap().to_owned()];
|
||||
let exit_code = run::process_status(tool, all_args);
|
||||
if exit_code != 0 {
|
||||
command_failed.raise((tool.to_owned(), all_args, exit_code))
|
||||
}
|
||||
else {
|
||||
let out_name_str = out_name.as_str().unwrap().to_owned();
|
||||
exec.discover_output("binary",
|
||||
out_name_str,
|
||||
digest_only_date(&out_name));
|
||||
context.add_library_path(out_name.dir_path());
|
||||
out_name_str
|
||||
}
|
||||
}
|
||||
|
||||
pub fn my_workspace(context: &Context, package_name: &str) -> Path {
|
||||
use bad_pkg_id = conditions::bad_pkg_id::cond;
|
||||
|
||||
// (this assumes no particular version is requested)
|
||||
let pkgid = PkgId::new(package_name);
|
||||
let workspaces = pkg_parent_workspaces(context, &pkgid);
|
||||
if workspaces.is_empty() {
|
||||
bad_pkg_id.raise((Path::new(package_name), package_name.to_owned()));
|
||||
}
|
||||
workspaces[0]
|
||||
}
|
||||
|
||||
fn mk_crate(p: Path) -> Crate {
|
||||
|
|
|
|||
|
|
@ -53,3 +53,9 @@ condition! {
|
|||
condition! {
|
||||
pub git_checkout_failed: (~str, Path) -> ();
|
||||
}
|
||||
|
||||
condition! {
|
||||
// str is output of applying the command (first component)
|
||||
// to the args (second component)
|
||||
pub command_failed: (~str, ~[~str], int) -> ~str;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,15 @@ impl BuildContext {
|
|||
pub fn compile_upto(&self) -> StopBefore {
|
||||
self.context.compile_upto()
|
||||
}
|
||||
|
||||
pub fn add_library_path(&mut self, p: Path) {
|
||||
debug!("Adding library path: {}", p.display());
|
||||
self.context.add_library_path(p);
|
||||
}
|
||||
|
||||
pub fn additional_library_paths(&self) -> ~[Path] {
|
||||
self.context.rustc_flags.additional_library_paths.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -85,6 +94,9 @@ pub struct RustcFlags {
|
|||
target: Option<~str>,
|
||||
// Target CPU (defaults to rustc's default target CPU)
|
||||
target_cpu: Option<~str>,
|
||||
// Additional library directories, which get passed with the -L flag
|
||||
// This can't be set with a rustpkg flag, only from package scripts
|
||||
additional_library_paths: ~[Path],
|
||||
// Any -Z features
|
||||
experimental_features: Option<~[~str]>
|
||||
}
|
||||
|
|
@ -99,6 +111,7 @@ impl Clone for RustcFlags {
|
|||
save_temps: self.save_temps,
|
||||
target: self.target.clone(),
|
||||
target_cpu: self.target_cpu.clone(),
|
||||
additional_library_paths: self.additional_library_paths.clone(),
|
||||
experimental_features: self.experimental_features.clone()
|
||||
}
|
||||
}
|
||||
|
|
@ -148,6 +161,10 @@ impl Context {
|
|||
pub fn compile_upto(&self) -> StopBefore {
|
||||
self.rustc_flags.compile_upto
|
||||
}
|
||||
|
||||
pub fn add_library_path(&mut self, p: Path) {
|
||||
self.rustc_flags.additional_library_paths.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
/// We assume that if ../../rustc exists, then we're running
|
||||
|
|
@ -210,6 +227,7 @@ impl RustcFlags {
|
|||
save_temps: false,
|
||||
target: None,
|
||||
target_cpu: None,
|
||||
additional_library_paths: ~[],
|
||||
experimental_features: None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use path_util::{find_dir_using_rust_path_hack, make_dir_rwx_recursive, default_w
|
|||
use path_util::{target_build_dir, versionize, dir_has_crate_file};
|
||||
use util::{compile_crate, DepMap};
|
||||
use workcache_support;
|
||||
use workcache_support::crate_tag;
|
||||
use workcache_support::{digest_only_date, digest_file_with_date, crate_tag};
|
||||
use extra::workcache;
|
||||
use extra::treemap::TreeMap;
|
||||
|
||||
|
|
@ -390,7 +390,8 @@ impl PkgSrc {
|
|||
deps: &mut DepMap,
|
||||
crates: &[Crate],
|
||||
cfgs: &[~str],
|
||||
what: OutputType) {
|
||||
what: OutputType,
|
||||
inputs_to_discover: &[(~str, Path)]) {
|
||||
for crate in crates.iter() {
|
||||
let path = self.start_dir.join(&crate.file);
|
||||
debug!("build_crates: compiling {}", path.display());
|
||||
|
|
@ -408,7 +409,19 @@ impl PkgSrc {
|
|||
let sub_dir = self.build_workspace().clone();
|
||||
let sub_flags = crate.flags.clone();
|
||||
let sub_deps = deps.clone();
|
||||
let inputs = inputs_to_discover.map(|&(ref k, ref p)|
|
||||
(k.clone(), p.as_str().unwrap().to_owned()));
|
||||
do prep.exec |exec| {
|
||||
for &(ref kind, ref p) in inputs.iter() {
|
||||
let pth = Path::new(p.clone());
|
||||
exec.discover_input(*kind, *p, if *kind == ~"file" {
|
||||
digest_file_with_date(&pth)
|
||||
} else if *kind == ~"binary" {
|
||||
digest_only_date(&Path::new(p.clone()))
|
||||
} else {
|
||||
fail!("Bad kind in build_crates")
|
||||
});
|
||||
}
|
||||
let result = compile_crate(&subcx,
|
||||
exec,
|
||||
&id,
|
||||
|
|
@ -452,22 +465,43 @@ impl PkgSrc {
|
|||
build_context: &BuildContext,
|
||||
// DepMap is a map from str (crate name) to (kind, name) --
|
||||
// it tracks discovered dependencies per-crate
|
||||
cfgs: ~[~str]) -> DepMap {
|
||||
cfgs: ~[~str],
|
||||
inputs_to_discover: &[(~str, Path)]) -> DepMap {
|
||||
let mut deps = TreeMap::new();
|
||||
|
||||
let libs = self.libs.clone();
|
||||
let mains = self.mains.clone();
|
||||
let tests = self.tests.clone();
|
||||
let benchs = self.benchs.clone();
|
||||
debug!("Building libs in {}, destination = {}",
|
||||
self.source_workspace.display(), self.build_workspace().display());
|
||||
self.build_crates(build_context, &mut deps, libs, cfgs, Lib);
|
||||
self.destination_workspace.display(),
|
||||
self.destination_workspace.display());
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
libs,
|
||||
cfgs,
|
||||
Lib,
|
||||
inputs_to_discover);
|
||||
debug!("Building mains");
|
||||
self.build_crates(build_context, &mut deps, mains, cfgs, Main);
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
mains,
|
||||
cfgs,
|
||||
Main,
|
||||
inputs_to_discover);
|
||||
debug!("Building tests");
|
||||
self.build_crates(build_context, &mut deps, tests, cfgs, Test);
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
tests,
|
||||
cfgs,
|
||||
Test,
|
||||
inputs_to_discover);
|
||||
debug!("Building benches");
|
||||
self.build_crates(build_context, &mut deps, benchs, cfgs, Bench);
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
benchs,
|
||||
cfgs,
|
||||
Bench,
|
||||
inputs_to_discover);
|
||||
deps
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -461,7 +461,6 @@ pub fn versionize(p: &Path, v: &Version) -> Path {
|
|||
p.with_filename(q)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
pub fn chmod_read_only(p: &Path) -> bool {
|
||||
#[fixed_stack_segment];
|
||||
|
|
@ -483,3 +482,6 @@ pub fn chmod_read_only(p: &Path) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn platform_library_name(s: &str) -> ~str {
|
||||
format!("{}{}{}", os::consts::DLL_PREFIX, s, os::consts::DLL_SUFFIX)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ use rustc::metadata::filesearch;
|
|||
use rustc::metadata::filesearch::rust_path;
|
||||
use extra::{getopts};
|
||||
use syntax::{ast, diagnostic};
|
||||
use util::*;
|
||||
use messages::{error, warn, note};
|
||||
use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
|
||||
use path_util::{U_RWX, in_rust_path};
|
||||
|
|
@ -47,15 +46,16 @@ use context::{Context, BuildContext,
|
|||
LLVMAssemble, LLVMCompileBitcode};
|
||||
use package_id::PkgId;
|
||||
use package_source::PkgSrc;
|
||||
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench, Tests};
|
||||
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
|
||||
use target::{Tests, MaybeCustom, Inferred, JustOne};
|
||||
use workcache_support::digest_only_date;
|
||||
use exit_codes::{COPY_FAILED_CODE, BAD_FLAG_CODE};
|
||||
|
||||
pub mod api;
|
||||
mod conditions;
|
||||
mod context;
|
||||
pub mod context;
|
||||
mod crate;
|
||||
mod exit_codes;
|
||||
pub mod exit_codes;
|
||||
mod installed_packages;
|
||||
mod messages;
|
||||
mod package_id;
|
||||
|
|
@ -67,7 +67,7 @@ mod target;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod util;
|
||||
mod version;
|
||||
pub mod version;
|
||||
pub mod workcache_support;
|
||||
mod workspace;
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ impl<'self> PkgScript<'self> {
|
|||
/// Given the path name for a package script
|
||||
/// and a package ID, parse the package script into
|
||||
/// a PkgScript that we can then execute
|
||||
fn parse<'a>(sysroot: @Path,
|
||||
fn parse<'a>(sysroot: Path,
|
||||
script: Path,
|
||||
workspace: &Path,
|
||||
id: &'a PkgId) -> PkgScript<'a> {
|
||||
|
|
@ -107,7 +107,7 @@ impl<'self> PkgScript<'self> {
|
|||
debug!("pkgscript parse: {}", sysroot.display());
|
||||
let options = @session::options {
|
||||
binary: binary,
|
||||
maybe_sysroot: Some(sysroot),
|
||||
maybe_sysroot: Some(@sysroot),
|
||||
crate_type: session::bin_crate,
|
||||
.. (*session::basic_options()).clone()
|
||||
};
|
||||
|
|
@ -132,12 +132,7 @@ impl<'self> PkgScript<'self> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Run the contents of this package script, where <what>
|
||||
/// is the command to pass to it (e.g., "build", "clean", "install")
|
||||
/// Returns a pair of an exit code and list of configs (obtained by
|
||||
/// calling the package script's configs() function if it exists
|
||||
fn run_custom(&mut self, exec: &mut workcache::Exec,
|
||||
sysroot: &Path) -> (~[~str], ExitCode) {
|
||||
fn build_custom(&mut self, exec: &mut workcache::Exec) -> ~str {
|
||||
let sess = self.sess;
|
||||
|
||||
debug!("Working directory = {}", self.build_dir.display());
|
||||
|
|
@ -152,17 +147,28 @@ impl<'self> PkgScript<'self> {
|
|||
&self.build_dir,
|
||||
sess,
|
||||
crate);
|
||||
debug!("Running program: {} {} {}", exe.display(),
|
||||
sysroot.display(), "install");
|
||||
// Discover the output
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
exec.discover_output("binary", exe.as_str().unwrap(), digest_only_date(&exe));
|
||||
// Discover the output
|
||||
exec.discover_output("binary", exe.as_str().unwrap().to_owned(), digest_only_date(&exe));
|
||||
exe.as_str().unwrap().to_owned()
|
||||
}
|
||||
|
||||
|
||||
/// Run the contents of this package script, where <what>
|
||||
/// is the command to pass to it (e.g., "build", "clean", "install")
|
||||
/// Returns a pair of an exit code and list of configs (obtained by
|
||||
/// calling the package script's configs() function if it exists
|
||||
fn run_custom(exe: &Path, sysroot: &Path) -> (~[~str], int) {
|
||||
debug!("Running program: {} {} {}", exe.as_str().unwrap().to_owned(),
|
||||
sysroot.display(), "install");
|
||||
// FIXME #7401 should support commands besides `install`
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let status = run::process_status(exe.as_str().unwrap(),
|
||||
[sysroot.as_str().unwrap().to_owned(), ~"install"]);
|
||||
if status != 0 {
|
||||
return (~[], status);
|
||||
debug!("run_custom: first pkg command failed with {:?}", status);
|
||||
(~[], status)
|
||||
}
|
||||
else {
|
||||
debug!("Running program (configs): {} {} {}",
|
||||
|
|
@ -170,6 +176,7 @@ impl<'self> PkgScript<'self> {
|
|||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let output = run::process_output(exe.as_str().unwrap(),
|
||||
[sysroot.as_str().unwrap().to_owned(), ~"configs"]);
|
||||
debug!("run_custom: second pkg command did {:?}", output.status);
|
||||
// Run the configs() function to get the configs
|
||||
let cfgs = str::from_utf8_slice(output.output).word_iter()
|
||||
.map(|w| w.to_owned()).collect();
|
||||
|
|
@ -263,7 +270,7 @@ impl CtxMethods for BuildContext {
|
|||
let cwd = os::getcwd();
|
||||
match cmd {
|
||||
"build" => {
|
||||
self.build_args(args, &Everything);
|
||||
self.build_args(args, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
}
|
||||
"clean" => {
|
||||
if args.len() < 1 {
|
||||
|
|
@ -301,12 +308,14 @@ impl CtxMethods for BuildContext {
|
|||
let inferred_pkgid =
|
||||
PkgId::new(cwd.filename_str().unwrap());
|
||||
self.install(PkgSrc::new(cwd, default_workspace(),
|
||||
true, inferred_pkgid), &Everything);
|
||||
true, inferred_pkgid),
|
||||
&WhatToBuild::new(MaybeCustom, Everything));
|
||||
}
|
||||
None => { usage::install(); return; }
|
||||
Some((ws, pkgid)) => {
|
||||
let pkg_src = PkgSrc::new(ws.clone(), ws.clone(), false, pkgid);
|
||||
self.install(pkg_src, &Everything);
|
||||
self.install(pkg_src, &WhatToBuild::new(MaybeCustom,
|
||||
Everything));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -320,7 +329,7 @@ impl CtxMethods for BuildContext {
|
|||
if workspaces.is_empty() {
|
||||
let d = default_workspace();
|
||||
let src = PkgSrc::new(d.clone(), d, false, pkgid.clone());
|
||||
self.install(src, &Everything);
|
||||
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
}
|
||||
else {
|
||||
for workspace in workspaces.iter() {
|
||||
|
|
@ -331,7 +340,7 @@ impl CtxMethods for BuildContext {
|
|||
dest,
|
||||
self.context.use_rust_path_hack,
|
||||
pkgid.clone());
|
||||
self.install(src, &Everything);
|
||||
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -354,7 +363,8 @@ impl CtxMethods for BuildContext {
|
|||
}
|
||||
"test" => {
|
||||
// Build the test executable
|
||||
let maybe_id_and_workspace = self.build_args(args, &Tests);
|
||||
let maybe_id_and_workspace = self.build_args(args,
|
||||
&WhatToBuild::new(MaybeCustom, Tests));
|
||||
match maybe_id_and_workspace {
|
||||
Some((pkg_id, workspace)) => {
|
||||
// Assuming it's built, run the tests
|
||||
|
|
@ -420,6 +430,7 @@ impl CtxMethods for BuildContext {
|
|||
pkgid = {} pkgsrc start_dir = {}", workspace.display(),
|
||||
in_rust_path(&workspace), is_git_dir(&workspace.join(&pkgid.path)),
|
||||
pkgid.to_str(), pkg_src.start_dir.display());
|
||||
debug!("build: what to build = {:?}", what_to_build);
|
||||
|
||||
// If workspace isn't in the RUST_PATH, and it's a git repo,
|
||||
// then clone it into the first entry in RUST_PATH, and repeat
|
||||
|
|
@ -448,27 +459,27 @@ impl CtxMethods for BuildContext {
|
|||
debug!("Package source directory = {}", pkg_src.to_str());
|
||||
let opt = pkg_src.package_script_option();
|
||||
debug!("Calling pkg_script_option on {:?}", opt);
|
||||
let cfgs = match pkg_src.package_script_option() {
|
||||
Some(package_script_path) => {
|
||||
let cfgs = match (pkg_src.package_script_option(), what_to_build.build_type) {
|
||||
(Some(package_script_path), MaybeCustom) => {
|
||||
let sysroot = self.sysroot_to_use();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let pkg_script_path_str = package_script_path.as_str().unwrap();
|
||||
let (cfgs, hook_result) =
|
||||
do self.workcache_context.with_prep(pkg_script_path_str) |prep| {
|
||||
let sub_sysroot = sysroot.clone();
|
||||
let package_script_path_clone = package_script_path.clone();
|
||||
let sub_ws = workspace.clone();
|
||||
let sub_id = pkgid.clone();
|
||||
declare_package_script_dependency(prep, &*pkg_src);
|
||||
// Build the package script if needed
|
||||
let script_build = format!("build_package_script({})",
|
||||
package_script_path.display());
|
||||
let pkg_exe = do self.workcache_context.with_prep(script_build) |prep| {
|
||||
let subsysroot = sysroot.clone();
|
||||
let psp = package_script_path.clone();
|
||||
let ws = workspace.clone();
|
||||
let pid = pkgid.clone();
|
||||
do prep.exec |exec| {
|
||||
let mut pscript = PkgScript::parse(@sub_sysroot.clone(),
|
||||
package_script_path_clone.clone(),
|
||||
&sub_ws,
|
||||
&sub_id);
|
||||
|
||||
pscript.run_custom(exec, &sub_sysroot)
|
||||
let mut pscript = PkgScript::parse(subsysroot.clone(),
|
||||
psp.clone(),
|
||||
&ws,
|
||||
&pid);
|
||||
pscript.build_custom(exec)
|
||||
}
|
||||
};
|
||||
// We always *run* the package script
|
||||
let (cfgs, hook_result) = PkgScript::run_custom(&Path::new(pkg_exe), &sysroot);
|
||||
debug!("Command return code = {:?}", hook_result);
|
||||
if hook_result != 0 {
|
||||
fail!("Error running custom build command")
|
||||
|
|
@ -477,7 +488,11 @@ impl CtxMethods for BuildContext {
|
|||
// otherwise, the package script succeeded
|
||||
cfgs
|
||||
}
|
||||
None => {
|
||||
(Some(_), Inferred) => {
|
||||
debug!("There is a package script, but we're ignoring it");
|
||||
~[]
|
||||
}
|
||||
(None, _) => {
|
||||
debug!("No package script, continuing");
|
||||
~[]
|
||||
}
|
||||
|
|
@ -486,13 +501,13 @@ impl CtxMethods for BuildContext {
|
|||
// If there was a package script, it should have finished
|
||||
// the build already. Otherwise...
|
||||
if !custom {
|
||||
match what_to_build {
|
||||
match what_to_build.sources {
|
||||
// Find crates inside the workspace
|
||||
&Everything => pkg_src.find_crates(),
|
||||
Everything => pkg_src.find_crates(),
|
||||
// Find only tests
|
||||
&Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path::new(s)) }),
|
||||
Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path::new(s)) }),
|
||||
// Don't infer any crates -- just build the one that was requested
|
||||
&JustOne(ref p) => {
|
||||
JustOne(ref p) => {
|
||||
// We expect that p is relative to the package source's start directory,
|
||||
// so check that assumption
|
||||
debug!("JustOne: p = {}", p.display());
|
||||
|
|
@ -512,7 +527,7 @@ impl CtxMethods for BuildContext {
|
|||
}
|
||||
}
|
||||
// Build it!
|
||||
pkg_src.build(self, cfgs);
|
||||
pkg_src.build(self, cfgs, []);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -551,6 +566,8 @@ impl CtxMethods for BuildContext {
|
|||
// just means inferring all the crates in it, then building each one.
|
||||
self.build(&mut pkg_src, what);
|
||||
|
||||
debug!("Done building package source {}", pkg_src.to_str());
|
||||
|
||||
let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
|
||||
pkg_src.tests.clone(), pkg_src.benchs.clone()];
|
||||
debug!("In declare inputs for {}", id.to_str());
|
||||
|
|
@ -823,6 +840,7 @@ pub fn main_args(args: &[~str]) -> int {
|
|||
save_temps: save_temps,
|
||||
target: target,
|
||||
target_cpu: target_cpu,
|
||||
additional_library_paths: ~[], // No way to set this from the rustpkg command line
|
||||
experimental_features: experimental_features
|
||||
};
|
||||
|
||||
|
|
@ -895,7 +913,8 @@ pub fn main_args(args: &[~str]) -> int {
|
|||
use_rust_path_hack: use_rust_path_hack,
|
||||
sysroot: sroot.clone(), // Currently, only tests override this
|
||||
},
|
||||
workcache_context: api::default_context(default_workspace()).workcache_context
|
||||
workcache_context: api::default_context(sroot.clone(),
|
||||
default_workspace()).workcache_context
|
||||
}.run(sub_cmd, rm_args.clone())
|
||||
};
|
||||
// FIXME #9262: This is using the same error code for all errors,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,31 @@ pub enum Target {
|
|||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum WhatToBuild {
|
||||
pub struct WhatToBuild {
|
||||
build_type: BuildType, // Whether or not to ignore the pkg.rs file
|
||||
sources: SourceType, // Which crates to build
|
||||
inputs_to_discover: ~[(~str, Path)] // Inputs to these crates to be discovered
|
||||
// (For now all of these inputs will be taken as discovered inputs
|
||||
// for all of the crates)
|
||||
// (Paired with their kinds)
|
||||
}
|
||||
|
||||
impl WhatToBuild {
|
||||
pub fn new(build_type: BuildType, sources: SourceType) -> WhatToBuild {
|
||||
WhatToBuild { build_type: build_type,
|
||||
sources: sources,
|
||||
inputs_to_discover: ~[] }
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum BuildType {
|
||||
Inferred, // Ignore the pkg.rs file even if one exists
|
||||
MaybeCustom // Use the pkg.rs file if it exists
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum SourceType {
|
||||
/// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
|
||||
JustOne(Path),
|
||||
/// Build any test.rs files that can be recursively found in the active workspace
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use path_util::{target_executable_in_workspace, target_test_in_workspace,
|
|||
library_in_workspace, installed_library_in_workspace,
|
||||
built_bench_in_workspace, built_test_in_workspace,
|
||||
built_library_in_workspace, built_executable_in_workspace, target_build_dir,
|
||||
chmod_read_only};
|
||||
chmod_read_only, platform_library_name};
|
||||
use rustc::back::link::get_cc_prog;
|
||||
use rustc::metadata::filesearch::rust_path;
|
||||
use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
|
||||
|
|
@ -299,12 +299,6 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
|
|||
cmd, args, str::from_utf8(output.output),
|
||||
str::from_utf8(output.error),
|
||||
output.status);
|
||||
/*
|
||||
By the way, rustpkg *won't* return a nonzero exit code if it fails --
|
||||
see #4547
|
||||
So tests that use this need to check the existence of a file
|
||||
to make sure the command succeeded
|
||||
*/
|
||||
if output.status != 0 {
|
||||
debug!("Command {} {:?} failed with exit code {:?}; its output was --- {} ---",
|
||||
cmd, args, output.status,
|
||||
|
|
@ -600,7 +594,7 @@ fn test_install_valid() {
|
|||
temp_workspace.clone(),
|
||||
false,
|
||||
temp_pkg_id.clone());
|
||||
ctxt.install(src, &Everything);
|
||||
ctxt.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
// Check that all files exist
|
||||
let exec = target_executable_in_workspace(&temp_pkg_id, temp_workspace);
|
||||
debug!("exec = {}", exec.display());
|
||||
|
|
@ -639,7 +633,7 @@ fn test_install_invalid() {
|
|||
temp_workspace.clone(),
|
||||
false,
|
||||
pkgid.clone());
|
||||
ctxt.install(pkg_src, &Everything);
|
||||
ctxt.install(pkg_src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
};
|
||||
// Not the best test -- doesn't test that we failed in the right way.
|
||||
// Best we can do for now.
|
||||
|
|
@ -897,14 +891,14 @@ fn rustpkg_local_pkg() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore (reason = "test makes bogus assumptions about build directory layout: issue #8690")]
|
||||
fn package_script_with_default_build() {
|
||||
let dir = create_local_package(&PkgId::new("fancy-lib"));
|
||||
let dir = dir.path();
|
||||
debug!("dir = {}", dir.display());
|
||||
let mut source = test_sysroot().dir_path();
|
||||
source.pop(); source.pop();
|
||||
source.push_many(["src", "librustpkg", "testsuite", "pass", "src", "fancy-lib", "pkg.rs"]);
|
||||
let source = Path::new(file!()).dir_path().join_many(
|
||||
[~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"pkg.rs"]);
|
||||
debug!("package_script_with_default_build: {}", source.display());
|
||||
if !os::copy_file(&source,
|
||||
&dir.join_many(["src", "fancy-lib-0.1", "pkg.rs"])) {
|
||||
|
|
@ -912,7 +906,10 @@ fn package_script_with_default_build() {
|
|||
}
|
||||
command_line_test([~"install", ~"fancy-lib"], dir);
|
||||
assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion);
|
||||
assert!(os::path_exists(&target_build_dir(dir).join_many(["fancy-lib", "generated.rs"])));
|
||||
assert!(os::path_exists(&target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"])));
|
||||
let generated_path = target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]);
|
||||
debug!("generated path = {}", generated_path.display());
|
||||
assert!(os::path_exists(&generated_path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2251,6 +2248,106 @@ fn find_sources_in_cwd() {
|
|||
assert_executable_exists(&source_dir.join(".rust"), "foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_dependency_ok() {
|
||||
// Pkg has a custom build script that adds a single C file as a dependency, and
|
||||
// registers a hook to build it if it's not fresh
|
||||
// After running `build`, test that the C library built
|
||||
|
||||
let dir = create_local_package(&PkgId::new("cdep"));
|
||||
let dir = dir.path();
|
||||
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
|
||||
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
|
||||
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
|
||||
writeFile(&dir.join_many(["src", "cdep-0.1", "foo.c"]), "void f() {}");
|
||||
|
||||
debug!("dir = {}", dir.display());
|
||||
let source = Path::new(file!()).dir_path().join_many(
|
||||
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
|
||||
if !os::copy_file(&source,
|
||||
&dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) {
|
||||
fail!("Couldn't copy file");
|
||||
}
|
||||
command_line_test([~"build", ~"cdep"], dir);
|
||||
assert_executable_exists(dir, "cdep");
|
||||
let out_dir = target_build_dir(dir).join("cdep");
|
||||
let c_library_path = out_dir.join(platform_library_name("foo"));
|
||||
debug!("c library path: {}", c_library_path.display());
|
||||
assert!(os::path_exists(&c_library_path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_dependency_no_rebuilding() {
|
||||
let dir = create_local_package(&PkgId::new("cdep"));
|
||||
let dir = dir.path();
|
||||
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
|
||||
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
|
||||
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
|
||||
writeFile(&dir.join_many(["src", "cdep-0.1", "foo.c"]), "void f() {}");
|
||||
|
||||
debug!("dir = {}", dir.display());
|
||||
let source = Path::new(file!()).dir_path().join_many(
|
||||
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
|
||||
if !os::copy_file(&source,
|
||||
&dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"])) {
|
||||
fail!("Couldn't copy file");
|
||||
}
|
||||
command_line_test([~"build", ~"cdep"], dir);
|
||||
assert_executable_exists(dir, "cdep");
|
||||
let out_dir = target_build_dir(dir).join("cdep");
|
||||
let c_library_path = out_dir.join(platform_library_name("foo"));
|
||||
debug!("c library path: {}", c_library_path.display());
|
||||
assert!(os::path_exists(&c_library_path));
|
||||
|
||||
// Now, make it read-only so rebuilding will fail
|
||||
assert!(chmod_read_only(&c_library_path));
|
||||
|
||||
match command_line_test_partial([~"build", ~"cdep"], dir) {
|
||||
Success(*) => (), // ok
|
||||
Fail(status) if status == 65 => fail!("test_c_dependency_no_rebuilding failed: \
|
||||
it tried to rebuild foo.c"),
|
||||
Fail(_) => fail!("test_c_dependency_no_rebuilding failed for some other reason")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_c_dependency_yes_rebuilding() {
|
||||
let dir = create_local_package(&PkgId::new("cdep"));
|
||||
let dir = dir.path();
|
||||
writeFile(&dir.join_many(["src", "cdep-0.1", "main.rs"]),
|
||||
"#[link_args = \"-lfoo\"]\nextern { fn f(); } \
|
||||
\n#[fixed_stack_segment]\nfn main() { unsafe { f(); } }");
|
||||
let c_file_name = dir.join_many(["src", "cdep-0.1", "foo.c"]);
|
||||
writeFile(&c_file_name, "void f() {}");
|
||||
|
||||
let source = Path::new(file!()).dir_path().join_many(
|
||||
[~"testsuite", ~"pass", ~"src", ~"c-dependencies", ~"pkg.rs"]);
|
||||
let target = dir.join_many([~"src", ~"cdep-0.1", ~"pkg.rs"]);
|
||||
debug!("Copying {} -> {}", source.display(), target.display());
|
||||
if !os::copy_file(&source, &target) {
|
||||
fail!("Couldn't copy file");
|
||||
}
|
||||
command_line_test([~"build", ~"cdep"], dir);
|
||||
assert_executable_exists(dir, "cdep");
|
||||
let out_dir = target_build_dir(dir).join("cdep");
|
||||
let c_library_path = out_dir.join(platform_library_name("foo"));
|
||||
debug!("c library path: {}", c_library_path.display());
|
||||
assert!(os::path_exists(&c_library_path));
|
||||
|
||||
// Now, make the Rust library read-only so rebuilding will fail
|
||||
match built_library_in_workspace(&PkgId::new("cdep"), dir) {
|
||||
Some(ref pth) => assert!(chmod_read_only(pth)),
|
||||
None => assert_built_library_exists(dir, "cdep")
|
||||
}
|
||||
|
||||
match command_line_test_partial([~"build", ~"cdep"], dir) {
|
||||
Success(*) => fail!("test_c_dependency_yes_rebuilding failed: \
|
||||
it didn't rebuild and should have"),
|
||||
Fail(status) if status == 65 => (),
|
||||
Fail(_) => fail!("test_c_dependency_yes_rebuilding failed for some other reason")
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if p exists and is executable
|
||||
fn is_executable(p: &Path) -> bool {
|
||||
use std::libc::consts::os::posix88::{S_IXUSR};
|
||||
|
|
|
|||
13
src/librustpkg/testsuite/pass/src/c-dependencies/bar.rs
Normal file
13
src/librustpkg/testsuite/pass/src/c-dependencies/bar.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn assert_true() {
|
||||
assert!(true);
|
||||
}
|
||||
12
src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs
Normal file
12
src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn do_nothing() {
|
||||
}
|
||||
14
src/librustpkg/testsuite/pass/src/c-dependencies/lib.rs
Normal file
14
src/librustpkg/testsuite/pass/src/c-dependencies/lib.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern mod std;
|
||||
|
||||
pub mod foo;
|
||||
pub mod bar;
|
||||
83
src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
Normal file
83
src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern mod rustpkg;
|
||||
extern mod rustc;
|
||||
|
||||
use std::{io, os, task};
|
||||
use rustpkg::api;
|
||||
use rustpkg::version::NoVersion;
|
||||
use rustpkg::workcache_support::digest_file_with_date;
|
||||
use rustpkg::exit_codes::COPY_FAILED_CODE;
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
|
||||
// by convention, first arg is sysroot
|
||||
if args.len() < 2 {
|
||||
fail!("Package script requires a directory where rustc libraries live as the first \
|
||||
argument");
|
||||
}
|
||||
|
||||
let path_for_db = api::default_workspace();
|
||||
debug!("path_for_db = {}", path_for_db.display());
|
||||
|
||||
let sysroot_arg = args[1].clone();
|
||||
let sysroot = Path::new(sysroot_arg);
|
||||
if !os::path_exists(&sysroot) {
|
||||
fail!("Package script requires a sysroot that exists; {} doesn't", sysroot.display());
|
||||
}
|
||||
|
||||
if args[2] != ~"install" {
|
||||
io::println(format!("Warning: I don't know how to {}", args[2]));
|
||||
return;
|
||||
}
|
||||
|
||||
let mut context = api::default_context(sysroot, path_for_db);
|
||||
let my_workspace = api::my_workspace(&context.context, "cdep");
|
||||
let foo_c_name = my_workspace.join_many(["src", "cdep-0.1", "foo.c"]);
|
||||
|
||||
let out_lib_path = do context.workcache_context.with_prep("foo.c") |prep| {
|
||||
let sub_cx = context.context.clone();
|
||||
debug!("foo_c_name = {}", foo_c_name.display());
|
||||
prep.declare_input("file",
|
||||
foo_c_name.as_str().unwrap().to_owned(),
|
||||
digest_file_with_date(&foo_c_name));
|
||||
let out_path = do prep.exec |exec| {
|
||||
let out_path = api::build_library_in_workspace(exec,
|
||||
&mut sub_cx.clone(),
|
||||
"cdep",
|
||||
"gcc",
|
||||
[~"-c"],
|
||||
[~"foo.c"],
|
||||
"foo");
|
||||
let out_p = Path::new(out_path);
|
||||
out_p.as_str().unwrap().to_owned()
|
||||
};
|
||||
out_path
|
||||
};
|
||||
let out_lib_path = Path::new(out_lib_path);
|
||||
debug!("out_lib_path = {}", out_lib_path.display());
|
||||
context.add_library_path(out_lib_path.dir_path());
|
||||
|
||||
let context_clone = context.clone();
|
||||
let task_res = do task::try {
|
||||
let mut cc = context_clone.clone();
|
||||
api::install_pkg(&mut cc,
|
||||
os::getcwd(),
|
||||
~"cdep",
|
||||
NoVersion,
|
||||
~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]);
|
||||
};
|
||||
|
||||
if task_res.is_err() {
|
||||
os::set_exit_status(COPY_FAILED_CODE);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,4 +21,4 @@ extern mod std;
|
|||
|
||||
pub mod foo;
|
||||
pub mod bar;
|
||||
#[path = "../../build/fancy_lib/generated.rs"] pub mod generated;
|
||||
#[path = "../../build/fancy-lib/generated.rs"] pub mod generated;
|
||||
|
|
|
|||
|
|
@ -15,42 +15,37 @@ use std::{io, os};
|
|||
use rustpkg::api;
|
||||
use rustpkg::version::NoVersion;
|
||||
|
||||
use rustc::metadata::filesearch;
|
||||
|
||||
pub fn main() {
|
||||
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
||||
let args = os::args();
|
||||
|
||||
// by convention, first arg is sysroot
|
||||
if args.len() < 2 {
|
||||
debug!("Failing, arg len");
|
||||
fail!("Package script requires a directory where rustc libraries live as the first \
|
||||
argument");
|
||||
}
|
||||
|
||||
let sysroot_arg = args[1].clone();
|
||||
let sysroot = Path(sysroot_arg);
|
||||
let sysroot = Path::new(sysroot_arg);
|
||||
if !os::path_exists(&sysroot) {
|
||||
fail!("Package script requires a sysroot that exists; %s doesn't", sysroot.to_str());
|
||||
debug!("Failing, sysroot");
|
||||
fail!("Package script requires a sysroot that exists;{} doesn't", sysroot.display());
|
||||
}
|
||||
|
||||
if args[2] != ~"install" {
|
||||
debug!("Failing, weird command");
|
||||
println!("Warning: I don't know how to {}", args[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
let out_path = Path("build/fancy-lib");
|
||||
if !os::path_exists(&out_path) {
|
||||
assert!(os::make_dir(&out_path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
|
||||
}
|
||||
debug!("Checking self_exe_path");
|
||||
let out_path = os::self_exe_path().expect("Couldn't get self_exe path");
|
||||
|
||||
let file = io::file_writer(&out_path.push("generated.rs"),
|
||||
[io::Create]).unwrap();
|
||||
file.write_str("pub fn wheeeee() { for [1, 2, 3].each() |_| { assert!(true); } }");
|
||||
debug!("Writing file");
|
||||
let file = io::file_writer(&out_path.join("generated.rs"), [io::Create]).unwrap();
|
||||
file.write_str("pub fn wheeeee() { let xs = [1, 2, 3]; \
|
||||
for _ in xs.iter() { assert!(true); } }");
|
||||
|
||||
|
||||
debug!("api_____install_____lib, my sysroot:");
|
||||
debug!(sysroot.to_str());
|
||||
|
||||
api::install_lib(@sysroot, os::getcwd(), ~"fancy-lib", Path("lib.rs"),
|
||||
NoVersion);
|
||||
let context = api::default_context(sysroot, api::default_workspace());
|
||||
api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,13 @@ use context::{in_target, StopBefore, Link, Assemble, BuildContext};
|
|||
use package_id::PkgId;
|
||||
use package_source::PkgSrc;
|
||||
use workspace::pkg_parent_workspaces;
|
||||
use path_util::{U_RWX, system_library, target_build_dir};
|
||||
use path_util::{system_library, target_build_dir};
|
||||
use path_util::{default_workspace, built_library_in_workspace};
|
||||
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
|
||||
pub use target::{Target, Build, Install};
|
||||
use extra::treemap::TreeMap;
|
||||
use path_util::U_RWX;
|
||||
pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
|
||||
use workcache_support::{digest_file_with_date, digest_only_date};
|
||||
|
||||
// It would be nice to have the list of commands in just one place -- for example,
|
||||
|
|
@ -233,12 +235,14 @@ pub fn compile_input(context: &BuildContext,
|
|||
Nothing => link::output_type_exe
|
||||
};
|
||||
|
||||
debug!("Output type = {:?}", output_type);
|
||||
|
||||
let options = @session::options {
|
||||
crate_type: crate_type,
|
||||
optimize: if opt { session::Aggressive } else { session::No },
|
||||
test: what == Test || what == Bench,
|
||||
maybe_sysroot: Some(sysroot_to_use),
|
||||
addl_lib_search_paths: @mut (~[]),
|
||||
addl_lib_search_paths: @mut context.additional_library_paths(),
|
||||
output_type: output_type,
|
||||
.. (*driver::build_session_options(binary,
|
||||
&matches,
|
||||
|
|
@ -246,6 +250,8 @@ pub fn compile_input(context: &BuildContext,
|
|||
@diagnostic::Emitter)).clone()
|
||||
};
|
||||
|
||||
debug!("Created options...");
|
||||
|
||||
let addl_lib_search_paths = @mut options.addl_lib_search_paths;
|
||||
// Make sure all the library directories actually exist, since the linker will complain
|
||||
// otherwise
|
||||
|
|
@ -258,16 +264,22 @@ pub fn compile_input(context: &BuildContext,
|
|||
}
|
||||
}
|
||||
|
||||
debug!("About to build session...");
|
||||
|
||||
let sess = driver::build_session(options,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
|
||||
debug!("About to build config...");
|
||||
|
||||
// Infer dependencies that rustpkg needs to build, by scanning for
|
||||
// `extern mod` directives.
|
||||
let cfg = driver::build_configuration(sess);
|
||||
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||
crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
|
||||
|
||||
debug!("About to call find_and_install_dependencies...");
|
||||
|
||||
find_and_install_dependencies(context, pkg_id, in_file, sess, exec, &crate, deps,
|
||||
|p| {
|
||||
debug!("a dependency: {}", p.display());
|
||||
|
|
@ -377,7 +389,6 @@ pub fn compile_crate_from_input(input: &Path,
|
|||
|
||||
debug!("Built {}, date = {:?}", outputs.out_filename.display(),
|
||||
datestamp(&outputs.out_filename));
|
||||
|
||||
Some(outputs.out_filename)
|
||||
}
|
||||
|
||||
|
|
@ -431,7 +442,9 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
|
|||
};
|
||||
debug!("Finding and installing... {}", lib_name);
|
||||
// Check standard Rust library path first
|
||||
match system_library(&self.context.sysroot(), lib_name) {
|
||||
let whatever = system_library(&self.context.sysroot(), lib_name);
|
||||
debug!("system library returned {:?}", whatever);
|
||||
match whatever {
|
||||
Some(ref installed_path) => {
|
||||
debug!("It exists: {}", installed_path.display());
|
||||
// Say that [path for c] has a discovered dependency on
|
||||
|
|
@ -478,7 +491,10 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
|
|||
self.context.context.use_rust_path_hack,
|
||||
pkg_id.clone());
|
||||
let (outputs_disc, inputs_disc) =
|
||||
self.context.install(pkg_src, &JustOne(Path::new(lib_crate_filename)));
|
||||
self.context.install(
|
||||
pkg_src,
|
||||
&WhatToBuild::new(Inferred,
|
||||
JustOne(Path::new(lib_crate_filename))));
|
||||
debug!("Installed {}, returned {:?} dependencies and \
|
||||
{:?} transitive dependencies",
|
||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
||||
|
|
|
|||
|
|
@ -490,7 +490,6 @@ pub struct Formatter<'self> {
|
|||
|
||||
/// Output buffer.
|
||||
buf: &'self mut io::Writer,
|
||||
|
||||
priv curarg: vec::VecIterator<'self, Argument<'self>>,
|
||||
priv args: &'self [Argument<'self>],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1009,7 +1009,7 @@ impl<R:Reader,C> Reader for Wrapper<R, C> {
|
|||
}
|
||||
|
||||
pub struct FILERes {
|
||||
f: *libc::FILE,
|
||||
priv f: *libc::FILE,
|
||||
}
|
||||
|
||||
impl FILERes {
|
||||
|
|
@ -1282,7 +1282,7 @@ impl Writer for fd_t {
|
|||
}
|
||||
|
||||
pub struct FdRes {
|
||||
fd: fd_t,
|
||||
priv fd: fd_t,
|
||||
}
|
||||
|
||||
impl FdRes {
|
||||
|
|
@ -1792,7 +1792,7 @@ pub mod fsync {
|
|||
|
||||
// Artifacts that need to fsync on destruction
|
||||
pub struct Res<t> {
|
||||
arg: Arg<t>,
|
||||
priv arg: Arg<t>,
|
||||
}
|
||||
|
||||
impl <t> Res<t> {
|
||||
|
|
@ -1815,9 +1815,9 @@ pub mod fsync {
|
|||
}
|
||||
|
||||
pub struct Arg<t> {
|
||||
val: t,
|
||||
opt_level: Option<Level>,
|
||||
fsync_fn: extern "Rust" fn(f: &t, Level) -> int,
|
||||
priv val: t,
|
||||
priv opt_level: Option<Level>,
|
||||
priv fsync_fn: extern "Rust" fn(f: &t, Level) -> int,
|
||||
}
|
||||
|
||||
// fsync file after executing blk
|
||||
|
|
|
|||
|
|
@ -1790,9 +1790,9 @@ impl<'self, A, St> Iterator<A> for Unfold<'self, A, St> {
|
|||
#[deriving(Clone)]
|
||||
pub struct Counter<A> {
|
||||
/// The current state the counter is at (next value to be yielded)
|
||||
state: A,
|
||||
priv state: A,
|
||||
/// The amount that this iterator is stepping by
|
||||
step: A
|
||||
priv step: A
|
||||
}
|
||||
|
||||
/// Creates a new counter with the specified start/step
|
||||
|
|
|
|||
|
|
@ -8,38 +8,226 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Sampling from random distributions
|
||||
/*!
|
||||
Sampling from random distributions.
|
||||
|
||||
// Some implementations use the Ziggurat method
|
||||
// https://en.wikipedia.org/wiki/Ziggurat_algorithm
|
||||
//
|
||||
// The version used here is ZIGNOR [Doornik 2005, "An Improved
|
||||
// Ziggurat Method to Generate Normal Random Samples"] which is slower
|
||||
// (about double, it generates an extra random number) than the
|
||||
// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for
|
||||
// Generating Random Variables"], but more robust. If one wanted, one
|
||||
// could implement VIZIGNOR the ZIGNOR paper for more speed.
|
||||
This is a generalization of `Rand` to allow parameters to control the
|
||||
exact properties of the generated values, e.g. the mean and standard
|
||||
deviation of a normal distribution. The `Sample` trait is the most
|
||||
general, and allows for generating values that change some state
|
||||
internally. The `IndependentSample` trait is for generating values
|
||||
that do not need to record state.
|
||||
|
||||
*/
|
||||
|
||||
use iter::range;
|
||||
use option::{Some, None};
|
||||
use num;
|
||||
use rand::{Rng,Rand};
|
||||
use clone::Clone;
|
||||
|
||||
pub use self::range::Range;
|
||||
|
||||
pub mod range;
|
||||
|
||||
/// Types that can be used to create a random instance of `Support`.
|
||||
pub trait Sample<Support> {
|
||||
/// Generate a random value of `Support`, using `rng` as the
|
||||
/// source of randomness.
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
|
||||
}
|
||||
|
||||
/// `Sample`s that do not require keeping track of state.
|
||||
///
|
||||
/// Since no state is recored, each sample is (statistically)
|
||||
/// independent of all others, assuming the `Rng` used has this
|
||||
/// property.
|
||||
// XXX maybe having this separate is overkill (the only reason is to
|
||||
// take &self rather than &mut self)? or maybe this should be the
|
||||
// trait called `Sample` and the other should be `DependentSample`.
|
||||
pub trait IndependentSample<Support>: Sample<Support> {
|
||||
/// Generate a random value.
|
||||
fn ind_sample<R: Rng>(&self, &mut R) -> Support;
|
||||
}
|
||||
|
||||
/// A wrapper for generating types that implement `Rand` via the
|
||||
/// `Sample` & `IndependentSample` traits.
|
||||
pub struct RandSample<Sup>;
|
||||
|
||||
impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
|
||||
rng.gen()
|
||||
}
|
||||
}
|
||||
|
||||
/// A value with a particular weight for use with `WeightedChoice`.
|
||||
pub struct Weighted<T> {
|
||||
/// The numerical weight of this item
|
||||
weight: uint,
|
||||
/// The actual item which is being weighted
|
||||
item: T,
|
||||
}
|
||||
|
||||
/// A distribution that selects from a finite collection of weighted items.
|
||||
///
|
||||
/// Each item has an associated weight that influences how likely it
|
||||
/// is to be chosen: higher weight is more likely.
|
||||
///
|
||||
/// The `Clone` restriction is a limitation of the `Sample` and
|
||||
/// `IndepedentSample` traits. Note that `&T` is (cheaply) `Clone` for
|
||||
/// all `T`, as is `uint`, so one can store references or indices into
|
||||
/// another vector.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::distributions::{Weighted, WeightedChoice, IndepedentSample};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let wc = WeightedChoice::new(~[Weighted { weight: 2, item: 'a' },
|
||||
/// Weighted { weight: 4, item: 'b' },
|
||||
/// Weighted { weight: 1, item: 'c' }]);
|
||||
/// let rng = rand::task_rng();
|
||||
/// for _ in range(0, 16) {
|
||||
/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
|
||||
/// println!("{}", wc.ind_sample(rng));
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct WeightedChoice<T> {
|
||||
priv items: ~[Weighted<T>],
|
||||
priv weight_range: Range<uint>
|
||||
}
|
||||
|
||||
impl<T: Clone> WeightedChoice<T> {
|
||||
/// Create a new `WeightedChoice`.
|
||||
///
|
||||
/// Fails if:
|
||||
/// - `v` is empty
|
||||
/// - the total weight is 0
|
||||
/// - the total weight is larger than a `uint` can contain.
|
||||
pub fn new(mut items: ~[Weighted<T>]) -> WeightedChoice<T> {
|
||||
// strictly speaking, this is subsumed by the total weight == 0 case
|
||||
assert!(!items.is_empty(), "WeightedChoice::new called with no items");
|
||||
|
||||
let mut running_total = 0u;
|
||||
|
||||
// we convert the list from individual weights to cumulative
|
||||
// weights so we can binary search. This *could* drop elements
|
||||
// with weight == 0 as an optimisation.
|
||||
for item in items.mut_iter() {
|
||||
running_total = running_total.checked_add(&item.weight)
|
||||
.expect("WeightedChoice::new called with a total weight larger \
|
||||
than a uint can contain");
|
||||
|
||||
item.weight = running_total;
|
||||
}
|
||||
assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");
|
||||
|
||||
WeightedChoice {
|
||||
items: items,
|
||||
// we're likely to be generating numbers in this range
|
||||
// relatively often, so might as well cache it
|
||||
weight_range: Range::new(0, running_total)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Sample<T> for WeightedChoice<T> {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
|
||||
}
|
||||
|
||||
impl<T: Clone> IndependentSample<T> for WeightedChoice<T> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
|
||||
// we want to find the first element that has cumulative
|
||||
// weight > sample_weight, which we do by binary since the
|
||||
// cumulative weights of self.items are sorted.
|
||||
|
||||
// choose a weight in [0, total_weight)
|
||||
let sample_weight = self.weight_range.ind_sample(rng);
|
||||
|
||||
// short circuit when it's the first item
|
||||
if sample_weight < self.items[0].weight {
|
||||
return self.items[0].item.clone();
|
||||
}
|
||||
|
||||
let mut idx = 0;
|
||||
let mut modifier = self.items.len();
|
||||
|
||||
// now we know that every possibility has an element to the
|
||||
// left, so we can just search for the last element that has
|
||||
// cumulative weight <= sample_weight, then the next one will
|
||||
// be "it". (Note that this greatest element will never be the
|
||||
// last element of the vector, since sample_weight is chosen
|
||||
// in [0, total_weight) and the cumulative weight of the last
|
||||
// one is exactly the total weight.)
|
||||
while modifier > 1 {
|
||||
let i = idx + modifier / 2;
|
||||
if self.items[i].weight <= sample_weight {
|
||||
// we're small, so look to the right, but allow this
|
||||
// exact element still.
|
||||
idx = i;
|
||||
// we need the `/ 2` to round up otherwise we'll drop
|
||||
// the trailing elements when `modifier` is odd.
|
||||
modifier += 1;
|
||||
} else {
|
||||
// otherwise we're too big, so go left. (i.e. do
|
||||
// nothing)
|
||||
}
|
||||
modifier /= 2;
|
||||
}
|
||||
return self.items[idx + 1].item.clone();
|
||||
}
|
||||
}
|
||||
|
||||
mod ziggurat_tables;
|
||||
|
||||
// inlining should mean there is no performance penalty for this
|
||||
#[inline]
|
||||
/// Sample a random number using the Ziggurat method (specifically the
|
||||
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
|
||||
/// directly from the paper:
|
||||
///
|
||||
/// * `rng`: source of randomness
|
||||
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
|
||||
/// * `X`: the $x_i$ abscissae.
|
||||
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
|
||||
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
|
||||
/// * `pdf`: the probability density function
|
||||
/// * `zero_case`: manual sampling from the tail when we chose the
|
||||
/// bottom box (i.e. i == 0)
|
||||
|
||||
// the perf improvement (25-50%) is definitely worth the extra code
|
||||
// size from force-inlining.
|
||||
#[inline(always)]
|
||||
fn ziggurat<R:Rng>(rng: &mut R,
|
||||
center_u: bool,
|
||||
symmetric: bool,
|
||||
X: ziggurat_tables::ZigTable,
|
||||
F: ziggurat_tables::ZigTable,
|
||||
F_DIFF: ziggurat_tables::ZigTable,
|
||||
pdf: &'static fn(f64) -> f64, // probability density function
|
||||
pdf: &'static fn(f64) -> f64,
|
||||
zero_case: &'static fn(&mut R, f64) -> f64) -> f64 {
|
||||
static SCALE: f64 = (1u64 << 53) as f64;
|
||||
loop {
|
||||
let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()};
|
||||
let i: uint = rng.gen::<uint>() & 0xff;
|
||||
// reimplement the f64 generation as an optimisation suggested
|
||||
// by the Doornik paper: we have a lot of precision-space
|
||||
// (i.e. there are 11 bits of the 64 of a u64 to use after
|
||||
// creating a f64), so we might as well reuse some to save
|
||||
// generating a whole extra random number. (Seems to be 15%
|
||||
// faster.)
|
||||
let bits: u64 = rng.gen();
|
||||
let i = (bits & 0xff) as uint;
|
||||
let f = (bits >> 11) as f64 / SCALE;
|
||||
|
||||
// u is either U(-1, 1) or U(0, 1) depending on if this is a
|
||||
// symmetric distribution or not.
|
||||
let u = if symmetric {2.0 * f - 1.0} else {f};
|
||||
let x = u * X[i];
|
||||
|
||||
let test_x = if center_u {num::abs(x)} else {x};
|
||||
let test_x = if symmetric {num::abs(x)} else {x};
|
||||
|
||||
// algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
|
||||
if test_x < X[i + 1] {
|
||||
|
|
@ -49,30 +237,25 @@ fn ziggurat<R:Rng>(rng: &mut R,
|
|||
return zero_case(rng, u);
|
||||
}
|
||||
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
|
||||
if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) {
|
||||
if F[i + 1] + F_DIFF[i + 1] * rng.gen() < pdf(x) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a
|
||||
/// standard normal, or Gaussian). Multiplying the generated values by the
|
||||
/// desired standard deviation `sigma` then adding the desired mean `mu` will
|
||||
/// give N(mu, sigma^2) distributed random numbers.
|
||||
/// A wrapper around an `f64` to generate N(0, 1) random numbers
|
||||
/// (a.k.a. a standard normal, or Gaussian).
|
||||
///
|
||||
/// Note that this has to be unwrapped before use as an `f64` (using either
|
||||
/// `*` or `cast::transmute` is safe).
|
||||
/// See `Normal` for the general normal distribution. That this has to
|
||||
/// be unwrapped before use as an `f64` (using either `*` or
|
||||
/// `cast::transmute` is safe).
|
||||
///
|
||||
/// # Example
|
||||
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
|
||||
///
|
||||
/// ```
|
||||
/// use std::rand::distributions::StandardNormal;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
|
||||
/// println!("{} is from a N(2, 9) distribution", normal)
|
||||
/// }
|
||||
/// ```
|
||||
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random
|
||||
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
|
||||
/// College, Oxford
|
||||
pub struct StandardNormal(f64);
|
||||
|
||||
impl Rand for StandardNormal {
|
||||
|
|
@ -110,23 +293,62 @@ impl Rand for StandardNormal {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by
|
||||
/// the desired rate `lambda` will give Exp(lambda) distributed random
|
||||
/// numbers.
|
||||
/// The normal distribution `N(mean, std_dev**2)`.
|
||||
///
|
||||
/// Note that this has to be unwrapped before use as an `f64` (using either
|
||||
/// `*` or `cast::transmute` is safe).
|
||||
/// This uses the ZIGNOR variant of the Ziggurat method, see
|
||||
/// `StandardNormal` for more details.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::rand::distributions::Exp1;
|
||||
/// use std::rand;
|
||||
/// use std::rand::distributions::{Normal, IndependentSample};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let exp2 = (*rand::random::<Exp1>()) * 0.5;
|
||||
/// println!("{} is from a Exp(2) distribution", exp2);
|
||||
/// let normal = Normal::new(2.0, 3.0);
|
||||
/// let v = normal.ind_sample(rand::task_rng());
|
||||
/// println!("{} is from a N(2, 9) distribution", v)
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Normal {
|
||||
priv mean: f64,
|
||||
priv std_dev: f64
|
||||
}
|
||||
|
||||
impl Normal {
|
||||
/// Construct a new `Normal` distribution with the given mean and
|
||||
/// standard deviation. Fails if `std_dev < 0`.
|
||||
pub fn new(mean: f64, std_dev: f64) -> Normal {
|
||||
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
|
||||
Normal {
|
||||
mean: mean,
|
||||
std_dev: std_dev
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Sample<f64> for Normal {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for Normal {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
self.mean + self.std_dev * (*rng.gen::<StandardNormal>())
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around an `f64` to generate Exp(1) random numbers.
|
||||
///
|
||||
/// See `Exp` for the general exponential distribution.Note that this
|
||||
// has to be unwrapped before use as an `f64` (using either
|
||||
/// `*` or `cast::transmute` is safe).
|
||||
///
|
||||
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
|
||||
/// exact description in the paper was adjusted to use tables for the
|
||||
/// exponential distribution rather than normal.
|
||||
///
|
||||
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
|
||||
/// Generate Normal Random
|
||||
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
|
||||
/// College, Oxford
|
||||
pub struct Exp1(f64);
|
||||
|
||||
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
|
||||
|
|
@ -148,3 +370,221 @@ impl Rand for Exp1 {
|
|||
pdf, zero_case))
|
||||
}
|
||||
}
|
||||
|
||||
/// The exponential distribution `Exp(lambda)`.
|
||||
///
|
||||
/// This distribution has density function: `f(x) = lambda *
|
||||
/// exp(-lambda * x)` for `x > 0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::rand;
|
||||
/// use std::rand::distributions::{Exp, IndependentSample};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let exp = Exp::new(2.0);
|
||||
/// let v = exp.ind_sample(rand::task_rng());
|
||||
/// println!("{} is from a Exp(2) distribution", v);
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Exp {
|
||||
/// `lambda` stored as `1/lambda`, since this is what we scale by.
|
||||
priv lambda_inverse: f64
|
||||
}
|
||||
|
||||
impl Exp {
|
||||
/// Construct a new `Exp` with the given shape parameter
|
||||
/// `lambda`. Fails if `lambda <= 0`.
|
||||
pub fn new(lambda: f64) -> Exp {
|
||||
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
|
||||
Exp { lambda_inverse: 1.0 / lambda }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample<f64> for Exp {
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
|
||||
}
|
||||
impl IndependentSample<f64> for Exp {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
|
||||
(*rng.gen::<Exp1>()) * self.lambda_inverse
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::*;
|
||||
use super::*;
|
||||
use iter::range;
|
||||
use option::{Some, None};
|
||||
|
||||
struct ConstRand(uint);
|
||||
impl Rand for ConstRand {
|
||||
fn rand<R: Rng>(_: &mut R) -> ConstRand {
|
||||
ConstRand(0)
|
||||
}
|
||||
}
|
||||
|
||||
// 0, 1, 2, 3, ...
|
||||
struct CountingRng { i: u32 }
|
||||
impl Rng for CountingRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.i += 1;
|
||||
self.i - 1
|
||||
}
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.next_u32() as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rand_sample() {
|
||||
let mut rand_sample = RandSample::<ConstRand>;
|
||||
|
||||
assert_eq!(*rand_sample.sample(task_rng()), 0);
|
||||
assert_eq!(*rand_sample.ind_sample(task_rng()), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normal() {
|
||||
let mut norm = Normal::new(10.0, 10.0);
|
||||
let rng = task_rng();
|
||||
for _ in range(0, 1000) {
|
||||
norm.sample(rng);
|
||||
norm.ind_sample(rng);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_normal_invalid_sd() {
|
||||
Normal::new(10.0, -1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exp() {
|
||||
let mut exp = Exp::new(10.0);
|
||||
let rng = task_rng();
|
||||
for _ in range(0, 1000) {
|
||||
assert!(exp.sample(rng) >= 0.0);
|
||||
assert!(exp.ind_sample(rng) >= 0.0);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_exp_invalid_lambda_zero() {
|
||||
Exp::new(0.0);
|
||||
}
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_exp_invalid_lambda_neg() {
|
||||
Exp::new(-10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weighted_choice() {
|
||||
// this makes assumptions about the internal implementation of
|
||||
// WeightedChoice, specifically: it doesn't reorder the items,
|
||||
// it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
|
||||
// 1, internally; modulo a modulo operation).
|
||||
|
||||
macro_rules! t (
|
||||
($items:expr, $expected:expr) => {{
|
||||
let wc = WeightedChoice::new($items);
|
||||
let expected = $expected;
|
||||
|
||||
let mut rng = CountingRng { i: 0 };
|
||||
|
||||
for &val in expected.iter() {
|
||||
assert_eq!(wc.ind_sample(&mut rng), val)
|
||||
}
|
||||
}}
|
||||
);
|
||||
|
||||
t!(~[Weighted { weight: 1, item: 10}], ~[10]);
|
||||
|
||||
// skip some
|
||||
t!(~[Weighted { weight: 0, item: 20},
|
||||
Weighted { weight: 2, item: 21},
|
||||
Weighted { weight: 0, item: 22},
|
||||
Weighted { weight: 1, item: 23}],
|
||||
~[21,21, 23]);
|
||||
|
||||
// different weights
|
||||
t!(~[Weighted { weight: 4, item: 30},
|
||||
Weighted { weight: 3, item: 31}],
|
||||
~[30,30,30,30, 31,31,31]);
|
||||
|
||||
// check that we're binary searching
|
||||
// correctly with some vectors of odd
|
||||
// length.
|
||||
t!(~[Weighted { weight: 1, item: 40},
|
||||
Weighted { weight: 1, item: 41},
|
||||
Weighted { weight: 1, item: 42},
|
||||
Weighted { weight: 1, item: 43},
|
||||
Weighted { weight: 1, item: 44}],
|
||||
~[40, 41, 42, 43, 44]);
|
||||
t!(~[Weighted { weight: 1, item: 50},
|
||||
Weighted { weight: 1, item: 51},
|
||||
Weighted { weight: 1, item: 52},
|
||||
Weighted { weight: 1, item: 53},
|
||||
Weighted { weight: 1, item: 54},
|
||||
Weighted { weight: 1, item: 55},
|
||||
Weighted { weight: 1, item: 56}],
|
||||
~[50, 51, 52, 53, 54, 55, 56]);
|
||||
}
|
||||
|
||||
#[test] #[should_fail]
|
||||
fn test_weighted_choice_no_items() {
|
||||
WeightedChoice::<int>::new(~[]);
|
||||
}
|
||||
#[test] #[should_fail]
|
||||
fn test_weighted_choice_zero_weight() {
|
||||
WeightedChoice::new(~[Weighted { weight: 0, item: 0},
|
||||
Weighted { weight: 0, item: 1}]);
|
||||
}
|
||||
#[test] #[should_fail]
|
||||
fn test_weighted_choice_weight_overflows() {
|
||||
let x = (-1) as uint / 2; // x + x + 2 is the overflow
|
||||
WeightedChoice::new(~[Weighted { weight: x, item: 0 },
|
||||
Weighted { weight: 1, item: 1 },
|
||||
Weighted { weight: x, item: 2 },
|
||||
Weighted { weight: 1, item: 3 }]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bench {
|
||||
use extra::test::BenchHarness;
|
||||
use rand::*;
|
||||
use super::*;
|
||||
use iter::range;
|
||||
use option::{Some, None};
|
||||
use mem::size_of;
|
||||
|
||||
static N: u64 = 100;
|
||||
|
||||
#[bench]
|
||||
fn rand_normal(bh: &mut BenchHarness) {
|
||||
let mut rng = XorShiftRng::new();
|
||||
let mut normal = Normal::new(-2.71828, 3.14159);
|
||||
|
||||
do bh.iter {
|
||||
for _ in range(0, N) {
|
||||
normal.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
bh.bytes = size_of::<f64>() as u64 * N;
|
||||
}
|
||||
#[bench]
|
||||
fn rand_exp(bh: &mut BenchHarness) {
|
||||
let mut rng = XorShiftRng::new();
|
||||
let mut exp = Exp::new(2.71828 * 3.14159);
|
||||
|
||||
do bh.iter {
|
||||
for _ in range(0, N) {
|
||||
exp.sample(&mut rng);
|
||||
}
|
||||
}
|
||||
bh.bytes = size_of::<f64>() as u64 * N;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,24 @@
|
|||
|
||||
//! The ISAAC random number generator.
|
||||
|
||||
use cast;
|
||||
use rand::{Rng, SeedableRng, OSRng};
|
||||
use iter::{Iterator, range, range_step, Repeat};
|
||||
use option::{None, Some};
|
||||
use vec::raw;
|
||||
use mem;
|
||||
|
||||
static RAND_SIZE_LEN: u32 = 8;
|
||||
static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
|
||||
|
||||
/// A random number generator that uses the [ISAAC
|
||||
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
|
||||
/// A random number generator that uses the ISAAC algorithm[1].
|
||||
///
|
||||
/// The ISAAC algorithm is suitable for cryptographic purposes.
|
||||
/// The ISAAC algorithm is generally accepted as suitable for
|
||||
/// cryptographic purposes, but this implementation has not be
|
||||
/// verified as such. Prefer a generator like `OSRng` that defers to
|
||||
/// the operating system for cases that need high security.
|
||||
///
|
||||
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
|
||||
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
|
||||
pub struct IsaacRng {
|
||||
priv cnt: u32,
|
||||
priv rsl: [u32, .. RAND_SIZE],
|
||||
|
|
@ -42,9 +48,12 @@ impl IsaacRng {
|
|||
pub fn new() -> IsaacRng {
|
||||
let mut rng = EMPTY;
|
||||
|
||||
{
|
||||
let bytes = unsafe {cast::transmute::<&mut [u32], &mut [u8]>(rng.rsl)};
|
||||
OSRng::new().fill_bytes(bytes);
|
||||
unsafe {
|
||||
let ptr = raw::to_mut_ptr(rng.rsl);
|
||||
|
||||
do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
|
||||
OSRng::new().fill_bytes(slice);
|
||||
}
|
||||
}
|
||||
|
||||
rng.init(true);
|
||||
|
|
@ -212,11 +221,16 @@ impl<'self> SeedableRng<&'self [u32]> for IsaacRng {
|
|||
static RAND_SIZE_64_LEN: uint = 8;
|
||||
static RAND_SIZE_64: uint = 1 << RAND_SIZE_64_LEN;
|
||||
|
||||
/// A random number generator that uses the 64-bit variant of the
|
||||
/// [ISAAC
|
||||
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
|
||||
/// A random number generator that uses ISAAC-64[1], the 64-bit
|
||||
/// variant of the ISAAC algorithm.
|
||||
///
|
||||
/// The ISAAC algorithm is suitable for cryptographic purposes.
|
||||
/// The ISAAC algorithm is generally accepted as suitable for
|
||||
/// cryptographic purposes, but this implementation has not be
|
||||
/// verified as such. Prefer a generator like `OSRng` that defers to
|
||||
/// the operating system for cases that need high security.
|
||||
///
|
||||
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number
|
||||
/// generator*](http://www.burtleburtle.net/bob/rand/isaacafa.html)
|
||||
pub struct Isaac64Rng {
|
||||
priv cnt: uint,
|
||||
priv rsl: [u64, .. RAND_SIZE_64],
|
||||
|
|
@ -238,10 +252,15 @@ impl Isaac64Rng {
|
|||
/// seed.
|
||||
pub fn new() -> Isaac64Rng {
|
||||
let mut rng = EMPTY_64;
|
||||
{
|
||||
let bytes = unsafe {cast::transmute::<&mut [u64], &mut [u8]>(rng.rsl)};
|
||||
OSRng::new().fill_bytes(bytes);
|
||||
|
||||
unsafe {
|
||||
let ptr = raw::to_mut_ptr(rng.rsl);
|
||||
|
||||
do raw::mut_buf_as_slice(ptr as *mut u8, mem::size_of_val(&rng.rsl)) |slice| {
|
||||
OSRng::new().fill_bytes(slice);
|
||||
}
|
||||
}
|
||||
|
||||
rng.init(true);
|
||||
rng
|
||||
}
|
||||
|
|
@ -434,14 +453,14 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_rng_32_seeded() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_seeded() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u));
|
||||
|
|
@ -472,46 +491,46 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_rng_32_true_values() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = vec::from_fn(10, |_| ra.next_u32());
|
||||
assert_eq!(v,
|
||||
~[447462228, 2081944040, 3163797308, 2379916134, 2377489184,
|
||||
1132373754, 536342443, 2995223415, 1265094839, 345325140]);
|
||||
~[2558573138, 873787463, 263499565, 2103644246, 3595684709,
|
||||
4203127393, 264982119, 2765226902, 2737944514, 3900253796]);
|
||||
|
||||
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
|
||||
let seed = &[12345, 67890, 54321, 9876];
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in range(0, 10000) { rb.next_u32(); }
|
||||
|
||||
let v = vec::from_fn(10, |_| rb.next_u32());
|
||||
assert_eq!(v,
|
||||
~[612373032, 292987903, 1819311337, 3141271980, 422447569,
|
||||
310096395, 1083172510, 867909094, 2478664230, 2073577855]);
|
||||
~[3676831399, 3183332890, 2834741178, 3854698763, 2717568474,
|
||||
1576568959, 3507990155, 179069555, 141456972, 2478885421]);
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_true_values() {
|
||||
let seed = &[2, 32, 4, 32, 51];
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = vec::from_fn(10, |_| ra.next_u64());
|
||||
assert_eq!(v,
|
||||
~[15015576812873463115, 12461067598045625862, 14818626436142668771,
|
||||
5562406406765984441, 11813289907965514161, 13443797187798420053,
|
||||
6935026941854944442, 7750800609318664042, 14428747036317928637,
|
||||
14028894460301215947]);
|
||||
~[547121783600835980, 14377643087320773276, 17351601304698403469,
|
||||
1238879483818134882, 11952566807690396487, 13970131091560099343,
|
||||
4469761996653280935, 15552757044682284409, 6860251611068737823,
|
||||
13722198873481261842]);
|
||||
|
||||
let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1];
|
||||
let seed = &[12345, 67890, 54321, 9876];
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in range(0, 10000) { rb.next_u64(); }
|
||||
|
||||
let v = vec::from_fn(10, |_| rb.next_u64());
|
||||
assert_eq!(v,
|
||||
~[13557216323596688637, 17060829581390442094, 4927582063811333743,
|
||||
2699639759356482270, 4819341314392384881, 6047100822963614452,
|
||||
11086255989965979163, 11901890363215659856, 5370800226050011580,
|
||||
16496463556025356451]);
|
||||
~[18143823860592706164, 8491801882678285927, 2699425367717515619,
|
||||
17196852593171130876, 2606123525235546165, 15790932315217671084,
|
||||
596345674630742204, 9947027391921273664, 11788097613744130851,
|
||||
10391409374914919106]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,23 @@ from an operating-system source of randomness, e.g. `/dev/urandom` on
|
|||
Unix systems, and will automatically reseed itself from this source
|
||||
after generating 32 KiB of random data.
|
||||
|
||||
# Cryptographic security
|
||||
|
||||
An application that requires random numbers for cryptographic purposes
|
||||
should prefer `OSRng`, which reads randomness from one of the source
|
||||
that the operating system provides (e.g. `/dev/urandom` on
|
||||
Unixes). The other random number generators provided by this module
|
||||
are either known to be insecure (`XorShiftRng`), or are not verified
|
||||
to be secure (`IsaacRng`, `Isaac64Rng` and `StdRng`).
|
||||
|
||||
*Note*: on Linux, `/dev/random` is more secure than `/dev/urandom`,
|
||||
but it is a blocking RNG, and will wait until it has determined that
|
||||
it has collected enough entropy to fulfill a request for random
|
||||
data. It can be used with the `Rng` trait provided by this module by
|
||||
opening the file and passing it to `reader::ReaderRng`. Since it
|
||||
blocks, `/dev/random` should only be used to retrieve small amounts of
|
||||
randomness.
|
||||
|
||||
# Examples
|
||||
|
||||
```rust
|
||||
|
|
@ -52,20 +69,21 @@ fn main () {
|
|||
```
|
||||
*/
|
||||
|
||||
use mem::size_of;
|
||||
use unstable::raw::Slice;
|
||||
use cast;
|
||||
use cmp::Ord;
|
||||
use container::Container;
|
||||
use iter::{Iterator, range};
|
||||
use local_data;
|
||||
use prelude::*;
|
||||
use str;
|
||||
use u64;
|
||||
use vec;
|
||||
|
||||
pub use self::isaac::{IsaacRng, Isaac64Rng};
|
||||
pub use self::os::OSRng;
|
||||
|
||||
use self::distributions::{Range, IndependentSample};
|
||||
use self::distributions::range::SampleRange;
|
||||
|
||||
pub mod distributions;
|
||||
pub mod isaac;
|
||||
pub mod os;
|
||||
|
|
@ -80,14 +98,6 @@ pub trait Rand {
|
|||
fn rand<R: Rng>(rng: &mut R) -> Self;
|
||||
}
|
||||
|
||||
/// A value with a particular weight compared to other values
|
||||
pub struct Weighted<T> {
|
||||
/// The numerical weight of this item
|
||||
weight: uint,
|
||||
/// The actual item which is being weighted
|
||||
item: T,
|
||||
}
|
||||
|
||||
/// A random number generator
|
||||
pub trait Rng {
|
||||
/// Return the next random u32. This rarely needs to be called
|
||||
|
|
@ -136,46 +146,26 @@ pub trait Rng {
|
|||
/// }
|
||||
/// ```
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
let mut slice: Slice<u64> = unsafe { cast::transmute_copy(&dest) };
|
||||
slice.len /= size_of::<u64>();
|
||||
let as_u64: &mut [u64] = unsafe { cast::transmute(slice) };
|
||||
for dest in as_u64.mut_iter() {
|
||||
*dest = self.next_u64();
|
||||
}
|
||||
|
||||
// the above will have filled up the vector as much as
|
||||
// possible in multiples of 8 bytes.
|
||||
let mut remaining = dest.len() % 8;
|
||||
|
||||
// space for a u32
|
||||
if remaining >= 4 {
|
||||
let mut slice: Slice<u32> = unsafe { cast::transmute_copy(&dest) };
|
||||
slice.len /= size_of::<u32>();
|
||||
let as_u32: &mut [u32] = unsafe { cast::transmute(slice) };
|
||||
as_u32[as_u32.len() - 1] = self.next_u32();
|
||||
remaining -= 4;
|
||||
}
|
||||
// exactly filled
|
||||
if remaining == 0 { return }
|
||||
|
||||
// now we know we've either got 1, 2 or 3 spots to go,
|
||||
// i.e. exactly one u32 is enough.
|
||||
let rand = self.next_u32();
|
||||
let remaining_index = dest.len() - remaining;
|
||||
match dest.mut_slice_from(remaining_index) {
|
||||
[ref mut a] => {
|
||||
*a = rand as u8;
|
||||
// this could, in theory, be done by transmuting dest to a
|
||||
// [u64], but this is (1) likely to be undefined behaviour for
|
||||
// LLVM, (2) has to be very careful about alignment concerns,
|
||||
// (3) adds more `unsafe` that needs to be checked, (4)
|
||||
// probably doesn't give much performance gain if
|
||||
// optimisations are on.
|
||||
let mut count = 0;
|
||||
let mut num = 0;
|
||||
for byte in dest.mut_iter() {
|
||||
if count == 0 {
|
||||
// we could micro-optimise here by generating a u32 if
|
||||
// we only need a few more bytes to fill the vector
|
||||
// (i.e. at most 4).
|
||||
num = self.next_u64();
|
||||
count = 8;
|
||||
}
|
||||
[ref mut a, ref mut b] => {
|
||||
*a = rand as u8;
|
||||
*b = (rand >> 8) as u8;
|
||||
}
|
||||
[ref mut a, ref mut b, ref mut c] => {
|
||||
*a = rand as u8;
|
||||
*b = (rand >> 8) as u8;
|
||||
*c = (rand >> 16) as u8;
|
||||
}
|
||||
_ => fail!("Rng.fill_bytes: the impossible occurred: remaining != 1, 2 or 3")
|
||||
|
||||
*byte = (num & 0xff) as u8;
|
||||
num >>= 8;
|
||||
count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,14 +208,14 @@ pub trait Rng {
|
|||
vec::from_fn(len, |_| self.gen())
|
||||
}
|
||||
|
||||
/// Generate a random primitive integer in the range [`low`,
|
||||
/// `high`). Fails if `low >= high`.
|
||||
/// Generate a random value in the range [`low`, `high`). Fails if
|
||||
/// `low >= high`.
|
||||
///
|
||||
/// This gives a uniform distribution (assuming this RNG is itself
|
||||
/// uniform), even for edge cases like `gen_integer_range(0u8,
|
||||
/// 170)`, which a naive modulo operation would return numbers
|
||||
/// less than 85 with double the probability to those greater than
|
||||
/// 85.
|
||||
/// This is a convenience wrapper around
|
||||
/// `distributions::Range`. If this function will be called
|
||||
/// repeatedly with the same arguments, one should use `Range`, as
|
||||
/// that will amortize the computations that allow for perfect
|
||||
/// uniformity, as they only happen on initialization.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
@ -235,22 +225,15 @@ pub trait Rng {
|
|||
///
|
||||
/// fn main() {
|
||||
/// let mut rng = rand::task_rng();
|
||||
/// let n: uint = rng.gen_integer_range(0u, 10);
|
||||
/// let n: uint = rng.gen_range(0u, 10);
|
||||
/// println!("{}", n);
|
||||
/// let m: int = rng.gen_integer_range(-40, 400);
|
||||
/// let m: float = rng.gen_range(-40.0, 1.3e5);
|
||||
/// println!("{}", m);
|
||||
/// }
|
||||
/// ```
|
||||
fn gen_integer_range<T: Rand + Int>(&mut self, low: T, high: T) -> T {
|
||||
assert!(low < high, "RNG.gen_integer_range called with low >= high");
|
||||
let range = (high - low).to_u64().unwrap();
|
||||
let accept_zone = u64::max_value - u64::max_value % range;
|
||||
loop {
|
||||
let rand = self.gen::<u64>();
|
||||
if rand < accept_zone {
|
||||
return low + NumCast::from(rand % range).unwrap();
|
||||
}
|
||||
}
|
||||
fn gen_range<T: Ord + SampleRange>(&mut self, low: T, high: T) -> T {
|
||||
assert!(low < high, "Rng.gen_range called with low >= high");
|
||||
Range::new(low, high).ind_sample(self)
|
||||
}
|
||||
|
||||
/// Return a bool with a 1 in n chance of true
|
||||
|
|
@ -267,7 +250,7 @@ pub trait Rng {
|
|||
/// }
|
||||
/// ```
|
||||
fn gen_weighted_bool(&mut self, n: uint) -> bool {
|
||||
n == 0 || self.gen_integer_range(0, n) == 0
|
||||
n == 0 || self.gen_range(0, n) == 0
|
||||
}
|
||||
|
||||
/// Return a random string of the specified length composed of
|
||||
|
|
@ -317,95 +300,10 @@ pub trait Rng {
|
|||
if values.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(&values[self.gen_integer_range(0u, values.len())])
|
||||
Some(&values[self.gen_range(0u, values.len())])
|
||||
}
|
||||
}
|
||||
|
||||
/// Choose an item respecting the relative weights, failing if the sum of
|
||||
/// the weights is 0
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng = rand::rng();
|
||||
/// let x = [rand::Weighted {weight: 4, item: 'a'},
|
||||
/// rand::Weighted {weight: 2, item: 'b'},
|
||||
/// rand::Weighted {weight: 2, item: 'c'}];
|
||||
/// println!("{}", rng.choose_weighted(x));
|
||||
/// }
|
||||
/// ```
|
||||
fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T {
|
||||
self.choose_weighted_option(v).expect("Rng.choose_weighted: total weight is 0")
|
||||
}
|
||||
|
||||
/// Choose Some(item) respecting the relative weights, returning none if
|
||||
/// the sum of the weights is 0
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng = rand::rng();
|
||||
/// let x = [rand::Weighted {weight: 4, item: 'a'},
|
||||
/// rand::Weighted {weight: 2, item: 'b'},
|
||||
/// rand::Weighted {weight: 2, item: 'c'}];
|
||||
/// println!("{:?}", rng.choose_weighted_option(x));
|
||||
/// }
|
||||
/// ```
|
||||
fn choose_weighted_option<T:Clone>(&mut self, v: &[Weighted<T>])
|
||||
-> Option<T> {
|
||||
let mut total = 0u;
|
||||
for item in v.iter() {
|
||||
total += item.weight;
|
||||
}
|
||||
if total == 0u {
|
||||
return None;
|
||||
}
|
||||
let chosen = self.gen_integer_range(0u, total);
|
||||
let mut so_far = 0u;
|
||||
for item in v.iter() {
|
||||
so_far += item.weight;
|
||||
if so_far > chosen {
|
||||
return Some(item.item.clone());
|
||||
}
|
||||
}
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
/// Return a vec containing copies of the items, in order, where
|
||||
/// the weight of the item determines how many copies there are
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng = rand::rng();
|
||||
/// let x = [rand::Weighted {weight: 4, item: 'a'},
|
||||
/// rand::Weighted {weight: 2, item: 'b'},
|
||||
/// rand::Weighted {weight: 2, item: 'c'}];
|
||||
/// println!("{}", rng.weighted_vec(x));
|
||||
/// }
|
||||
/// ```
|
||||
fn weighted_vec<T:Clone>(&mut self, v: &[Weighted<T>]) -> ~[T] {
|
||||
let mut r = ~[];
|
||||
for item in v.iter() {
|
||||
for _ in range(0u, item.weight) {
|
||||
r.push(item.item.clone());
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
/// Shuffle a vec
|
||||
///
|
||||
/// # Example
|
||||
|
|
@ -447,7 +345,7 @@ pub trait Rng {
|
|||
// invariant: elements with index >= i have been locked in place.
|
||||
i -= 1u;
|
||||
// lock element i in place.
|
||||
values.swap(i, self.gen_integer_range(0u, i + 1u));
|
||||
values.swap(i, self.gen_range(0u, i + 1u));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -473,7 +371,7 @@ pub trait Rng {
|
|||
continue
|
||||
}
|
||||
|
||||
let k = self.gen_integer_range(0, i + 1);
|
||||
let k = self.gen_range(0, i + 1);
|
||||
if k < reservoir.len() {
|
||||
reservoir[k] = elem
|
||||
}
|
||||
|
|
@ -520,8 +418,8 @@ pub trait SeedableRng<Seed>: Rng {
|
|||
|
||||
/// Create a random number generator with a default algorithm and seed.
|
||||
///
|
||||
/// It returns the cryptographically-safest `Rng` algorithm currently
|
||||
/// available in Rust. If you require a specifically seeded `Rng` for
|
||||
/// It returns the strongest `Rng` algorithm currently implemented in
|
||||
/// pure Rust. If you require a specifically seeded `Rng` for
|
||||
/// consistency over time you should pick one algorithm and create the
|
||||
/// `Rng` yourself.
|
||||
///
|
||||
|
|
@ -596,12 +494,16 @@ pub fn weak_rng() -> XorShiftRng {
|
|||
XorShiftRng::new()
|
||||
}
|
||||
|
||||
/// An [Xorshift random number
|
||||
/// generator](http://en.wikipedia.org/wiki/Xorshift).
|
||||
/// An Xorshift[1] random number
|
||||
/// generator.
|
||||
///
|
||||
/// The Xorshift algorithm is not suitable for cryptographic purposes
|
||||
/// but is very fast. If you do not know for sure that it fits your
|
||||
/// requirements, use a more secure one such as `IsaacRng`.
|
||||
/// requirements, use a more secure one such as `IsaacRng` or `OSRng`.
|
||||
///
|
||||
/// [1]: Marsaglia, George (July 2003). ["Xorshift
|
||||
/// RNGs"](http://www.jstatsoft.org/v08/i14/paper). *Journal of
|
||||
/// Statistical Software*. Vol. 8 (Issue 14).
|
||||
pub struct XorShiftRng {
|
||||
priv x: u32,
|
||||
priv y: u32,
|
||||
|
|
@ -749,47 +651,68 @@ pub fn random<T: Rand>() -> T {
|
|||
mod test {
|
||||
use iter::{Iterator, range};
|
||||
use option::{Option, Some};
|
||||
use vec;
|
||||
use super::*;
|
||||
|
||||
struct ConstRng { i: u64 }
|
||||
impl Rng for ConstRng {
|
||||
fn next_u32(&mut self) -> u32 { self.i as u32 }
|
||||
fn next_u64(&mut self) -> u64 { self.i }
|
||||
|
||||
// no fill_bytes on purpose
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fill_bytes_default() {
|
||||
let mut r = weak_rng();
|
||||
let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 };
|
||||
|
||||
let mut v = [0u8, .. 100];
|
||||
r.fill_bytes(v);
|
||||
// check every remainder mod 8, both in small and big vectors.
|
||||
let lengths = [0, 1, 2, 3, 4, 5, 6, 7,
|
||||
80, 81, 82, 83, 84, 85, 86, 87];
|
||||
for &n in lengths.iter() {
|
||||
let mut v = vec::from_elem(n, 0u8);
|
||||
r.fill_bytes(v);
|
||||
|
||||
// use this to get nicer error messages.
|
||||
for (i, &byte) in v.iter().enumerate() {
|
||||
if byte == 0 {
|
||||
fail!("byte {} of {} is zero", i, n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gen_integer_range() {
|
||||
fn test_gen_range() {
|
||||
let mut r = rng();
|
||||
for _ in range(0, 1000) {
|
||||
let a = r.gen_integer_range(-3i, 42);
|
||||
let a = r.gen_range(-3i, 42);
|
||||
assert!(a >= -3 && a < 42);
|
||||
assert_eq!(r.gen_integer_range(0, 1), 0);
|
||||
assert_eq!(r.gen_integer_range(-12, -11), -12);
|
||||
assert_eq!(r.gen_range(0, 1), 0);
|
||||
assert_eq!(r.gen_range(-12, -11), -12);
|
||||
}
|
||||
|
||||
for _ in range(0, 1000) {
|
||||
let a = r.gen_integer_range(10, 42);
|
||||
let a = r.gen_range(10, 42);
|
||||
assert!(a >= 10 && a < 42);
|
||||
assert_eq!(r.gen_integer_range(0, 1), 0);
|
||||
assert_eq!(r.gen_integer_range(3_000_000u, 3_000_001), 3_000_000);
|
||||
assert_eq!(r.gen_range(0, 1), 0);
|
||||
assert_eq!(r.gen_range(3_000_000u, 3_000_001), 3_000_000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_gen_integer_range_fail_int() {
|
||||
fn test_gen_range_fail_int() {
|
||||
let mut r = rng();
|
||||
r.gen_integer_range(5i, -2);
|
||||
r.gen_range(5i, -2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_gen_integer_range_fail_uint() {
|
||||
fn test_gen_range_fail_uint() {
|
||||
let mut r = rng();
|
||||
r.gen_integer_range(5u, 2u);
|
||||
r.gen_range(5u, 2u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -843,44 +766,6 @@ mod test {
|
|||
assert_eq!(r.choose_option(v), Some(&i));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_choose_weighted() {
|
||||
let mut r = rng();
|
||||
assert!(r.choose_weighted([
|
||||
Weighted { weight: 1u, item: 42 },
|
||||
]) == 42);
|
||||
assert!(r.choose_weighted([
|
||||
Weighted { weight: 0u, item: 42 },
|
||||
Weighted { weight: 1u, item: 43 },
|
||||
]) == 43);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_choose_weighted_option() {
|
||||
let mut r = rng();
|
||||
assert!(r.choose_weighted_option([
|
||||
Weighted { weight: 1u, item: 42 },
|
||||
]) == Some(42));
|
||||
assert!(r.choose_weighted_option([
|
||||
Weighted { weight: 0u, item: 42 },
|
||||
Weighted { weight: 1u, item: 43 },
|
||||
]) == Some(43));
|
||||
let v: Option<int> = r.choose_weighted_option([]);
|
||||
assert!(v.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weighted_vec() {
|
||||
let mut r = rng();
|
||||
let empty: ~[int] = ~[];
|
||||
assert_eq!(r.weighted_vec([]), empty);
|
||||
assert!(r.weighted_vec([
|
||||
Weighted { weight: 0u, item: 3u },
|
||||
Weighted { weight: 1u, item: 2u },
|
||||
Weighted { weight: 2u, item: 1u },
|
||||
]) == ~[2u, 1u, 1u]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shuffle() {
|
||||
let mut r = rng();
|
||||
|
|
@ -894,7 +779,7 @@ mod test {
|
|||
let mut r = task_rng();
|
||||
r.gen::<int>();
|
||||
assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]);
|
||||
assert_eq!(r.gen_integer_range(0u, 1u), 0u);
|
||||
assert_eq!(r.gen_range(0u, 1u), 0u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -953,41 +838,53 @@ mod bench {
|
|||
use extra::test::BenchHarness;
|
||||
use rand::*;
|
||||
use mem::size_of;
|
||||
use iter::range;
|
||||
use option::{Some, None};
|
||||
|
||||
static N: u64 = 100;
|
||||
|
||||
#[bench]
|
||||
fn rand_xorshift(bh: &mut BenchHarness) {
|
||||
let mut rng = XorShiftRng::new();
|
||||
do bh.iter {
|
||||
rng.gen::<uint>();
|
||||
for _ in range(0, N) {
|
||||
rng.gen::<uint>();
|
||||
}
|
||||
}
|
||||
bh.bytes = size_of::<uint>() as u64;
|
||||
bh.bytes = size_of::<uint>() as u64 * N;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rand_isaac(bh: &mut BenchHarness) {
|
||||
let mut rng = IsaacRng::new();
|
||||
do bh.iter {
|
||||
rng.gen::<uint>();
|
||||
for _ in range(0, N) {
|
||||
rng.gen::<uint>();
|
||||
}
|
||||
}
|
||||
bh.bytes = size_of::<uint>() as u64;
|
||||
bh.bytes = size_of::<uint>() as u64 * N;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rand_isaac64(bh: &mut BenchHarness) {
|
||||
let mut rng = Isaac64Rng::new();
|
||||
do bh.iter {
|
||||
rng.gen::<uint>();
|
||||
for _ in range(0, N) {
|
||||
rng.gen::<uint>();
|
||||
}
|
||||
}
|
||||
bh.bytes = size_of::<uint>() as u64;
|
||||
bh.bytes = size_of::<uint>() as u64 * N;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rand_std(bh: &mut BenchHarness) {
|
||||
let mut rng = StdRng::new();
|
||||
do bh.iter {
|
||||
rng.gen::<uint>();
|
||||
for _ in range(0, N) {
|
||||
rng.gen::<uint>();
|
||||
}
|
||||
}
|
||||
bh.bytes = size_of::<uint>() as u64;
|
||||
bh.bytes = size_of::<uint>() as u64 * N;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
|
|
|||
|
|
@ -30,8 +30,12 @@ type HCRYPTPROV = c_long;
|
|||
// assume they work when we call them.
|
||||
|
||||
/// A random number generator that retrieves randomness straight from
|
||||
/// the operating system. On Unix-like systems this reads from
|
||||
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
|
||||
/// the operating system. Platform sources:
|
||||
///
|
||||
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
||||
/// `/dev/urandom`.
|
||||
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
|
||||
/// service provider with the `PROV_RSA_FULL` type.
|
||||
///
|
||||
/// This does not block.
|
||||
#[cfg(unix)]
|
||||
|
|
@ -39,8 +43,12 @@ pub struct OSRng {
|
|||
priv inner: ReaderRng<file::FileStream>
|
||||
}
|
||||
/// A random number generator that retrieves randomness straight from
|
||||
/// the operating system. On Unix-like systems this reads from
|
||||
/// `/dev/urandom`, on Windows this uses `CryptGenRandom`.
|
||||
/// the operating system. Platform sources:
|
||||
///
|
||||
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
|
||||
/// `/dev/urandom`.
|
||||
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
|
||||
/// service provider with the `PROV_RSA_FULL` type.
|
||||
///
|
||||
/// This does not block.
|
||||
#[cfg(windows)]
|
||||
|
|
|
|||
235
src/libstd/rand/range.rs
Normal file
235
src/libstd/rand/range.rs
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Generating numbers between two others.
|
||||
|
||||
// this is surprisingly complicated to be both generic & correct
|
||||
|
||||
use cmp::Ord;
|
||||
use num::Bounded;
|
||||
use rand::Rng;
|
||||
use rand::distributions::{Sample, IndependentSample};
|
||||
|
||||
/// Sample values uniformly between two bounds.
|
||||
///
|
||||
/// This gives a uniform distribution (assuming the RNG used to sample
|
||||
/// it is itself uniform & the `SampleRange` implementation for the
|
||||
/// given type is correct), even for edge cases like `low = 0u8`,
|
||||
/// `high = 170u8`, for which a naive modulo operation would return
|
||||
/// numbers less than 85 with double the probability to those greater
|
||||
/// than 85.
|
||||
///
|
||||
/// Types should attempt to sample in `[low, high)`, i.e., not
|
||||
/// including `high`, but this may be very difficult. All the
|
||||
/// primitive integer types satisfy this property, and the float types
|
||||
/// normally satisfy it, but rounding may mean `high` can occur.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::rand;
|
||||
/// use std::rand::distributions::{IndependentSample, Range};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let between = Range::new(10u, 10000u);
|
||||
/// let rng = rand::task_rng();
|
||||
/// let mut sum = 0;
|
||||
/// for _ in range(0, 1000) {
|
||||
/// sum += between.ind_sample(rng);
|
||||
/// }
|
||||
/// println!("{}", sum);
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Range<X> {
|
||||
priv low: X,
|
||||
priv range: X,
|
||||
priv accept_zone: X
|
||||
}
|
||||
|
||||
impl<X: SampleRange + Ord> Range<X> {
|
||||
/// Create a new `Range` instance that samples uniformly from
|
||||
/// `[low, high)`. Fails if `low >= high`.
|
||||
pub fn new(low: X, high: X) -> Range<X> {
|
||||
assert!(low < high, "Range::new called with `low >= high`");
|
||||
SampleRange::construct_range(low, high)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
|
||||
#[inline]
|
||||
fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
|
||||
}
|
||||
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
|
||||
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
|
||||
SampleRange::sample_range(self, rng)
|
||||
}
|
||||
}
|
||||
|
||||
/// The helper trait for types that have a sensible way to sample
|
||||
/// uniformly between two values. This should not be used directly,
|
||||
/// and is only to facilitate `Range`.
|
||||
pub trait SampleRange {
|
||||
/// Construct the `Range` object that `sample_range`
|
||||
/// requires. This should not ever be called directly, only via
|
||||
/// `Range::new`, which will check that `low < high`, so this
|
||||
/// function doesn't have to repeat the check.
|
||||
fn construct_range(low: Self, high: Self) -> Range<Self>;
|
||||
|
||||
/// Sample a value from the given `Range` with the given `Rng` as
|
||||
/// a source of randomness.
|
||||
fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! integer_impl {
|
||||
($ty:ty, $unsigned:ty) => {
|
||||
impl SampleRange for $ty {
|
||||
// we play free and fast with unsigned vs signed here
|
||||
// (when $ty is signed), but that's fine, since the
|
||||
// contract of this macro is for $ty and $unsigned to be
|
||||
// "bit-equal", so casting between them is a no-op & a
|
||||
// bijection.
|
||||
|
||||
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
|
||||
let range = high as $unsigned - low as $unsigned;
|
||||
let unsigned_max: $unsigned = Bounded::max_value();
|
||||
|
||||
// this is the largest number that fits into $unsigned
|
||||
// that `range` divides evenly, so, if we've sampled
|
||||
// `n` uniformly from this region, then `n % range` is
|
||||
// uniform in [0, range)
|
||||
let zone = unsigned_max - unsigned_max % range;
|
||||
|
||||
Range {
|
||||
low: low,
|
||||
range: range as $ty,
|
||||
accept_zone: zone as $ty
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
|
||||
loop {
|
||||
// rejection sample
|
||||
let v = rng.gen::<$unsigned>();
|
||||
// until we find something that fits into the
|
||||
// region which r.range evenly divides (this will
|
||||
// be uniformly distributed)
|
||||
if v < r.accept_zone as $unsigned {
|
||||
// and return it, with some adjustments
|
||||
return r.low + (v % r.range as $unsigned) as $ty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
integer_impl! { i8, u8 }
|
||||
integer_impl! { i16, u16 }
|
||||
integer_impl! { i32, u32 }
|
||||
integer_impl! { i64, u64 }
|
||||
integer_impl! { int, uint }
|
||||
integer_impl! { u8, u8 }
|
||||
integer_impl! { u16, u16 }
|
||||
integer_impl! { u32, u32 }
|
||||
integer_impl! { u64, u64 }
|
||||
integer_impl! { uint, uint }
|
||||
|
||||
macro_rules! float_impl {
|
||||
($ty:ty) => {
|
||||
impl SampleRange for $ty {
|
||||
fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
|
||||
Range {
|
||||
low: low,
|
||||
range: high - low,
|
||||
accept_zone: 0.0 // unused
|
||||
}
|
||||
}
|
||||
fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
|
||||
r.low + r.range * rng.gen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float_impl! { f32 }
|
||||
float_impl! { f64 }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rand::*;
|
||||
use num::Bounded;
|
||||
use iter::range;
|
||||
use option::{Some, None};
|
||||
use vec::ImmutableVector;
|
||||
|
||||
#[should_fail]
|
||||
#[test]
|
||||
fn test_range_bad_limits_equal() {
|
||||
Range::new(10, 10);
|
||||
}
|
||||
#[should_fail]
|
||||
#[test]
|
||||
fn test_range_bad_limits_flipped() {
|
||||
Range::new(10, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_integers() {
|
||||
let rng = task_rng();
|
||||
macro_rules! t (
|
||||
($($ty:ty),*) => {{
|
||||
$(
|
||||
let v: &[($ty, $ty)] = [(0, 10),
|
||||
(10, 127),
|
||||
(Bounded::min_value(), Bounded::max_value())];
|
||||
for &(low, high) in v.iter() {
|
||||
let mut sampler: Range<$ty> = Range::new(low, high);
|
||||
for _ in range(0, 1000) {
|
||||
let v = sampler.sample(rng);
|
||||
assert!(low <= v && v < high);
|
||||
let v = sampler.ind_sample(rng);
|
||||
assert!(low <= v && v < high);
|
||||
}
|
||||
}
|
||||
)*
|
||||
}}
|
||||
);
|
||||
t!(i8, i16, i32, i64, int,
|
||||
u8, u16, u32, u64, uint)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_floats() {
|
||||
let rng = task_rng();
|
||||
macro_rules! t (
|
||||
($($ty:ty),*) => {{
|
||||
$(
|
||||
let v: &[($ty, $ty)] = [(0.0, 100.0),
|
||||
(-1e35, -1e25),
|
||||
(1e-35, 1e-25),
|
||||
(-1e35, 1e35)];
|
||||
for &(low, high) in v.iter() {
|
||||
let mut sampler: Range<$ty> = Range::new(low, high);
|
||||
for _ in range(0, 1000) {
|
||||
let v = sampler.sample(rng);
|
||||
assert!(low <= v && v < high);
|
||||
let v = sampler.ind_sample(rng);
|
||||
assert!(low <= v && v < high);
|
||||
}
|
||||
}
|
||||
)*
|
||||
}}
|
||||
);
|
||||
|
||||
t!(f32, f64)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ pub fn align(size: uint, align: uint) -> uint {
|
|||
|
||||
/// Adaptor to wrap around visitors implementing MovePtr.
|
||||
pub struct MovePtrAdaptor<V> {
|
||||
inner: V
|
||||
priv inner: V
|
||||
}
|
||||
pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> {
|
||||
MovePtrAdaptor { inner: v }
|
||||
|
|
|
|||
|
|
@ -98,10 +98,10 @@ enum VariantState {
|
|||
}
|
||||
|
||||
pub struct ReprVisitor<'self> {
|
||||
ptr: *c_void,
|
||||
ptr_stk: ~[*c_void],
|
||||
var_stk: ~[VariantState],
|
||||
writer: &'self mut io::Writer
|
||||
priv ptr: *c_void,
|
||||
priv ptr_stk: ~[*c_void],
|
||||
priv var_stk: ~[VariantState],
|
||||
priv writer: &'self mut io::Writer
|
||||
}
|
||||
|
||||
pub fn ReprVisitor<'a>(ptr: *c_void,
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ static ALL_BITS: uint = FROZEN_BIT | MUT_BIT;
|
|||
|
||||
#[deriving(Eq)]
|
||||
pub struct BorrowRecord {
|
||||
box: *mut raw::Box<()>,
|
||||
priv box: *mut raw::Box<()>,
|
||||
file: *c_char,
|
||||
line: size_t
|
||||
priv line: size_t
|
||||
}
|
||||
|
||||
fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
|
||||
|
|
|
|||
|
|
@ -48,14 +48,14 @@ struct Packet<T> {
|
|||
|
||||
// A one-shot channel.
|
||||
pub struct ChanOne<T> {
|
||||
void_packet: *mut Void,
|
||||
suppress_finalize: bool
|
||||
priv void_packet: *mut Void,
|
||||
priv suppress_finalize: bool
|
||||
}
|
||||
|
||||
/// A one-shot port.
|
||||
pub struct PortOne<T> {
|
||||
void_packet: *mut Void,
|
||||
suppress_finalize: bool
|
||||
priv void_packet: *mut Void,
|
||||
priv suppress_finalize: bool
|
||||
}
|
||||
|
||||
pub fn oneshot<T: Send>() -> (PortOne<T>, ChanOne<T>) {
|
||||
|
|
@ -1117,7 +1117,7 @@ mod test {
|
|||
let total = stress_factor() + 10;
|
||||
let mut rng = rand::rng();
|
||||
do total.times {
|
||||
let msgs = rng.gen_integer_range(0u, 10);
|
||||
let msgs = rng.gen_range(0u, 10);
|
||||
let pipe_clone = pipe.clone();
|
||||
let end_chan_clone = end_chan.clone();
|
||||
do spawntask_random {
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ pub static RED_ZONE: uint = 20 * 1024;
|
|||
// then misalign the regs again.
|
||||
pub struct Context {
|
||||
/// The context entry point, saved here for later destruction
|
||||
start: Option<~~fn()>,
|
||||
priv start: Option<~~fn()>,
|
||||
/// Hold the registers while the task or scheduler is suspended
|
||||
regs: ~Registers,
|
||||
priv regs: ~Registers,
|
||||
/// Lower bound and upper bound for the stack
|
||||
stack_bounds: Option<(uint, uint)>,
|
||||
priv stack_bounds: Option<(uint, uint)>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
|
|
@ -391,36 +391,32 @@ pub unsafe fn record_sp_limit(limit: uint) {
|
|||
/// As with the setter, this function does not have a __morestack header and can
|
||||
/// therefore be called in a "we're out of stack" situation.
|
||||
#[inline(always)]
|
||||
// NOTE: after the next snapshot, can remove the initialization before inline
|
||||
// assembly due to an improvement in how it's handled, then this specific
|
||||
// allow directive should get removed.
|
||||
#[allow(dead_assignment)]
|
||||
pub unsafe fn get_sp_limit() -> uint {
|
||||
return target_get_sp_limit();
|
||||
|
||||
// x86-64
|
||||
#[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
let mut limit: uint = 0;
|
||||
let limit;
|
||||
asm!("movq $$0x60+90*8, %rsi
|
||||
movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
|
||||
return limit;
|
||||
}
|
||||
#[cfg(target_arch = "x86_64", target_os = "linux")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
let mut limit: uint = 0;
|
||||
let limit;
|
||||
asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
|
||||
return limit;
|
||||
}
|
||||
#[cfg(target_arch = "x86_64", target_os = "win32")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
let mut limit: uint = 0;
|
||||
let limit;
|
||||
asm!("movq %gs:0x28, $0" : "=r"(limit) ::: "volatile");
|
||||
return limit;
|
||||
}
|
||||
#[cfg(target_arch = "x86_64", target_os = "freebsd")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
let mut limit: uint = 0;
|
||||
let limit;
|
||||
asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
|
||||
return limit;
|
||||
}
|
||||
|
|
@ -428,7 +424,7 @@ pub unsafe fn get_sp_limit() -> uint {
|
|||
// x86
|
||||
#[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
let mut limit: uint = 0;
|
||||
let limit;
|
||||
asm!("movl $$0x48+90*4, %eax
|
||||
movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
|
||||
return limit;
|
||||
|
|
@ -436,13 +432,13 @@ pub unsafe fn get_sp_limit() -> uint {
|
|||
#[cfg(target_arch = "x86", target_os = "linux")]
|
||||
#[cfg(target_arch = "x86", target_os = "freebsd")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
let mut limit: uint = 0;
|
||||
let limit;
|
||||
asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
|
||||
return limit;
|
||||
}
|
||||
#[cfg(target_arch = "x86", target_os = "win32")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
let mut limit: uint = 0;
|
||||
let limit;
|
||||
asm!("movl %fs:0x14, $0" : "=r"(limit) ::: "volatile");
|
||||
return limit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ pub struct ModEntry<'self> {
|
|||
}
|
||||
|
||||
pub struct CrateMap<'self> {
|
||||
version: i32,
|
||||
entries: &'self [ModEntry<'self>],
|
||||
children: &'self [&'self CrateMap<'self>]
|
||||
priv version: i32,
|
||||
priv entries: &'self [ModEntry<'self>],
|
||||
priv children: &'self [&'self CrateMap<'self>]
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
|
|
|||
|
|
@ -362,8 +362,8 @@ impl Seek for FileWriter {
|
|||
/// For this reason, it is best to use the access-constrained wrappers that are
|
||||
/// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`.
|
||||
pub struct FileStream {
|
||||
fd: ~RtioFileStream,
|
||||
last_nread: int,
|
||||
priv fd: ~RtioFileStream,
|
||||
priv last_nread: int,
|
||||
}
|
||||
|
||||
/// a `std::rt::io::Reader` trait impl for file I/O.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use super::*;
|
|||
|
||||
/// A Writer decorator that compresses using the 'deflate' scheme
|
||||
pub struct DeflateWriter<W> {
|
||||
inner_writer: W
|
||||
priv inner_writer: W
|
||||
}
|
||||
|
||||
impl<W: Writer> DeflateWriter<W> {
|
||||
|
|
@ -56,7 +56,7 @@ impl<W: Writer> Decorator<W> for DeflateWriter<W> {
|
|||
|
||||
/// A Reader decorator that decompresses using the 'deflate' scheme
|
||||
pub struct InflateReader<R> {
|
||||
inner_reader: R
|
||||
priv inner_reader: R
|
||||
}
|
||||
|
||||
impl<R: Reader> InflateReader<R> {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rt::io::{Reader, Writer};
|
|||
|
||||
pub struct MockReader {
|
||||
read: ~fn(buf: &mut [u8]) -> Option<uint>,
|
||||
eof: ~fn() -> bool
|
||||
priv eof: ~fn() -> bool
|
||||
}
|
||||
|
||||
impl MockReader {
|
||||
|
|
@ -31,8 +31,8 @@ impl Reader for MockReader {
|
|||
}
|
||||
|
||||
pub struct MockWriter {
|
||||
write: ~fn(buf: &[u8]),
|
||||
flush: ~fn()
|
||||
priv write: ~fn(buf: &[u8]),
|
||||
priv flush: ~fn()
|
||||
}
|
||||
|
||||
impl MockWriter {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
This module defines the Rust interface for synchronous I/O.
|
||||
It models byte-oriented input and output with the Reader and Writer traits.
|
||||
Types that implement both `Reader` and `Writer` and called 'streams',
|
||||
and automatically implement trait `Stream`.
|
||||
Types that implement both `Reader` and `Writer` are called 'streams',
|
||||
and automatically implement the `Stream` trait.
|
||||
Implementations are provided for common I/O streams like
|
||||
file, TCP, UDP, Unix domain sockets.
|
||||
Readers and Writers may be composed to add capabilities like string
|
||||
|
|
|
|||
|
|
@ -219,17 +219,17 @@ pub struct Death {
|
|||
// might kill it. This is optional so we can take it by-value at exit time.
|
||||
kill_handle: Option<KillHandle>,
|
||||
// Handle to a watching parent, if we have one, for exit code propagation.
|
||||
watching_parent: Option<KillHandle>,
|
||||
priv watching_parent: Option<KillHandle>,
|
||||
// Action to be done with the exit code. If set, also makes the task wait
|
||||
// until all its watched children exit before collecting the status.
|
||||
on_exit: Option<~fn(bool)>,
|
||||
// nesting level counter for task::unkillable calls (0 == killable).
|
||||
unkillable: int,
|
||||
priv unkillable: int,
|
||||
// nesting level counter for unstable::atomically calls (0 == can deschedule).
|
||||
wont_sleep: int,
|
||||
priv wont_sleep: int,
|
||||
// A "spare" handle to the kill flag inside the kill handle. Used during
|
||||
// blocking/waking as an optimization to avoid two xadds on the refcount.
|
||||
spare_kill_flag: Option<KillFlagHandle>,
|
||||
priv spare_kill_flag: Option<KillFlagHandle>,
|
||||
}
|
||||
|
||||
impl Drop for KillFlag {
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ pub type OpaqueBox = c_void;
|
|||
pub type TypeDesc = c_void;
|
||||
|
||||
pub struct LocalHeap {
|
||||
memory_region: *MemoryRegion,
|
||||
boxed_region: *BoxedRegion
|
||||
priv memory_region: *MemoryRegion,
|
||||
priv boxed_region: *BoxedRegion
|
||||
}
|
||||
|
||||
impl LocalHeap {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use libc::c_void;
|
|||
use cast;
|
||||
|
||||
pub struct RC<T> {
|
||||
p: *c_void // ~(uint, T)
|
||||
priv p: *c_void // ~(uint, T)
|
||||
}
|
||||
|
||||
impl<T> RC<T> {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ pub struct FileOpenConfig {
|
|||
/// Flags for file access mode (as per open(2))
|
||||
flags: int,
|
||||
/// File creation mode, ignored unless O_CREAT is passed as part of flags
|
||||
mode: int
|
||||
priv mode: int
|
||||
}
|
||||
|
||||
pub trait IoFactory {
|
||||
|
|
|
|||
|
|
@ -66,26 +66,26 @@ pub struct Scheduler {
|
|||
event_loop: ~EventLoopObject,
|
||||
/// The scheduler runs on a special task. When it is not running
|
||||
/// it is stored here instead of the work queue.
|
||||
sched_task: Option<~Task>,
|
||||
priv sched_task: Option<~Task>,
|
||||
/// An action performed after a context switch on behalf of the
|
||||
/// code running before the context switch
|
||||
cleanup_job: Option<CleanupJob>,
|
||||
priv cleanup_job: Option<CleanupJob>,
|
||||
/// Should this scheduler run any task, or only pinned tasks?
|
||||
run_anything: bool,
|
||||
/// If the scheduler shouldn't run some tasks, a friend to send
|
||||
/// them to.
|
||||
friend_handle: Option<SchedHandle>,
|
||||
priv friend_handle: Option<SchedHandle>,
|
||||
/// A fast XorShift rng for scheduler use
|
||||
rng: XorShiftRng,
|
||||
/// A toggleable idle callback
|
||||
idle_callback: Option<~PausibleIdleCallback>,
|
||||
priv idle_callback: Option<~PausibleIdleCallback>,
|
||||
/// A countdown that starts at a random value and is decremented
|
||||
/// every time a yield check is performed. When it hits 0 a task
|
||||
/// will yield.
|
||||
yield_check_count: uint,
|
||||
priv yield_check_count: uint,
|
||||
/// A flag to tell the scheduler loop it needs to do some stealing
|
||||
/// in order to introduce randomness as part of a yield
|
||||
steal_for_yield: bool
|
||||
priv steal_for_yield: bool
|
||||
}
|
||||
|
||||
/// An indication of how hard to work on a given operation, the difference
|
||||
|
|
@ -431,7 +431,7 @@ impl Scheduler {
|
|||
fn try_steals(&mut self) -> Option<~Task> {
|
||||
let work_queues = &mut self.work_queues;
|
||||
let len = work_queues.len();
|
||||
let start_index = self.rng.gen_integer_range(0, len);
|
||||
let start_index = self.rng.gen_range(0, len);
|
||||
for index in range(0, len).map(|i| (i + start_index) % len) {
|
||||
match work_queues[index].steal() {
|
||||
Some(task) => {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ use ops::Drop;
|
|||
use libc::{c_uint, uintptr_t};
|
||||
|
||||
pub struct StackSegment {
|
||||
buf: ~[u8],
|
||||
valgrind_id: c_uint
|
||||
priv buf: ~[u8],
|
||||
priv valgrind_id: c_uint
|
||||
}
|
||||
|
||||
impl StackSegment {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ use send_str::SendStr;
|
|||
|
||||
pub struct Task {
|
||||
heap: LocalHeap,
|
||||
gc: GarbageCollector,
|
||||
priv gc: GarbageCollector,
|
||||
storage: LocalStorage,
|
||||
logger: StdErrLogger,
|
||||
unwinder: Unwinder,
|
||||
|
|
@ -69,7 +69,7 @@ pub struct Coroutine {
|
|||
/// The segment of stack on which the task is currently running or
|
||||
/// if the task is blocked, on which the task will resume
|
||||
/// execution.
|
||||
current_stack_segment: StackSegment,
|
||||
priv current_stack_segment: StackSegment,
|
||||
/// Always valid if the task is alive and not running.
|
||||
saved_context: Context
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ use uint;
|
|||
type raw_thread = libc::c_void;
|
||||
|
||||
pub struct Thread {
|
||||
main: ~fn(),
|
||||
raw_thread: *raw_thread,
|
||||
joined: bool,
|
||||
priv main: ~fn(),
|
||||
priv raw_thread: *raw_thread,
|
||||
priv joined: bool
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ struct TubeState<T> {
|
|||
}
|
||||
|
||||
pub struct Tube<T> {
|
||||
p: RC<TubeState<T>>
|
||||
priv p: RC<TubeState<T>>
|
||||
}
|
||||
|
||||
impl<T> Tube<T> {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option<UvError>)
|
|||
pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
|
||||
|
||||
pub struct RequestData {
|
||||
getaddrinfo_cb: Option<GetAddrInfoCallback>,
|
||||
priv getaddrinfo_cb: Option<GetAddrInfoCallback>,
|
||||
}
|
||||
|
||||
impl GetAddrInfoRequest {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub struct FsRequest(*uvll::uv_fs_t);
|
|||
impl Request for FsRequest {}
|
||||
|
||||
pub struct RequestData {
|
||||
complete_cb: Option<FsCallback>
|
||||
priv complete_cb: Option<FsCallback>
|
||||
}
|
||||
|
||||
impl FsRequest {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ pub mod pipe;
|
|||
/// with dtors may not be destructured, but tuple structs can,
|
||||
/// but the results are not correct.
|
||||
pub struct Loop {
|
||||
handle: *uvll::uv_loop_t
|
||||
priv handle: *uvll::uv_loop_t
|
||||
}
|
||||
|
||||
/// The trait implemented by uv 'watchers' (handles). Watchers are
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
|
|||
|
||||
// Obviously an Event Loop is always home.
|
||||
pub struct UvEventLoop {
|
||||
uvio: UvIoFactory
|
||||
priv uvio: UvIoFactory
|
||||
}
|
||||
|
||||
impl UvEventLoop {
|
||||
|
|
@ -240,9 +240,9 @@ impl EventLoop for UvEventLoop {
|
|||
}
|
||||
|
||||
pub struct UvPausibleIdleCallback {
|
||||
watcher: IdleWatcher,
|
||||
idle_flag: bool,
|
||||
closed: bool
|
||||
priv watcher: IdleWatcher,
|
||||
priv idle_flag: bool,
|
||||
priv closed: bool
|
||||
}
|
||||
|
||||
impl UvPausibleIdleCallback {
|
||||
|
|
@ -294,10 +294,10 @@ fn test_callback_run_once() {
|
|||
// The entire point of async is to call into a loop from other threads so it does not need to home.
|
||||
pub struct UvRemoteCallback {
|
||||
// The uv async handle for triggering the callback
|
||||
async: AsyncWatcher,
|
||||
priv async: AsyncWatcher,
|
||||
// A flag to tell the callback to exit, set from the dtor. This is
|
||||
// almost never contested - only in rare races with the dtor.
|
||||
exit_flag: Exclusive<bool>
|
||||
priv exit_flag: Exclusive<bool>
|
||||
}
|
||||
|
||||
impl UvRemoteCallback {
|
||||
|
|
@ -804,8 +804,8 @@ impl IoFactory for UvIoFactory {
|
|||
}
|
||||
|
||||
pub struct UvTcpListener {
|
||||
watcher : TcpWatcher,
|
||||
home: SchedHandle,
|
||||
priv watcher : TcpWatcher,
|
||||
priv home: SchedHandle,
|
||||
}
|
||||
|
||||
impl HomingIO for UvTcpListener {
|
||||
|
|
@ -866,8 +866,8 @@ impl RtioTcpListener for UvTcpListener {
|
|||
}
|
||||
|
||||
pub struct UvTcpAcceptor {
|
||||
listener: UvTcpListener,
|
||||
incoming: Tube<Result<~RtioTcpStreamObject, IoError>>,
|
||||
priv listener: UvTcpListener,
|
||||
priv incoming: Tube<Result<~RtioTcpStreamObject, IoError>>,
|
||||
}
|
||||
|
||||
impl HomingIO for UvTcpAcceptor {
|
||||
|
|
@ -991,7 +991,7 @@ fn write_stream(mut watcher: StreamWatcher,
|
|||
|
||||
pub struct UvUnboundPipe {
|
||||
pipe: Pipe,
|
||||
home: SchedHandle,
|
||||
priv home: SchedHandle,
|
||||
}
|
||||
|
||||
impl HomingIO for UvUnboundPipe {
|
||||
|
|
@ -1043,8 +1043,8 @@ impl RtioPipe for UvPipeStream {
|
|||
}
|
||||
|
||||
pub struct UvTcpStream {
|
||||
watcher: TcpWatcher,
|
||||
home: SchedHandle,
|
||||
priv watcher: TcpWatcher,
|
||||
priv home: SchedHandle,
|
||||
}
|
||||
|
||||
impl HomingIO for UvTcpStream {
|
||||
|
|
@ -1143,8 +1143,8 @@ impl RtioTcpStream for UvTcpStream {
|
|||
}
|
||||
|
||||
pub struct UvUdpSocket {
|
||||
watcher: UdpWatcher,
|
||||
home: SchedHandle,
|
||||
priv watcher: UdpWatcher,
|
||||
priv home: SchedHandle,
|
||||
}
|
||||
|
||||
impl HomingIO for UvUdpSocket {
|
||||
|
|
@ -1353,8 +1353,8 @@ impl RtioUdpSocket for UvUdpSocket {
|
|||
}
|
||||
|
||||
pub struct UvTimer {
|
||||
watcher: timer::TimerWatcher,
|
||||
home: SchedHandle,
|
||||
priv watcher: timer::TimerWatcher,
|
||||
priv home: SchedHandle,
|
||||
}
|
||||
|
||||
impl HomingIO for UvTimer {
|
||||
|
|
@ -1400,10 +1400,10 @@ impl RtioTimer for UvTimer {
|
|||
}
|
||||
|
||||
pub struct UvFileStream {
|
||||
loop_: Loop,
|
||||
fd: c_int,
|
||||
close_on_drop: bool,
|
||||
home: SchedHandle
|
||||
priv loop_: Loop,
|
||||
priv fd: c_int,
|
||||
priv close_on_drop: bool,
|
||||
priv home: SchedHandle
|
||||
}
|
||||
|
||||
impl HomingIO for UvFileStream {
|
||||
|
|
@ -1533,11 +1533,11 @@ impl RtioFileStream for UvFileStream {
|
|||
}
|
||||
|
||||
pub struct UvProcess {
|
||||
process: process::Process,
|
||||
priv process: process::Process,
|
||||
|
||||
// Sadly, this structure must be created before we return it, so in that
|
||||
// brief interim the `home` is None.
|
||||
home: Option<SchedHandle>,
|
||||
priv home: Option<SchedHandle>,
|
||||
|
||||
// All None until the process exits (exit_error may stay None)
|
||||
priv exit_status: Option<int>,
|
||||
|
|
|
|||
|
|
@ -134,26 +134,26 @@ pub type uv_pipe_t = c_void;
|
|||
|
||||
pub struct uv_timespec_t {
|
||||
tv_sec: libc::c_long,
|
||||
tv_nsec: libc::c_long
|
||||
priv tv_nsec: libc::c_long
|
||||
}
|
||||
|
||||
pub struct uv_stat_t {
|
||||
st_dev: libc::uint64_t,
|
||||
priv st_dev: libc::uint64_t,
|
||||
st_mode: libc::uint64_t,
|
||||
st_nlink: libc::uint64_t,
|
||||
st_uid: libc::uint64_t,
|
||||
st_gid: libc::uint64_t,
|
||||
st_rdev: libc::uint64_t,
|
||||
st_ino: libc::uint64_t,
|
||||
priv st_nlink: libc::uint64_t,
|
||||
priv st_uid: libc::uint64_t,
|
||||
priv st_gid: libc::uint64_t,
|
||||
priv st_rdev: libc::uint64_t,
|
||||
priv st_ino: libc::uint64_t,
|
||||
st_size: libc::uint64_t,
|
||||
st_blksize: libc::uint64_t,
|
||||
st_blocks: libc::uint64_t,
|
||||
st_flags: libc::uint64_t,
|
||||
st_gen: libc::uint64_t,
|
||||
priv st_blksize: libc::uint64_t,
|
||||
priv st_blocks: libc::uint64_t,
|
||||
priv st_flags: libc::uint64_t,
|
||||
priv st_gen: libc::uint64_t,
|
||||
st_atim: uv_timespec_t,
|
||||
st_mtim: uv_timespec_t,
|
||||
st_ctim: uv_timespec_t,
|
||||
st_birthtim: uv_timespec_t
|
||||
priv st_birthtim: uv_timespec_t
|
||||
}
|
||||
|
||||
impl uv_stat_t {
|
||||
|
|
@ -231,37 +231,37 @@ pub type socklen_t = c_int;
|
|||
#[cfg(target_os = "android")]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub struct addrinfo {
|
||||
ai_flags: c_int,
|
||||
ai_family: c_int,
|
||||
ai_socktype: c_int,
|
||||
ai_protocol: c_int,
|
||||
ai_addrlen: socklen_t,
|
||||
priv ai_flags: c_int,
|
||||
priv ai_family: c_int,
|
||||
priv ai_socktype: c_int,
|
||||
priv ai_protocol: c_int,
|
||||
priv ai_addrlen: socklen_t,
|
||||
ai_addr: *sockaddr,
|
||||
ai_canonname: *char,
|
||||
priv ai_canonname: *char,
|
||||
ai_next: *addrinfo
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub struct addrinfo {
|
||||
ai_flags: c_int,
|
||||
ai_family: c_int,
|
||||
ai_socktype: c_int,
|
||||
ai_protocol: c_int,
|
||||
ai_addrlen: socklen_t,
|
||||
ai_canonname: *char,
|
||||
priv ai_flags: c_int,
|
||||
priv ai_family: c_int,
|
||||
priv ai_socktype: c_int,
|
||||
priv ai_protocol: c_int,
|
||||
priv ai_addrlen: socklen_t,
|
||||
priv ai_canonname: *char,
|
||||
ai_addr: *sockaddr,
|
||||
ai_next: *addrinfo
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub struct addrinfo {
|
||||
ai_flags: c_int,
|
||||
ai_family: c_int,
|
||||
ai_socktype: c_int,
|
||||
ai_protocol: c_int,
|
||||
ai_addrlen: size_t,
|
||||
ai_canonname: *char,
|
||||
priv ai_flags: c_int,
|
||||
priv ai_family: c_int,
|
||||
priv ai_socktype: c_int,
|
||||
priv ai_protocol: c_int,
|
||||
priv ai_addrlen: size_t,
|
||||
priv ai_canonname: *char,
|
||||
ai_addr: *sockaddr,
|
||||
ai_next: *addrinfo
|
||||
}
|
||||
|
|
@ -960,8 +960,8 @@ pub unsafe fn freeaddrinfo(ai: *addrinfo) {
|
|||
}
|
||||
|
||||
pub struct uv_err_data {
|
||||
err_name: ~str,
|
||||
err_msg: ~str,
|
||||
priv err_name: ~str,
|
||||
priv err_msg: ~str,
|
||||
}
|
||||
|
||||
extern {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ pub struct Process {
|
|||
|
||||
/// Options that can be given when starting a Process.
|
||||
pub struct ProcessOptions<'self> {
|
||||
|
||||
/**
|
||||
* If this is None then the new process will have the same initial
|
||||
* environment as the parent process.
|
||||
|
|
@ -99,7 +98,6 @@ impl <'self> ProcessOptions<'self> {
|
|||
|
||||
/// The output of a finished process.
|
||||
pub struct ProcessOutput {
|
||||
|
||||
/// The status (exit code) of the process.
|
||||
status: int,
|
||||
|
||||
|
|
|
|||
|
|
@ -998,7 +998,6 @@ pub fn utf8_char_width(b: u8) -> uint {
|
|||
pub struct CharRange {
|
||||
/// Current `char`
|
||||
ch: char,
|
||||
|
||||
/// Index of the first byte of the next `char`
|
||||
next: uint
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ pub enum SchedMode {
|
|||
*
|
||||
*/
|
||||
pub struct SchedOpts {
|
||||
mode: SchedMode,
|
||||
priv mode: SchedMode,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,11 +144,11 @@ pub struct SchedOpts {
|
|||
* scheduler other tasks will be impeded or even blocked indefinitely.
|
||||
*/
|
||||
pub struct TaskOpts {
|
||||
linked: bool,
|
||||
supervised: bool,
|
||||
watched: bool,
|
||||
indestructible: bool,
|
||||
notify_chan: Option<Chan<TaskResult>>,
|
||||
priv linked: bool,
|
||||
priv supervised: bool,
|
||||
priv watched: bool,
|
||||
priv indestructible: bool,
|
||||
priv notify_chan: Option<Chan<TaskResult>>,
|
||||
name: Option<SendStr>,
|
||||
sched: SchedOpts,
|
||||
stack_size: Option<uint>
|
||||
|
|
@ -170,9 +170,9 @@ pub struct TaskOpts {
|
|||
// FIXME (#3724): Replace the 'consumed' bit with move mode on self
|
||||
pub struct TaskBuilder {
|
||||
opts: TaskOpts,
|
||||
gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
|
||||
can_not_copy: Option<util::NonCopyable>,
|
||||
consumed: bool,
|
||||
priv gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
|
||||
priv can_not_copy: Option<util::NonCopyable>,
|
||||
priv consumed: bool,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -308,10 +308,10 @@ fn each_ancestor(list: &mut AncestorList,
|
|||
// One of these per task.
|
||||
pub struct Taskgroup {
|
||||
// List of tasks with whose fates this one's is intertwined.
|
||||
tasks: TaskGroupArc, // 'none' means the group has failed.
|
||||
priv tasks: TaskGroupArc, // 'none' means the group has failed.
|
||||
// Lists of tasks who will kill us if they fail, but whom we won't kill.
|
||||
ancestors: AncestorList,
|
||||
notifier: Option<AutoNotify>,
|
||||
priv ancestors: AncestorList,
|
||||
priv notifier: Option<AutoNotify>,
|
||||
}
|
||||
|
||||
impl Drop for Taskgroup {
|
||||
|
|
|
|||
|
|
@ -49,23 +49,23 @@ pub struct TyDesc {
|
|||
align: uint,
|
||||
|
||||
// Called on a copy of a value of type `T` *after* memcpy
|
||||
take_glue: GlueFn,
|
||||
priv take_glue: GlueFn,
|
||||
|
||||
// Called when a value of type `T` is no longer needed
|
||||
drop_glue: GlueFn,
|
||||
|
||||
// Called by drop glue when a value of type `T` can be freed
|
||||
free_glue: GlueFn,
|
||||
priv free_glue: GlueFn,
|
||||
|
||||
// Called by reflection visitor to visit a value of type `T`
|
||||
visit_glue: GlueFn,
|
||||
priv visit_glue: GlueFn,
|
||||
|
||||
// If T represents a box pointer (`@U` or `~U`), then
|
||||
// `borrow_offset` is the amount that the pointer must be adjusted
|
||||
// to find the payload. This is always derivable from the type
|
||||
// `U`, but in the case of `@Trait` or `~Trait` objects, the type
|
||||
// `U` is unknown.
|
||||
borrow_offset: uint,
|
||||
priv borrow_offset: uint,
|
||||
|
||||
// Name corresponding to the type
|
||||
name: &'static str
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use unstable::intrinsics::TyDesc;
|
|||
pub struct Box<T> {
|
||||
ref_count: uint,
|
||||
type_desc: *TyDesc,
|
||||
prev: *Box<T>,
|
||||
priv prev: *Box<T>,
|
||||
next: *Box<T>,
|
||||
data: T
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
|
|||
type rust_little_lock = *libc::c_void;
|
||||
|
||||
pub struct LittleLock {
|
||||
l: rust_little_lock,
|
||||
priv l: rust_little_lock,
|
||||
}
|
||||
|
||||
impl Drop for LittleLock {
|
||||
|
|
@ -353,7 +353,7 @@ struct ExData<T> {
|
|||
* need to block or deschedule while accessing shared state, use extra::sync::RWArc.
|
||||
*/
|
||||
pub struct Exclusive<T> {
|
||||
x: UnsafeArc<ExData<T>>
|
||||
priv x: UnsafeArc<ExData<T>>
|
||||
}
|
||||
|
||||
impl<T:Send> Clone for Exclusive<T> {
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ pub enum MethodProvenance {
|
|||
pub enum Def {
|
||||
DefFn(DefId, purity),
|
||||
DefStaticMethod(/* method */ DefId, MethodProvenance, purity),
|
||||
DefSelf(NodeId),
|
||||
DefSelf(NodeId, bool /* is_mutbl */),
|
||||
DefSelfTy(/* trait id */ NodeId),
|
||||
DefMod(DefId),
|
||||
DefForeignMod(DefId),
|
||||
|
|
@ -921,10 +921,10 @@ pub enum ret_style {
|
|||
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
|
||||
pub enum explicit_self_ {
|
||||
sty_static, // no self
|
||||
sty_value, // `self`
|
||||
sty_region(Option<Lifetime>, Mutability), // `&'lt self`
|
||||
sty_value(Mutability), // `self`
|
||||
sty_region(Option<Lifetime>, Mutability), // `&'lt self`
|
||||
sty_box(Mutability), // `@self`
|
||||
sty_uniq // `~self`
|
||||
sty_uniq(Mutability) // `~self`
|
||||
}
|
||||
|
||||
pub type explicit_self = Spanned<explicit_self_>;
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ pub fn def_id_of_def(d: Def) -> DefId {
|
|||
DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
|
||||
id
|
||||
}
|
||||
DefArg(id, _) | DefLocal(id, _) | DefSelf(id) | DefSelfTy(id)
|
||||
DefArg(id, _) | DefLocal(id, _) | DefSelf(id, _) | DefSelfTy(id)
|
||||
| DefUpvar(id, _, _, _) | DefBinding(id, _) | DefRegion(id)
|
||||
| DefTyParamBinder(id) | DefLabel(id) => {
|
||||
local_def(id)
|
||||
|
|
|
|||
|
|
@ -240,13 +240,13 @@ pub fn get_explicit_self(cx: @ExtCtxt, span: Span, self_ptr: &Option<PtrTy>)
|
|||
let self_path = cx.expr_self(span);
|
||||
match *self_ptr {
|
||||
None => {
|
||||
(self_path, respan(span, ast::sty_value))
|
||||
(self_path, respan(span, ast::sty_value(ast::MutImmutable)))
|
||||
}
|
||||
Some(ref ptr) => {
|
||||
let self_ty = respan(
|
||||
span,
|
||||
match *ptr {
|
||||
Send => ast::sty_uniq,
|
||||
Send => ast::sty_uniq(ast::MutImmutable),
|
||||
Managed(mutbl) => ast::sty_box(mutbl),
|
||||
Borrowed(ref lt, mutbl) => {
|
||||
let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s)));
|
||||
|
|
|
|||
|
|
@ -3438,15 +3438,11 @@ impl Parser {
|
|||
|
||||
// parse the argument list and result type of a function
|
||||
// that may have a self type.
|
||||
fn parse_fn_decl_with_self(
|
||||
&self,
|
||||
parse_arg_fn:
|
||||
&fn(&Parser) -> arg
|
||||
) -> (explicit_self, fn_decl) {
|
||||
fn maybe_parse_explicit_self(
|
||||
cnstr: &fn(v: Mutability) -> ast::explicit_self_,
|
||||
p: &Parser
|
||||
) -> ast::explicit_self_ {
|
||||
fn parse_fn_decl_with_self(&self, parse_arg_fn: &fn(&Parser) -> arg)
|
||||
-> (explicit_self, fn_decl) {
|
||||
|
||||
fn maybe_parse_explicit_self(cnstr: &fn(v: Mutability) -> ast::explicit_self_,
|
||||
p: &Parser) -> ast::explicit_self_ {
|
||||
// We need to make sure it isn't a type
|
||||
if p.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) ||
|
||||
((p.look_ahead(1, |t| token::is_keyword(keywords::Const, t)) ||
|
||||
|
|
@ -3524,25 +3520,39 @@ impl Parser {
|
|||
self.span_err(*self.last_span,
|
||||
"mutability declaration not allowed here");
|
||||
}
|
||||
sty_uniq
|
||||
sty_uniq(MutImmutable)
|
||||
}, self)
|
||||
}
|
||||
token::IDENT(*) if self.is_self_ident() => {
|
||||
self.bump();
|
||||
sty_value
|
||||
sty_value(MutImmutable)
|
||||
}
|
||||
token::BINOP(token::STAR) => {
|
||||
// Possibly "*self" or "*mut self" -- not supported. Try to avoid
|
||||
// emitting cryptic "unexpected token" errors.
|
||||
self.bump();
|
||||
if self.token_is_mutability(self.token) {
|
||||
self.bump();
|
||||
}
|
||||
let mutability = if self.token_is_mutability(self.token) {
|
||||
self.parse_mutability()
|
||||
} else { MutImmutable };
|
||||
if self.is_self_ident() {
|
||||
self.span_err(*self.span, "cannot pass self by unsafe pointer");
|
||||
self.bump();
|
||||
}
|
||||
sty_value
|
||||
sty_value(mutability)
|
||||
}
|
||||
_ if self.token_is_mutability(self.token) &&
|
||||
self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => {
|
||||
let mutability = self.parse_mutability();
|
||||
self.expect_self_ident();
|
||||
sty_value(mutability)
|
||||
}
|
||||
_ if self.token_is_mutability(self.token) &&
|
||||
self.look_ahead(1, |t| *t == token::TILDE) &&
|
||||
self.look_ahead(2, |t| token::is_keyword(keywords::Self, t)) => {
|
||||
let mutability = self.parse_mutability();
|
||||
self.bump();
|
||||
self.expect_self_ident();
|
||||
sty_uniq(mutability)
|
||||
}
|
||||
_ => {
|
||||
sty_static
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue