diff --git a/doc/rust.md b/doc/rust.md index 2d4b0c15cb83..40a3bc12798f 100644 --- a/doc/rust.md +++ b/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 diff --git a/doc/tutorial.md b/doc/tutorial.md index 42617a96daab..7451919c5bec 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -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 diff --git a/mk/tests.mk b/mk/tests.mk index c06c234e951d..d6fc5ecb8e5a 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -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: $$@) diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index 66dad4721aa9..1ce52d1d2784 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -521,15 +521,15 @@ fn borrow_rwlock(state: *mut RWArcInner) -> *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> { diff --git a/src/libextra/base64.rs b/src/libextra/base64.rs index 3960be466869..032de0b5f4a7 100644 --- a/src/libextra/base64.rs +++ b/src/libextra/base64.rs @@ -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 + priv line_length: Option } /// 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::()); assert_eq!(v.to_base64(STANDARD).from_base64().unwrap(), v); } diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index bf0fde807d3f..96123ad75b25 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -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() -> ! { diff --git a/src/libextra/crypto/cryptoutil.rs b/src/libextra/crypto/cryptoutil.rs index 97b82383d843..bb3524a7d490 100644 --- a/src/libextra/crypto/cryptoutil.rs +++ b/src/libextra/crypto/cryptoutil.rs @@ -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)); diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs index 006ae3520c60..34515a2b955c 100644 --- a/src/libextra/ebml.rs +++ b/src/libextra/ebml.rs @@ -50,7 +50,7 @@ impl Doc { } pub struct TaggedDoc { - tag: uint, + priv tag: uint, doc: Doc, } diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index fda88c583ce0..49072dab6d02 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -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 { diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 9d6c2e8aa820..3f3b588e8bc1 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -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::(range)); } do 20.times { diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index a0ce29cd1b64..38b4d83fe0be 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -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] } diff --git a/src/libextra/glob.rs b/src/libextra/glob.rs index cdcb730e8bed..5297b48b0e15 100644 --- a/src/libextra/glob.rs +++ b/src/libextra/glob.rs @@ -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 { diff --git a/src/libextra/io_util.rs b/src/libextra/io_util.rs index 904ed13eabbc..27a09be3a625 100644 --- a/src/libextra/io_util.rs +++ b/src/libextra/io_util.rs @@ -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 { diff --git a/src/libextra/json.rs b/src/libextra/json.rs index e151568ad7f8..90260282e4b5 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -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 { diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index abb802c06f3b..bdec950c87bc 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -20,8 +20,8 @@ use super::bigint::BigInt; #[deriving(Clone)] #[allow(missing_doc)] pub struct Ratio { - numer: T, - denom: T + priv numer: T, + priv denom: T } /// Alias for a `Ratio` of machine-sized integers. diff --git a/src/libextra/semver.rs b/src/libextra/semver.rs index e5ef9ee12d5a..02c35000ce3a 100644 --- a/src/libextra/semver.rs +++ b/src/libextra/semver.rs @@ -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 { diff --git a/src/libextra/sort.rs b/src/libextra/sort.rs index d884f4f05c17..2a456f8de3eb 100644 --- a/src/libextra/sort.rs +++ b/src/libextra/sort.rs @@ -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); diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index cc6ce715ad33..40f99716ca79 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -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 { diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index 5a2c1e0998ca..131cf063d1d3 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -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 } diff --git a/src/libextra/task_pool.rs b/src/libextra/task_pool.rs index 804ccd2a9fde..f7db66dc4e0c 100644 --- a/src/libextra/task_pool.rs +++ b/src/libextra/task_pool.rs @@ -28,8 +28,8 @@ enum Msg { } pub struct TaskPool { - channels: ~[Chan>], - next_index: uint, + priv channels: ~[Chan>], + priv next_index: uint, } #[unsafe_destructor] diff --git a/src/libextra/term.rs b/src/libextra/term.rs index cebe0ba9aa65..878224890e61 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -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, } diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index d1a0a86334af..c0a5d9d53aa9 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -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 { diff --git a/src/libextra/terminfo/terminfo.rs b/src/libextra/terminfo/terminfo.rs index 57e00885b2fb..06bf6e47c329 100644 --- a/src/libextra/terminfo/terminfo.rs +++ b/src/libextra/terminfo/terminfo.rs @@ -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 diff --git a/src/libextra/test.rs b/src/libextra/test.rs index 1f8405dca949..f95c7aa22b7f 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -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)] diff --git a/src/libextra/time.rs b/src/libextra/time.rs index ab701f1f982c..71569be3a819 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -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 { diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index ad196b32fb2c..7ef9ba76b995 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -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); diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 3ee102513231..4d79b2059db5 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -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, - logger: RWArc, - cfg: Arc, + priv logger: RWArc, + priv cfg: Arc, /// 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 + priv freshness: Arc } 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> { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index aa1c4c1eb7ec..102327303294 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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])); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 9f40593a93ae..bae0dcc2a520 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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); } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 294bbcb46f7b..3d7f28b8b30b 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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) } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 6c53fc1602f2..71934c9f2a7e 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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_)); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 37e89e58fa56..eb03027ad71f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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 } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 1ed517c95129..5001614647a8 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -227,7 +227,7 @@ pub fn moved_variable_node_id_from_def(def: Def) -> Option { DefBinding(nid, _) | DefArg(nid, _) | DefLocal(nid, _) | - DefSelf(nid) => Some(nid), + DefSelf(nid, _) => Some(nid), _ => None } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index b480aaac1acb..ee36b807ac79 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -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, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 238b15fe5979..56f1e0478410 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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 => { diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index a5be9a3ca5e1..d9f7cdeeb2ef 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -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), } } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a8c18c721671..61384c72efa2 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -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), } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index ccda6bbaf9d1..dd0c6c12a69a 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -672,7 +672,7 @@ fn ty_of_method_or_bare_fn( { 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( 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})) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index f6efd3aa5ad1..af1d5ce3cc60 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -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, } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index eddf8aa51850..4514564ff1f6 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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); diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 06a130594623..09fc7b5c15c3 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -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) => { diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 6ee7f8c17274..dd1ad8263da8 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -388,8 +388,8 @@ impl Clean 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"); diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs index 1f5802927a64..c67b6f52c7e3 100644 --- a/src/librustpkg/api.rs +++ b/src/librustpkg/api.rs @@ -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 { diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index 01bd4e6736ed..91edc2758264 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -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; +} diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 3f1f2a1f59d5..72197219fc5a 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -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 } } diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index 68d2d9662e34..17ba79862e0c 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -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 } diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index c47c89d777b4..a48ef23115cc 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -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) +} diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index 6c55f7af0c06..37a5a2ea7113 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -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 - /// 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 + /// 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, diff --git a/src/librustpkg/target.rs b/src/librustpkg/target.rs index b21641a5e53e..9863fd0a89ee 100644 --- a/src/librustpkg/target.rs +++ b/src/librustpkg/target.rs @@ -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 diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 58c6b4ff81fb..16e13f700921 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -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}; diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/bar.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/bar.rs new file mode 100644 index 000000000000..ffbc6e2a7f9b --- /dev/null +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/bar.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn assert_true() { + assert!(true); +} diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs new file mode 100644 index 000000000000..542a6af402d0 --- /dev/null +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/foo.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn do_nothing() { +} \ No newline at end of file diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/lib.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/lib.rs new file mode 100644 index 000000000000..bd1cb240a34c --- /dev/null +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/lib.rs @@ -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 or the MIT license +// , 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; diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs new file mode 100644 index 000000000000..b667dc0a576f --- /dev/null +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs @@ -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 or the MIT license +// , 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); + } +} diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/lib.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/lib.rs index dc068eed143e..17386cd03c22 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/lib.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/lib.rs @@ -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; diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index db11ffa0cc64..0b838b3e0f9e 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -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, ~[]); } diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 9144c08cb733..3824f6d38def 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -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()); diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index e7fa81fc87ac..9d5c9c1a5cd6 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -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>], } diff --git a/src/libstd/io.rs b/src/libstd/io.rs index 94a6b7cfea8d..4e55c5fe60eb 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -1009,7 +1009,7 @@ impl Reader for Wrapper { } 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 { - arg: Arg, + priv arg: Arg, } impl Res { @@ -1815,9 +1815,9 @@ pub mod fsync { } pub struct Arg { - val: t, - opt_level: Option, - fsync_fn: extern "Rust" fn(f: &t, Level) -> int, + priv val: t, + priv opt_level: Option, + priv fsync_fn: extern "Rust" fn(f: &t, Level) -> int, } // fsync file after executing blk diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 01af3d931573..771be3b2a134 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -1790,9 +1790,9 @@ impl<'self, A, St> Iterator for Unfold<'self, A, St> { #[deriving(Clone)] pub struct Counter { /// 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 diff --git a/src/libstd/rand/distributions.rs b/src/libstd/rand/distributions.rs index 0902100dca60..e7bcf8ce5d3a 100644 --- a/src/libstd/rand/distributions.rs +++ b/src/libstd/rand/distributions.rs @@ -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 { + /// Generate a random value of `Support`, using `rng` as the + /// source of randomness. + fn sample(&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: Sample { + /// Generate a random value. + fn ind_sample(&self, &mut R) -> Support; +} + +/// A wrapper for generating types that implement `Rand` via the +/// `Sample` & `IndependentSample` traits. +pub struct RandSample; + +impl Sample for RandSample { + fn sample(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } +} + +impl IndependentSample for RandSample { + fn ind_sample(&self, rng: &mut R) -> Sup { + rng.gen() + } +} + +/// A value with a particular weight for use with `WeightedChoice`. +pub struct Weighted { + /// 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 { + priv items: ~[Weighted], + priv weight_range: Range +} + +impl WeightedChoice { + /// 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]) -> WeightedChoice { + // 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 Sample for WeightedChoice { + fn sample(&mut self, rng: &mut R) -> T { self.ind_sample(rng) } +} + +impl IndependentSample for WeightedChoice { + fn ind_sample(&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(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::() & 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(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::()) * 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::()) * 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 for Normal { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for Normal { + fn ind_sample(&self, rng: &mut R) -> f64 { + self.mean + self.std_dev * (*rng.gen::()) + } +} + +/// 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::().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 for Exp { + fn sample(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } +} +impl IndependentSample for Exp { + fn ind_sample(&self, rng: &mut R) -> f64 { + (*rng.gen::()) * 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(_: &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::; + + 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::::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::() 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::() as u64 * N; + } +} diff --git a/src/libstd/rand/isaac.rs b/src/libstd/rand/isaac.rs index 0068b60cfa51..42254b211a17 100644 --- a/src/libstd/rand/isaac.rs +++ b/src/libstd/rand/isaac.rs @@ -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]); } } diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index f5c60417bacb..a6efdfc66db2 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -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(rng: &mut R) -> Self; } -/// A value with a particular weight compared to other values -pub struct Weighted { - /// 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 = unsafe { cast::transmute_copy(&dest) }; - slice.len /= size_of::(); - 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 = unsafe { cast::transmute_copy(&dest) }; - slice.len /= size_of::(); - 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(&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::(); - if rand < accept_zone { - return low + NumCast::from(rand % range).unwrap(); - } - } + fn gen_range(&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(&mut self, v: &[Weighted]) -> 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(&mut self, v: &[Weighted]) - -> Option { - 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(&mut self, v: &[Weighted]) -> ~[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: 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 { 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 = 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::(); 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::(); + for _ in range(0, N) { + rng.gen::(); + } } - bh.bytes = size_of::() as u64; + bh.bytes = size_of::() as u64 * N; } #[bench] fn rand_isaac(bh: &mut BenchHarness) { let mut rng = IsaacRng::new(); do bh.iter { - rng.gen::(); + for _ in range(0, N) { + rng.gen::(); + } } - bh.bytes = size_of::() as u64; + bh.bytes = size_of::() as u64 * N; } #[bench] fn rand_isaac64(bh: &mut BenchHarness) { let mut rng = Isaac64Rng::new(); do bh.iter { - rng.gen::(); + for _ in range(0, N) { + rng.gen::(); + } } - bh.bytes = size_of::() as u64; + bh.bytes = size_of::() as u64 * N; } #[bench] fn rand_std(bh: &mut BenchHarness) { let mut rng = StdRng::new(); do bh.iter { - rng.gen::(); + for _ in range(0, N) { + rng.gen::(); + } } - bh.bytes = size_of::() as u64; + bh.bytes = size_of::() as u64 * N; } #[bench] diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 4c8cf06c55e8..5ed8d6b10d1b 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -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 } /// 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)] diff --git a/src/libstd/rand/range.rs b/src/libstd/rand/range.rs new file mode 100644 index 000000000000..1b805a0b8f76 --- /dev/null +++ b/src/libstd/rand/range.rs @@ -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 or the MIT license +// , 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 { + priv low: X, + priv range: X, + priv accept_zone: X +} + +impl Range { + /// Create a new `Range` instance that samples uniformly from + /// `[low, high)`. Fails if `low >= high`. + pub fn new(low: X, high: X) -> Range { + assert!(low < high, "Range::new called with `low >= high`"); + SampleRange::construct_range(low, high) + } +} + +impl Sample for Range { + #[inline] + fn sample(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) } +} +impl IndependentSample for Range { + fn ind_sample(&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; + + /// Sample a value from the given `Range` with the given `Rng` as + /// a source of randomness. + fn sample_range(r: &Range, 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: &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: &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) + } + +} diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index 1cd767277167..d63b14f982d4 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -41,7 +41,7 @@ pub fn align(size: uint, align: uint) -> uint { /// Adaptor to wrap around visitors implementing MovePtr. pub struct MovePtrAdaptor { - inner: V + priv inner: V } pub fn MovePtrAdaptor(v: V) -> MovePtrAdaptor { MovePtrAdaptor { inner: v } diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index 4feb1ca19104..d03621eb60d2 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -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, diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs index 3c2000c522c4..4426a3eafe1e 100644 --- a/src/libstd/rt/borrowck.rs +++ b/src/libstd/rt/borrowck.rs @@ -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]> { diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index 4eae8bdc9a82..6319fdead17d 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -48,14 +48,14 @@ struct Packet { // A one-shot channel. pub struct ChanOne { - void_packet: *mut Void, - suppress_finalize: bool + priv void_packet: *mut Void, + priv suppress_finalize: bool } /// A one-shot port. pub struct PortOne { - void_packet: *mut Void, - suppress_finalize: bool + priv void_packet: *mut Void, + priv suppress_finalize: bool } pub fn oneshot() -> (PortOne, ChanOne) { @@ -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 { diff --git a/src/libstd/rt/context.rs b/src/libstd/rt/context.rs index 7f7545ca230f..b86dbfd6fb05 100644 --- a/src/libstd/rt/context.rs +++ b/src/libstd/rt/context.rs @@ -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; } diff --git a/src/libstd/rt/crate_map.rs b/src/libstd/rt/crate_map.rs index d33e1af90f8d..dd71426938dc 100644 --- a/src/libstd/rt/crate_map.rs +++ b/src/libstd/rt/crate_map.rs @@ -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))] diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index e25b03be361a..a43bcd8142e1 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -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. diff --git a/src/libstd/rt/io/flate.rs b/src/libstd/rt/io/flate.rs index 7c72ce6ba891..8a5aa171eb80 100644 --- a/src/libstd/rt/io/flate.rs +++ b/src/libstd/rt/io/flate.rs @@ -17,7 +17,7 @@ use super::*; /// A Writer decorator that compresses using the 'deflate' scheme pub struct DeflateWriter { - inner_writer: W + priv inner_writer: W } impl DeflateWriter { @@ -56,7 +56,7 @@ impl Decorator for DeflateWriter { /// A Reader decorator that decompresses using the 'deflate' scheme pub struct InflateReader { - inner_reader: R + priv inner_reader: R } impl InflateReader { diff --git a/src/libstd/rt/io/mock.rs b/src/libstd/rt/io/mock.rs index c46e1372c641..44709c7b7b68 100644 --- a/src/libstd/rt/io/mock.rs +++ b/src/libstd/rt/io/mock.rs @@ -13,7 +13,7 @@ use rt::io::{Reader, Writer}; pub struct MockReader { read: ~fn(buf: &mut [u8]) -> Option, - 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 { diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 97d44da765a5..a80c1aab3988 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -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 diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 8029e3f64317..19f17ca966d2 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -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, // Handle to a watching parent, if we have one, for exit code propagation. - watching_parent: Option, + priv watching_parent: Option, // 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, + priv spare_kill_flag: Option, } impl Drop for KillFlag { diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 262da9f3b8e5..14df292343e9 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -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 { diff --git a/src/libstd/rt/rc.rs b/src/libstd/rt/rc.rs index 2ba00c3a2fba..2699dab6d38a 100644 --- a/src/libstd/rt/rc.rs +++ b/src/libstd/rt/rc.rs @@ -24,7 +24,7 @@ use libc::c_void; use cast; pub struct RC { - p: *c_void // ~(uint, T) + priv p: *c_void // ~(uint, T) } impl RC { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index ca521c792dc7..501def8b0607 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -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 { diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 336d2518e437..ee163bab3c06 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -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, + priv cleanup_job: Option, /// 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, + priv friend_handle: Option, /// 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) => { diff --git a/src/libstd/rt/stack.rs b/src/libstd/rt/stack.rs index fddee5882b9a..55bd4b0732a6 100644 --- a/src/libstd/rt/stack.rs +++ b/src/libstd/rt/stack.rs @@ -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 { diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index a6f9e11e40e9..c4f352501a08 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -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 } diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index e774b81da350..949d73ecc4fc 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -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 { diff --git a/src/libstd/rt/tube.rs b/src/libstd/rt/tube.rs index b8e535e4c7df..16fd3fa38eae 100644 --- a/src/libstd/rt/tube.rs +++ b/src/libstd/rt/tube.rs @@ -28,7 +28,7 @@ struct TubeState { } pub struct Tube { - p: RC> + priv p: RC> } impl Tube { diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs index 83a7e64b1397..f2abcd3aca7e 100644 --- a/src/libstd/rt/uv/addrinfo.rs +++ b/src/libstd/rt/uv/addrinfo.rs @@ -25,7 +25,7 @@ type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option) pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t); pub struct RequestData { - getaddrinfo_cb: Option, + priv getaddrinfo_cb: Option, } impl GetAddrInfoRequest { diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 3a6d858df791..5d64ca4d755c 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -25,7 +25,7 @@ pub struct FsRequest(*uvll::uv_fs_t); impl Request for FsRequest {} pub struct RequestData { - complete_cb: Option + priv complete_cb: Option } impl FsRequest { diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 67926b35a621..3a6a3acbc534 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -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 diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index c7e51b3485dd..8dd0f8a6b106 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -180,7 +180,7 @@ fn socket_name>(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 + priv exit_flag: Exclusive } 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>, + priv listener: UvTcpListener, + priv incoming: Tube>, } 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, + priv home: Option, // All None until the process exits (exit_error may stay None) priv exit_status: Option, diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index a80d5cbc1fb4..96c5dd068d0b 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -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 { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 36e73a6dd51b..c4cb8be2061f 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -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, diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 883934124a6c..f134788942cd 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -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 } diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 970a62b676fc..30c99c628853 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -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>, + priv linked: bool, + priv supervised: bool, + priv watched: bool, + priv indestructible: bool, + priv notify_chan: Option>, name: Option, sched: SchedOpts, stack_size: Option @@ -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, - consumed: bool, + priv gen_body: Option<~fn(v: ~fn()) -> ~fn()>, + priv can_not_copy: Option, + priv consumed: bool, } /** diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 7cf0f04c7e9f..dec13eded398 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -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, + priv ancestors: AncestorList, + priv notifier: Option, } impl Drop for Taskgroup { diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 68fdfd730132..ee44bf4d9964 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -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 diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs index ac0e83df7ef5..b5d7cc47fdc5 100644 --- a/src/libstd/unstable/raw.rs +++ b/src/libstd/unstable/raw.rs @@ -15,7 +15,7 @@ use unstable::intrinsics::TyDesc; pub struct Box { ref_count: uint, type_desc: *TyDesc, - prev: *Box, + priv prev: *Box, next: *Box, data: T } diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 4c6ad469d8cb..9d15dd031e0d 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -304,7 +304,7 @@ pub unsafe fn atomically(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 { * need to block or deschedule while accessing shared state, use extra::sync::RWArc. */ pub struct Exclusive { - x: UnsafeArc> + priv x: UnsafeArc> } impl Clone for Exclusive { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 01033e829f6a..372f1950c1de 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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, Mutability), // `&'lt self` + sty_value(Mutability), // `self` + sty_region(Option, Mutability), // `&'lt self` sty_box(Mutability), // `@self` - sty_uniq // `~self` + sty_uniq(Mutability) // `~self` } pub type explicit_self = Spanned; diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index bdebc9872e69..1d9d5512ff42 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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) diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs index 83c73e3d85f2..c60259304aef 100644 --- a/src/libsyntax/ext/deriving/ty.rs +++ b/src/libsyntax/ext/deriving/ty.rs @@ -240,13 +240,13 @@ pub fn get_explicit_self(cx: @ExtCtxt, span: Span, self_ptr: &Option) 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))); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ed6019e1a55a..605e259cf0c2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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 diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b245bd75ace7..0e330da31e62 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1686,8 +1686,14 @@ pub fn explicit_self_to_str(explicit_self: &ast::explicit_self_, intr: @ident_in pub fn print_explicit_self(s: @ps, explicit_self: ast::explicit_self_) -> bool { match explicit_self { ast::sty_static => { return false; } - ast::sty_value => { word(s.s, "self"); } - ast::sty_uniq => { word(s.s, "~self"); } + ast::sty_value(m) => { + print_mutability(s, m); + word(s.s, "self"); + } + ast::sty_uniq(m) => { + print_mutability(s, m); + word(s.s, "~self"); + } ast::sty_region(ref lt, m) => { word(s.s, "&"); print_opt_lifetime(s, lt); diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 17f05b590905..770205376616 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -672,6 +672,8 @@ extern "C" CDECL void rust_win32_rand_acquire(HCRYPTPROV* phProv) { win32_require (_T("CryptAcquireContext"), + // changes to the parameters here should be reflected in the docs of + // std::rand::os::OSRng CryptAcquireContext(phProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT|CRYPT_SILENT)); diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index f549f747ef79..dbd1edffe782 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -90,7 +90,7 @@ fn vec_plus() { let mut v = ~[]; let mut i = 0; while i < 1500 { - let rv = vec::from_elem(r.gen_integer_range(0u, i + 1), i); + let rv = vec::from_elem(r.gen_range(0u, i + 1), i); if r.gen() { v.push_all_move(rv); } else { @@ -106,7 +106,7 @@ fn vec_append() { let mut v = ~[]; let mut i = 0; while i < 1500 { - let rv = vec::from_elem(r.gen_integer_range(0u, i + 1), i); + let rv = vec::from_elem(r.gen_range(0u, i + 1), i); if r.gen() { v = vec::append(v, rv); } @@ -122,7 +122,7 @@ fn vec_push_all() { let mut v = ~[]; for i in range(0u, 1500) { - let mut rv = vec::from_elem(r.gen_integer_range(0u, i + 1), i); + let mut rv = vec::from_elem(r.gen_range(0u, i + 1), i); if r.gen() { v.push_all(rv); } diff --git a/src/test/compile-fail/issue-5216.rs b/src/test/compile-fail/issue-5216.rs new file mode 100644 index 000000000000..9f88ba72f059 --- /dev/null +++ b/src/test/compile-fail/issue-5216.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f() { } +struct S(&fn()); //~ ERROR Illegal anonymous lifetime +pub static C: S = S(f); //~ ERROR Illegal anonymous lifetime + + +fn g() { } +type T = &fn(); //~ ERROR Illegal anonymous lifetime +pub static D: T = g; //~ ERROR Illegal anonymous lifetime + +fn main() {} diff --git a/src/test/compile-fail/issue-5500-1.rs b/src/test/compile-fail/issue-5500-1.rs new file mode 100644 index 000000000000..f709aadf4ac8 --- /dev/null +++ b/src/test/compile-fail/issue-5500-1.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-test + +struct TrieMapIterator<'self> { + priv node: &'self uint +} + +fn main() { + let a = 5; + let _iter = TrieMapIterator{node: &a}; //~ ERROR bad + _iter.node = & + fail!() +} diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs new file mode 100644 index 000000000000..7bf20037f5ab --- /dev/null +++ b/src/test/compile-fail/issue-5500.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-test + +fn main() { &fail!() } //~ ERROR bad diff --git a/src/test/run-pass/by-value-self-in-mut-slot.rs b/src/test/run-pass/by-value-self-in-mut-slot.rs new file mode 100644 index 000000000000..aa88004cd119 --- /dev/null +++ b/src/test/run-pass/by-value-self-in-mut-slot.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct X { + a: int +} + +trait Changer { + fn change(mut self) -> Self; +} + +impl Changer for X { + fn change(mut self) -> X { + self.a = 55; + self + } +} + +pub fn main() { + let x = X { a: 32 }; + let new_x = x.change(); + assert_eq!(new_x.a, 55); +} diff --git a/src/test/run-pass/issue-6334.rs b/src/test/run-pass/issue-6334.rs new file mode 100644 index 000000000000..740a2212726d --- /dev/null +++ b/src/test/run-pass/issue-6334.rs @@ -0,0 +1,56 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-test + +// Tests that everything still compiles and runs fine even when +// we reorder the bounds. + +trait A { + fn a(&self) -> uint; +} + +trait B { + fn b(&self) -> uint; +} + +trait C { + fn combine(&self, t: &T) -> uint; +} + +struct Foo; + +impl A for Foo { + fn a(&self) -> uint { 1 } +} + +impl B for Foo { + fn b(&self) -> uint { 2 } +} + +struct Bar; + +impl C for Bar { + // Note below: bounds in impl decl are in reverse order. + fn combine(&self, t: &T) -> uint { + (t.a() * 100) + t.b() + } +} + +fn use_c(s: &S, t: &T) -> uint { + s.combine(t) +} + +fn main() { + let foo = Foo; + let bar = Bar; + let r = use_c(&bar, &foo); + assert_eq!(r, 102); +} diff --git a/src/test/run-pass/self-in-mut-slot-default-method.rs b/src/test/run-pass/self-in-mut-slot-default-method.rs new file mode 100644 index 000000000000..08d10fd11703 --- /dev/null +++ b/src/test/run-pass/self-in-mut-slot-default-method.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct X { + a: int +} + +trait Changer { + fn change(mut self) -> Self { + self.set_to(55); + self + } + + fn change_again(mut ~self) -> ~Self { + self.set_to(45); + self + } + + fn set_to(&mut self, a: int); +} + +impl Changer for X { + fn set_to(&mut self, a: int) { + self.a = a; + } +} + +pub fn main() { + let x = X { a: 32 }; + let new_x = x.change(); + assert_eq!(new_x.a, 55); + + let x = ~new_x; + let new_x = x.change_again(); + assert_eq!(new_x.a, 45); +} diff --git a/src/test/run-pass/uniq-self-in-mut-slot.rs b/src/test/run-pass/uniq-self-in-mut-slot.rs new file mode 100644 index 000000000000..7c2f52211761 --- /dev/null +++ b/src/test/run-pass/uniq-self-in-mut-slot.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct X { + a: int +} + +trait Changer { + fn change(mut ~self) -> ~Self; +} + +impl Changer for X { + fn change(mut ~self) -> ~X { + self.a = 55; + self + } +} + +pub fn main() { + let x = ~X { a: 32 }; + let new_x = x.change(); + assert_eq!(new_x.a, 55); +}