From: bors Date: Fri, 9 Aug 2013 04:41:05 +0000 (-0700) Subject: auto merge of #8350 : dim-an/rust/fix-struct-match, r=pcwalton X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=a931e04b757a795e3867ea98c81cee731bd54ac1;hp=0fadfc5fb7de47f0ffcb55a8bbfe0a75c2a4dbee;p=rust.git auto merge of #8350 : dim-an/rust/fix-struct-match, r=pcwalton Code that collects fields in struct-like patterns used to ignore wildcard patterns like `Foo{_}`. But `enter_defaults` considered struct-like patterns as default in order to overcome this (accoring to my understanding of situation). However such behaviour caused code like this: ``` enum E { Foo{f: int}, Bar } let e = Bar; match e { Foo{f: _f} => { /* do something (1) */ } _ => { /* do something (2) */ } } ``` consider pattern `Foo{f: _f}` as default. That caused inproper behaviour and even segfaults while trying to destruct `Bar` as `Foo{f: _f}`. Issues: #5625 , #5530. This patch fixes `collect_record_or_struct_fields` to split cases of single wildcard struct-like pattern and no struct-like pattern at all. Former case resolved with `enter_rec_or_struct` (and not with `enter_defaults`). Closes #5625. Closes #5530. --- diff --git a/Makefile.in b/Makefile.in index d78176e5699..a9a41a073d0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -297,7 +297,7 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/librustc/, \ LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \ - *.rs */*.rs */*/*.rs)) + *.rs */*.rs */*/*.rs */*/*/*.rs)) DRIVER_CRATE := $(S)src/driver/driver.rs diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index 047b57e56a6..d1aa793e5fc 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -228,6 +228,48 @@ unsafe fn kaboom(ptr: *int) -> int { *ptr } This function can only be called from an `unsafe` block or another `unsafe` function. +# Accessing foreign globals + +Foreign APIs often export a global variable which could do something like track +global state. In order to access these variables, you declare them in `extern` +blocks with the `static` keyword: + +~~~{.xfail-test} +use std::libc; + +#[link_args = "-lreadline"] +extern { + static rl_readline_version: libc::c_int; +} + +fn main() { + println(fmt!("You have readline version %d installed.", + rl_readline_version as int)); +} +~~~ + +Alternatively, you may need to alter global state provided by a foreign +interface. To do this, statics can be declared with `mut` so rust can mutate +them. + +~~~{.xfail-test} +use std::libc; +use std::ptr; + +#[link_args = "-lreadline"] +extern { + static mut rl_prompt: *libc::c_char; +} + +fn main() { + do "[my-awesome-shell] $".as_c_str |buf| { + unsafe { rl_prompt = buf; } + // get a line, process it + unsafe { rl_prompt = ptr::null(); } + } +} +~~~ + # Foreign calling conventions Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index b2ef624d1ac..d190c332e66 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -424,7 +424,7 @@ there is no way to "catch" the exception. All tasks are, by default, _linked_ to each other. That means that the fates of all tasks are intertwined: if one fails, so do all the others. -~~~ +~~~{.xfail-test .linked-failure} # use std::task::spawn; # use std::task; # fn do_some_work() { loop { task::yield() } } @@ -447,7 +447,7 @@ pattern-match on a result to check whether it's an `Ok` result with an `int` field (representing a successful result) or an `Err` result (representing termination with an error). -~~~ +~~~{.xfail-test .linked-failure} # use std::task; # fn some_condition() -> bool { false } # fn calculate_result() -> int { 0 } @@ -490,9 +490,10 @@ proceed). Hence, you will need different _linked failure modes_. By default, task failure is _bidirectionally linked_, which means that if either task fails, it kills the other one. -~~~ +~~~{.xfail-test .linked-failure} # use std::task; -# fn sleep_forever() { loop { task::yield() } } +# use std::comm::oneshot; +# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } # do task::try { do spawn { do spawn { @@ -511,11 +512,12 @@ function `task::try`, which we saw previously, uses `spawn_supervised` internally, with additional logic to wait for the child task to finish before returning. Hence: -~~~ +~~~{.xfail-test .linked-failure} # use std::comm::{stream, Chan, Port}; +# use std::comm::oneshot; # use std::task::{spawn, try}; # use std::task; -# fn sleep_forever() { loop { task::yield() } } +# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } # do task::try { let (receiver, sender): (Port, Chan) = stream(); do spawn { // Bidirectionally linked @@ -541,10 +543,11 @@ also fail. Supervised task failure propagates across multiple generations even if an intermediate generation has already exited: -~~~ +~~~{.xfail-test .linked-failure} # use std::task; -# fn sleep_forever() { loop { task::yield() } } -# fn wait_for_a_while() { do 1000.times { task::yield() } } +# use std::comm::oneshot; +# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } } +# fn wait_for_a_while() { for _ in range(0, 1000u) { task::yield() } } # do task::try:: { do task::spawn_supervised { do task::spawn_supervised { @@ -560,10 +563,10 @@ fail!(); // Will kill grandchild even if child has already exited Finally, tasks can be configured to not propagate failure to each other at all, using `task::spawn_unlinked` for _isolated failure_. -~~~ +~~~{.xfail-test .linked-failure} # use std::task; # fn random() -> uint { 100 } -# fn sleep_for(i: uint) { do i.times { task::yield() } } +# fn sleep_for(i: uint) { for _ in range(0, i) { task::yield() } } # do task::try::<()> { let (time1, time2) = (random(), random()); do task::spawn_unlinked { @@ -588,7 +591,7 @@ that repeatedly receives a `uint` message, converts it to a string, and sends the string in response. The child terminates when it receives `0`. Here is the function that implements the child task: -~~~~ +~~~{.xfail-test .linked-failure} # use extra::comm::DuplexStream; # use std::uint; fn stringifier(channel: &DuplexStream<~str, uint>) { @@ -611,7 +614,7 @@ response itself is simply the stringified version of the received value, Here is the code for the parent task: -~~~~ +~~~{.xfail-test .linked-failure} # use std::task::spawn; # use std::uint; # use extra::comm::DuplexStream; diff --git a/doc/tutorial.md b/doc/tutorial.md index a5f2001eaf5..40e276ae04a 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -1894,7 +1894,7 @@ struct TimeBomb { impl Drop for TimeBomb { fn drop(&self) { - do self.explosivity.times { + for _ in range(0, self.explosivity) { println("blam!"); } } @@ -2288,8 +2288,8 @@ pub mod farm { } impl Farm { - priv fn feed_chickens(&self) { ... } - priv fn feed_cows(&self) { ... } + fn feed_chickens(&self) { ... } + fn feed_cows(&self) { ... } pub fn add_chicken(&self, c: Chicken) { ... } } diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 4e4261e8b2b..4262aba9a85 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -109,8 +109,8 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Path { compile_lib_path: getopts::opt_str(matches, "compile-lib-path"), run_lib_path: getopts::opt_str(matches, "run-lib-path"), rustc_path: opt_path(matches, "rustc-path"), - clang_path: getopts::opt_maybe_str(matches, "clang-path").map(|s| Path(*s)), - llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map(|s| Path(*s)), + clang_path: getopts::opt_maybe_str(matches, "clang-path").map_move(|s| Path(s)), + llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map_move(|s| Path(s)), src_base: opt_path(matches, "src-base"), build_base: opt_path(matches, "build-base"), aux_base: opt_path(matches, "aux-base"), @@ -123,14 +123,14 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Path { } else { None }, - logfile: getopts::opt_maybe_str(matches, "logfile").map(|s| Path(*s)), - save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map(|s| Path(*s)), + logfile: getopts::opt_maybe_str(matches, "logfile").map_move(|s| Path(s)), + save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map_move(|s| Path(s)), ratchet_metrics: - getopts::opt_maybe_str(matches, "ratchet-metrics").map(|s| Path(*s)), + getopts::opt_maybe_str(matches, "ratchet-metrics").map_move(|s| Path(s)), ratchet_noise_percent: getopts::opt_maybe_str(matches, - "ratchet-noise-percent").map(|s| - f64::from_str(*s).unwrap()), + "ratchet-noise-percent").map_move(|s| + f64::from_str(s).unwrap()), runtool: getopts::opt_maybe_str(matches, "runtool"), rustcflags: getopts::opt_maybe_str(matches, "rustcflags"), jit: getopts::opt_present(matches, "jit"), diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 5c1cc78d678..9c176b504b2 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -162,9 +162,8 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { round += 1; } - let mut expected = - match props.pp_exact { - Some(ref file) => { + let mut expected = match props.pp_exact { + Some(ref file) => { let filepath = testfile.dir_path().push_rel(file); io::read_whole_file_str(&filepath).unwrap() } @@ -413,8 +412,8 @@ fn prefix_matches( line : &str, prefix : &str ) -> bool { } } - for i in range(0u, found_flags.len()) { - if !found_flags[i] { + for (i, &flag) in found_flags.iter().enumerate() { + if !flag { let ee = &expected_errors[i]; fatal_ProcRes(fmt!("expected %s on line %u not found: %s", ee.kind, ee.line, ee.msg), ProcRes); diff --git a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang index a6415beab36..b1180098bd2 100644 --- a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang +++ b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang @@ -50,6 +50,7 @@ for if impl + in let log loop diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index cb4468f48ec..69203b753cd 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -611,6 +611,7 @@ fn test_mutex_arc_condvar() { } } } + #[test] #[should_fail] #[ignore(cfg(windows))] fn test_arc_condvar_poison() { unsafe { @@ -846,22 +847,16 @@ fn test_rw_downgrade() { } assert_eq!(*state, 42); *state = 31337; - // FIXME: #7372: hits type inference bug with iterators // send to other readers - for i in range(0u, reader_convos.len()) { - match reader_convos[i] { - (ref rc, _) => rc.send(()), - } + for &(ref rc, _) in reader_convos.iter() { + rc.send(()) } } let read_mode = arc.downgrade(write_mode); do (&read_mode).read |state| { - // FIXME: #7372: hits type inference bug with iterators // complete handshake with other readers - for i in range(0u, reader_convos.len()) { - match reader_convos[i] { - (_, ref rp) => rp.recv(), - } + for &(_, ref rp) in reader_convos.iter() { + rp.recv() } wc1.send(()); // tell writer to try again assert_eq!(*state, 31337); diff --git a/src/libextra/base64.rs b/src/libextra/base64.rs index 550b891a4db..b4431004bd7 100644 --- a/src/libextra/base64.rs +++ b/src/libextra/base64.rs @@ -9,6 +9,7 @@ // except according to those terms. //! Base64 binary-to-text encoding +use std::str; /// Available encoding character sets pub enum CharacterSet { @@ -40,21 +41,13 @@ pub struct Config { pub static MIME: Config = Config {char_set: Standard, pad: true, line_length: Some(76)}; -static STANDARD_CHARS: [char, ..64] = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' -]; - -static URLSAFE_CHARS: [char, ..64] = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' -]; +static STANDARD_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz", + "0123456789+/"); + +static URLSAFE_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz", + "0123456789-_"); /// A trait for converting a value to base64 encoding. pub trait ToBase64 { @@ -80,12 +73,12 @@ impl<'self> ToBase64 for &'self [u8] { * ~~~ */ fn to_base64(&self, config: Config) -> ~str { - let chars = match config.char_set { + let bytes = match config.char_set { Standard => STANDARD_CHARS, UrlSafe => URLSAFE_CHARS }; - let mut s = ~""; + let mut v: ~[u8] = ~[]; let mut i = 0; let mut cur_length = 0; let len = self.len(); @@ -93,7 +86,8 @@ fn to_base64(&self, config: Config) -> ~str { match config.line_length { Some(line_length) => if cur_length >= line_length { - s.push_str("\r\n"); + v.push('\r' as u8); + v.push('\n' as u8); cur_length = 0; }, None => () @@ -104,10 +98,10 @@ fn to_base64(&self, config: Config) -> ~str { (self[i + 2] as u32); // This 24-bit number gets separated into four 6-bit numbers. - s.push_char(chars[(n >> 18) & 63]); - s.push_char(chars[(n >> 12) & 63]); - s.push_char(chars[(n >> 6 ) & 63]); - s.push_char(chars[n & 63]); + v.push(bytes[(n >> 18) & 63]); + v.push(bytes[(n >> 12) & 63]); + v.push(bytes[(n >> 6 ) & 63]); + v.push(bytes[n & 63]); cur_length += 4; i += 3; @@ -117,7 +111,8 @@ fn to_base64(&self, config: Config) -> ~str { match config.line_length { Some(line_length) => if cur_length >= line_length { - s.push_str("\r\n"); + v.push('\r' as u8); + v.push('\n' as u8); }, None => () } @@ -129,48 +124,29 @@ fn to_base64(&self, config: Config) -> ~str { 0 => (), 1 => { let n = (self[i] as u32) << 16; - s.push_char(chars[(n >> 18) & 63]); - s.push_char(chars[(n >> 12) & 63]); + v.push(bytes[(n >> 18) & 63]); + v.push(bytes[(n >> 12) & 63]); if config.pad { - s.push_str("=="); + v.push('=' as u8); + v.push('=' as u8); } } 2 => { let n = (self[i] as u32) << 16 | (self[i + 1u] as u32) << 8; - s.push_char(chars[(n >> 18) & 63]); - s.push_char(chars[(n >> 12) & 63]); - s.push_char(chars[(n >> 6 ) & 63]); + v.push(bytes[(n >> 18) & 63]); + v.push(bytes[(n >> 12) & 63]); + v.push(bytes[(n >> 6 ) & 63]); if config.pad { - s.push_char('='); + v.push('=' as u8); } } _ => fail!("Algebra is broken, please alert the math police") } - s - } -} -impl<'self> ToBase64 for &'self str { - /** - * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding. - * - * - * # Example - * - * ~~~ {.rust} - * extern mod extra; - * use extra::base64::{ToBase64, standard}; - * - * fn main () { - * let str = "Hello, World".to_base64(standard); - * printfln!("%s", str); - * } - * ~~~ - * - */ - fn to_base64(&self, config: Config) -> ~str { - self.as_bytes().to_base64(config) + unsafe { + str::raw::from_bytes_owned(v) + } } } @@ -181,22 +157,31 @@ pub trait FromBase64 { fn from_base64(&self) -> Result<~[u8], ~str>; } -impl<'self> FromBase64 for &'self [u8] { +impl<'self> FromBase64 for &'self str { /** - * Convert base64 `u8` vector into u8 byte values. - * Every 4 encoded characters is converted into 3 octets, modulo padding. + * Convert any base64 encoded string (literal, `@`, `&`, or `~`) + * to the byte values it encodes. + * + * You can use the `from_bytes` function in `std::str` + * to turn a `[u8]` into a string with characters corresponding to those + * values. * * # Example * + * This converts a string literal to base64 and back. + * * ~~~ {.rust} * extern mod extra; * use extra::base64::{ToBase64, FromBase64, standard}; + * use std::str; * * fn main () { - * let str = [52,32].to_base64(standard); - * printfln!("%s", str); - * let bytes = str.from_base64(); + * let hello_str = "Hello, World".to_base64(standard); + * printfln!("%s", hello_str); + * let bytes = hello_str.from_base64(); * printfln!("%?", bytes); + * let result_str = str::from_bytes(bytes); + * printfln!("%s", result_str); * } * ~~~ */ @@ -205,12 +190,11 @@ fn from_base64(&self) -> Result<~[u8], ~str> { let mut buf: u32 = 0; let mut modulus = 0; - let mut it = self.iter(); - for &byte in it { - let ch = byte as char; + let mut it = self.byte_iter().enumerate(); + for (idx, byte) in it { let val = byte as u32; - match ch { + match byte as char { 'A'..'Z' => buf |= val - 0x41, 'a'..'z' => buf |= val - 0x47, '0'..'9' => buf |= val + 0x04, @@ -218,7 +202,8 @@ fn from_base64(&self) -> Result<~[u8], ~str> { '/'|'_' => buf |= 0x3F, '\r'|'\n' => loop, '=' => break, - _ => return Err(~"Invalid Base64 character") + _ => return Err(fmt!("Invalid character '%c' at position %u", + self.char_at(idx), idx)) } buf <<= 6; @@ -231,8 +216,11 @@ fn from_base64(&self) -> Result<~[u8], ~str> { } } - if !it.all(|&byte| {byte as char == '='}) { - return Err(~"Invalid Base64 character"); + for (idx, byte) in it { + if (byte as char) != '=' { + return Err(fmt!("Invalid character '%c' at position %u", + self.char_at(idx), idx)); + } } match modulus { @@ -251,39 +239,6 @@ fn from_base64(&self) -> Result<~[u8], ~str> { } } -impl<'self> FromBase64 for &'self str { - /** - * Convert any base64 encoded string (literal, `@`, `&`, or `~`) - * to the byte values it encodes. - * - * You can use the `from_bytes` function in `std::str` - * to turn a `[u8]` into a string with characters corresponding to those - * values. - * - * # Example - * - * This converts a string literal to base64 and back. - * - * ~~~ {.rust} - * extern mod extra; - * use extra::base64::{ToBase64, FromBase64, standard}; - * use std::str; - * - * fn main () { - * let hello_str = "Hello, World".to_base64(standard); - * printfln!("%s", hello_str); - * let bytes = hello_str.from_base64(); - * printfln!("%?", bytes); - * let result_str = str::from_bytes(bytes); - * printfln!("%s", result_str); - * } - * ~~~ - */ - fn from_base64(&self) -> Result<~[u8], ~str> { - self.as_bytes().from_base64() - } -} - #[cfg(test)] mod test { use test::BenchHarness; @@ -291,27 +246,28 @@ mod test { #[test] fn test_to_base64_basic() { - assert_eq!("".to_base64(STANDARD), ~""); - assert_eq!("f".to_base64(STANDARD), ~"Zg=="); - assert_eq!("fo".to_base64(STANDARD), ~"Zm8="); - assert_eq!("foo".to_base64(STANDARD), ~"Zm9v"); - assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg=="); - assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE="); - assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy"); + assert_eq!("".as_bytes().to_base64(STANDARD), ~""); + assert_eq!("f".as_bytes().to_base64(STANDARD), ~"Zg=="); + assert_eq!("fo".as_bytes().to_base64(STANDARD), ~"Zm8="); + assert_eq!("foo".as_bytes().to_base64(STANDARD), ~"Zm9v"); + assert_eq!("foob".as_bytes().to_base64(STANDARD), ~"Zm9vYg=="); + assert_eq!("fooba".as_bytes().to_base64(STANDARD), ~"Zm9vYmE="); + assert_eq!("foobar".as_bytes().to_base64(STANDARD), ~"Zm9vYmFy"); } #[test] fn test_to_base64_line_break() { assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD}) .contains("\r\n")); - assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}), + assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4), + ..STANDARD}), ~"Zm9v\r\nYmFy"); } #[test] fn test_to_base64_padding() { - assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg"); - assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8"); + assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zg"); + assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zm8"); } #[test] @@ -345,7 +301,7 @@ fn test_from_base64_urlsafe() { #[test] fn test_from_base64_invalid_char() { assert!("Zm$=".from_base64().is_err()) - assert!("Zg==$".from_base64().is_err()); + assert!("Zg==$".from_base64().is_err()); } #[test] @@ -369,20 +325,20 @@ fn test_base64_random() { } #[bench] - pub fn to_base64(bh: & mut BenchHarness) { + pub fn bench_to_base64(bh: & mut BenchHarness) { let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; do bh.iter { - s.to_base64(STANDARD); + s.as_bytes().to_base64(STANDARD); } bh.bytes = s.len() as u64; } #[bench] - pub fn from_base64(bh: & mut BenchHarness) { + pub fn bench_from_base64(bh: & mut BenchHarness) { let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; - let b = s.to_base64(STANDARD); + let b = s.as_bytes().to_base64(STANDARD); do bh.iter { b.from_base64(); } diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 6dedd9ee4dd..20a3add3e7b 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -145,14 +145,16 @@ pub fn process(&mut self, let len = b.storage.len(); assert_eq!(self.storage.len(), len); let mut changed = false; - for i in range(0, len) { + for (i, (a, b)) in self.storage.mut_iter() + .zip(b.storage.iter()) + .enumerate() { let mask = big_mask(nbits, i); - let w0 = self.storage[i] & mask; - let w1 = b.storage[i] & mask; + let w0 = *a & mask; + let w1 = *b & mask; let w = op(w0, w1) & mask; if w0 != w { changed = true; - self.storage[i] = w; + *a = w; } } changed @@ -160,7 +162,7 @@ pub fn process(&mut self, #[inline] pub fn each_storage(&mut self, op: &fn(v: &mut uint) -> bool) -> bool { - range(0u, self.storage.len()).advance(|i| op(&mut self.storage[i])) + self.storage.mut_iter().advance(|elt| op(elt)) } #[inline] @@ -205,10 +207,9 @@ pub fn set(&mut self, i: uint, x: bool) { #[inline] pub fn equals(&self, b: &BigBitv, nbits: uint) -> bool { - let len = b.storage.len(); - for i in range(0, len) { + for (i, elt) in b.storage.iter().enumerate() { let mask = big_mask(nbits, i); - if mask & self.storage[i] != mask & b.storage[i] { + if mask & self.storage[i] != mask & *elt { return false; } } diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 75487a44f26..b0839a55795 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -164,7 +164,7 @@ fn push_front_node(&mut self, mut new_head: ~Node) { /// Remove the first Node and return it, or None if the list is empty #[inline] fn pop_front_node(&mut self) -> Option<~Node> { - do self.list_head.take().map_consume |mut front_node| { + do self.list_head.take().map_move |mut front_node| { self.length -= 1; match front_node.next.take() { Some(node) => self.list_head = link_with_prev(node, Rawlink::none()), @@ -190,7 +190,7 @@ fn push_back_node(&mut self, mut new_tail: ~Node) { /// Remove the last Node and return it, or None if the list is empty #[inline] fn pop_back_node(&mut self) -> Option<~Node> { - do self.list_tail.resolve().map_consume_default(None) |tail| { + do self.list_tail.resolve().map_move_default(None) |tail| { self.length -= 1; self.list_tail = tail.prev; match tail.prev.resolve() { @@ -237,7 +237,7 @@ fn push_front(&mut self, elt: T) { /// /// O(1) fn pop_front(&mut self) -> Option { - self.pop_front_node().map_consume(|~Node{value, _}| value) + self.pop_front_node().map_move(|~Node{value, _}| value) } /// Add an element last in the list @@ -251,7 +251,7 @@ fn push_back(&mut self, elt: T) { /// /// O(1) fn pop_back(&mut self) -> Option { - self.pop_back_node().map_consume(|~Node{value, _}| value) + self.pop_back_node().map_move(|~Node{value, _}| value) } } @@ -267,7 +267,7 @@ pub fn new() -> DList { /// If the list is empty, do nothing. #[inline] pub fn rotate_forward(&mut self) { - do self.pop_back_node().map_consume |tail| { + do self.pop_back_node().map_move |tail| { self.push_front_node(tail) }; } @@ -277,7 +277,7 @@ pub fn rotate_forward(&mut self) { /// If the list is empty, do nothing. #[inline] pub fn rotate_backward(&mut self) { - do self.pop_front_node().map_consume |head| { + do self.pop_front_node().map_move |head| { self.push_back_node(head) }; } @@ -463,7 +463,7 @@ fn next_back(&mut self) -> Option<&'self A> { if self.nelem == 0 { return None; } - do self.tail.resolve().map_consume |prev| { + do self.tail.resolve().map_move |prev| { self.nelem -= 1; self.tail = prev.prev; &prev.value @@ -477,7 +477,7 @@ fn next(&mut self) -> Option<&'self mut A> { if self.nelem == 0 { return None; } - do self.head.resolve().map_consume |next| { + do self.head.resolve().map_move |next| { self.nelem -= 1; self.head = match next.next { Some(ref mut node) => Rawlink::some(&mut **node), @@ -499,7 +499,7 @@ fn next_back(&mut self) -> Option<&'self mut A> { if self.nelem == 0 { return None; } - do self.tail.resolve().map_consume |prev| { + do self.tail.resolve().map_move |prev| { self.nelem -= 1; self.tail = prev.prev; &mut prev.value @@ -553,7 +553,7 @@ fn peek_next<'a>(&'a mut self) -> Option<&'a mut A> { if self.nelem == 0 { return None } - self.head.resolve().map_consume(|head| &mut head.value) + self.head.resolve().map_move(|head| &mut head.value) } } diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs index 58929778a59..44781a1fd19 100644 --- a/src/libextra/extra.rs +++ b/src/libextra/extra.rs @@ -102,6 +102,7 @@ pub mod semver; pub mod fileinput; pub mod flate; +pub mod hex; #[cfg(unicode)] mod unicode; diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index 7a36b25eac5..14b02688cff 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -129,27 +129,27 @@ struct FileInput_ { `Some(path)` is the file represented by `path`, `None` is `stdin`. Consumed as the files are read. */ - priv files: ~[Option], + files: ~[Option], /** The current file: `Some(r)` for an open file, `None` before starting and after reading everything. */ - priv current_reader: Option<@io::Reader>, - priv state: FileInputState, + current_reader: Option<@io::Reader>, + state: FileInputState, /** Used to keep track of whether we need to insert the newline at the end of a file that is missing it, which is needed to separate the last and first lines. */ - priv previous_was_newline: bool + previous_was_newline: bool } // XXX: remove this when Reader has &mut self. Should be removable via // "self.fi." -> "self." and renaming FileInput_. Documentation above // will likely have to be updated to use `let mut in = ...`. pub struct FileInput { - priv fi: @mut FileInput_ + fi: @mut FileInput_ } impl FileInput { @@ -198,7 +198,7 @@ pub fn from_args() -> FileInput { FileInput::from_vec(pathed) } - priv fn current_file_eof(&self) -> bool { + fn current_file_eof(&self) -> bool { match self.fi.current_reader { None => false, Some(r) => r.eof() @@ -240,7 +240,7 @@ pub fn next_file(&self) -> bool { Returns `true` if it had to move to the next file and did so successfully. */ - priv fn next_file_if_eof(&self) -> bool { + fn next_file_if_eof(&self) -> bool { match self.fi.current_reader { None => self.next_file(), Some(r) => { diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs index 8024b9aa159..ed8cbcd0663 100644 --- a/src/libextra/flate.rs +++ b/src/libextra/flate.rs @@ -43,8 +43,10 @@ pub fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void, static LZ_FAST : c_int = 0x1; // LZ with only one probe static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal" static LZ_BEST : c_int = 0xfff; // LZ with 4095 probes, "best" +static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum +static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum -pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -52,7 +54,7 @@ pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { rustrt::tdefl_compress_mem_to_heap(b as *c_void, len as size_t, &mut outsz, - LZ_NORM); + flags); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); @@ -62,7 +64,15 @@ pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { } } -pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { +pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] { + deflate_bytes_internal(bytes, LZ_NORM) +} + +pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { + deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) +} + +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] { do bytes.as_imm_buf |b, len| { unsafe { let mut outsz : size_t = 0; @@ -70,7 +80,7 @@ pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { rustrt::tinfl_decompress_mem_to_heap(b as *c_void, len as size_t, &mut outsz, - 0); + flags); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, outsz as uint); @@ -80,6 +90,14 @@ pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { } } +pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] { + inflate_bytes_internal(bytes, 0) +} + +pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] { + inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) +} + #[cfg(test)] mod tests { use super::*; @@ -109,4 +127,12 @@ fn test_flate_round_trip() { assert_eq!(input, out); } } + + #[test] + fn test_zlib_flate() { + let bytes = ~[1, 2, 3, 4, 5]; + let deflated = deflate_bytes(bytes); + let inflated = inflate_bytes(deflated); + assert_eq!(inflated, bytes); + } } diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 7d2a0658969..cc65c49d73a 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -46,7 +46,7 @@ impl Drop for Future { fn drop(&self) {} } -priv enum FutureState { +enum FutureState { Pending(~fn() -> A), Evaluating, Forced(A) diff --git a/src/libextra/getopts.rs b/src/libextra/getopts.rs index 15aac8ef47c..1b65528923a 100644 --- a/src/libextra/getopts.rs +++ b/src/libextra/getopts.rs @@ -114,7 +114,8 @@ pub enum Occur { pub struct Opt { name: Name, hasarg: HasArg, - occur: Occur + occur: Occur, + aliases: ~[Opt], } fn mkname(nm: &str) -> Name { @@ -127,29 +128,29 @@ fn mkname(nm: &str) -> Name { /// Create an option that is required and takes an argument pub fn reqopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Req}; + return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]}; } /// Create an option that is optional and takes an argument pub fn optopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Optional}; + return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]}; } /// Create an option that is optional and does not take an argument pub fn optflag(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: No, occur: Optional}; + return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]}; } /** Create an option that is optional, does not take an argument, * and may occur multiple times. */ pub fn optflagmulti(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: No, occur: Multi}; + return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]}; } /// Create an option that is optional and takes an optional argument pub fn optflagopt(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Maybe, occur: Optional}; + return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]}; } /** @@ -157,7 +158,7 @@ pub fn optflagopt(name: &str) -> Opt { * multiple times */ pub fn optmulti(name: &str) -> Opt { - return Opt {name: mkname(name), hasarg: Yes, occur: Multi}; + return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]}; } #[deriving(Clone, Eq)] @@ -189,7 +190,20 @@ fn name_str(nm: &Name) -> ~str { } fn find_opt(opts: &[Opt], nm: Name) -> Option { - opts.iter().position(|opt| opt.name == nm) + // search main options + let pos = opts.iter().position(|opt| opt.name == nm); + if pos.is_some() { + return pos + } + + // search in aliases + for candidate in opts.iter() { + if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() { + return opts.iter().position(|opt| opt.name == candidate.name); + } + } + + None } /** @@ -488,8 +502,6 @@ pub mod groups { use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req}; use getopts::{Short, Yes}; - use std::vec; - /** one group of options, e.g., both -h and --help, along with * their shared description and properties */ @@ -542,6 +554,20 @@ pub fn optflag(short_name: &str, long_name: &str, occur: Optional}; } + /// Create a long option that can occur more than once and does not + /// take an argument + pub fn optflagmulti(short_name: &str, long_name: &str, + desc: &str) -> OptGroup { + let len = short_name.len(); + assert!(len == 1 || len == 0); + return OptGroup {short_name: short_name.to_owned(), + long_name: long_name.to_owned(), + hint: ~"", + desc: desc.to_owned(), + hasarg: No, + occur: Multi}; + } + /// Create a long option that is optional and takes an optional argument pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { @@ -573,7 +599,7 @@ pub fn optmulti(short_name: &str, long_name: &str, // translate OptGroup into Opt // (both short and long names correspond to different Opts) - pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { + pub fn long_to_short(lopt: &OptGroup) -> Opt { let OptGroup{short_name: short_name, long_name: long_name, hasarg: hasarg, @@ -581,24 +607,29 @@ pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { _} = (*lopt).clone(); match (short_name.len(), long_name.len()) { - (0,0) => fail!("this long-format option was given no name"), - - (0,_) => ~[Opt {name: Long((long_name)), - hasarg: hasarg, - occur: occur}], - - (1,0) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}], - - (1,_) => ~[Opt {name: Short(short_name.char_at(0)), - hasarg: hasarg, - occur: occur}, - Opt {name: Long((long_name)), - hasarg: hasarg, - occur: occur}], - - (_,_) => fail!("something is wrong with the long-form opt") + (0,0) => fail!("this long-format option was given no name"), + + (0,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, + + (1,0) => Opt {name: Short(short_name.char_at(0)), + hasarg: hasarg, + occur: occur, + aliases: ~[]}, + + (1,_) => Opt {name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: ~[Opt { + name: Short(short_name.char_at(0)), + hasarg: hasarg, + occur: occur, + aliases: ~[] + }]}, + + (_,_) => fail!("something is wrong with the long-form opt") } } @@ -606,7 +637,7 @@ pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] { * Parse command line args with the provided long format options */ pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result { - ::getopts::getopts(args, vec::flat_map(opts, long_to_short)) + ::getopts::getopts(args, opts.map(long_to_short)) } /** @@ -708,9 +739,9 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str { * Fails during iteration if the string contains a non-whitespace * sequence longer than the limit. */ - priv fn each_split_within<'a>(ss: &'a str, - lim: uint, - it: &fn(&'a str) -> bool) -> bool { + fn each_split_within<'a>(ss: &'a str, + lim: uint, + it: &fn(&'a str) -> bool) -> bool { // Just for fun, let's write this as an state machine: enum SplitWithinState { @@ -778,7 +809,7 @@ enum LengthLimit { } #[test] - priv fn test_split_within() { + fn test_split_within() { fn t(s: &str, i: uint, u: &[~str]) { let mut v = ~[]; do each_split_within(s, i) |s| { v.push(s.to_owned()); true }; @@ -1440,7 +1471,8 @@ fn test_groups_optmulti() { #[test] fn test_groups_long_to_short() { - let short = ~[reqopt("b"), reqopt("banana")]; + let mut short = reqopt("banana"); + short.aliases = ~[reqopt("b")]; let verbose = groups::reqopt("b", "banana", "some bananas", "VAL"); assert_eq!(groups::long_to_short(&verbose), short); @@ -1448,10 +1480,16 @@ fn test_groups_long_to_short() { #[test] fn test_groups_getopts() { + let mut banana = reqopt("banana"); + banana.aliases = ~[reqopt("b")]; + let mut apple = optopt("apple"); + apple.aliases = ~[optopt("a")]; + let mut kiwi = optflag("kiwi"); + kiwi.aliases = ~[optflag("k")]; let short = ~[ - reqopt("b"), reqopt("banana"), - optopt("a"), optopt("apple"), - optflag("k"), optflagopt("kiwi"), + banana, + apple, + kiwi, optflagopt("p"), optmulti("l") ]; @@ -1464,7 +1502,7 @@ fn test_groups_getopts() { groups::optmulti("l", "", "Desc", "VAL"), ]; - let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k", + let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k", ~"-p", ~"16", ~"l", ~"35"]; // FIXME #4681: sort options here? @@ -1472,6 +1510,19 @@ fn test_groups_getopts() { == groups::getopts(sample_args, verbose)); } + #[test] + fn test_groups_aliases_long_and_short() { + let opts = ~[ + groups::optflagmulti("a", "apple", "Desc"), + ]; + + let args = ~[~"-a", ~"--apple", ~"-a"]; + + let matches = groups::getopts(args, opts).unwrap(); + assert_eq!(3, opt_count(&matches, "a")); + assert_eq!(3, opt_count(&matches, "apple")); + } + #[test] fn test_groups_usage() { let optgroups = ~[ diff --git a/src/libextra/hex.rs b/src/libextra/hex.rs new file mode 100644 index 00000000000..d5345cb956b --- /dev/null +++ b/src/libextra/hex.rs @@ -0,0 +1,193 @@ +// 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. + +//! Hex binary-to-text encoding +use std::str; +use std::vec; + +/// A trait for converting a value to hexadecimal encoding +pub trait ToHex { + /// Converts the value of `self` to a hex value, returning the owned + /// string. + fn to_hex(&self) -> ~str; +} + +static CHARS: &'static[u8] = bytes!("0123456789abcdef"); + +impl<'self> ToHex for &'self [u8] { + /** + * Turn a vector of `u8` bytes into a hexadecimal string. + * + * # Example + * + * ~~~ {.rust} + * extern mod extra; + * use extra::hex::ToHex; + * + * fn main () { + * let str = [52,32].to_hex(); + * printfln!("%s", str); + * } + * ~~~ + */ + fn to_hex(&self) -> ~str { + let mut v = vec::with_capacity(self.len() * 2); + for &byte in self.iter() { + v.push(CHARS[byte >> 4]); + v.push(CHARS[byte & 0xf]); + } + + unsafe { + str::raw::from_bytes_owned(v) + } + } +} + +/// A trait for converting hexadecimal encoded values +pub trait FromHex { + /// Converts the value of `self`, interpreted as hexadecimal encoded data, + /// into an owned vector of bytes, returning the vector. + fn from_hex(&self) -> Result<~[u8], ~str>; +} + +impl<'self> FromHex for &'self str { + /** + * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`) + * to the byte values it encodes. + * + * You can use the `from_bytes` function in `std::str` + * to turn a `[u8]` into a string with characters corresponding to those + * values. + * + * # Example + * + * This converts a string literal to hexadecimal and back. + * + * ~~~ {.rust} + * extern mod extra; + * use extra::hex::{FromHex, ToHex}; + * use std::str; + * + * fn main () { + * let hello_str = "Hello, World".to_hex(); + * printfln!("%s", hello_str); + * let bytes = hello_str.from_hex().unwrap(); + * printfln!("%?", bytes); + * let result_str = str::from_bytes(bytes); + * printfln!("%s", result_str); + * } + * ~~~ + */ + fn from_hex(&self) -> Result<~[u8], ~str> { + // This may be an overestimate if there is any whitespace + let mut b = vec::with_capacity(self.len() / 2); + let mut modulus = 0; + let mut buf = 0u8; + + for (idx, byte) in self.byte_iter().enumerate() { + buf <<= 4; + + match byte as char { + 'A'..'F' => buf |= byte - ('A' as u8) + 10, + 'a'..'f' => buf |= byte - ('a' as u8) + 10, + '0'..'9' => buf |= byte - ('0' as u8), + ' '|'\r'|'\n'|'\t' => { + buf >>= 4; + loop + } + _ => return Err(fmt!("Invalid character '%c' at position %u", + self.char_at(idx), idx)) + } + + modulus += 1; + if modulus == 2 { + modulus = 0; + b.push(buf); + } + } + + match modulus { + 0 => Ok(b), + _ => Err(~"Invalid input length") + } + } +} + +#[cfg(test)] +mod tests { + use test::BenchHarness; + use hex::*; + + #[test] + pub fn test_to_hex() { + assert_eq!("foobar".as_bytes().to_hex(), ~"666f6f626172"); + } + + #[test] + pub fn test_from_hex_okay() { + assert_eq!("666f6f626172".from_hex().unwrap(), + "foobar".as_bytes().to_owned()); + assert_eq!("666F6F626172".from_hex().unwrap(), + "foobar".as_bytes().to_owned()); + } + + #[test] + pub fn test_from_hex_odd_len() { + assert!("666".from_hex().is_err()); + assert!("66 6".from_hex().is_err()); + } + + #[test] + pub fn test_from_hex_invalid_char() { + assert!("66y6".from_hex().is_err()); + } + + #[test] + pub fn test_from_hex_ignores_whitespace() { + assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(), + "foobar".as_bytes().to_owned()); + } + + #[test] + pub fn test_to_hex_all_bytes() { + for i in range(0, 256) { + assert_eq!([i as u8].to_hex(), fmt!("%02x", i as uint)); + } + } + + #[test] + pub fn test_from_hex_all_bytes() { + for i in range(0, 256) { + assert_eq!(fmt!("%02x", i as uint).from_hex().unwrap(), ~[i as u8]); + assert_eq!(fmt!("%02X", i as uint).from_hex().unwrap(), ~[i as u8]); + } + } + + #[bench] + pub fn bench_to_hex(bh: & mut BenchHarness) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + do bh.iter { + s.as_bytes().to_hex(); + } + bh.bytes = s.len() as u64; + } + + #[bench] + pub fn bench_from_hex(bh: & mut BenchHarness) { + let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \ + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン"; + let b = s.as_bytes().to_hex(); + do bh.iter { + b.from_hex(); + } + bh.bytes = b.len() as u64; + } +} diff --git a/src/libextra/iter.rs b/src/libextra/iter.rs deleted file mode 100644 index 7fd47fdbd39..00000000000 --- a/src/libextra/iter.rs +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2012 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. - -/*! Composable internal iterators - -Internal iterators are functions implementing the protocol used by the `for` loop. - -An internal iterator takes `fn(...) -> bool` as a parameter, with returning `false` used to signal -breaking out of iteration. The adaptors in the module work with any such iterator, not just ones -tied to specific traits. For example: - -~~~ {.rust} -println(iter::to_vec(|f| uint::range(0, 20, f)).to_str()); -~~~ - -An external iterator object implementing the interface in the `iterator` module can be used as an -internal iterator by calling the `advance` method. For example: - -~~~ {.rust} -let xs = [0u, 1, 2, 3, 4, 5]; -let ys = [30, 40, 50, 60]; -let mut it = xs.iter().chain(ys.iter()); -for &x: &uint in it { - println(x.to_str()); -} -~~~ - -Internal iterators provide a subset of the functionality of an external iterator. It's not possible -to interleave them to implement algorithms like `zip`, `union` and `merge`. However, they're often -much easier to implement. - -*/ - -use std::vec; -use std::cmp::Ord; -use std::option::{Option, Some, None}; -use std::num::{One, Zero}; -use std::ops::{Add, Mul}; - -#[allow(missing_doc)] -pub trait FromIter { - /// Build a container with elements from an internal iterator. - /// - /// # Example: - /// - /// ~~~ {.rust} - /// let xs = ~[1, 2, 3]; - /// let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) }; - /// assert_eq!(xs, ys); - /// ~~~ - pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> Self; -} - -/** - * Return true if `predicate` is true for any values yielded by an internal iterator. - * - * Example: - * - * ~~~ {.rust} - * let xs = ~[1u, 2, 3, 4, 5]; - * assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f))); - * assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f))); - * ~~~ - */ -#[inline] -pub fn any(predicate: &fn(T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { - do iter |x| { - predicate(x) - } -} - -/** - * Return true if `predicate` is true for all values yielded by an internal iterator. - * - * # Example: - * - * ~~~ {.rust} - * assert!(all(|&x: &uint| x < 6, |f| uint::range(1, 6, f))); - * assert!(!all(|&x: &uint| x < 5, |f| uint::range(1, 6, f))); - * ~~~ - */ -#[inline] -pub fn all(predicate: &fn(T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { - // If we ever break, iter will return false, so this will only return true - // if predicate returns true for everything. - iter(|x| predicate(x)) -} - -/** - * Return the first element where `predicate` returns `true`. Return `None` if no element is found. - * - * # Example: - * - * ~~~ {.rust} - * let xs = ~[1u, 2, 3, 4, 5, 6]; - * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4); - * ~~~ - */ -#[inline] -pub fn find(predicate: &fn(&T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { - let mut ret = None; - do iter |x| { - if predicate(&x) { - ret = Some(x); - false - } else { true } - }; - ret -} - -/** - * Return the largest item yielded by an iterator. Return `None` if the iterator is empty. - * - * # Example: - * - * ~~~ {.rust} - * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15); - * ~~~ - */ -#[inline] -pub fn max(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { - let mut result = None; - do iter |x| { - match result { - Some(ref mut y) => { - if x > *y { - *y = x; - } - } - None => result = Some(x) - } - true - }; - result -} - -/** - * Return the smallest item yielded by an iterator. Return `None` if the iterator is empty. - * - * # Example: - * - * ~~~ {.rust} - * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &-5); - * ~~~ - */ -#[inline] -pub fn min(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option { - let mut result = None; - do iter |x| { - match result { - Some(ref mut y) => { - if x < *y { - *y = x; - } - } - None => result = Some(x) - } - true - }; - result -} - -/** - * Reduce an iterator to an accumulated value. - * - * # Example: - * - * ~~~ {.rust} - * assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); - * ~~~ - */ -#[inline] -pub fn fold(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T { - let mut result = start; - do iter |x| { - f(&mut result, x); - true - }; - result -} - -/** - * Reduce an iterator to an accumulated value. - * - * `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it - * forces the iterator to yield borrowed pointers. - * - * # Example: - * - * ~~~ {.rust} - * fn product>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - * fold_ref(One::one::(), iter, |a, x| *a = a.mul(x)) - * } - * ~~~ - */ -#[inline] -pub fn fold_ref(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T { - let mut result = start; - do iter |x| { - f(&mut result, x); - true - }; - result -} - -/** - * Return the sum of the items yielding by an iterator. - * - * # Example: - * - * ~~~ {.rust} - * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do sum |f| { xs.iter().advance(f) }, 10); - * ~~~ - */ -#[inline] -pub fn sum>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - fold_ref(Zero::zero::(), iter, |a, x| *a = a.add(x)) -} - -/** - * Return the product of the items yielded by an iterator. - * - * # Example: - * - * ~~~ {.rust} - * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do product |f| { xs.iter().advance(f) }, 24); - * ~~~ - */ -#[inline] -pub fn product>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - fold_ref(One::one::(), iter, |a, x| *a = a.mul(x)) -} - -impl FromIter for ~[T]{ - #[inline] - pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] { - let mut v = ~[]; - do iter |x| { v.push(x); true }; - v - } -} - -#[cfg(test)] -mod tests { - use super::*; - use prelude::*; - - use int; - use uint; - - #[test] - fn test_from_iter() { - let xs = ~[1, 2, 3]; - let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) }; - assert_eq!(xs, ys); - } - - #[test] - fn test_any() { - let xs = ~[1u, 2, 3, 4, 5]; - assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f))); - assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f))); - } - - #[test] - fn test_all() { - assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f))); - assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f))); - } - - #[test] - fn test_find() { - let xs = ~[1u, 2, 3, 4, 5, 6]; - assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4); - } - - #[test] - fn test_max() { - let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15); - } - - #[test] - fn test_min() { - let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(min(|f| xs.iter().advance(f)).unwrap(), &-5); - } - - #[test] - fn test_fold() { - assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); - } - - #[test] - fn test_sum() { - let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do sum |f| { xs.iter().advance(f) }, 10); - } - - #[test] - fn test_empty_sum() { - let xs: ~[int] = ~[]; - assert_eq!(do sum |f| { xs.iter().advance(f) }, 0); - } - - #[test] - fn test_product() { - let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do product |f| { xs.iter().advance(f) }, 24); - } - - #[test] - fn test_empty_product() { - let xs: ~[int] = ~[]; - assert_eq!(do product |f| { xs.iter().advance(f) }, 1); - } -} diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index bced00902c9..0c8701bd0b5 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -59,13 +59,13 @@ pub mod BigDigit { pub static bits: uint = 32; pub static base: uint = 1 << bits; - priv static hi_mask: uint = (-1 as uint) << bits; - priv static lo_mask: uint = (-1 as uint) >> bits; + static hi_mask: uint = (-1 as uint) << bits; + static lo_mask: uint = (-1 as uint) >> bits; - priv fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit } + fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit } - priv fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit } + fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit } /// Split one machine sized unsigned integer into two BigDigits. @@ -548,7 +548,7 @@ impl BigUint { pub fn new(v: ~[BigDigit]) -> BigUint { // omit trailing zeros - let new_len = v.rposition(|n| *n != 0).map_default(0, |p| *p + 1); + let new_len = v.rposition(|n| *n != 0).map_move_default(0, |p| p + 1); if new_len == v.len() { return BigUint { data: v }; } let mut v = v; @@ -613,7 +613,7 @@ pub fn to_uint(&self) -> uint { } - priv fn shl_unit(&self, n_unit: uint) -> BigUint { + fn shl_unit(&self, n_unit: uint) -> BigUint { if n_unit == 0 || self.is_zero() { return (*self).clone(); } return BigUint::new(vec::from_elem(n_unit, ZERO_BIG_DIGIT) @@ -621,7 +621,7 @@ pub fn to_uint(&self) -> uint { } - priv fn shl_bits(&self, n_bits: uint) -> BigUint { + fn shl_bits(&self, n_bits: uint) -> BigUint { if n_bits == 0 || self.is_zero() { return (*self).clone(); } let mut carry = 0; @@ -637,7 +637,7 @@ pub fn to_uint(&self) -> uint { } - priv fn shr_unit(&self, n_unit: uint) -> BigUint { + fn shr_unit(&self, n_unit: uint) -> BigUint { if n_unit == 0 { return (*self).clone(); } if self.data.len() < n_unit { return Zero::zero(); } return BigUint::from_slice( @@ -646,7 +646,7 @@ pub fn to_uint(&self) -> uint { } - priv fn shr_bits(&self, n_bits: uint) -> BigUint { + fn shr_bits(&self, n_bits: uint) -> BigUint { if n_bits == 0 || self.data.is_empty() { return (*self).clone(); } let mut borrow = 0; @@ -661,7 +661,7 @@ pub fn to_uint(&self) -> uint { #[cfg(target_arch = "x86_64")] -priv fn get_radix_base(radix: uint) -> (uint, uint) { +fn get_radix_base(radix: uint) -> (uint, uint) { assert!(1 < radix && radix <= 16); match radix { 2 => (4294967296, 32), @@ -687,7 +687,7 @@ pub fn to_uint(&self) -> uint { #[cfg(target_arch = "x86")] #[cfg(target_arch = "mips")] -priv fn get_radix_base(radix: uint) -> (uint, uint) { +fn get_radix_base(radix: uint) -> (uint, uint) { assert!(1 < radix && radix <= 16); match radix { 2 => (65536, 16), @@ -1145,7 +1145,7 @@ pub fn parse_bytes(buf: &[u8], radix: uint) start = 1; } return BigUint::parse_bytes(buf.slice(start, buf.len()), radix) - .map_consume(|bu| BigInt::from_biguint(sign, bu)); + .map_move(|bu| BigInt::from_biguint(sign, bu)); } pub fn to_uint(&self) -> uint { @@ -2028,7 +2028,7 @@ fn check(n: int, ans: &str) { #[test] fn test_from_str_radix() { fn check(s: &str, ans: Option) { - let ans = ans.map(|&n| IntConvertible::from_int::(n)); + let ans = ans.map_move(|n| IntConvertible::from_int::(n)); assert_eq!(FromStrRadix::from_str_radix(s, 10), ans); } check("10", Some(10)); diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index 9833bd5d1cb..da8089250b3 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -696,7 +696,7 @@ fn test_from_iterator() { let u: ~[int] = deq.iter().transform(|&x| x).collect(); assert_eq!(u, v); - let mut seq = iterator::Counter::new(0u, 2).take_(256); + let mut seq = iterator::count(0u, 2).take_(256); let deq: RingBuf = seq.collect(); for (i, &x) in deq.iter().enumerate() { assert_eq!(2*i, x); diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index 3f62317eb89..a601270e8ec 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -16,7 +16,6 @@ #[allow(missing_doc)]; use std::iterator::{Iterator, IteratorUtil, Enumerate, FilterMap, Invert}; -use std::uint; use std::util::replace; use std::vec::{VecIterator, VecMutIterator}; use std::vec; @@ -29,14 +28,12 @@ pub struct SmallIntMap { impl Container for SmallIntMap { /// Return the number of elements in the map fn len(&self) -> uint { - let mut sz = 0; - for i in range(0u, self.v.len()) { - match self.v[i] { - Some(_) => sz += 1, - None => {} - } - } - sz + self.v.iter().count(|elt| elt.is_some()) + } + + /// Return true if there are no elements in the map + fn is_empty(&self) -> bool { + self.v.iter().all(|elt| elt.is_none()) } } @@ -116,48 +113,6 @@ impl SmallIntMap { /// Create an empty SmallIntMap pub fn new() -> SmallIntMap { SmallIntMap{v: ~[]} } - /// Visit all key-value pairs in order - pub fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) -> bool { - for i in range(0u, self.v.len()) { - match self.v[i] { - Some(ref elt) => if !it(&i, elt) { return false; }, - None => () - } - } - true - } - - /// Visit all keys in order - pub fn each_key(&self, blk: &fn(key: &uint) -> bool) -> bool { - self.each(|k, _| blk(k)) - } - - /// Visit all values in order - pub fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) -> bool { - self.each(|_, v| blk(v)) - } - - /// Iterate over the map and mutate the contained values - pub fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) -> bool { - for i in range(0, self.v.len()) { - match self.v[i] { - Some(ref mut elt) => if !it(&i, elt) { return false; }, - None => () - } - } - true - } - - /// Visit all key-value pairs in reverse order - pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool { - do uint::range_rev(self.v.len(), 0) |i| { - match self.v[i] { - Some(ref elt) => it(i, elt), - None => true - } - } - } - pub fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") } @@ -203,7 +158,7 @@ pub fn consume(&mut self) { let values = replace(&mut self.v, ~[]); values.consume_iter().enumerate().filter_map(|(i, v)| { - v.map_consume(|v| (i, v)) + v.map_move(|v| (i, v)) }) } } diff --git a/src/libextra/sort.rs b/src/libextra/sort.rs index 8090dd26ef2..daafdbc3718 100644 --- a/src/libextra/sort.rs +++ b/src/libextra/sort.rs @@ -469,10 +469,7 @@ fn merge_lo(&mut self, array: &mut [T], base1: uint, len1: uint, base2: uint, len2: uint) { assert!(len1 != 0 && len2 != 0 && base1+len1 == base2); - let mut tmp = ~[]; - for i in range(base1, base1+len1) { - tmp.push(array[i].clone()); - } + let mut tmp = array.slice(base1, base1 + len1).to_owned(); let mut c1 = 0; let mut c2 = base2; @@ -579,10 +576,7 @@ fn merge_hi(&mut self, array: &mut [T], base1: uint, len1: uint, base2: uint, len2: uint) { assert!(len1 != 1 && len2 != 0 && base1 + len1 == base2); - let mut tmp = ~[]; - for i in range(base2, base2+len2) { - tmp.push(array[i].clone()); - } + let mut tmp = array.slice(base2, base2 + len2).to_owned(); let mut c1 = base1 + len1 - 1; let mut c2 = len2 - 1; diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index 68d5af43688..881d931fe0a 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -10,6 +10,7 @@ use sort; use std::cmp; +use std::hashmap; use std::io; use std::num; @@ -222,7 +223,7 @@ fn iqr(self) -> f64 { // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using // linear interpolation. If samples are not sorted, return nonsensical value. -priv fn percentile_of_sorted(sorted_samples: &[f64], +fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { assert!(sorted_samples.len() != 0); if sorted_samples.len() == 1 { @@ -352,6 +353,16 @@ pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) { w.write_str(histr); } +/// Returns a HashMap with the number of occurences of every element in the +/// sequence that the iterator exposes. +pub fn freq_count, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap { + let mut map = hashmap::HashMap::new::(); + for elem in iter { + map.insert_or_update_with(elem, 1, |_, count| *count += 1); + } + map +} + // Test vectors generated from R, using the script src/etc/stat-test-vectors.r. #[cfg(test)] diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index 63e371899a9..4172c715adb 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -935,6 +935,7 @@ fn test_mutex_killed_simple() { // child task must have finished by the time try returns do m.lock { } } + #[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_mutex_killed_cond() { // Getting killed during cond wait must not corrupt the mutex while @@ -961,6 +962,7 @@ fn test_mutex_killed_cond() { assert!(!woken); } } + #[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_mutex_killed_broadcast() { use std::unstable::finally::Finally; diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 1cfb4f4afa6..d0412b8954d 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -75,7 +75,7 @@ pub enum Attr { } #[cfg(not(target_os = "win32"))] -priv fn cap_for_attr(attr: attr::Attr) -> &'static str { +fn cap_for_attr(attr: attr::Attr) -> &'static str { match attr { attr::Bold => "bold", attr::Dim => "dim", @@ -127,7 +127,7 @@ pub fn new(out: @io::Writer) -> Result { let inf = ti.unwrap(); let nc = if inf.strings.find_equiv(&("setaf")).is_some() && inf.strings.find_equiv(&("setab")).is_some() { - inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n) + inf.numbers.find_equiv(&("colors")).map_move_default(0, |&n| n) } else { 0 }; return Ok(Terminal {out: out, ti: inf, num_colors: nc}); @@ -220,7 +220,7 @@ pub fn reset(&self) { cap = self.ti.strings.find_equiv(&("op")); } } - let s = do cap.map_consume_default(Err(~"can't find terminfo capability `sgr0`")) |op| { + let s = do cap.map_move_default(Err(~"can't find terminfo capability `sgr0`")) |op| { expand(*op, [], &mut Variables::new()) }; if s.is_ok() { @@ -234,7 +234,7 @@ pub fn reset(&self) { } } - priv fn dim_if_necessary(&self, color: color::Color) -> color::Color { + fn dim_if_necessary(&self, color: color::Color) -> color::Color { if color >= self.num_colors && color >= 8 && color < 16 { color-8 } else { color } diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index b619e0f33b6..0929575ee9e 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -430,7 +430,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) } #[deriving(Eq)] -priv struct Flags { +struct Flags { width: uint, precision: uint, alternate: bool, @@ -440,13 +440,13 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) } impl Flags { - priv fn new() -> Flags { + fn new() -> Flags { Flags{ width: 0, precision: 0, alternate: false, left: false, sign: false, space: false } } } -priv enum FormatOp { +enum FormatOp { FormatDigit, FormatOctal, FormatHex, @@ -455,7 +455,7 @@ impl Flags { } impl FormatOp { - priv fn from_char(c: char) -> FormatOp { + fn from_char(c: char) -> FormatOp { match c { 'd' => FormatDigit, 'o' => FormatOctal, @@ -465,7 +465,7 @@ impl FormatOp { _ => fail!("bad FormatOp char") } } - priv fn to_char(self) -> char { + fn to_char(self) -> char { match self { FormatDigit => 'd', FormatOctal => 'o', @@ -476,7 +476,7 @@ impl FormatOp { } } -priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { +fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { let mut s = match val { Number(d) => { match op { diff --git a/src/libextra/test.rs b/src/libextra/test.rs index e87be146226..761cb1bd76f 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -238,20 +238,20 @@ pub fn parse_opts(args: &[~str]) -> OptRes { let run_ignored = getopts::opt_present(&matches, "ignored"); let logfile = getopts::opt_maybe_str(&matches, "logfile"); - let logfile = logfile.map(|s| Path(*s)); + let logfile = logfile.map_move(|s| Path(s)); let run_benchmarks = getopts::opt_present(&matches, "bench"); let run_tests = ! run_benchmarks || getopts::opt_present(&matches, "test"); let ratchet_metrics = getopts::opt_maybe_str(&matches, "ratchet-metrics"); - let ratchet_metrics = ratchet_metrics.map(|s| Path(*s)); + let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s)); let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent"); - let ratchet_noise_percent = ratchet_noise_percent.map(|s| f64::from_str(*s).unwrap()); + let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| f64::from_str(s).unwrap()); let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics"); - let save_metrics = save_metrics.map(|s| Path(*s)); + let save_metrics = save_metrics.map_move(|s| Path(s)); let test_opts = TestOpts { filter: filter, diff --git a/src/libextra/time.rs b/src/libextra/time.rs index efc3dc87adc..f6a5fd98234 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -254,7 +254,7 @@ pub fn rfc3339(&self) -> ~str { } } -priv fn do_strptime(s: &str, format: &str) -> Result { +fn do_strptime(s: &str, format: &str) -> Result { fn match_str(s: &str, pos: uint, needle: &str) -> bool { let mut i = pos; for ch in needle.byte_iter() { @@ -687,7 +687,7 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm) } } -priv fn do_strftime(format: &str, tm: &Tm) -> ~str { +fn do_strftime(format: &str, tm: &Tm) -> ~str { fn parse_type(ch: char, tm: &Tm) -> ~str { //FIXME (#2350): Implement missing types. let die = || fmt!("strftime: can't understand this format %c ", ch); diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 487ad050e78..4d898dfb2b4 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -13,7 +13,6 @@ //! `TotalOrd`. -use std::num; use std::util::{swap, replace}; use std::iterator::{FromIterator, Extendable}; @@ -42,39 +41,23 @@ pub struct TreeMap { impl Eq for TreeMap { fn eq(&self, other: &TreeMap) -> bool { - if self.len() != other.len() { - false - } else { - let mut x = self.iter(); - let mut y = other.iter(); - for _ in range(0u, self.len()) { - if x.next().unwrap() != y.next().unwrap() { - return false - } - } - true - } + self.len() == other.len() && + self.iter().zip(other.iter()).all(|(a, b)| a == b) } - fn ne(&self, other: &TreeMap) -> bool { !self.eq(other) } } // Lexicographical comparison fn lt(a: &TreeMap, b: &TreeMap) -> bool { - let mut x = a.iter(); - let mut y = b.iter(); - - let (a_len, b_len) = (a.len(), b.len()); - for _ in range(0u, num::min(a_len, b_len)) { - let (key_a, value_a) = x.next().unwrap(); - let (key_b, value_b) = y.next().unwrap(); + // the Zip iterator is as long as the shortest of a and b. + for ((key_a, value_a), (key_b, value_b)) in a.iter().zip(b.iter()) { if *key_a < *key_b { return true; } if *key_a > *key_b { return false; } if *value_a < *value_b { return true; } if *value_a > *value_b { return false; } } - a_len < b_len + a.len() < b.len() } impl Ord for TreeMap { @@ -151,36 +134,11 @@ impl TreeMap { /// Create an empty TreeMap pub fn new() -> TreeMap { TreeMap{root: None, length: 0} } - /// Visit all keys in order - pub fn each_key(&self, f: &fn(&K) -> bool) -> bool { - self.iter().advance(|(k, _)| f(k)) - } - - /// Visit all values in order - pub fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool { - self.iter().advance(|(_, v)| f(v)) - } - /// Iterate over the map and mutate the contained values pub fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool { mutate_values(&mut self.root, f) } - /// Visit all key-value pairs in reverse order - pub fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool { - each_reverse(&self.root, f) - } - - /// Visit all keys in reverse order - pub fn each_key_reverse(&self, f: &fn(&K) -> bool) -> bool { - self.each_reverse(|k, _| f(k)) - } - - /// Visit all values in reverse order - pub fn each_value_reverse(&self, f: &fn(&V) -> bool) -> bool { - self.each_reverse(|_, v| f(v)) - } - /// Get a lazy iterator over the key-value pairs in the map. /// Requires that it be frozen (immutable). pub fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> { @@ -192,6 +150,12 @@ pub fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> { } } + /// Get a lazy reverse iterator over the key-value pairs in the map. + /// Requires that it be frozen (immutable). + pub fn rev_iter<'a>(&'a self) -> TreeMapRevIterator<'a, K, V> { + TreeMapRevIterator{iter: self.iter()} + } + /// Get a lazy iterator that should be initialized using /// `iter_traverse_left`/`iter_traverse_right`/`iter_traverse_complete`. fn iter_for_traversal<'a>(&'a self) -> TreeMapIterator<'a, K, V> { @@ -270,20 +234,18 @@ pub struct TreeMapIterator<'self, K, V> { priv remaining_max: uint } -impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { - /// Advance the iterator to the next node (in order) and return a - /// tuple with a reference to the key and value. If there are no - /// more nodes, return `None`. - fn next(&mut self) -> Option<(&'self K, &'self V)> { +impl<'self, K, V> TreeMapIterator<'self, K, V> { + #[inline(always)] + fn next_(&mut self, forward: bool) -> Option<(&'self K, &'self V)> { while !self.stack.is_empty() || self.node.is_some() { match *self.node { Some(ref x) => { self.stack.push(x); - self.node = &x.left; + self.node = if forward { &x.left } else { &x.right }; } None => { let res = self.stack.pop(); - self.node = &res.right; + self.node = if forward { &res.right } else { &res.left }; self.remaining_max -= 1; if self.remaining_min > 0 { self.remaining_min -= 1; @@ -294,6 +256,15 @@ fn next(&mut self) -> Option<(&'self K, &'self V)> { } None } +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return `None`. + fn next(&mut self) -> Option<(&'self K, &'self V)> { + self.next_(true) + } #[inline] fn size_hint(&self) -> (uint, Option) { @@ -301,6 +272,25 @@ fn size_hint(&self) -> (uint, Option) { } } +/// Lazy backward iterator over a map +pub struct TreeMapRevIterator<'self, K, V> { + priv iter: TreeMapIterator<'self, K, V>, +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapRevIterator<'self, K, V> { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return `None`. + fn next(&mut self) -> Option<(&'self K, &'self V)> { + self.iter.next_(false) + } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + self.iter.size_hint() + } +} + /// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to /// initialize TreeMapIterator pointing to element inside tree structure. /// @@ -391,6 +381,14 @@ fn size_hint(&self) -> (uint, Option) { } impl<'self, T> Iterator<&'self T> for TreeSetIterator<'self, T> { + /// Advance the iterator to the next node (in order). If there are no more nodes, return `None`. + #[inline] + fn next(&mut self) -> Option<&'self T> { + do self.iter.next().map_move |(value, _)| { value } + } +} + +impl<'self, T> Iterator<&'self T> for TreeSetRevIterator<'self, T> { /// Advance the iterator to the next node (in order). If there are no more nodes, return `None`. #[inline] fn next(&mut self) -> Option<&'self T> { @@ -449,20 +447,7 @@ fn contains(&self, value: &T) -> bool { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. fn is_disjoint(&self, other: &TreeSet) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() && b.is_some() { - let a1 = a.unwrap(); - let b1 = b.unwrap(); - match a1.cmp(b1) { - Less => a = x.next(), - Greater => b = y.next(), - Equal => return false - } - } - true + self.intersection(other).next().is_none() } /// Return true if the set is a subset of another @@ -521,6 +506,13 @@ pub fn iter<'a>(&'a self) -> TreeSetIterator<'a, T> { TreeSetIterator{iter: self.map.iter()} } + /// Get a lazy iterator over the values in the set. + /// Requires that it be frozen (immutable). + #[inline] + pub fn rev_iter<'a>(&'a self) -> TreeSetRevIterator<'a, T> { + TreeSetRevIterator{iter: self.map.rev_iter()} + } + /// Get a lazy iterator pointing to the first value not less than `v` (greater or equal). /// If all elements in the set are less than `v` empty iterator is returned. #[inline] @@ -535,138 +527,170 @@ pub fn upper_bound_iter<'a>(&'a self, v: &T) -> TreeSetIterator<'a, T> { TreeSetIterator{iter: self.map.upper_bound_iter(v)} } - /// Visit all values in reverse order - #[inline] - pub fn each_reverse(&self, f: &fn(&T) -> bool) -> bool { - self.map.each_key_reverse(f) + /// Visit the values (in-order) representing the difference + pub fn difference<'a>(&'a self, other: &'a TreeSet) -> Difference<'a, T> { + Difference{a: Focus::new(self.iter()), b: Focus::new(other.iter())} } - /// Visit the values (in-order) representing the difference - pub fn difference(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); + /// Visit the values (in-order) representing the symmetric difference + pub fn symmetric_difference<'a>(&'a self, other: &'a TreeSet) + -> SymDifference<'a, T> { + SymDifference{a: Focus::new(self.iter()), b: Focus::new(other.iter())} + } - let mut a = x.next(); - let mut b = y.next(); + /// Visit the values (in-order) representing the intersection + pub fn intersection<'a>(&'a self, other: &'a TreeSet) + -> Intersection<'a, T> { + Intersection{a: Focus::new(self.iter()), b: Focus::new(other.iter())} + } - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); - } + /// Visit the values (in-order) representing the union + pub fn union<'a>(&'a self, other: &'a TreeSet) -> Union<'a, T> { + Union{a: Focus::new(self.iter()), b: Focus::new(other.iter())} + } +} - let a1 = a.unwrap(); - let b1 = b.unwrap(); +/// Lazy forward iterator over a set +pub struct TreeSetIterator<'self, T> { + priv iter: TreeMapIterator<'self, T, ()> +} - let cmp = a1.cmp(b1); +/// Lazy backward iterator over a set +pub struct TreeSetRevIterator<'self, T> { + priv iter: TreeMapRevIterator<'self, T, ()> +} - if cmp == Less { - if !f(a1) { return false; } - a = x.next(); - } else { - if cmp == Equal { a = x.next() } - b = y.next(); - } - } - return true; - } +// Encapsulate an iterator and hold its latest value until stepped forward +struct Focus { + priv iter: T, + priv focus: Option, +} - /// Visit the values (in-order) representing the symmetric difference - pub fn symmetric_difference(&self, other: &TreeSet, - f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); +impl> Focus { + fn new(mut it: T) -> Focus { + Focus{focus: it.next(), iter: it} + } + fn step(&mut self) { + self.focus = self.iter.next() + } +} - let mut a = x.next(); - let mut b = y.next(); +/// Lazy iterator producing elements in the set difference (in-order) +pub struct Difference<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); - } +/// Lazy iterator producing elements in the set symmetric difference (in-order) +pub struct SymDifference<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - let a1 = a.unwrap(); - let b1 = b.unwrap(); +/// Lazy iterator producing elements in the set intersection (in-order) +pub struct Intersection<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - let cmp = a1.cmp(b1); +/// Lazy iterator producing elements in the set intersection (in-order) +pub struct Union<'self, T> { + priv a: Focus<&'self T, TreeSetIterator<'self, T>>, + priv b: Focus<&'self T, TreeSetIterator<'self, T>>, +} - if cmp == Less { - if !f(a1) { return false; } - a = x.next(); - } else { - if cmp == Greater { - if !f(b1) { return false; } - } else { - a = x.next(); +impl<'self, T: TotalOrd> Iterator<&'self T> for Difference<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (None , _ ) => return None, + (ret , None ) => { self.a.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + return Some(a1); + } else { + if cmp == Equal { self.a.step() } + self.b.step(); + } } - b = y.next(); } } - b.iter().advance(|&x| f(x)) && y.advance(f) } +} - /// Visit the values (in-order) representing the intersection - pub fn intersection(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() && b.is_some() { - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Less { - a = x.next(); - } else { - if cmp == Equal { - if !f(a1) { return false } +impl<'self, T: TotalOrd> Iterator<&'self T> for SymDifference<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (ret , None ) => { self.a.step(); return ret }, + (None , ret ) => { self.b.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + return Some(a1); + } else { + self.b.step(); + if cmp == Greater { + return Some(b1); + } else { + self.a.step(); + } + } } - b = y.next(); } } - return true; } +} - /// Visit the values (in-order) representing the union - pub fn union(&self, other: &TreeSet, f: &fn(&T) -> bool) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - - let mut a = x.next(); - let mut b = y.next(); - - while a.is_some() { - if b.is_none() { - return f(a.unwrap()) && x.advance(f); +impl<'self, T: TotalOrd> Iterator<&'self T> for Intersection<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (None , _ ) => return None, + (_ , None ) => return None, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Less { + self.a.step(); + } else { + self.b.step(); + if cmp == Equal { + return Some(a1); + } + } + }, } + } + } +} - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - let cmp = a1.cmp(b1); - - if cmp == Greater { - if !f(b1) { return false; } - b = y.next(); - } else { - if !f(a1) { return false; } - if cmp == Equal { - b = y.next(); +impl<'self, T: TotalOrd> Iterator<&'self T> for Union<'self, T> { + fn next(&mut self) -> Option<&'self T> { + loop { + match (self.a.focus, self.b.focus) { + (ret , None) => { self.a.step(); return ret }, + (None , ret ) => { self.b.step(); return ret }, + (Some(a1), Some(b1)) => { + let cmp = a1.cmp(b1); + if cmp == Greater { + self.b.step(); + return Some(b1); + } else { + self.a.step(); + if cmp == Equal { + self.b.step(); + } + return Some(a1); + } } - a = x.next(); } } - b.iter().advance(|&x| f(x)) && y.advance(f) } } -/// Lazy forward iterator over a set -pub struct TreeSetIterator<'self, T> { - priv iter: TreeMapIterator<'self, T, ()> -} // Nodes keep track of their level in the tree, starting at 1 in the // leaves and with a red child sharing the level of the parent. @@ -687,18 +711,6 @@ pub fn new(key: K, value: V) -> TreeNode { } } -fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each(&x.left, |k,v| f(k,v)) && f(&x.key, &x.value) && - each(&x.right, |k,v| f(k,v))) -} - -fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&'r K, &'r V) -> bool) -> bool { - node.iter().advance(|x| each_reverse(&x.right, |k,v| f(k,v)) && f(&x.key, &x.value) && - each_reverse(&x.left, |k,v| f(k,v))) -} - fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, f: &fn(&'r K, &'r mut V) -> bool) -> bool { @@ -1129,7 +1141,7 @@ fn test_interval_iteration() { } #[test] - fn test_each_reverse() { + fn test_rev_iter() { let mut m = TreeMap::new(); assert!(m.insert(3, 6)); @@ -1139,12 +1151,11 @@ fn test_each_reverse() { assert!(m.insert(1, 2)); let mut n = 4; - do m.each_reverse |k, v| { + for (k, v) in m.rev_iter() { assert_eq!(*k, n); assert_eq!(*v, n * 2); n -= 1; - true - }; + } } #[test] @@ -1405,7 +1416,7 @@ fn test_iterator() { } #[test] - fn test_each_reverse() { + fn test_rev_iter() { let mut m = TreeSet::new(); assert!(m.insert(3)); @@ -1415,11 +1426,10 @@ fn test_each_reverse() { assert!(m.insert(1)); let mut n = 4; - do m.each_reverse |x| { + for x in m.rev_iter() { assert_eq!(*x, n); n -= 1; - true - }; + } } fn check(a: &[int], b: &[int], expected: &[int], @@ -1442,7 +1452,7 @@ fn check(a: &[int], b: &[int], expected: &[int], #[test] fn test_intersection() { fn check_intersection(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.intersection(y, z)) + check(a, b, expected, |x, y, f| x.intersection(y).advance(f)) } check_intersection([], [], []); @@ -1458,7 +1468,7 @@ fn check_intersection(a: &[int], b: &[int], expected: &[int]) { #[test] fn test_difference() { fn check_difference(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.difference(y, z)) + check(a, b, expected, |x, y, f| x.difference(y).advance(f)) } check_difference([], [], []); @@ -1476,7 +1486,7 @@ fn check_difference(a: &[int], b: &[int], expected: &[int]) { fn test_symmetric_difference() { fn check_symmetric_difference(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.symmetric_difference(y, z)) + check(a, b, expected, |x, y, f| x.symmetric_difference(y).advance(f)) } check_symmetric_difference([], [], []); @@ -1491,7 +1501,7 @@ fn check_symmetric_difference(a: &[int], b: &[int], fn test_union() { fn check_union(a: &[int], b: &[int], expected: &[int]) { - check(a, b, expected, |x, y, z| x.union(y, z)) + check(a, b, expected, |x, y, f| x.union(y).advance(f)) } check_union([], [], []); diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 0256519abb7..b4ba8acae47 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -221,7 +221,7 @@ fn digest>(t: &T) -> ~str { fn digest_file(path: &Path) -> ~str { let mut sha = ~Sha1::new(); let s = io::read_whole_file_str(path); - (*sha).input_str(*s.get_ref()); + (*sha).input_str(s.unwrap()); (*sha).result_str() } @@ -378,7 +378,7 @@ fn test() { let pth = Path("foo.c"); { let r = io::file_writer(&pth, [io::Create]); - r.get_ref().write_str("int main() { return 0; }"); + r.unwrap().write_str("int main() { return 0; }"); } let cx = Context::new(RWArc::new(Database::new(Path("db.json"))), diff --git a/src/librust/rust.rs b/src/librust/rust.rs index 1ac8146bb58..010486cdf85 100644 --- a/src/librust/rust.rs +++ b/src/librust/rust.rs @@ -130,7 +130,7 @@ fn rustc_help() { fn find_cmd(command_string: &str) -> Option { do COMMANDS.iter().find_ |command| { command.cmd == command_string - }.map_consume(|x| *x) + }.map_move(|x| *x) } fn cmd_help(args: &[~str]) -> ValidUsage { diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index c3c100a89f1..28c7df4b33a 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -669,8 +669,7 @@ pub fn build_session_options(binary: @str, } else if opt_present(matches, "emit-llvm") { link::output_type_bitcode } else { link::output_type_exe }; - let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot"); - let sysroot_opt = sysroot_opt.map(|m| @Path(*m)); + let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m)); let target_opt = getopts::opt_maybe_str(matches, "target"); let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature"); let save_temps = getopts::opt_present(matches, "save-temps"); diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index d8b59d579c8..d6584846655 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -61,7 +61,9 @@ fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod { filter_item(cx, *a).chain(|x| fld.fold_item(x)) }.collect(); let filtered_view_items = do m.view_items.iter().filter_map |a| { - filter_view_item(cx, a).map(|&x| fld.fold_view_item(x)) + do filter_view_item(cx, a).map_move |x| { + fld.fold_view_item(x) + } }.collect(); ast::_mod { view_items: filtered_view_items, @@ -83,7 +85,9 @@ fn fold_foreign_mod( ) -> ast::foreign_mod { let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect(); let filtered_view_items = do nm.view_items.iter().filter_map |a| { - filter_view_item(cx, a).map(|&x| fld.fold_view_item(x)) + do filter_view_item(cx, a).map_move |x| { + fld.fold_view_item(x) + } }.collect(); ast::foreign_mod { sort: nm.sort, @@ -138,7 +142,7 @@ fn fold_block( filter_stmt(cx, *a).chain(|stmt| fld.fold_stmt(stmt)) }.collect(); let filtered_view_items = do b.view_items.iter().filter_map |a| { - filter_view_item(cx, a).map(|&x| fld.fold_view_item(x)) + filter_view_item(cx, a).map(|x| fld.fold_view_item(*x)) }.collect(); ast::Block { view_items: filtered_view_items, diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 356cdaf754e..90db3f8edb0 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2159,7 +2159,7 @@ pub fn find_name<'r>(&'r self, ty: &Type) -> Option<&'r str> { } pub fn find_type(&self, s: &str) -> Option { - self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x)) + self.named_types.find_equiv(&s).map_move(|x| Type::from_ref(*x)) } // We have a depth count, because we seem to make infinite types. diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 33623a40cfb..a5f541412de 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -133,7 +133,7 @@ pub fn add_extern_mod_stmt_cnum(cstore: &mut CStore, pub fn find_extern_mod_stmt_cnum(cstore: &CStore, emod_id: ast::NodeId) -> Option { - cstore.extern_mod_crate_map.find(&emod_id).map_consume(|x| *x) + cstore.extern_mod_crate_map.find(&emod_id).map_move(|x| *x) } #[deriving(Clone)] diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index c3097d1aa66..8d357126018 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -198,8 +198,8 @@ fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id { } fn get_provided_source(d: ebml::Doc, cdata: cmd) -> Option { - do reader::maybe_get_doc(d, tag_item_method_provided_source).map |doc| { - translate_def_id(cdata, reader::with_doc_data(*doc, parse_def_id)) + do reader::maybe_get_doc(d, tag_item_method_provided_source).map_move |doc| { + translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id)) } } @@ -265,10 +265,10 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, } fn item_ty_region_param(item: ebml::Doc) -> Option { - reader::maybe_get_doc(item, tag_region_param).map(|doc| { - let mut decoder = reader::Decoder(*doc); + do reader::maybe_get_doc(item, tag_region_param).map_move |doc| { + let mut decoder = reader::Decoder(doc); Decodable::decode(&mut decoder) - }) + } } fn item_ty_param_count(item: ebml::Doc) -> uint { @@ -415,7 +415,7 @@ pub fn get_impl_trait(cdata: cmd, tcx: ty::ctxt) -> Option<@ty::TraitRef> { let item_doc = lookup_item(id, cdata.data); - do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map |&tp| { + do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map_move |tp| { @doc_trait_ref(tp, tcx, cdata) } } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index c3bb2000447..88e168db558 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -159,10 +159,10 @@ pub fn check_for_conflicting_loans(&self, scope_id: ast::NodeId) { true }; - for i in range(0u, new_loan_indices.len()) { - let old_loan = &self.all_loans[new_loan_indices[i]]; - for j in range(i+1, new_loan_indices.len()) { - let new_loan = &self.all_loans[new_loan_indices[j]]; + for (i, &x) in new_loan_indices.iter().enumerate() { + let old_loan = &self.all_loans[x]; + for &y in new_loan_indices.slice_from(i+1).iter() { + let new_loan = &self.all_loans[y]; self.report_error_if_loans_conflict(old_loan, new_loan); } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 3db90ed5d74..d410021063c 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -286,13 +286,15 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { } mc::cat_deref(cmt_base, _, _) => { - opt_loan_path(cmt_base).map( - |&lp| @LpExtend(lp, cmt.mutbl, LpDeref)) + do opt_loan_path(cmt_base).map_move |lp| { + @LpExtend(lp, cmt.mutbl, LpDeref) + } } mc::cat_interior(cmt_base, ik) => { - opt_loan_path(cmt_base).map( - |&lp| @LpExtend(lp, cmt.mutbl, LpInterior(ik))) + do opt_loan_path(cmt_base).map_move |lp| { + @LpExtend(lp, cmt.mutbl, LpInterior(ik)) + } } mc::cat_downcast(cmt_base) | diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 77e81709a03..3b56764f2fc 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -493,9 +493,9 @@ pub fn compare_lit_exprs(tcx: middle::ty::ctxt, a: &expr, b: &expr) -> Option Option { - compare_lit_exprs(tcx, a, b).map(|&val| val == 0) + compare_lit_exprs(tcx, a, b).map_move(|val| val == 0) } pub fn lit_eq(a: &lit, b: &lit) -> Option { - compare_const_vals(&lit_to_const(a), &lit_to_const(b)).map(|&val| val == 0) + compare_const_vals(&lit_to_const(a), &lit_to_const(b)).map_move(|val| val == 0) } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 008add975d4..46b6d2214ae 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -983,10 +983,10 @@ fn bitwise(out_vec: &mut [uint], op: &fn(uint, uint) -> uint) -> bool { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; - for i in range(0u, out_vec.len()) { - let old_val = out_vec[i]; - let new_val = op(old_val, in_vec[i]); - out_vec[i] = new_val; + for (out_elt, in_elt) in out_vec.mut_iter().zip(in_vec.iter()) { + let old_val = *out_elt; + let new_val = op(old_val, *in_elt); + *out_elt = new_val; changed |= (old_val != new_val); } changed diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 28d24b169ca..46394454d00 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -187,12 +187,12 @@ pub fn next_adjacent(&self, edge: EdgeIndex, dir: Direction) -> EdgeIndex { pub fn each_node(&self, f: &fn(NodeIndex, &Node) -> bool) -> bool { //! Iterates over all edges defined in the graph. - range(0u, self.nodes.len()).advance(|i| f(NodeIndex(i), &self.nodes[i])) + self.nodes.iter().enumerate().advance(|(i, node)| f(NodeIndex(i), node)) } pub fn each_edge(&self, f: &fn(EdgeIndex, &Edge) -> bool) -> bool { - //! Iterates over all edges defined in the graph. - range(0u, self.nodes.len()).advance(|i| f(EdgeIndex(i), &self.edges[i])) + //! Iterates over all edges defined in the graph + self.edges.iter().enumerate().advance(|(i, edge)| f(EdgeIndex(i), edge)) } pub fn each_outgoing_edge(&self, diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 0dfad430f4d..42bc435a58a 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -393,7 +393,7 @@ pub fn match_and_collect_item(&mut self, return; // Didn't match. } - let item_index = self.item_refs.find(&value).map(|x| **x); + let item_index = self.item_refs.find(&value).map_move(|x| *x); // prevent borrow checker from considering ^~~~~~~~~~~ // self to be borrowed (annoying) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 0387f344796..b3961630490 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -607,9 +607,9 @@ pub fn variable_from_path(&self, expr: &expr) -> Option { match expr.node { expr_path(_) => { let def = self.tcx.def_map.get_copy(&expr.id); - moves::moved_variable_node_id_from_def(def).map( - |rdef| self.variable(*rdef, expr.span) - ) + do moves::moved_variable_node_id_from_def(def).map_move |rdef| { + self.variable(rdef, expr.span) + } } _ => None } @@ -623,9 +623,9 @@ pub fn variable_from_def_map(&self, node_id: NodeId, span: span) -> Option { match self.tcx.def_map.find(&node_id) { Some(&def) => { - moves::moved_variable_node_id_from_def(def).map( - |rdef| self.variable(*rdef, span) - ) + do moves::moved_variable_node_id_from_def(def).map_move |rdef| { + self.variable(rdef, span) + } } None => { self.tcx.sess.span_bug( diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2d121209118..4da22be4428 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -111,7 +111,7 @@ pub fn record_cleanup_scope(&mut self, scope_id: ast::NodeId) { pub fn opt_encl_scope(&self, id: ast::NodeId) -> Option { //! Returns the narrowest scope that encloses `id`, if any. - self.scope_map.find(&id).map(|&x| *x) + self.scope_map.find(&id).map_move(|x| *x) } pub fn encl_scope(&self, id: ast::NodeId) -> ast::NodeId { @@ -579,8 +579,7 @@ pub fn add_variance(&self, variance: region_variance) -> region_variance { /// the new variance is joined with the old variance. pub fn add_rp(&mut self, id: ast::NodeId, variance: region_variance) { assert!(id != 0); - let old_variance = self.region_paramd_items.find(&id). - map_consume(|x| *x); + let old_variance = self.region_paramd_items.find(&id).map_move(|x| *x); let joined_variance = match old_variance { None => variance, Some(v) => join_variance(v, variance) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 625dcd5d9cc..f55fdd22c9a 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -13,7 +13,7 @@ use metadata::csearch::{each_path, get_trait_method_def_ids}; use metadata::csearch::get_method_name_and_explicit_self; use metadata::csearch::get_static_methods_if_impl; -use metadata::csearch::get_type_name_if_impl; +use metadata::csearch::{get_type_name_if_impl, get_struct_fields}; use metadata::cstore::find_extern_mod_stmt_cnum; use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; @@ -1700,9 +1700,12 @@ trait method '%s'", } def_struct(def_id) => { debug!("(building reduced graph for external \ - crate) building type %s", + crate) building type and value for %s", final_ident); child_name_bindings.define_type(privacy, def, dummy_sp()); + if get_struct_fields(self.session.cstore, def_id).len() == 0 { + child_name_bindings.define_value(privacy, def, dummy_sp()); + } self.structs.insert(def_id); } def_method(*) => { @@ -3358,7 +3361,7 @@ pub fn upvarify(@mut self, // item, it's ok match def { def_ty_param(did, _) - if self.def_map.find(&did.node).map_consume(|x| *x) + if self.def_map.find(&did.node).map_move(|x| *x) == Some(def_typaram_binder(item_id)) => { // ok } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 2efed8f36d7..db8a86fe948 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -92,7 +92,7 @@ static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key; pub fn with_insn_ctxt(blk: &fn(&[&'static str])) { - let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k)); + let opt = local_data::get(task_local_insn_key, |k| k.map_move(|k| *k)); if opt.is_some() { blk(*opt.unwrap()); } @@ -108,7 +108,7 @@ pub struct _InsnCtxt { _x: () } impl Drop for _InsnCtxt { fn drop(&self) { do local_data::modify(task_local_insn_key) |c| { - do c.map_consume |ctx| { + do c.map_move |ctx| { let mut ctx = (*ctx).clone(); ctx.pop(); @ctx @@ -120,7 +120,7 @@ fn drop(&self) { pub fn push_ctxt(s: &'static str) -> _InsnCtxt { debug!("new InsnCtxt: %s", s); do local_data::modify(task_local_insn_key) |c| { - do c.map_consume |ctx| { + do c.map_move |ctx| { let mut ctx = (*ctx).clone(); ctx.push(s); @ctx @@ -1742,8 +1742,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext, _ => {} } - for arg_n in range(0u, arg_tys.len()) { - let arg_ty = arg_tys[arg_n]; + for (arg_n, &arg_ty) in arg_tys.iter().enumerate() { let raw_llarg = raw_llargs[arg_n]; // For certain mode/type combinations, the raw llarg values are passed diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs index fe1c288d177..f5fb68a7057 100644 --- a/src/librustc/middle/trans/cabi_mips.rs +++ b/src/librustc/middle/trans/cabi_mips.rs @@ -159,7 +159,7 @@ fn struct_ty(ty: Type, padding: Option, coerce: bool) -> Type { let size = ty_size(ty) * 8; - let mut fields = padding.map_default(~[], |p| ~[*p]); + let mut fields = padding.map_move_default(~[], |p| ~[p]); if coerce { fields = vec::append(fields, coerce_to_int(size)); diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index 530e1ff8e5b..dd24ec3ff1a 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -145,8 +145,8 @@ fn ty_size(ty: Type) -> uint { } fn all_mem(cls: &mut [RegClass]) { - for i in range(0u, cls.len()) { - cls[i] = Memory; + for elt in cls.mut_iter() { + *elt = Memory; } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f303e7b8275..240696ec190 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1010,8 +1010,7 @@ pub fn node_id_type_params(bcx: @mut Block, id: ast::NodeId) -> ~[ty::t] { pub fn node_vtables(bcx: @mut Block, id: ast::NodeId) -> Option { let raw_vtables = bcx.ccx().maps.vtable_map.find(&id); - raw_vtables.map( - |&vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts)) + raw_vtables.map_move(|vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts)) } pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res) diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 802163583d6..56ba1ae1694 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -241,7 +241,7 @@ fn drop(&self) { static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key; pub fn task_llcx() -> ContextRef { - let opt = local_data::get(task_local_llcx_key, |k| k.map(|&k| *k)); + let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k)); *opt.expect("task-local LLVMContextRef wasn't ever set!") } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 5153296337d..b1e600b9d73 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -888,6 +888,11 @@ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) { let offset = get_param(decl, first_real_arg + 1); Ret(bcx, GEP(bcx, ptr, [offset])); } + "offset_inbounds" => { + let ptr = get_param(decl, first_real_arg); + let offset = get_param(decl, first_real_arg + 1); + Ret(bcx, InBoundsGEP(bcx, ptr, [offset])); + } "memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32), "memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64), "memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32), diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index b67d88c07e1..9be01ef1db9 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -162,7 +162,7 @@ pub fn trans_method_callee(bcx: @mut Block, data: Method(MethodData { llfn: callee_fn.llfn, llself: val, - temp_cleanup: temp_cleanups.head_opt().map(|&v| *v), + temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v), self_ty: node_id_type(bcx, this.id), self_mode: mentry.self_mode, }) @@ -339,7 +339,7 @@ pub fn trans_monomorphized_callee(bcx: @mut Block, data: Method(MethodData { llfn: llfn_val, llself: llself_val, - temp_cleanup: temp_cleanups.head_opt().map(|&v| *v), + temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v), self_ty: node_id_type(bcx, base.id), self_mode: mentry.self_mode, }) diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 42d5527ee43..f25bf011f5d 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -148,7 +148,8 @@ fn store_type_uses(cx: Context, fn_id: def_id) -> @~[type_uses] { "visit_tydesc" | "forget" | "frame_address" | "morestack_addr" => 0, - "offset" | "memcpy32" | "memcpy64" | "memmove32" | "memmove64" | + "offset" | "offset_inbounds" | + "memcpy32" | "memcpy64" | "memmove32" | "memmove64" | "memset32" | "memset64" => use_repr, "sqrtf32" | "sqrtf64" | "powif32" | "powif64" | @@ -205,15 +206,8 @@ fn store_type_uses(cx: Context, fn_id: def_id) -> @~[type_uses] { pub fn type_needs(cx: &Context, use_: uint, ty: ty::t) { // Optimization -- don't descend type if all params already have this use - let len = { - let uses = &*cx.uses; - uses.len() - }; - for i in range(0u, len) { - if cx.uses[i] & use_ != use_ { - type_needs_inner(cx, use_, ty, @Nil); - return; - } + if cx.uses.iter().any(|&elt| elt & use_ != use_) { + type_needs_inner(cx, use_, ty, @Nil); } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a53bdff85f9..849c35cdd2c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3557,7 +3557,7 @@ pub fn def_has_ty_params(def: ast::def) -> bool { pub fn provided_source(cx: ctxt, id: ast::def_id) -> Option { - cx.provided_method_sources.find(&id).map(|x| **x) + cx.provided_method_sources.find(&id).map_move(|x| *x) } pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[@Method] { @@ -3710,8 +3710,9 @@ fn struct_ctor_id(cx: ctxt, struct_did: ast::def_id) -> Option { Some(&ast_map::node_item(item, _)) => { match item.node { ast::item_struct(struct_def, _) => { - struct_def.ctor_id.map(|ctor_id| - ast_util::local_def(*ctor_id)) + do struct_def.ctor_id.map_move |ctor_id| { + ast_util::local_def(ctor_id) + } } _ => cx.sess.bug("called struct_ctor_id on non-struct") } @@ -4443,15 +4444,15 @@ pub fn count_traits_and_supertraits(tcx: ctxt, } pub fn get_tydesc_ty(tcx: ctxt) -> Result { - do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| { - tcx.intrinsic_defs.find_copy(tydesc_lang_item) + do tcx.lang_items.require(TyDescStructLangItem).map_move |tydesc_lang_item| { + tcx.intrinsic_defs.find_copy(&tydesc_lang_item) .expect("Failed to resolve TyDesc") } } pub fn get_opaque_ty(tcx: ctxt) -> Result { - do tcx.lang_items.require(OpaqueStructLangItem).map |opaque_lang_item| { - tcx.intrinsic_defs.find_copy(opaque_lang_item) + do tcx.lang_items.require(OpaqueStructLangItem).map_move |opaque_lang_item| { + tcx.intrinsic_defs.find_copy(&opaque_lang_item) .expect("Failed to resolve Opaque") } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 53853e4fe1a..750bd506f3e 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -621,9 +621,9 @@ fn ty_of_method_or_bare_fn( in_binding_rscope(rscope, RegionParamNames(bound_lifetime_names.clone())); - let opt_transformed_self_ty = opt_self_info.map(|&self_info| { + let opt_transformed_self_ty = do opt_self_info.map_move |self_info| { transform_self_ty(this, &rb, self_info) - }); + }; let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, a, None)); diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 7caed390601..d8a9350e695 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -158,9 +158,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, None => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), ~"a structure pattern", None); fcx.write_error(pat.id); @@ -201,9 +201,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, _ => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), ~"an enum or structure pattern", None); fcx.write_error(pat.id); @@ -535,9 +535,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { _ => ty::terr_mismatch }; fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); + e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); fcx.write_error(pat.id); } } @@ -584,9 +584,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { fcx.infcx().type_error_message_str_with_expected( pat.span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), ~"a vector pattern", None); @@ -642,9 +642,9 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fcx.infcx().type_error_message_str_with_expected( span, |expected, actual| { - expected.map_default(~"", |e| { + expected.map_move_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - *e, actual)})}, + e, actual)})}, Some(expected), fmt!("%s pattern", match pointer_kind { Managed => "an @-box", diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index e1e7d10db0a..ae0a95688ed 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -772,8 +772,8 @@ pub fn consider_candidates(&self, self.tcx().sess.span_err( self.expr.span, "multiple applicable methods in scope"); - for idx in range(0u, relevant_candidates.len()) { - self.report_candidate(idx, &relevant_candidates[idx].origin); + for (idx, candidate) in relevant_candidates.iter().enumerate() { + self.report_candidate(idx, &candidate.origin); } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index ea8a11fc7b3..da0e219310f 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -364,8 +364,8 @@ pub fn check_fn(ccx: @mut CrateCtxt, |br| ty::re_free(ty::FreeRegion {scope_id: body.id, bound_region: br})); let opt_self_info = - opt_self_info.map( - |si| SelfInfo {self_ty: opt_self_ty.unwrap(), ..*si}); + opt_self_info.map_move( + |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si}); (isr, opt_self_info, fn_sig) }; @@ -536,7 +536,7 @@ pub fn check_method(ccx: @mut CrateCtxt, { let method_def_id = local_def(method.id); let method_ty = ty::method(ccx.tcx, method_def_id); - let opt_self_info = method_ty.transformed_self_ty.map(|&ty| { + let opt_self_info = method_ty.transformed_self_ty.map_move(|ty| { SelfInfo {self_ty: ty, self_id: method.self_id, span: method.explicit_self.span} @@ -557,7 +557,7 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, for p in fields.iter() { let (id, sp) = *p; - let orig_sp = field_names.find(&id).map_consume(|x| *x); + let orig_sp = field_names.find(&id).map_move(|x| *x); match orig_sp { Some(orig_sp) => { tcx.sess.span_err(sp, fmt!("Duplicate field name %s in record type declaration", @@ -601,7 +601,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { check_bare_fn(ccx, decl, body, it.id, None); } ast::item_impl(_, _, _, ref ms) => { - let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = ccx.tcx.region_paramd_items.find(&it.id).map_move(|x| *x); debug!("item_impl %s with id %d rp %?", ccx.tcx.sess.str_of(it.ident), it.id, rp); for m in ms.iter() { @@ -1877,8 +1877,7 @@ fn check_struct_or_variant_fields(fcx: @mut FnCtxt, for field in ast_fields.iter() { let mut expected_field_type = ty::mk_err(); - let pair = class_field_map.find(&field.ident). - map_consume(|x| *x); + let pair = class_field_map.find(&field.ident).map_move(|x| *x); match pair { None => { tcx.sess.span_err( @@ -1962,7 +1961,7 @@ fn check_struct_constructor(fcx: @mut FnCtxt, if class_id.crate == ast::LOCAL_CRATE { region_parameterized = tcx.region_paramd_items.find(&class_id.node). - map_consume(|x| *x); + map_move(|x| *x); match tcx.items.find(&class_id.node) { Some(&ast_map::node_item(@ast::item { node: ast::item_struct(_, ref generics), @@ -2050,7 +2049,7 @@ fn check_struct_enum_variant(fcx: @mut FnCtxt, let raw_type; if enum_id.crate == ast::LOCAL_CRATE { region_parameterized = - tcx.region_paramd_items.find(&enum_id.node).map_consume(|x| *x); + tcx.region_paramd_items.find(&enum_id.node).map_move(|x| *x); match tcx.items.find(&enum_id.node) { Some(&ast_map::node_item(@ast::item { node: ast::item_enum(_, ref generics), @@ -3481,6 +3480,20 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t { mutbl: ast::m_imm })) } + "offset_inbounds" => { + (1, + ~[ + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + }), + ty::mk_int() + ], + ty::mk_ptr(tcx, ty::mt { + ty: param(ccx, 0), + mutbl: ast::m_imm + })) + } "memcpy32" => { (1, ~[ diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 2685055bd84..cb4827104b6 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -40,9 +40,9 @@ pub fn replace_bound_regions_in_fn_sig( debug!("replace_bound_regions_in_fn_sig(self_ty=%?, fn_sig=%s, \ all_tys=%?)", - opt_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)), + opt_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)), ppaux::fn_sig_to_str(tcx, fn_sig), - all_tys.map(|&t| ppaux::ty_to_str(tcx, t))); + all_tys.map(|t| ppaux::ty_to_str(tcx, *t))); let _i = indenter(); let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| { @@ -52,12 +52,12 @@ pub fn replace_bound_regions_in_fn_sig( let new_fn_sig = ty::fold_sig(fn_sig, |t| { replace_bound_regions(tcx, isr, t) }); - let new_self_ty = opt_self_ty.map(|&t| replace_bound_regions(tcx, isr, t)); + let new_self_ty = opt_self_ty.map(|t| replace_bound_regions(tcx, isr, *t)); debug!("result of replace_bound_regions_in_fn_sig: \ new_self_ty=%?, \ fn_sig=%s", - new_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)), + new_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)), ppaux::fn_sig_to_str(tcx, &new_fn_sig)); return (isr, new_self_ty, new_fn_sig); diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index abb97f0d1c7..700d96727ea 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -131,9 +131,7 @@ fn lookup_vtables_for_param(vcx: &VtableContext, // ty is the value supplied for the type parameter A... let mut param_result = ~[]; - do ty::each_bound_trait_and_supertraits( - tcx, type_param_bounds.trait_bounds) |trait_ref| - { + do ty::each_bound_trait_and_supertraits(tcx, type_param_bounds.trait_bounds) |trait_ref| { // ...and here trait_ref is each bound that was declared on A, // expressed in terms of the type parameters. diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index bc8de29b78b..c3df0d06f83 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -554,8 +554,8 @@ pub fn check_trait_methods_are_implemented( let mut provided_names = HashSet::new(); // Implemented methods - for i in range(0u, all_methods.len()) { - provided_names.insert(all_methods[i].ident); + for elt in all_methods.iter() { + provided_names.insert(elt.ident); } let r = ty::trait_methods(tcx, trait_did); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 2bef2c08bb2..907a076b1a1 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -198,7 +198,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) { let tcx = ccx.tcx; - let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|&x| *x); + let region_paramd = tcx.region_paramd_items.find(&trait_id).map_move(|x| *x); match tcx.items.get_copy(&trait_id) { ast_map::node_item(@ast::item { node: ast::item_trait(ref generics, _, ref ms), @@ -817,7 +817,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, pub fn convert(ccx: &CrateCtxt, it: &ast::item) { let tcx = ccx.tcx; - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); debug!("convert: item %s with id %d rp %?", tcx.sess.str_of(it.ident), it.id, rp); match it.node { @@ -1020,7 +1020,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::item) -> @ty::TraitDef { Some(&def) => return def, _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); match it.node { ast::item_trait(ref generics, _, _) => { let self_ty = ty::mk_self(tcx, def_id); @@ -1049,7 +1049,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item) Some(&tpt) => return tpt, _ => {} } - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); match it.node { ast::item_static(ref t, _, _) => { let typ = ccx.to_ty(&empty_rscope, t); @@ -1086,7 +1086,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item) None => { } } - let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x); let region_parameterization = RegionParameterization::from_variance_and_generics(rp, generics); let tpt = { diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 854ee835cc7..7fa7daf6149 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -716,12 +716,13 @@ pub fn type_error_message_str_with_expected(@mut self, err: Option<&ty::type_err>) { debug!("hi! expected_ty = %?, actual_ty = %s", expected_ty, actual_ty); - let error_str = err.map_default(~"", |t_err| - fmt!(" (%s)", - ty::type_err_to_str(self.tcx, *t_err))); - let resolved_expected = expected_ty.map(|&e_ty| - { self.resolve_type_vars_if_possible(e_ty) }); - if !resolved_expected.map_default(false, |&e| { ty::type_is_error(e) }) { + let error_str = do err.map_move_default(~"") |t_err| { + fmt!(" (%s)", ty::type_err_to_str(self.tcx, t_err)) + }; + let resolved_expected = do expected_ty.map_move |e_ty| { + self.resolve_type_vars_if_possible(e_ty) + }; + if !resolved_expected.map_move_default(false, |e| { ty::type_is_error(e) }) { match resolved_expected { None => self.tcx.sess.span_err(sp, fmt!("%s%s", mk_msg(None, actual_ty), error_str)), diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 63503f3e6b6..91b6a4ce3bc 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -374,8 +374,8 @@ pub fn combine_vars(&mut self, pub fn vars_created_since_snapshot(&mut self, snapshot: uint) -> ~[RegionVid] { do vec::build |push| { - for i in range(snapshot, self.undo_log.len()) { - match self.undo_log[i] { + for &elt in self.undo_log.slice_from(snapshot).iter() { + match elt { AddVar(vid) => push(vid), _ => () } diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index bbcf42b1c5d..c9e2b8dd37b 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -215,7 +215,7 @@ fn named_region(&self, span: span, id: ast::ident) pub struct type_rscope(Option); impl type_rscope { - priv fn replacement(&self) -> ty::Region { + fn replacement(&self) -> ty::Region { if self.is_some() { ty::re_bound(ty::br_self) } else { diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index 46414a7a5e2..5bc22db0ca1 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -136,7 +136,7 @@ pub fn usage(argv0: &str) { pub fn describe_warnings() { use extra::sort::Sort; - printfln!(" + println(" Available lint options: -W Warn about -A Allow @@ -157,7 +157,7 @@ pub fn describe_warnings() { fn padded(max: uint, s: &str) -> ~str { str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s } - printfln!("\nAvailable lint checks:\n"); + println("\nAvailable lint checks:\n"); printfln!(" %s %7.7s %s", padded(max_key, "name"), "default", "meaning"); printfln!(" %s %7.7s %s\n", @@ -173,7 +173,7 @@ fn padded(max: uint, s: &str) -> ~str { } pub fn describe_debug_flags() { - printfln!("\nAvailable debug options:\n"); + println("\nAvailable debug options:\n"); let r = session::debugging_opts_map(); for tuple in r.iter() { match *tuple { @@ -249,13 +249,12 @@ pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) { let sopts = build_session_options(binary, matches, demitter); let sess = build_session(sopts, demitter); - let odir = getopts::opt_maybe_str(matches, "out-dir"); - let odir = odir.map(|o| Path(*o)); - let ofile = getopts::opt_maybe_str(matches, "o"); - let ofile = ofile.map(|o| Path(*o)); + let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o)); + let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o)); let cfg = build_configuration(sess, binary, &input); - let pretty = getopts::opt_default(matches, "pretty", "normal").map( - |a| parse_pretty(sess, *a)); + let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| { + parse_pretty(sess, a) + }; match pretty { Some::(ppm) => { pretty_print_input(sess, cfg, &input, ppm); @@ -299,10 +298,18 @@ pub enum monitor_msg { */ pub fn monitor(f: ~fn(diagnostic::Emitter)) { use std::comm::*; + + // XXX: This is a hack for newsched since it doesn't support split stacks. + // rustc needs a lot of stack! + static STACK_SIZE: uint = 4000000; + let (p, ch) = stream(); let ch = SharedChan::new(ch); let ch_capture = ch.clone(); - match do task::try || { + let mut task_builder = task::task(); + task_builder.supervised(); + task_builder.opts.stack_size = Some(STACK_SIZE); + match do task_builder.try { let ch = ch_capture.clone(); let ch_capture = ch.clone(); // The 'diagnostics emitter'. Every error, warning, etc. should diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index d387bbea592..3598eb7c0fb 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -140,7 +140,7 @@ fn config_from_opts( let result = result::Ok(config); let result = do result.chain |config| { let output_dir = getopts::opt_maybe_str(matches, opt_output_dir()); - let output_dir = output_dir.map(|s| Path(*s)); + let output_dir = output_dir.map_move(|s| Path(s)); result::Ok(Config { output_dir: output_dir.unwrap_or_default(config.output_dir.clone()), .. config @@ -148,8 +148,8 @@ fn config_from_opts( }; let result = do result.chain |config| { let output_format = getopts::opt_maybe_str(matches, opt_output_format()); - do output_format.map_default(result::Ok(config.clone())) |output_format| { - do parse_output_format(*output_format).chain |output_format| { + do output_format.map_move_default(result::Ok(config.clone())) |output_format| { + do parse_output_format(output_format).chain |output_format| { result::Ok(Config { output_format: output_format, .. config.clone() @@ -160,8 +160,8 @@ fn config_from_opts( let result = do result.chain |config| { let output_style = getopts::opt_maybe_str(matches, opt_output_style()); - do output_style.map_default(result::Ok(config.clone())) |output_style| { - do parse_output_style(*output_style).chain |output_style| { + do output_style.map_move_default(result::Ok(config.clone())) |output_style| { + do parse_output_style(output_style).chain |output_style| { result::Ok(Config { output_style: output_style, .. config.clone() diff --git a/src/librustdoc/doc.rs b/src/librustdoc/doc.rs index d24fd1f5bfe..aba7ea1f0d7 100644 --- a/src/librustdoc/doc.rs +++ b/src/librustdoc/doc.rs @@ -54,7 +54,7 @@ pub struct CrateDoc { pub enum ItemTag { ModTag(ModDoc), NmodTag(NmodDoc), - ConstTag(ConstDoc), + StaticTag(StaticDoc), FnTag(FnDoc), EnumTag(EnumDoc), TraitTag(TraitDoc), @@ -95,7 +95,7 @@ pub struct NmodDoc { index: Option } -pub type ConstDoc = SimpleItemDoc; +pub type StaticDoc = SimpleItemDoc; pub type FnDoc = SimpleItemDoc; @@ -214,8 +214,8 @@ pub fn fns(&self) -> ~[FnDoc] { md!(FnTag) } - pub fn consts(&self) -> ~[ConstDoc] { - md!(ConstTag) + pub fn statics(&self) -> ~[StaticDoc] { + md!(StaticTag) } pub fn enums(&self) -> ~[EnumDoc] { @@ -249,7 +249,7 @@ pub trait PageUtils { fn mods(&self) -> ~[ModDoc]; fn nmods(&self) -> ~[NmodDoc]; fn fns(&self) -> ~[FnDoc]; - fn consts(&self) -> ~[ConstDoc]; + fn statics(&self) -> ~[StaticDoc]; fn enums(&self) -> ~[EnumDoc]; fn traits(&self) -> ~[TraitDoc]; fn impls(&self) -> ~[ImplDoc]; @@ -270,8 +270,8 @@ fn fns(&self) -> ~[FnDoc] { pu!(FnTag) } - fn consts(&self) -> ~[ConstDoc] { - pu!(ConstTag) + fn statics(&self) -> ~[StaticDoc] { + pu!(StaticTag) } fn enums(&self) -> ~[EnumDoc] { @@ -301,7 +301,7 @@ fn item(&self) -> ItemDoc { &doc::ModTag(ref doc) => doc.item.clone(), &doc::NmodTag(ref doc) => doc.item.clone(), &doc::FnTag(ref doc) => doc.item.clone(), - &doc::ConstTag(ref doc) => doc.item.clone(), + &doc::StaticTag(ref doc) => doc.item.clone(), &doc::EnumTag(ref doc) => doc.item.clone(), &doc::TraitTag(ref doc) => doc.item.clone(), &doc::ImplTag(ref doc) => doc.item.clone(), diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index f849cfade9b..2cab62296a4 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -101,8 +101,8 @@ fn moddoc_from_mod( )) } ast::item_static(*) => { - Some(doc::ConstTag( - constdoc_from_const(ItemDoc) + Some(doc::StaticTag( + staticdoc_from_static(ItemDoc) )) } ast::item_enum(enum_definition, _) => { @@ -165,7 +165,7 @@ fn fndoc_from_fn(itemdoc: doc::ItemDoc) -> doc::FnDoc { } } -fn constdoc_from_const(itemdoc: doc::ItemDoc) -> doc::ConstDoc { +fn staticdoc_from_static(itemdoc: doc::ItemDoc) -> doc::StaticDoc { doc::SimpleItemDoc { item: itemdoc, sig: None @@ -356,10 +356,10 @@ fn extract_from_seq_srv() { } #[test] - fn should_extract_const_name_and_id() { + fn should_extract_static_name_and_id() { let doc = mk_doc(@"static a: int = 0;"); - assert!(doc.cratemod().consts()[0].id() != 0); - assert!(doc.cratemod().consts()[0].name_() == ~"a"); + assert!(doc.cratemod().statics()[0].id() != 0); + assert!(doc.cratemod().statics()[0].name_() == ~"a"); } #[test] diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ad0dabdc3a4..589232f6e2f 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -21,7 +21,7 @@ pub struct Fold { fold_mod: FoldMod, fold_nmod: FoldNmod, fold_fn: FoldFn, - fold_const: FoldConst, + fold_static: FoldStatic, fold_enum: FoldEnum, fold_trait: FoldTrait, fold_impl: FoldImpl, @@ -39,7 +39,7 @@ fn clone(&self) -> Fold { fold_mod: self.fold_mod, fold_nmod: self.fold_nmod, fold_fn: self.fold_fn, - fold_const: self.fold_const, + fold_static: self.fold_static, fold_enum: self.fold_enum, fold_trait: self.fold_trait, fold_impl: self.fold_impl, @@ -55,7 +55,7 @@ fn clone(&self) -> Fold { type FoldMod = @fn(fold: &Fold, doc: doc::ModDoc) -> doc::ModDoc; type FoldNmod = @fn(fold: &Fold, doc: doc::NmodDoc) -> doc::NmodDoc; type FoldFn = @fn(fold: &Fold, doc: doc::FnDoc) -> doc::FnDoc; -type FoldConst = @fn(fold: &Fold, doc: doc::ConstDoc) -> doc::ConstDoc; +type FoldStatic = @fn(fold: &Fold, doc: doc::StaticDoc) -> doc::StaticDoc; type FoldEnum = @fn(fold: &Fold, doc: doc::EnumDoc) -> doc::EnumDoc; type FoldTrait = @fn(fold: &Fold, doc: doc::TraitDoc) -> doc::TraitDoc; type FoldImpl = @fn(fold: &Fold, doc: doc::ImplDoc) -> doc::ImplDoc; @@ -73,7 +73,7 @@ fn mk_fold( fold_mod: FoldMod, fold_nmod: FoldNmod, fold_fn: FoldFn, - fold_const: FoldConst, + fold_static: FoldStatic, fold_enum: FoldEnum, fold_trait: FoldTrait, fold_impl: FoldImpl, @@ -88,7 +88,7 @@ fn mk_fold( fold_mod: fold_mod, fold_nmod: fold_nmod, fold_fn: fold_fn, - fold_const: fold_const, + fold_static: fold_static, fold_enum: fold_enum, fold_trait: fold_trait, fold_impl: fold_impl, @@ -106,7 +106,7 @@ pub fn default_any_fold(ctxt: T) -> Fold { |f, d| default_any_fold_mod(f, d), |f, d| default_any_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -124,7 +124,7 @@ pub fn default_seq_fold(ctxt: T) -> Fold { |f, d| default_seq_fold_mod(f, d), |f, d| default_seq_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -142,7 +142,7 @@ pub fn default_par_fold(ctxt: T) -> Fold { |f, d| default_par_fold_mod(f, d), |f, d| default_par_fold_nmod(f, d), |f, d| default_seq_fold_fn(f, d), - |f, d| default_seq_fold_const(f, d), + |f, d| default_seq_fold_static(f, d), |f, d| default_seq_fold_enum(f, d), |f, d| default_seq_fold_trait(f, d), |f, d| default_seq_fold_impl(f, d), @@ -272,8 +272,8 @@ pub fn fold_ItemTag(fold: &Fold, doc: doc::ItemTag) -> doc::ItemTag { doc::FnTag(FnDoc) => { doc::FnTag((fold.fold_fn)(fold, FnDoc)) } - doc::ConstTag(ConstDoc) => { - doc::ConstTag((fold.fold_const)(fold, ConstDoc)) + doc::StaticTag(StaticDoc) => { + doc::StaticTag((fold.fold_static)(fold, StaticDoc)) } doc::EnumTag(EnumDoc) => { doc::EnumTag((fold.fold_enum)(fold, EnumDoc)) @@ -303,10 +303,10 @@ pub fn default_seq_fold_fn( } } -pub fn default_seq_fold_const( +pub fn default_seq_fold_static( fold: &Fold, - doc: doc::ConstDoc -) -> doc::ConstDoc { + doc: doc::StaticDoc +) -> doc::StaticDoc { doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item.clone()), .. doc @@ -374,7 +374,7 @@ fn default_fold_should_produce_same_doc() { } #[test] -fn default_fold_should_produce_same_consts() { +fn default_fold_should_produce_same_statics() { let source = @"static a: int = 0;"; let ast = parse::from_str(source); let doc = extract::extract(ast, ~""); diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 85c360a9e0d..7d07b4864f5 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -150,8 +150,8 @@ pub fn header_kind(doc: doc::ItemTag) -> ~str { doc::FnTag(_) => { ~"Function" } - doc::ConstTag(_) => { - ~"Freeze" + doc::StaticTag(_) => { + ~"Static" } doc::EnumTag(_) => { ~"Enum" @@ -321,7 +321,7 @@ fn write_item_(ctxt: &Ctxt, doc: doc::ItemTag, write_header: bool) { doc::ModTag(ModDoc) => write_mod(ctxt, ModDoc), doc::NmodTag(nModDoc) => write_nmod(ctxt, nModDoc), doc::FnTag(FnDoc) => write_fn(ctxt, FnDoc), - doc::ConstTag(ConstDoc) => write_const(ctxt, ConstDoc), + doc::StaticTag(StaticDoc) => write_static(ctxt, StaticDoc), doc::EnumTag(EnumDoc) => write_enum(ctxt, EnumDoc), doc::TraitTag(TraitDoc) => write_trait(ctxt, TraitDoc), doc::ImplTag(ImplDoc) => write_impl(ctxt, ImplDoc), @@ -409,9 +409,9 @@ fn code_block(s: ~str) -> ~str { ~~~", s) } -fn write_const( +fn write_static( ctxt: &Ctxt, - doc: doc::ConstDoc + doc: doc::StaticDoc ) { write_sig(ctxt, doc.sig.clone()); write_common(ctxt, doc.desc(), doc.sections()); @@ -637,7 +637,7 @@ fn should_request_new_writer_for_each_page() { let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); write_markdown(doc, writer_factory); // We expect two pages to have been written - do 2.times { + for _ in range(0, 2u) { po.recv(); } } @@ -649,7 +649,7 @@ fn should_write_title_for_each_page() { ~"#[link(name = \"core\")]; mod a { }"); let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); write_markdown(doc, writer_factory); - do 2.times { + for _ in range(0, 2u) { let (page, markdown) = po.recv(); match page { doc::CratePage(_) => { @@ -775,13 +775,13 @@ fn should_leave_blank_line_between_fn_header_and_sig() { } #[test] - fn should_write_const_header() { + fn should_write_static_header() { let markdown = render(~"static a: bool = true;"); - assert!(markdown.contains("## Freeze `a`\n\n")); + assert!(markdown.contains("## Static `a`\n\n")); } #[test] - fn should_write_const_description() { + fn should_write_static_description() { let markdown = render( ~"#[doc = \"b\"]\ static a: bool = true;"); diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index 6f3f91f3c65..3e380732d0f 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -202,7 +202,7 @@ fn should_prune_priv_associated_methods_on_impls_without_vis_modifier() { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } @@ -212,7 +212,7 @@ fn should_prune_priv_associated_methods_on_pub_impls() { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } @@ -232,7 +232,7 @@ fn should_prune_priv_associated_methods_on_priv_impls() { let doc = mk_doc( ~"impl Foo {\ pub fn bar() { }\ - priv fn baz() { }\ + fn baz() { }\ }"); assert_eq!(doc.cratemod().impls()[0].methods.len(), 1); } diff --git a/src/librustdoc/sort_item_type_pass.rs b/src/librustdoc/sort_item_type_pass.rs index 366cc83df27..ba8f37601fd 100644 --- a/src/librustdoc/sort_item_type_pass.rs +++ b/src/librustdoc/sort_item_type_pass.rs @@ -18,7 +18,7 @@ pub fn mk_pass() -> Pass { fn by_score(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool { fn score(item: &doc::ItemTag) -> int { match *item { - doc::ConstTag(_) => 0, + doc::StaticTag(_) => 0, doc::TyTag(_) => 1, doc::EnumTag(_) => 2, doc::StructTag(_) => 3, @@ -43,7 +43,7 @@ fn test() { let source = ~"mod imod { } \ - static iconst: int = 0; \ + static istatic: int = 0; \ fn ifn() { } \ enum ienum { ivar } \ trait itrait { fn a(); } \ @@ -54,7 +54,7 @@ impl int { fn a() { } } \ let doc = extract::from_srv(srv.clone(), ~""); let doc = (mk_pass().f)(srv.clone(), doc); // hidden __std_macros module at the start. - assert_eq!(doc.cratemod().items[0].name_(), ~"iconst"); + assert_eq!(doc.cratemod().items[0].name_(), ~"istatic"); assert_eq!(doc.cratemod().items[1].name_(), ~"itype"); assert_eq!(doc.cratemod().items[2].name_(), ~"ienum"); assert_eq!(doc.cratemod().items[3].name_(), ~"istruct"); diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 684b4e9d198..196c7e892a8 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -39,7 +39,7 @@ pub fn run( let fold = Fold { ctxt: srv.clone(), fold_fn: fold_fn, - fold_const: fold_const, + fold_static: fold_static, fold_enum: fold_enum, fold_trait: fold_trait, fold_impl: fold_impl, @@ -93,10 +93,10 @@ fn get_fn_sig(srv: astsrv::Srv, fn_id: doc::AstId) -> Option<~str> { } } -fn fold_const( +fn fold_static( fold: &fold::Fold, - doc: doc::ConstDoc -) -> doc::ConstDoc { + doc: doc::StaticDoc +) -> doc::StaticDoc { let srv = fold.ctxt.clone(); doc::SimpleItemDoc { @@ -109,7 +109,7 @@ fn fold_const( }, _) => { pprust::ty_to_str(ty, extract::interner()) } - _ => fail!("fold_const: id not bound to a const item") + _ => fail!("fold_static: id not bound to a static item") } }}), .. doc @@ -260,9 +260,9 @@ fn fold_impl( }, _) => { let bounds = pprust::generics_to_str(generics, extract::interner()); let bounds = if bounds.is_empty() { None } else { Some(bounds) }; - let trait_types = opt_trait_type.map_default(~[], |p| { + let trait_types = do opt_trait_type.map_default(~[]) |p| { ~[pprust::path_to_str(&p.path, extract::interner())] - }); + }; (bounds, trait_types, Some(pprust::ty_to_str( @@ -384,9 +384,9 @@ fn should_add_foreign_fn_sig() { } #[test] - fn should_add_const_types() { + fn should_add_static_types() { let doc = mk_doc(~"static a: bool = true;"); - assert!(doc.cratemod().consts()[0].sig == Some(~"bool")); + assert!(doc.cratemod().statics()[0].sig == Some(~"bool")); } #[test] diff --git a/src/librusti/rusti.rs b/src/librusti/rusti.rs index 5d5518997f6..bb863df3348 100644 --- a/src/librusti/rusti.rs +++ b/src/librusti/rusti.rs @@ -203,7 +203,7 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str], } } } - result = do blk.expr.map_consume |e| { + result = do blk.expr.map_move |e| { do with_pp(intr) |pp, _| { pprust::print_expr(pp, e); } }; } @@ -579,16 +579,19 @@ fn run_program(prog: &str) { } fn run_program(_: &str) {} + #[ignore] #[test] fn super_basic() { run_program(""); } + #[ignore] #[test] fn regression_5937() { run_program("use std::hashmap;"); } + #[ignore] #[test] fn regression_5784() { run_program("let a = 3;"); @@ -604,6 +607,7 @@ fn new_tasks() { "); } + #[ignore] #[test] fn inferred_integers_usable() { run_program("let a = 2;\n()\n"); @@ -614,6 +618,7 @@ fn inferred_integers_usable() { "); } + #[ignore] #[test] fn local_variables_allow_shadowing() { run_program(" @@ -623,6 +628,7 @@ fn local_variables_allow_shadowing() { "); } + #[ignore] #[test] fn string_usable() { run_program(" @@ -634,6 +640,7 @@ fn string_usable() { "); } + #[ignore] #[test] fn vectors_usable() { run_program(" @@ -646,6 +653,7 @@ fn vectors_usable() { "); } + #[ignore] #[test] fn structs_usable() { run_program(" @@ -655,6 +663,7 @@ struct A{ a: int } "); } + #[ignore] #[test] fn mutable_variables_work() { run_program(" @@ -667,6 +676,7 @@ fn mutable_variables_work() { "); } + #[ignore] #[test] fn functions_saved() { run_program(" @@ -677,6 +687,7 @@ fn fib(x: int) -> int { if x < 2 {x} else { fib(x - 1) + fib(x - 2) } } "); } + #[ignore] #[test] fn modules_saved() { run_program(" @@ -685,6 +696,7 @@ mod b { pub fn foo() -> uint { 3 } } "); } + #[ignore] #[test] fn multiple_functions() { run_program(" @@ -694,6 +706,7 @@ fn f() {} "); } + #[ignore] #[test] fn multiple_items_same_name() { run_program(" @@ -706,6 +719,7 @@ fn f() {} "); } + #[ignore] #[test] fn simultaneous_definition_and_expression() { run_program(" @@ -713,6 +727,7 @@ fn simultaneous_definition_and_expression() { "); } + #[ignore] #[test] fn exit_quits() { let mut r = repl(); diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 828be5dce12..9fea8662129 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -998,6 +998,7 @@ fn test_rustpkg_test() { } #[test] +#[ignore(reason = "test not yet implemented")] fn test_uninstall() { let workspace = create_local_package(&PkgId::new("foo", &os::getcwd())); let _output = command_line_test([~"info", ~"foo"], &workspace); diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index a84f3137bbd..f2470bed732 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -12,7 +12,7 @@ use clone::Clone; use container::Container; -use iterator::{Iterator, range}; +use iterator::Iterator; use option::{Option, Some, None}; use sys; use unstable::raw::Repr; @@ -92,8 +92,8 @@ pub fn append(lhs: @[T], rhs: &[T]) -> @[T] { for x in lhs.iter() { push((*x).clone()); } - for i in range(0u, rhs.len()) { - push(rhs[i].clone()); + for elt in rhs.iter() { + push(elt.clone()); } } } diff --git a/src/libstd/borrow.rs b/src/libstd/borrow.rs index 9e3a3a28fe8..6c3d4c5f1fb 100644 --- a/src/libstd/borrow.rs +++ b/src/libstd/borrow.rs @@ -58,3 +58,15 @@ fn gt(&self, other: & &'self T) -> bool { *(*self) > *(*other) } } + +#[cfg(not(test))] +impl<'self, T: TotalOrd> TotalOrd for &'self T { + #[inline] + fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl<'self, T: TotalEq> TotalEq for &'self T { + #[inline] + fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) } +} diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index 43a632562b2..b66f89e8341 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -153,7 +153,6 @@ pub fn cmp2( Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the lexical ordering on a type `(int, int)`. */ -// used in deriving code in libsyntax #[inline] pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering { match o1 { diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 4356f1143da..a4de10f8c77 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -314,7 +314,7 @@ mod pipesy { #[allow(non_camel_case_types)] pub mod oneshot { - priv use std::kinds::Send; + use std::kinds::Send; use ptr::to_mut_unsafe_ptr; pub fn init() -> (server::Oneshot, client::Oneshot) { @@ -341,7 +341,7 @@ pub struct __Buffer { #[allow(non_camel_case_types)] pub mod client { - priv use std::kinds::Send; + use std::kinds::Send; #[allow(non_camel_case_types)] pub fn try_send(pipe: Oneshot, x_0: T) -> @@ -489,7 +489,7 @@ pub fn try_send_one(chan: ChanOne, data: T) -> bool { #[allow(non_camel_case_types)] pub mod streamp { - priv use std::kinds::Send; + use std::kinds::Send; pub fn init() -> (server::Open, client::Open) { pub use std::pipes::HasBuffer; @@ -501,7 +501,7 @@ pub enum Open { pub data(T, server::Open), } #[allow(non_camel_case_types)] pub mod client { - priv use std::kinds::Send; + use std::kinds::Send; #[allow(non_camel_case_types)] pub fn try_data(pipe: Open, x_0: T) -> diff --git a/src/libstd/either.rs b/src/libstd/either.rs index cfaef550c6f..bb74d9b3ec4 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -24,7 +24,7 @@ use vec::{OwnedVector, ImmutableVector}; /// `Either` is a type that represents one of two alternatives -#[deriving(Clone, Eq)] +#[deriving(Clone, Eq, IterBytes)] pub enum Either { Left(L), Right(R) diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs new file mode 100644 index 00000000000..2b8807b2291 --- /dev/null +++ b/src/libstd/fmt/mod.rs @@ -0,0 +1,368 @@ +// 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. + +use prelude::*; + +use cast; +use int; +use rt::io::Decorator; +use rt::io::mem::MemWriter; +use rt::io; +use str; +use sys; +use uint; +use util; +use vec; + +pub mod parse; +pub mod rt; + +/// A struct to represent both where to emit formatting strings to and how they +/// should be formatted. A mutable version of this is passed to all formatting +/// traits. +pub struct Formatter<'self> { + /// Flags for formatting (packed version of rt::Flag) + flags: uint, + /// Character used as 'fill' whenever there is alignment + fill: char, + /// Boolean indication of whether the output should be left-aligned + alignleft: bool, + /// Optionally specified integer width that the output should be + width: Option, + /// Optionally specified precision for numeric types + precision: Option, + + /// Output buffer. + buf: &'self mut io::Writer, + + priv curarg: vec::VecIterator<'self, Argument<'self>>, + priv args: &'self [Argument<'self>], +} + +/// This struct represents the generic "argument" which is taken by the Xprintf +/// family of functions. It contains a function to format the given value. At +/// compile time it is ensured that the function and the value have the correct +/// types, and then this struct is used to canonicalize arguments to one type. +pub struct Argument<'self> { + priv formatter: extern "Rust" fn(&util::Void, &mut Formatter), + priv value: &'self util::Void, +} + +#[allow(missing_doc)] +pub trait Bool { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Char { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Signed { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Unsigned { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Octal { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Binary { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait LowerHex { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait UpperHex { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait String { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Poly { fn fmt(&Self, &mut Formatter); } +#[allow(missing_doc)] +pub trait Pointer { fn fmt(&Self, &mut Formatter); } + +/// The sprintf function takes a precompiled format string and a list of +/// arguments, to return the resulting formatted string. +/// +/// This is currently an unsafe function because the types of all arguments +/// aren't verified by immediate callers of this function. This currently does +/// not validate that the correct types of arguments are specified for each +/// format specifier, nor that each argument itself contains the right function +/// for formatting the right type value. Because of this, the function is marked +/// as `unsafe` if this is being called manually. +/// +/// Thankfully the rust compiler provides the macro `ifmt!` which will perform +/// all of this validation at compile-time and provides a safe interface for +/// invoking this function. +/// +/// # Arguments +/// +/// * fmts - the precompiled format string to emit. +/// * args - the list of arguments to the format string. These are only the +/// positional arguments (not named) +/// +/// Note that this function assumes that there are enough arguments for the +/// format string. +pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str { + let output = MemWriter::new(); + { + let mut formatter = Formatter { + flags: 0, + width: None, + precision: None, + // FIXME(#8248): shouldn't need a transmute + buf: cast::transmute(&output as &io::Writer), + alignleft: false, + fill: ' ', + args: args, + curarg: args.iter(), + }; + for piece in fmt.iter() { + formatter.run(piece, None); + } + } + return str::from_bytes_owned(output.inner()); +} + +impl<'self> Formatter<'self> { + fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) { + let setcount = |slot: &mut Option, cnt: &parse::Count| { + match *cnt { + parse::CountIs(n) => { *slot = Some(n); } + parse::CountImplied => { *slot = None; } + parse::CountIsParam(i) => { + let v = self.args[i].value; + unsafe { *slot = Some(*(v as *util::Void as *uint)); } + } + parse::CountIsNextParam => { + let v = self.curarg.next().unwrap().value; + unsafe { *slot = Some(*(v as *util::Void as *uint)); } + } + } + }; + + match *piece { + rt::String(s) => { self.buf.write(s.as_bytes()); } + rt::CurrentArgument(()) => { self.buf.write(cur.unwrap().as_bytes()); } + rt::Argument(ref arg) => { + // Fill in the format parameters into the formatter + self.fill = arg.format.fill; + self.alignleft = arg.format.alignleft; + self.flags = arg.format.flags; + setcount(&mut self.width, &arg.format.width); + setcount(&mut self.precision, &arg.format.precision); + + // Extract the correct argument + let value = match arg.position { + rt::ArgumentNext => { *self.curarg.next().unwrap() } + rt::ArgumentIs(i) => self.args[i], + }; + + // Then actually do some printing + match arg.method { + None => { (value.formatter)(value.value, self); } + Some(ref method) => { self.execute(*method, value); } + } + } + } + } + + fn execute(&mut self, method: &rt::Method, arg: Argument) { + match *method { + // Pluralization is selection upon a numeric value specified as the + // parameter. + rt::Plural(offset, ref selectors, ref default) => { + // This is validated at compile-time to be a pointer to a + // '&uint' value. + let value: &uint = unsafe { cast::transmute(arg.value) }; + let value = *value; + + // First, attempt to match against explicit values without the + // offsetted value + for s in selectors.iter() { + match s.selector { + Right(val) if value == val => { + return self.runplural(value, s.result); + } + _ => {} + } + } + + // Next, offset the value and attempt to match against the + // keyword selectors. + let value = value - match offset { Some(i) => i, None => 0 }; + for s in selectors.iter() { + let run = match s.selector { + Left(parse::Zero) => value == 0, + Left(parse::One) => value == 1, + Left(parse::Two) => value == 2, + + // XXX: Few/Many should have a user-specified boundary + // One possible option would be in the function + // pointer of the 'arg: Argument' struct. + Left(parse::Few) => value < 8, + Left(parse::Many) => value >= 8, + + Right(*) => false + }; + if run { + return self.runplural(value, s.result); + } + } + + self.runplural(value, *default); + } + + // Select is just a matching against the string specified. + rt::Select(ref selectors, ref default) => { + // This is validated at compile-time to be a pointer to a + // string slice, + let value: & &str = unsafe { cast::transmute(arg.value) }; + let value = *value; + + for s in selectors.iter() { + if s.selector == value { + for piece in s.result.iter() { + self.run(piece, Some(value)); + } + return; + } + } + for piece in default.iter() { + self.run(piece, Some(value)); + } + } + } + } + + fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) { + do uint::to_str_bytes(value, 10) |buf| { + let valuestr = str::from_bytes_slice(buf); + for piece in pieces.iter() { + self.run(piece, Some(valuestr)); + } + } + } +} + +/// This is a function which calls are emitted to by the compiler itself to +/// create the Argument structures that are passed into the `sprintf` function. +#[doc(hidden)] +pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter), + t: &'a T) -> Argument<'a> { + unsafe { + Argument { + formatter: cast::transmute(f), + value: cast::transmute(t) + } + } +} + +/// When the compiler determines that the type of an argument *must* be a string +/// (such as for select), then it invokes this method. +#[doc(hidden)] +pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> { + argument(String::fmt, s) +} + +/// When the compiler determines that the type of an argument *must* be a uint +/// (such as for plural), then it invokes this method. +#[doc(hidden)] +pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> { + argument(Unsigned::fmt, s) +} + +// Implementations of the core formatting traits + +impl Bool for bool { + fn fmt(b: &bool, f: &mut Formatter) { + String::fmt(&(if *b {"true"} else {"false"}), f); + } +} + +impl<'self> String for &'self str { + fn fmt(s: & &'self str, f: &mut Formatter) { + // XXX: formatting args + f.buf.write(s.as_bytes()) + } +} + +impl Char for char { + fn fmt(c: &char, f: &mut Formatter) { + // XXX: formatting args + // XXX: shouldn't require an allocation + let mut s = ~""; + s.push_char(*c); + f.buf.write(s.as_bytes()); + } +} + +impl Signed for int { + fn fmt(c: &int, f: &mut Formatter) { + // XXX: formatting args + do int::to_str_bytes(*c, 10) |buf| { + f.buf.write(buf); + } + } +} + +impl Unsigned for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 10) |buf| { + f.buf.write(buf); + } + } +} + +impl Octal for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 8) |buf| { + f.buf.write(buf); + } + } +} + +impl LowerHex for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 16) |buf| { + f.buf.write(buf); + } + } +} + +impl UpperHex for uint { + fn fmt(c: &uint, f: &mut Formatter) { + // XXX: formatting args + do uint::to_str_bytes(*c, 16) |buf| { + let mut local = [0u8, ..16]; + for (l, &b) in local.mut_iter().zip(buf.iter()) { + *l = match b as char { + 'a' .. 'f' => (b - 'a' as u8) + 'A' as u8, + _ => b, + }; + } + f.buf.write(local.slice_to(buf.len())); + } + } +} + +impl Poly for T { + fn fmt(t: &T, f: &mut Formatter) { + // XXX: formatting args + let s = sys::log_str(t); + f.buf.write(s.as_bytes()); + } +} + +// n.b. use 'const' to get an implementation for both '*mut' and '*' at the same +// time. +impl Pointer for *const T { + fn fmt(t: &*const T, f: &mut Formatter) { + // XXX: formatting args + f.buf.write("0x".as_bytes()); + LowerHex::fmt(&(*t as uint), f); + } +} + +// If you expected tests to be here, look instead at the run-pass/ifmt.rs test, +// it's a lot easier than creating all of the rt::Piece structures here. diff --git a/src/libstd/fmt/parse.rs b/src/libstd/fmt/parse.rs new file mode 100644 index 00000000000..673ea1d3fa8 --- /dev/null +++ b/src/libstd/fmt/parse.rs @@ -0,0 +1,896 @@ +// 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. + +use prelude::*; + +use char; +use str; +use iterator; + +condition! { pub parse_error: ~str -> (); } + +/// A piece is a portion of the format string which represents the next part to +/// emit. These are emitted as a stream by the `Parser` class. +#[deriving(Eq)] +pub enum Piece<'self> { + /// A literal string which should directly be emitted + String(&'self str), + /// A back-reference to whatever the current argument is. This is used + /// inside of a method call to refer back to the original argument. + CurrentArgument, + /// This describes that formatting should process the next argument (as + /// specified inside) for emission. + Argument(Argument<'self>), +} + +/// Representation of an argument specification. +#[deriving(Eq)] +pub struct Argument<'self> { + /// Where to find this argument + position: Position<'self>, + /// How to format the argument + format: FormatSpec<'self>, + /// If not `None`, what method to invoke on the argument + method: Option<~Method<'self>> +} + +/// Specification for the formatting of an argument in the format string. +#[deriving(Eq)] +pub struct FormatSpec<'self> { + /// Optionally specified character to fill alignment with + fill: Option, + /// Optionally specified alignment + align: Option, + /// Packed version of various flags provided + flags: uint, + /// The integer precision to use + precision: Count, + /// The string width requested for the resulting format + width: Count, + /// The descriptor string representing the name of the format desired for + /// this argument, this can be empty or any number of characters, although + /// it is required to be one word. + ty: &'self str +} + +/// Enum describing where an argument for a format can be located. +#[deriving(Eq)] +pub enum Position<'self> { + ArgumentNext, ArgumentIs(uint), ArgumentNamed(&'self str) +} + +/// Enum of alignments which are supoprted. +#[deriving(Eq)] +pub enum Alignment { AlignLeft, AlignRight } + +/// Various flags which can be applied to format strings, the meaning of these +/// flags is defined by the formatters themselves. +#[deriving(Eq)] +pub enum Flag { + FlagSignPlus, + FlagSignMinus, + FlagAlternate, +} + +/// A count is used for the precision and width parameters of an integer, and +/// can reference either an argument or a literal integer. +#[deriving(Eq)] +pub enum Count { + CountIs(uint), + CountIsParam(uint), + CountIsNextParam, + CountImplied, +} + +/// Enum describing all of the possible methods which the formatting language +/// currently supports. +#[deriving(Eq)] +pub enum Method<'self> { + /// A plural method selects on an integer over a list of either integer or + /// keyword-defined clauses. The meaning of the keywords is defined by the + /// current locale. + /// + /// An offset is optionally present at the beginning which is used to match + /// against keywords, but it is not matched against the literal integers. + /// + /// The final element of this enum is the default "other" case which is + /// always required to be specified. + Plural(Option, ~[PluralArm<'self>], ~[Piece<'self>]), + + /// A select method selects over a string. Each arm is a different string + /// which can be selected for. + /// + /// As with `Plural`, a default "other" case is required as well. + Select(~[SelectArm<'self>], ~[Piece<'self>]), +} + +/// Structure representing one "arm" of the `plural` function. +#[deriving(Eq)] +pub struct PluralArm<'self> { + /// A selector can either be specified by a keyword or with an integer + /// literal. + selector: Either, + /// Array of pieces which are the format of this arm + result: ~[Piece<'self>], +} + +/// Enum of the 5 CLDR plural keywords. There is one more, "other", but that is +/// specially placed in the `Plural` variant of `Method` +/// +/// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html +#[deriving(Eq, IterBytes)] +pub enum PluralKeyword { + Zero, One, Two, Few, Many +} + +/// Structure representing one "arm" of the `select` function. +#[deriving(Eq)] +pub struct SelectArm<'self> { + /// String selector which guards this arm + selector: &'self str, + /// Array of pieces which are the format of this arm + result: ~[Piece<'self>], +} + +/// The parser structure for interpreting the input format string. This is +/// modelled as an iterator over `Piece` structures to form a stream of tokens +/// being output. +/// +/// This is a recursive-descent parser for the sake of simplicity, and if +/// necessary there's probably lots of room for improvement performance-wise. +pub struct Parser<'self> { + priv input: &'self str, + priv cur: str::CharOffsetIterator<'self>, +} + +impl<'self> iterator::Iterator> for Parser<'self> { + fn next(&mut self) -> Option> { + match self.cur.clone().next() { + Some((_, '#')) => { self.cur.next(); Some(CurrentArgument) } + Some((_, '{')) => { + self.cur.next(); + let ret = Some(Argument(self.argument())); + if !self.consume('}') { + self.err(~"unterminated format string"); + } + ret + } + Some((pos, '\\')) => { + self.cur.next(); + self.escape(); // ensure it's a valid escape sequence + Some(String(self.string(pos + 1))) // skip the '\' character + } + Some((_, '}')) | None => { None } + Some((pos, _)) => { + Some(String(self.string(pos))) + } + } + } +} + +impl<'self> Parser<'self> { + /// Creates a new parser for the given format string + pub fn new<'a>(s: &'a str) -> Parser<'a> { + Parser { + input: s, + cur: s.char_offset_iter(), + } + } + + /// Notifies of an error. The message doesn't actually need to be of type + /// ~str, but I think it does when this eventually uses conditions so it + /// might as well start using it now. + fn err(&self, msg: ~str) { + parse_error::cond.raise(msg); + } + + /// Optionally consumes the specified character. If the character is not at + /// the current position, then the current iterator isn't moved and false is + /// returned, otherwise the character is consumed and true is returned. + fn consume(&mut self, c: char) -> bool { + match self.cur.clone().next() { + Some((_, maybe)) if c == maybe => { + self.cur.next(); + true + } + Some(*) | None => false, + } + } + + /// Attempts to consume any amount of whitespace followed by a character + fn wsconsume(&mut self, c: char) -> bool { + self.ws(); self.consume(c) + } + + /// Consumes all whitespace characters until the first non-whitespace + /// character + fn ws(&mut self) { + loop { + match self.cur.clone().next() { + Some((_, c)) if char::is_whitespace(c) => { self.cur.next(); } + Some(*) | None => { return } + } + } + } + + /// Consumes an escape sequence, failing if there is not a valid character + /// to be escaped. + fn escape(&mut self) -> char { + match self.cur.next() { + Some((_, c @ '#')) | Some((_, c @ '{')) | + Some((_, c @ '\\')) | Some((_, c @ '}')) => { c } + Some((_, c)) => { + self.err(fmt!("invalid escape character `%c`", c)); + c + } + None => { + self.err(~"expected an escape sequence, but format string was \ + terminated"); + ' ' + } + } + } + + /// Parses all of a string which is to be considered a "raw literal" in a + /// format string. This is everything outside of the braces. + fn string(&mut self, start: uint) -> &'self str { + loop { + // we may not consume the character, so clone the iterator + match self.cur.clone().next() { + Some((pos, '\\')) | Some((pos, '#')) | + Some((pos, '}')) | Some((pos, '{')) => { + return self.input.slice(start, pos); + } + Some(*) => { self.cur.next(); } + None => { + self.cur.next(); + return self.input.slice(start, self.input.len()); + } + } + } + } + + /// Parses an Argument structure, or what's contained within braces inside + /// the format string + fn argument(&mut self) -> Argument<'self> { + Argument { + position: self.position(), + format: self.format(), + method: self.method(), + } + } + + /// Parses a positional argument for a format. This could either be an + /// integer index of an argument, a named argument, or a blank string. + fn position(&mut self) -> Position<'self> { + match self.integer() { + Some(i) => { ArgumentIs(i) } + None => { + match self.cur.clone().next() { + Some((_, c)) if char::is_alphabetic(c) => { + ArgumentNamed(self.word()) + } + _ => ArgumentNext + } + } + } + } + + /// Parses a format specifier at the current position, returning all of the + /// relevant information in the FormatSpec struct. + fn format(&mut self) -> FormatSpec<'self> { + let mut spec = FormatSpec { + fill: None, + align: None, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: self.input.slice(0, 0), + }; + if !self.consume(':') { return spec } + + // fill character + match self.cur.clone().next() { + Some((_, c)) => { + match self.cur.clone().skip(1).next() { + Some((_, '>')) | Some((_, '<')) => { + spec.fill = Some(c); + self.cur.next(); + } + Some(*) | None => {} + } + } + None => {} + } + // Alignment + if self.consume('<') { + spec.align = Some(AlignLeft); + } else if self.consume('>') { + spec.align = Some(AlignRight); + } + // Sign flags + if self.consume('+') { + spec.flags |= 1 << (FlagSignPlus as uint); + } else if self.consume('-') { + spec.flags |= 1 << (FlagSignMinus as uint); + } + // Alternate marker + if self.consume('#') { + spec.flags |= 1 << (FlagAlternate as uint); + } + // Width and precision + spec.width = self.count(); + if self.consume('.') { + if self.consume('*') { + spec.precision = CountIsNextParam; + } else { + spec.precision = self.count(); + } + } + // Finally the actual format specifier + spec.ty = self.word(); + return spec; + } + + /// Parses a method to be applied to the previously specified argument and + /// its format. The two current supported methods are 'plural' and 'select' + fn method(&mut self) -> Option<~Method<'self>> { + if !self.wsconsume(',') { + return None; + } + self.ws(); + match self.word() { + "select" => { + if !self.wsconsume(',') { + self.err(~"`select` must be followed by `,`"); + } + Some(self.select()) + } + "plural" => { + if !self.wsconsume(',') { + self.err(~"`plural` must be followed by `,`"); + } + Some(self.plural()) + } + "" => { + self.err(~"expected method after comma"); + return None; + } + method => { + self.err(fmt!("unknown method: `%s`", method)); + return None; + } + } + } + + /// Parses a 'select' statement (after the initial 'select' word) + fn select(&mut self) -> ~Method<'self> { + let mut other = None; + let mut arms = ~[]; + // Consume arms one at a time + loop { + self.ws(); + let selector = self.word(); + if selector == "" { + self.err(~"cannot have an empty selector"); + break + } + if !self.wsconsume('{') { + self.err(~"selector must be followed by `{`"); + } + let pieces = self.collect(); + if !self.wsconsume('}') { + self.err(~"selector case must be terminated by `}`"); + } + if selector == "other" { + if !other.is_none() { + self.err(~"multiple `other` statements in `select"); + } + other = Some(pieces); + } else { + arms.push(SelectArm { selector: selector, result: pieces }); + } + self.ws(); + match self.cur.clone().next() { + Some((_, '}')) => { break } + Some(*) | None => {} + } + } + // The "other" selector must be present + let other = match other { + Some(arm) => { arm } + None => { + self.err(~"`select` statement must provide an `other` case"); + ~[] + } + }; + ~Select(arms, other) + } + + /// Parses a 'plural' statement (after the initial 'plural' word) + fn plural(&mut self) -> ~Method<'self> { + let mut offset = None; + let mut other = None; + let mut arms = ~[]; + + // First, attempt to parse the 'offset:' field. We know the set of + // selector words which can appear in plural arms, and the only ones + // which start with 'o' are "other" and "offset", hence look two + // characters deep to see if we can consume the word "offset" + self.ws(); + let mut it = self.cur.clone(); + match it.next() { + Some((_, 'o')) => { + match it.next() { + Some((_, 'f')) => { + let word = self.word(); + if word != "offset" { + self.err(fmt!("expected `offset`, found `%s`", + word)); + } else { + if !self.consume(':') { + self.err(~"`offset` must be followed by `:`"); + } + match self.integer() { + Some(i) => { offset = Some(i); } + None => { + self.err(~"offset must be an integer"); + } + } + } + } + Some(*) | None => {} + } + } + Some(*) | None => {} + } + + // Next, generate all the arms + loop { + let mut isother = false; + let selector = if self.wsconsume('=') { + match self.integer() { + Some(i) => Right(i), + None => { + self.err(~"plural `=` selectors must be followed by an \ + integer"); + Right(0) + } + } + } else { + let word = self.word(); + match word { + "other" => { isother = true; Left(Zero) } + "zero" => Left(Zero), + "one" => Left(One), + "two" => Left(Two), + "few" => Left(Few), + "many" => Left(Many), + word => { + self.err(fmt!("unexpected plural selector `%s`", word)); + if word == "" { + break + } else { + Left(Zero) + } + } + } + }; + if !self.wsconsume('{') { + self.err(~"selector must be followed by `{`"); + } + let pieces = self.collect(); + if !self.wsconsume('}') { + self.err(~"selector case must be terminated by `}`"); + } + if isother { + if !other.is_none() { + self.err(~"multiple `other` statements in `select"); + } + other = Some(pieces); + } else { + arms.push(PluralArm { selector: selector, result: pieces }); + } + self.ws(); + match self.cur.clone().next() { + Some((_, '}')) => { break } + Some(*) | None => {} + } + } + + let other = match other { + Some(arm) => { arm } + None => { + self.err(~"`plural` statement must provide an `other` case"); + ~[] + } + }; + ~Plural(offset, arms, other) + } + + /// Parses a Count parameter at the current position. This does not check + /// for 'CountIsNextParam' because that is only used in precision, not + /// width. + fn count(&mut self) -> Count { + match self.integer() { + Some(i) => { + if self.consume('$') { + CountIsParam(i) + } else { + CountIs(i) + } + } + None => { CountImplied } + } + } + + /// Parses a word starting at the current position. A word is considered to + /// be an alphabetic character followed by any number of alphanumeric + /// characters. + fn word(&mut self) -> &'self str { + let start = match self.cur.clone().next() { + Some((pos, c)) if char::is_alphabetic(c) => { + self.cur.next(); + pos + } + Some(*) | None => { return self.input.slice(0, 0); } + }; + let mut end; + loop { + match self.cur.clone().next() { + Some((_, c)) if char::is_alphanumeric(c) => { + self.cur.next(); + } + Some((pos, _)) => { end = pos; break } + None => { end = self.input.len(); break } + } + } + self.input.slice(start, end) + } + + /// Optionally parses an integer at the current position. This doesn't deal + /// with overflow at all, it's just accumulating digits. + fn integer(&mut self) -> Option { + let mut cur = 0; + let mut found = false; + loop { + match self.cur.clone().next() { + Some((_, c)) => { + match char::to_digit(c, 10) { + Some(i) => { + cur = cur * 10 + i; + found = true; + self.cur.next(); + } + None => { break } + } + } + None => { break } + } + } + if found { + return Some(cur); + } else { + return None; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use prelude::*; + use realstd::fmt::{String}; + + fn same(fmt: &'static str, p: ~[Piece<'static>]) { + let mut parser = Parser::new(fmt); + assert_eq!(p, parser.collect()); + } + + fn fmtdflt() -> FormatSpec<'static> { + return FormatSpec { + fill: None, + align: None, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + } + } + + fn musterr(s: &str) { + Parser::new(s).next(); + } + + #[test] + fn simple() { + same("asdf", ~[String("asdf")]); + same("a\\{b", ~[String("a"), String("{b")]); + same("a\\#b", ~[String("a"), String("#b")]); + same("a\\}b", ~[String("a"), String("}b")]); + same("a\\}", ~[String("a"), String("}")]); + same("\\}", ~[String("}")]); + } + + #[test] #[should_fail] fn invalid01() { musterr("{") } + #[test] #[should_fail] fn invalid02() { musterr("\\") } + #[test] #[should_fail] fn invalid03() { musterr("\\a") } + #[test] #[should_fail] fn invalid04() { musterr("{3a}") } + #[test] #[should_fail] fn invalid05() { musterr("{:|}") } + #[test] #[should_fail] fn invalid06() { musterr("{:>>>}") } + + #[test] + fn format_nothing() { + same("{}", ~[Argument(Argument { + position: ArgumentNext, + format: fmtdflt(), + method: None, + })]); + } + #[test] + fn format_position() { + same("{3}", ~[Argument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + method: None, + })]); + } + #[test] + fn format_position_nothing_else() { + same("{3:}", ~[Argument(Argument { + position: ArgumentIs(3), + format: fmtdflt(), + method: None, + })]); + } + #[test] + fn format_type() { + same("{3:a}", ~[Argument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: None, + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "a", + }, + method: None, + })]); + } + #[test] + fn format_align_fill() { + same("{3:>}", ~[Argument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: None, + align: Some(AlignRight), + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + method: None, + })]); + same("{3:0<}", ~[Argument(Argument { + position: ArgumentIs(3), + format: FormatSpec { + fill: Some('0'), + align: Some(AlignLeft), + flags: 0, + precision: CountImplied, + width: CountImplied, + ty: "", + }, + method: None, + })]); + same("{3:* or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This is an internal module used by the ifmt! runtime. These structures are +//! emitted to static arrays to precompile format strings ahead of time. +//! +//! These definitions are similar to their `ct` equivalents, but differ in that +//! these can be statically allocated and are slightly optimized for the runtime + +#[allow(missing_doc)]; +#[doc(hidden)]; + +use either::Either; +use fmt::parse; +use option::Option; + +pub enum Piece<'self> { + String(&'self str), + // FIXME(#8259): this shouldn't require the unit-value here + CurrentArgument(()), + Argument(Argument<'self>), +} + +pub struct Argument<'self> { + position: Position, + format: FormatSpec, + method: Option<&'self Method<'self>> +} + +pub struct FormatSpec { + fill: char, + alignleft: bool, + flags: uint, + precision: parse::Count, + width: parse::Count, +} + +pub enum Position { + ArgumentNext, ArgumentIs(uint) +} + +pub enum Method<'self> { + Plural(Option, &'self [PluralArm<'self>], &'self [Piece<'self>]), + Select(&'self [SelectArm<'self>], &'self [Piece<'self>]), +} + +pub struct PluralArm<'self> { + selector: Either, + result: &'self [Piece<'self>], +} + +pub struct SelectArm<'self> { + selector: &'self str, + result: &'self [Piece<'self>], +} diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index fbc471c0ae0..84cba254dcf 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -19,7 +19,7 @@ use clone::Clone; use cmp::{Eq, Equiv}; use hash::Hash; -use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, range}; +use iterator::{Iterator, IteratorUtil, FromIterator, Extendable}; use iterator::{FilterMap, Chain, Repeat, Zip}; use num; use option::{None, Option, Some}; @@ -238,7 +238,7 @@ fn pop_internal(&mut self, hash: uint, k: &K) -> Option { let len_buckets = self.buckets.len(); let bucket = self.buckets[idx].take(); - let value = do bucket.map_consume |bucket| { + let value = do bucket.map_move |bucket| { bucket.value }; @@ -265,8 +265,8 @@ fn len(&self) -> uint { self.size } impl Mutable for HashMap { /// Clear the map, removing all key-value pairs. fn clear(&mut self) { - for idx in range(0u, self.buckets.len()) { - self.buckets[idx] = None; + for bkt in self.buckets.mut_iter() { + *bkt = None; } self.size = 0; } @@ -479,7 +479,7 @@ pub fn consume(self) -> HashMapConsumeIterator { impl HashMap { /// Like `find`, but returns a copy of the value. pub fn find_copy(&self, k: &K) -> Option { - self.find(k).map_consume(|v| (*v).clone()) + self.find(k).map_move(|v| (*v).clone()) } /// Like `get`, but returns a copy of the value. diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 56a0dca5667..d10a5541e41 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -18,9 +18,9 @@ */ use cmp; -use num::{Zero, One}; +use num::{Zero, One, Integer, Saturating}; use option::{Option, Some, None}; -use ops::{Add, Mul}; +use ops::{Add, Mul, Sub}; use cmp::Ord; use clone::Clone; use uint; @@ -313,7 +313,7 @@ fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option) /// ~~~ {.rust} /// let xs = [2u, 3]; /// let ys = [0u, 1, 0, 1, 2]; - /// let mut it = xs.iter().flat_map_(|&x| Counter::new(0u, 1).take_(x)); + /// let mut it = xs.iter().flat_map_(|&x| count(0u, 1).take_(x)); /// // Check that `it` has the same elements as `ys` /// let mut i = 0; /// for x: uint in it { @@ -351,7 +351,7 @@ fn flat_map_<'r, B, U: Iterator>(self, f: &'r fn(A) -> U) /// ~~~ {.rust} /// use std::iterator::Counter; /// - /// for i in Counter::new(0, 10) { + /// for i in count(0, 10) { /// printfln!("%d", i); /// } /// ~~~ @@ -674,7 +674,7 @@ fn max_by(&mut self, f: &fn(&A) -> B) -> Option { Some((y, y_val)) } } - }).map_consume(|(x, _)| x) + }).map_move(|(x, _)| x) } #[inline] @@ -689,7 +689,7 @@ fn min_by(&mut self, f: &fn(&A) -> B) -> Option { Some((y, y_val)) } } - }).map_consume(|(x, _)| x) + }).map_move(|(x, _)| x) } } @@ -723,7 +723,7 @@ pub trait MultiplicativeIterator { /// use std::iterator::Counter; /// /// fn factorial(n: uint) -> uint { - /// Counter::new(1u, 1).take_while(|&i| i <= n).product() + /// count(1u, 1).take_while(|&i| i <= n).product() /// } /// assert!(factorial(0) == 1); /// assert!(factorial(1) == 1); @@ -790,7 +790,7 @@ pub trait ClonableIterator { /// # Example /// /// ~~~ {.rust} - /// let a = Counter::new(1,1).take_(1); + /// let a = count(1,1).take_(1); /// let mut cy = a.cycle(); /// assert_eq!(cy.next(), Some(1)); /// assert_eq!(cy.next(), Some(1)); @@ -884,15 +884,10 @@ fn size_hint(&self) -> (uint, Option) { let (a_lower, a_upper) = self.a.size_hint(); let (b_lower, b_upper) = self.b.size_hint(); - let lower = if uint::max_value - a_lower < b_lower { - uint::max_value - } else { - a_lower + b_lower - }; + let lower = a_lower.saturating_add(b_lower); let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) if uint::max_value - x < y => Some(uint::max_value), - (Some(x), Some(y)) => Some(x + y), + (Some(x), Some(y)) => Some(x.saturating_add(y)), _ => None }; @@ -916,12 +911,7 @@ impl, U: RandomAccessIterator> RandomAccessIter #[inline] fn indexable(&self) -> uint { let (a, b) = (self.a.indexable(), self.b.indexable()); - let total = a + b; - if total < a || total < b { - uint::max_value - } else { - total - } + a.saturating_add(b) } #[inline] @@ -1273,11 +1263,10 @@ fn next(&mut self) -> Option { fn size_hint(&self) -> (uint, Option) { let (lower, upper) = self.iter.size_hint(); - let lower = if lower >= self.n { lower - self.n } else { 0 }; + let lower = lower.saturating_sub(self.n); let upper = match upper { - Some(x) if x >= self.n => Some(x - self.n), - Some(_) => Some(0), + Some(x) => Some(x.saturating_sub(self.n)), None => None }; @@ -1288,12 +1277,7 @@ fn size_hint(&self) -> (uint, Option) { impl> RandomAccessIterator for Skip { #[inline] fn indexable(&self) -> uint { - let N = self.iter.indexable(); - if N < self.n { - 0 - } else { - N - self.n - } + self.iter.indexable().saturating_sub(self.n) } #[inline] @@ -1316,10 +1300,9 @@ pub struct Take { impl> Iterator for Take { #[inline] fn next(&mut self) -> Option { - let next = self.iter.next(); if self.n != 0 { self.n -= 1; - next + self.iter.next() } else { None } @@ -1399,7 +1382,7 @@ fn next(&mut self) -> Option { return Some(x) } } - match self.iter.next().map_consume(|x| (self.f)(x)) { + match self.iter.next().map_move(|x| (self.f)(x)) { None => return self.backiter.chain_mut_ref(|it| it.next()), next => self.frontiter = next, } @@ -1410,9 +1393,10 @@ fn next(&mut self) -> Option { fn size_hint(&self) -> (uint, Option) { let (flo, fhi) = self.frontiter.map_default((0, Some(0)), |it| it.size_hint()); let (blo, bhi) = self.backiter.map_default((0, Some(0)), |it| it.size_hint()); + let lo = flo.saturating_add(blo); match (self.iter.size_hint(), fhi, bhi) { - ((0, Some(0)), Some(a), Some(b)) => (flo + blo, Some(a + b)), - _ => (flo + blo, None) + ((0, Some(0)), Some(a), Some(b)) => (lo, Some(a.saturating_add(b))), + _ => (lo, None) } } } @@ -1430,7 +1414,7 @@ fn next_back(&mut self) -> Option { y => return y } } - match self.iter.next_back().map_consume(|x| (self.f)(x)) { + match self.iter.next_back().map_move(|x| (self.f)(x)) { None => return self.frontiter.chain_mut_ref(|it| it.next_back()), next => self.backiter = next, } @@ -1527,12 +1511,10 @@ pub struct Counter { step: A } -impl Counter { - /// Creates a new counter with the specified start/step - #[inline] - pub fn new(start: A, step: A) -> Counter { - Counter{state: start, step: step} - } +/// Creates a new counter with the specified start/step +#[inline] +pub fn count(start: A, step: A) -> Counter { + Counter{state: start, step: step} } /// A range of numbers from [0, N) @@ -1549,7 +1531,7 @@ pub fn range + Ord + Clone + One>(start: A, stop: A) -> Range { Range{state: start, stop: stop, one: One::one()} } -impl + Ord + Clone + One> Iterator for Range { +impl + Ord + Clone> Iterator for Range { #[inline] fn next(&mut self) -> Option { if self.state < self.stop { @@ -1562,6 +1544,22 @@ fn next(&mut self) -> Option { } } +impl + Integer + Ord + Clone> DoubleEndedIterator for Range { + #[inline] + fn next_back(&mut self) -> Option { + if self.stop > self.state { + // Integer doesn't technically define this rule, but we're going to assume that every + // Integer is reachable from every other one by adding or subtracting enough Ones. This + // seems like a reasonable-enough rule that every Integer should conform to, even if it + // can't be statically checked. + self.stop = self.stop - self.one; + Some(self.stop.clone()) + } else { + None + } + } +} + impl + Clone> Iterator for Counter { #[inline] fn next(&mut self) -> Option { @@ -1619,7 +1617,7 @@ mod tests { #[test] fn test_counter_from_iter() { - let mut it = Counter::new(0, 5).take_(10); + let mut it = count(0, 5).take_(10); let xs: ~[int] = FromIterator::from_iterator(&mut it); assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); } @@ -1637,7 +1635,7 @@ fn test_iterator_chain() { } assert_eq!(i, expected.len()); - let ys = Counter::new(30u, 10).take_(4); + let ys = count(30u, 10).take_(4); let mut it = xs.iter().transform(|&x| x).chain_(ys); let mut i = 0; for x in it { @@ -1649,7 +1647,7 @@ fn test_iterator_chain() { #[test] fn test_filter_map() { - let mut it = Counter::new(0u, 1u).take_(10) + let mut it = count(0u, 1u).take_(10) .filter_map(|x| if x.is_even() { Some(x*x) } else { None }); assert_eq!(it.collect::<~[uint]>(), ~[0*0, 2*2, 4*4, 6*6, 8*8]); } @@ -1738,7 +1736,7 @@ fn add(old: &mut int, new: &uint) -> Option { fn test_iterator_flat_map() { let xs = [0u, 3, 6]; let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8]; - let mut it = xs.iter().flat_map_(|&x| Counter::new(x, 1).take_(3)); + let mut it = xs.iter().flat_map_(|&x| count(x, 1).take_(3)); let mut i = 0; for x in it { assert_eq!(x, ys[i]); @@ -1785,13 +1783,13 @@ fn count(st: &mut uint) -> Option { #[test] fn test_cycle() { let cycle_len = 3; - let it = Counter::new(0u, 1).take_(cycle_len).cycle(); + let it = count(0u, 1).take_(cycle_len).cycle(); assert_eq!(it.size_hint(), (uint::max_value, None)); for (i, x) in it.take_(100).enumerate() { assert_eq!(i % cycle_len, x); } - let mut it = Counter::new(0u, 1).take_(0).cycle(); + let mut it = count(0u, 1).take_(0).cycle(); assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next(), None); } @@ -1853,7 +1851,7 @@ fn test_iterator_min() { #[test] fn test_iterator_size_hint() { - let c = Counter::new(0, 1); + let c = count(0, 1); let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let v2 = &[10, 11, 12]; let vi = v.iter(); @@ -2139,4 +2137,17 @@ fn test_random_access_cycle() { check_randacc_iter(xs.iter().cycle().take_(27), 27); check_randacc_iter(empty.iter().cycle(), 0); } + + #[test] + fn test_double_ended_range() { + assert_eq!(range(11i, 14).invert().collect::<~[int]>(), ~[13i, 12, 11]); + for _ in range(10i, 0).invert() { + fail!("unreachable"); + } + + assert_eq!(range(11u, 14).invert().collect::<~[uint]>(), ~[13u, 12, 11]); + for _ in range(10u, 0).invert() { + fail!("unreachable"); + } + } } diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index c2a60e1c0e9..a73809d202c 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -110,16 +110,16 @@ fn test_tls_multitask() { set(my_key, @~"parent data"); do task::spawn { // TLS shouldn't carry over. - assert!(get(my_key, |k| k.map(|&k| *k)).is_none()); + assert!(get(my_key, |k| k.map_move(|k| *k)).is_none()); set(my_key, @~"child data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"child data"); // should be cleaned up for us } // Must work multiple times - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data"); } #[test] @@ -127,7 +127,7 @@ fn test_tls_overwrite() { static my_key: Key<@~str> = &Key; set(my_key, @~"first data"); set(my_key, @~"next data"); // Shouldn't leak. - assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"next data"); + assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data"); } #[test] diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index bd4dc69537c..57230b2fd24 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -12,7 +12,7 @@ use ptr::to_unsafe_ptr; -#[cfg(not(test))] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::*; pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; pub static RC_IMMORTAL : uint = 0x77777777; @@ -71,6 +71,29 @@ fn ge(&self, other: &@mut T) -> bool { *(*self) >= *(*other) } fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) } } +#[cfg(not(test))] +impl TotalOrd for @T { + #[inline] + fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalOrd for @mut T { + #[inline] + fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalEq for @T { + #[inline] + fn equals(&self, other: &@T) -> bool { (**self).equals(*other) } +} + +#[cfg(not(test))] +impl TotalEq for @mut T { + #[inline] + fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) } +} #[test] fn test() { let x = @3; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index c7db60e6fd2..60527905779 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -278,18 +278,22 @@ fn one() -> f64 { 1.0 } #[cfg(not(test))] impl Add for f64 { + #[inline] fn add(&self, other: &f64) -> f64 { *self + *other } } #[cfg(not(test))] impl Sub for f64 { + #[inline] fn sub(&self, other: &f64) -> f64 { *self - *other } } #[cfg(not(test))] impl Mul for f64 { + #[inline] fn mul(&self, other: &f64) -> f64 { *self * *other } } #[cfg(not(test))] impl Div for f64 { + #[inline] fn div(&self, other: &f64) -> f64 { *self / *other } } #[cfg(not(test))] diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 9842a570d7e..b692bedebfd 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -124,14 +124,6 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool) range_step_core(start, last, step, Closed, it) } - -#[inline] -/// Iterate over the range (`hi`..`lo`] -pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - if hi == min_value { return true; } - range_step_inclusive(hi-1, lo, -1 as $T, it) -} - impl Num for $T {} #[cfg(not(test))] @@ -889,10 +881,6 @@ fn test_int_from_str_overflow() { fn test_ranges() { let mut l = ~[]; - do range_rev(14,11) |i| { - l.push(i); - true - }; do range_step(20,26,2) |i| { l.push(i); true @@ -917,8 +905,7 @@ fn test_ranges() { l.push(i); true }; - assert_eq!(l, ~[13,12,11, - 20,22,24, + assert_eq!(l, ~[20,22,24, 36,34,32, max_value-2, max_value-3,max_value-1, @@ -926,9 +913,6 @@ fn test_ranges() { min_value+3,min_value+1]); // None of the `fail`s should execute. - do range_rev(0,10) |_i| { - fail!(~"unreachable"); - }; do range_step(10,0,1) |_i| { fail!(~"unreachable"); }; diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index 8b61a8a8734..bbadf1caca2 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -466,6 +466,56 @@ fn zero() -> ~T { ~Zero::zero() } fn is_zero(&self) -> bool { (**self).is_zero() } } +/// Saturating math operations +pub trait Saturating: Int { + /// Saturating addition operator. + /// Returns a+b, saturating at the numeric bounds instead of overflowing. + #[inline] + fn saturating_add(self, v: Self) -> Self { + let x = self + v; + if v >= Zero::zero() { + if x < self { + // overflow + Bounded::max_value::() + } else { x } + } else { + if x > self { + // underflow + Bounded::min_value::() + } else { x } + } + } + + /// Saturating subtraction operator. + /// Returns a-b, saturating at the numeric bounds instead of overflowing. + #[inline] + fn saturating_sub(self, v: Self) -> Self { + let x = self - v; + if v >= Zero::zero() { + if x > self { + // underflow + Bounded::min_value::() + } else { x } + } else { + if x < self { + // overflow + Bounded::max_value::() + } else { x } + } + } +} + +impl Saturating for int {} +impl Saturating for i8 {} +impl Saturating for i16 {} +impl Saturating for i32 {} +impl Saturating for i64 {} +impl Saturating for uint {} +impl Saturating for u8 {} +impl Saturating for u16 {} +impl Saturating for u32 {} +impl Saturating for u64 {} + /// Helper function for testing numeric operations #[cfg(test)] pub fn test_num(ten: T, two: T) { @@ -482,64 +532,111 @@ pub fn test_num(ten: T, two: T) { assert_eq!(ten.rem(&two), ten % two); } -macro_rules! test_cast_20( - ($_20:expr) => ({ - let _20 = $_20; - - assert_eq!(20u, _20.to_uint()); - assert_eq!(20u8, _20.to_u8()); - assert_eq!(20u16, _20.to_u16()); - assert_eq!(20u32, _20.to_u32()); - assert_eq!(20u64, _20.to_u64()); - assert_eq!(20i, _20.to_int()); - assert_eq!(20i8, _20.to_i8()); - assert_eq!(20i16, _20.to_i16()); - assert_eq!(20i32, _20.to_i32()); - assert_eq!(20i64, _20.to_i64()); - assert_eq!(20f, _20.to_float()); - assert_eq!(20f32, _20.to_f32()); - assert_eq!(20f64, _20.to_f64()); - - assert_eq!(_20, NumCast::from(20u)); - assert_eq!(_20, NumCast::from(20u8)); - assert_eq!(_20, NumCast::from(20u16)); - assert_eq!(_20, NumCast::from(20u32)); - assert_eq!(_20, NumCast::from(20u64)); - assert_eq!(_20, NumCast::from(20i)); - assert_eq!(_20, NumCast::from(20i8)); - assert_eq!(_20, NumCast::from(20i16)); - assert_eq!(_20, NumCast::from(20i32)); - assert_eq!(_20, NumCast::from(20i64)); - assert_eq!(_20, NumCast::from(20f)); - assert_eq!(_20, NumCast::from(20f32)); - assert_eq!(_20, NumCast::from(20f64)); - - assert_eq!(_20, cast(20u)); - assert_eq!(_20, cast(20u8)); - assert_eq!(_20, cast(20u16)); - assert_eq!(_20, cast(20u32)); - assert_eq!(_20, cast(20u64)); - assert_eq!(_20, cast(20i)); - assert_eq!(_20, cast(20i8)); - assert_eq!(_20, cast(20i16)); - assert_eq!(_20, cast(20i32)); - assert_eq!(_20, cast(20i64)); - assert_eq!(_20, cast(20f)); - assert_eq!(_20, cast(20f32)); - assert_eq!(_20, cast(20f64)); - }) -) +#[cfg(test)] +mod tests { + use super::*; + + macro_rules! test_cast_20( + ($_20:expr) => ({ + let _20 = $_20; + + assert_eq!(20u, _20.to_uint()); + assert_eq!(20u8, _20.to_u8()); + assert_eq!(20u16, _20.to_u16()); + assert_eq!(20u32, _20.to_u32()); + assert_eq!(20u64, _20.to_u64()); + assert_eq!(20i, _20.to_int()); + assert_eq!(20i8, _20.to_i8()); + assert_eq!(20i16, _20.to_i16()); + assert_eq!(20i32, _20.to_i32()); + assert_eq!(20i64, _20.to_i64()); + assert_eq!(20f, _20.to_float()); + assert_eq!(20f32, _20.to_f32()); + assert_eq!(20f64, _20.to_f64()); + + assert_eq!(_20, NumCast::from(20u)); + assert_eq!(_20, NumCast::from(20u8)); + assert_eq!(_20, NumCast::from(20u16)); + assert_eq!(_20, NumCast::from(20u32)); + assert_eq!(_20, NumCast::from(20u64)); + assert_eq!(_20, NumCast::from(20i)); + assert_eq!(_20, NumCast::from(20i8)); + assert_eq!(_20, NumCast::from(20i16)); + assert_eq!(_20, NumCast::from(20i32)); + assert_eq!(_20, NumCast::from(20i64)); + assert_eq!(_20, NumCast::from(20f)); + assert_eq!(_20, NumCast::from(20f32)); + assert_eq!(_20, NumCast::from(20f64)); + + assert_eq!(_20, cast(20u)); + assert_eq!(_20, cast(20u8)); + assert_eq!(_20, cast(20u16)); + assert_eq!(_20, cast(20u32)); + assert_eq!(_20, cast(20u64)); + assert_eq!(_20, cast(20i)); + assert_eq!(_20, cast(20i8)); + assert_eq!(_20, cast(20i16)); + assert_eq!(_20, cast(20i32)); + assert_eq!(_20, cast(20i64)); + assert_eq!(_20, cast(20f)); + assert_eq!(_20, cast(20f32)); + assert_eq!(_20, cast(20f64)); + }) + ) + + #[test] fn test_u8_cast() { test_cast_20!(20u8) } + #[test] fn test_u16_cast() { test_cast_20!(20u16) } + #[test] fn test_u32_cast() { test_cast_20!(20u32) } + #[test] fn test_u64_cast() { test_cast_20!(20u64) } + #[test] fn test_uint_cast() { test_cast_20!(20u) } + #[test] fn test_i8_cast() { test_cast_20!(20i8) } + #[test] fn test_i16_cast() { test_cast_20!(20i16) } + #[test] fn test_i32_cast() { test_cast_20!(20i32) } + #[test] fn test_i64_cast() { test_cast_20!(20i64) } + #[test] fn test_int_cast() { test_cast_20!(20i) } + #[test] fn test_f32_cast() { test_cast_20!(20f32) } + #[test] fn test_f64_cast() { test_cast_20!(20f64) } + #[test] fn test_float_cast() { test_cast_20!(20f) } + + #[test] + fn test_saturating_add_uint() { + use uint::max_value; + assert_eq!(3u.saturating_add(5u), 8u); + assert_eq!(3u.saturating_add(max_value-1), max_value); + assert_eq!(max_value.saturating_add(max_value), max_value); + assert_eq!((max_value-2).saturating_add(1), max_value-1); + } + + #[test] + fn test_saturating_sub_uint() { + use uint::max_value; + assert_eq!(5u.saturating_sub(3u), 2u); + assert_eq!(3u.saturating_sub(5u), 0u); + assert_eq!(0u.saturating_sub(1u), 0u); + assert_eq!((max_value-1).saturating_sub(max_value), 0); + } -#[test] fn test_u8_cast() { test_cast_20!(20u8) } -#[test] fn test_u16_cast() { test_cast_20!(20u16) } -#[test] fn test_u32_cast() { test_cast_20!(20u32) } -#[test] fn test_u64_cast() { test_cast_20!(20u64) } -#[test] fn test_uint_cast() { test_cast_20!(20u) } -#[test] fn test_i8_cast() { test_cast_20!(20i8) } -#[test] fn test_i16_cast() { test_cast_20!(20i16) } -#[test] fn test_i32_cast() { test_cast_20!(20i32) } -#[test] fn test_i64_cast() { test_cast_20!(20i64) } -#[test] fn test_int_cast() { test_cast_20!(20i) } -#[test] fn test_f32_cast() { test_cast_20!(20f32) } -#[test] fn test_f64_cast() { test_cast_20!(20f64) } -#[test] fn test_float_cast() { test_cast_20!(20f) } + #[test] + fn test_saturating_add_int() { + use int::{min_value,max_value}; + assert_eq!(3i.saturating_add(5i), 8i); + assert_eq!(3i.saturating_add(max_value-1), max_value); + assert_eq!(max_value.saturating_add(max_value), max_value); + assert_eq!((max_value-2).saturating_add(1), max_value-1); + assert_eq!(3i.saturating_add(-5i), -2i); + assert_eq!(min_value.saturating_add(-1i), min_value); + assert_eq!((-2i).saturating_add(-max_value), min_value); + } + + #[test] + fn test_saturating_sub_int() { + use int::{min_value,max_value}; + assert_eq!(3i.saturating_sub(5i), -2i); + assert_eq!(min_value.saturating_sub(1i), min_value); + assert_eq!((-2i).saturating_sub(max_value), min_value); + assert_eq!(3i.saturating_sub(-5i), 8i); + assert_eq!(3i.saturating_sub(-(max_value-1)), max_value); + assert_eq!(max_value.saturating_sub(-max_value), max_value); + assert_eq!((max_value-2).saturating_sub(-1), max_value-1); + } +} diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 7ab3c81b61f..1f22343ad9c 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -422,9 +422,9 @@ pub fn float_to_str_common range_step_core(start, last, step, Closed, it) } -#[inline] -/// Iterate over the range (`hi`..`lo`] -pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool { - if hi == min_value { return true; } - range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it) -} - impl Num for $T {} #[cfg(not(test))] @@ -654,10 +647,6 @@ pub fn to_str_radix37() { pub fn test_ranges() { let mut l = ~[]; - do range_rev(14,11) |i| { - l.push(i); - true - }; do range_step(20,26,2) |i| { l.push(i); true @@ -683,8 +672,7 @@ pub fn test_ranges() { true }; - assert_eq!(l, ~[13,12,11, - 20,22,24, + assert_eq!(l, ~[20,22,24, 36,34,32, max_value-2, max_value-3,max_value-1, @@ -692,9 +680,6 @@ pub fn test_ranges() { min_value+3,min_value+1]); // None of the `fail`s should execute. - do range_rev(0,0) |_i| { - fail!("unreachable"); - }; do range_step(10,0,1) |_i| { fail!("unreachable"); }; diff --git a/src/libstd/option.rs b/src/libstd/option.rs index ea1bddcdb4b..66b30d8dd03 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -208,6 +208,12 @@ pub fn map_mut<'a, U>(&'a mut self, f: &fn(&'a mut T) -> U) -> Option { match *self { Some(ref mut x) => Some(f(x)), None => None } } + /// Applies a function to the contained value or returns a default + #[inline] + pub fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { + match *self { None => def, Some(ref t) => f(t) } + } + /// Maps a `Some` value from one type to another by a mutable reference, /// or returns a default value. #[inline] @@ -218,21 +224,15 @@ pub fn map_mut_default<'a, U>(&'a mut self, def: U, f: &fn(&'a mut T) -> U) -> U /// As `map`, but consumes the option and gives `f` ownership to avoid /// copying. #[inline] - pub fn map_consume(self, f: &fn(v: T) -> U) -> Option { - match self { None => None, Some(v) => Some(f(v)) } - } - - /// Applies a function to the contained value or returns a default - #[inline] - pub fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { - match *self { None => def, Some(ref t) => f(t) } + pub fn map_move(self, f: &fn(T) -> U) -> Option { + match self { Some(x) => Some(f(x)), None => None } } /// As `map_default`, but consumes the option and gives `f` /// ownership to avoid copying. #[inline] - pub fn map_consume_default(self, def: U, f: &fn(v: T) -> U) -> U { - match self { None => def, Some(v) => f(v) } + pub fn map_move_default(self, def: U, f: &fn(T) -> U) -> U { + match self { None => def, Some(t) => f(t) } } /// Take the value out of the option, leaving a `None` in its place. @@ -241,20 +241,6 @@ pub fn take(&mut self) -> Option { util::replace(self, None) } - /// As `map_consume`, but swaps a None into the original option rather - /// than consuming it by-value. - #[inline] - pub fn take_map(&mut self, blk: &fn(T) -> U) -> Option { - self.take().map_consume(blk) - } - - /// As `map_consume_default`, but swaps a None into the original option - /// rather than consuming it by-value. - #[inline] - pub fn take_map_default (&mut self, def: U, blk: &fn(T) -> U) -> U { - self.take().map_consume_default(def, blk) - } - /// Apply a function to the contained value or do nothing. /// Returns true if the contained value was mutated. pub fn mutate(&mut self, f: &fn(T) -> T) -> bool { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index b0e1f35b4a0..f246a61a4d5 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -498,9 +498,7 @@ fn load_self() -> Option<~str> { } } - do load_self().map |pth| { - Path(*pth).dir_path() - } + load_self().map_move(|path| Path(path).dir_path()) } diff --git a/src/libstd/owned.rs b/src/libstd/owned.rs index e7a6e38fdb0..424c4fd6b2f 100644 --- a/src/libstd/owned.rs +++ b/src/libstd/owned.rs @@ -10,7 +10,7 @@ //! Operations on unique pointer types -#[cfg(not(test))] use cmp::{Eq, Ord}; +#[cfg(not(test))] use cmp::*; #[cfg(not(test))] impl Eq for ~T { @@ -31,3 +31,15 @@ fn ge(&self, other: &~T) -> bool { *(*self) >= *(*other) } #[inline] fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) } } + +#[cfg(not(test))] +impl TotalOrd for ~T { + #[inline] + fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) } +} + +#[cfg(not(test))] +impl TotalEq for ~T { + #[inline] + fn equals(&self, other: &~T) -> bool { (**self).equals(*other) } +} diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 517bc4a441a..65db55297b3 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -49,6 +49,7 @@ pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; pub use hash::Hash; pub use iter::Times; +pub use iterator::Extendable; pub use iterator::{Iterator, IteratorUtil, DoubleEndedIterator, DoubleEndedIteratorUtil}; pub use iterator::{ClonableIterator, OrdIterator}; pub use num::{Num, NumCast}; @@ -64,7 +65,7 @@ pub use ptr::RawPtr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, ToBytesConsume}; pub use str::{Str, StrVector, StrSlice, OwnedStr, NullTerminatedStr}; -pub use from_str::{FromStr}; +pub use from_str::FromStr; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index dfd11f9227d..5a2bd0c4de9 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -272,6 +272,7 @@ pub trait RawPtr { fn is_not_null(&self) -> bool; unsafe fn to_option(&self) -> Option<&T>; fn offset(&self, count: int) -> Self; + unsafe fn offset_inbounds(self, count: int) -> Self; } /// Extension methods for immutable pointers @@ -304,6 +305,22 @@ unsafe fn to_option(&self) -> Option<&T> { /// Calculates the offset from a pointer. #[inline] fn offset(&self, count: int) -> *T { offset(*self, count) } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. + #[inline] + #[cfg(stage0)] + unsafe fn offset_inbounds(self, count: int) -> *T { + intrinsics::offset(self, count) + } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. + #[inline] + #[cfg(not(stage0))] + unsafe fn offset_inbounds(self, count: int) -> *T { + intrinsics::offset_inbounds(self, count) + } } /// Extension methods for mutable pointers @@ -336,6 +353,30 @@ unsafe fn to_option(&self) -> Option<&T> { /// Calculates the offset from a mutable pointer. #[inline] fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. An arithmetic overflow is also + /// undefined behaviour. + /// + /// This method should be preferred over `offset` when the guarantee can be + /// satisfied, to enable better optimization. + #[inline] + #[cfg(stage0)] + unsafe fn offset_inbounds(self, count: int) -> *mut T { + intrinsics::offset(self as *T, count) as *mut T + } + + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. An arithmetic overflow is also + /// undefined behaviour. + /// + /// This method should be preferred over `offset` when the guarantee can be + /// satisfied, to enable better optimization. + #[inline] + #[cfg(not(stage0))] + unsafe fn offset_inbounds(self, count: int) -> *mut T { + intrinsics::offset_inbounds(self as *T, count) as *mut T + } } // Equality for pointers diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 4ef524d7715..5f8fa9fddbc 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -610,15 +610,32 @@ fn shuffle_mut(&mut self, values: &mut [T]) { } /// 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 +/// consistency over time you should pick one algorithm and create the +/// `Rng` yourself. pub fn rng() -> IsaacRng { IsaacRng::new() } +/// Create a weak random number generator with a default algorithm and seed. +/// +/// It returns the fatest `Rng` algorithm currently available in Rust without +/// consideration for cryptography or security. If you require a specifically +/// seeded `Rng` for consistency over time you should pick one algorithm and +/// create the `Rng` yourself. +pub fn weak_rng() -> XorShiftRng { + XorShiftRng::new() +} + 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). +/// +/// The ISAAC algorithm is suitable for cryptographic purposes. pub struct IsaacRng { priv cnt: u32, priv rsl: [u32, .. RAND_SIZE], @@ -794,8 +811,11 @@ fn next(&mut self) -> u32 { } /// An [Xorshift random number -/// generator](http://en.wikipedia.org/wiki/Xorshift). Not suitable for -/// cryptographic purposes. +/// generator](http://en.wikipedia.org/wiki/Xorshift). +/// +/// 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`. pub struct XorShiftRng { priv x: u32, priv y: u32, diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 91f42edf0ae..3e429c6116d 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -149,6 +149,40 @@ pub fn expect_err(self, reason: &str) -> E { } } + /// Call a method based on a previous result + /// + /// If `self` is `Ok` then the value is extracted and passed to `op` + /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is + /// `Err` then it is immediately returned. This function can be used to + /// compose the results of two functions. + /// + /// Example: + /// + /// let res = do read_file(file).map_move |buf| { + /// parse_bytes(buf) + /// } + #[inline] + pub fn map_move(self, op: &fn(T) -> U) -> Result { + match self { + Ok(t) => Ok(op(t)), + Err(e) => Err(e) + } + } + + /// Call a method based on a previous result + /// + /// If `self` is `Err` then the value is extracted and passed to `op` + /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is + /// `Ok` then it is immediately returned. This function can be used to pass + /// through a successful result while handling an error. + #[inline] + pub fn map_err_move(self, op: &fn(E) -> F) -> Result { + match self { + Ok(t) => Ok(t), + Err(e) => Err(op(e)) + } + } + /// Call a method based on a previous result /// /// If `self` is `Ok` then the value is extracted and passed to `op` @@ -312,7 +346,9 @@ pub fn iter_vec2(ss: &[S], ts: &[T], #[cfg(test)] mod tests { use super::*; + use either; + use str::OwnedStr; pub fn op1() -> Result { Ok(666) } @@ -359,14 +395,26 @@ pub fn test_impl_iter_err() { #[test] pub fn test_impl_map() { - assert_eq!(Ok::<~str, ~str>(~"a").map(|_x| ~"b"), Ok(~"b")); - assert_eq!(Err::<~str, ~str>(~"a").map(|_x| ~"b"), Err(~"a")); + assert_eq!(Ok::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Ok(~"ba")); + assert_eq!(Err::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Err(~"a")); } #[test] pub fn test_impl_map_err() { - assert_eq!(Ok::<~str, ~str>(~"a").map_err(|_x| ~"b"), Ok(~"a")); - assert_eq!(Err::<~str, ~str>(~"a").map_err(|_x| ~"b"), Err(~"b")); + assert_eq!(Ok::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Ok(~"a")); + assert_eq!(Err::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Err(~"ba")); + } + + #[test] + pub fn test_impl_map_move() { + assert_eq!(Ok::<~str, ~str>(~"a").map_move(|x| x + "b"), Ok(~"ab")); + assert_eq!(Err::<~str, ~str>(~"a").map_move(|x| x + "b"), Err(~"a")); + } + + #[test] + pub fn test_impl_map_err_move() { + assert_eq!(Ok::<~str, ~str>(~"a").map_err_move(|x| x + "b"), Ok(~"a")); + assert_eq!(Err::<~str, ~str>(~"a").map_err_move(|x| x + "b"), Err(~"ab")); } #[test] diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index a060059f5fc..936a6526508 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -159,7 +159,7 @@ fn try_send_inner(self, val: T, do_resched: bool) -> bool { // Port is blocked. Wake it up. let recvr = BlockedTask::cast_from_uint(task_as_state); if do_resched { - do recvr.wake().map_consume |woken_task| { + do recvr.wake().map_move |woken_task| { Scheduler::run_task(woken_task); }; } else { @@ -225,9 +225,10 @@ fn optimistic_check(&mut self) -> bool { fn optimistic_check(&mut self) -> bool { // The optimistic check is never necessary for correctness. For testing // purposes, making it randomly return false simulates a racing sender. - use rand::{Rand, rng}; - let mut rng = rng(); - let actually_check = Rand::rand(&mut rng); + use rand::{Rand}; + let actually_check = do Local::borrow:: |sched| { + Rand::rand(&mut sched.rng) + }; if actually_check { unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE } } else { @@ -381,7 +382,7 @@ fn drop(&self) { // The port is blocked waiting for a message we will never send. Wake it. assert!((*this.packet()).payload.is_none()); let recvr = BlockedTask::cast_from_uint(task_as_state); - do recvr.wake().map_consume |woken_task| { + do recvr.wake().map_move |woken_task| { Scheduler::run_task(woken_task); }; } @@ -508,7 +509,11 @@ fn peek(&self) -> bool { } } -impl Select for Port { +// XXX: Kind of gross. A Port should be selectable so you can make an array +// of them, but a &Port should also be selectable so you can select2 on it +// alongside a PortOne without passing the port by value in recv_ready. + +impl<'self, T> Select for &'self Port { #[inline] fn optimistic_check(&mut self) -> bool { do self.next.with_mut_ref |pone| { pone.optimistic_check() } @@ -526,12 +531,29 @@ fn unblock_from(&mut self) -> bool { } } -impl SelectPort<(T, Port)> for Port { - fn recv_ready(self) -> Option<(T, Port)> { +impl Select for Port { + #[inline] + fn optimistic_check(&mut self) -> bool { + (&*self).optimistic_check() + } + + #[inline] + fn block_on(&mut self, sched: &mut Scheduler, task: BlockedTask) -> bool { + (&*self).block_on(sched, task) + } + + #[inline] + fn unblock_from(&mut self) -> bool { + (&*self).unblock_from() + } +} + +impl<'self, T> SelectPort for &'self Port { + fn recv_ready(self) -> Option { match self.next.take().recv_ready() { Some(StreamPayload { val, next }) => { self.next.put_back(next); - Some((val, self)) + Some(val) } None => None } diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs index 1d7ff173149..6e671742fb6 100644 --- a/src/libstd/rt/env.rs +++ b/src/libstd/rt/env.rs @@ -10,7 +10,12 @@ //! Runtime environment settings +use from_str::FromStr; use libc::{size_t, c_char, c_int}; +use option::{Some, None}; +use os; + +// OLD RT stuff pub struct Environment { /// The number of threads to use by default @@ -47,3 +52,26 @@ pub fn get() -> &Environment { extern { fn rust_get_rt_env() -> &Environment; } + +// NEW RT stuff + +// Note that these are all accessed without any synchronization. +// They are expected to be initialized once then left alone. + +static mut MIN_STACK: uint = 2000000; + +pub fn init() { + unsafe { + match os::getenv("RUST_MIN_STACK") { + Some(s) => match FromStr::from_str(s) { + Some(i) => MIN_STACK = i, + None => () + }, + None => () + } + } +} + +pub fn min_stack() -> uint { + unsafe { MIN_STACK } +} diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs index c93945a6a9a..277897e5d2e 100644 --- a/src/libstd/rt/io/mem.rs +++ b/src/libstd/rt/io/mem.rs @@ -26,7 +26,7 @@ pub struct MemWriter { } impl MemWriter { - pub fn new() -> MemWriter { MemWriter { buf: ~[] } } + pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } } } impl Writer for MemWriter { diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 815ec9b5c61..81269d197d5 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -9,7 +9,11 @@ // except according to those terms. use num::FromStrRadix; +use vec::MutableCloneableVector; use to_str::ToStr; +use from_str::FromStr; +use option::{Option, None, Some}; + type Port = u16; @@ -73,3 +77,364 @@ fn to_str(&self) -> ~str { } } } + +struct Parser<'self> { + // parsing as ASCII, so can use byte array + s: &'self [u8], + pos: uint, +} + +impl<'self> Parser<'self> { + fn new(s: &'self str) -> Parser<'self> { + Parser { + s: s.as_bytes(), + pos: 0, + } + } + + fn is_eof(&self) -> bool { + self.pos == self.s.len() + } + + // Commit only if parser returns Some + fn read_atomically(&mut self, cb: &fn(&mut Parser) -> Option) -> Option { + let pos = self.pos; + let r = cb(self); + if r.is_none() { + self.pos = pos; + } + r + } + + // Commit only if parser read till EOF + fn read_till_eof(&mut self, cb: &fn(&mut Parser) -> Option) -> Option { + do self.read_atomically |p| { + cb(p).filtered(|_| p.is_eof()) + } + } + + // Return result of first successful parser + fn read_or(&mut self, parsers: &[&fn(&mut Parser) -> Option]) -> Option { + for pf in parsers.iter() { + match self.read_atomically(|p: &mut Parser| (*pf)(p)) { + Some(r) => return Some(r), + None => {} + } + } + None + } + + // Apply 3 parsers sequentially + fn read_seq_3(&mut self, + pa: &fn(&mut Parser) -> Option, + pb: &fn(&mut Parser) -> Option, + pc: &fn(&mut Parser) -> Option + ) -> Option<(A, B, C)> + { + do self.read_atomically |p| { + let a = pa(p); + let b = if a.is_some() { pb(p) } else { None }; + let c = if b.is_some() { pc(p) } else { None }; + match (a, b, c) { + (Some(a), Some(b), Some(c)) => Some((a, b, c)), + _ => None + } + } + } + + // Read next char + fn read_char(&mut self) -> Option { + if self.is_eof() { + None + } else { + let r = self.s[self.pos] as char; + self.pos += 1; + Some(r) + } + } + + // Return char and advance iff next char is equal to requested + fn read_given_char(&mut self, c: char) -> Option { + do self.read_atomically |p| { + p.read_char().filtered(|&next| next == c) + } + } + + // Read digit + fn read_digit(&mut self, radix: u8) -> Option { + fn parse_digit(c: char, radix: u8) -> Option { + // assuming radix is either 10 or 16 + if c >= '0' && c <= '9' { + Some((c - '0') as u8) + } else if radix > 10 && c >= 'a' && c < 'a' + (radix - 10) as char { + Some((c - 'a' + (10 as char)) as u8) + } else if radix > 10 && c >= 'A' && c < 'A' + (radix - 10) as char { + Some((c - 'A' + (10 as char)) as u8) + } else { + None + } + } + + do self.read_atomically |p| { + p.read_char().chain(|c| parse_digit(c, radix)) + } + } + + fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { + let mut r = 0u32; + let mut digit_count = 0; + loop { + match self.read_digit(radix) { + Some(d) => { + r = r * (radix as u32) + (d as u32); + digit_count += 1; + if digit_count > max_digits || r >= upto { + return None + } + } + None => { + if digit_count == 0 { + return None + } else { + return Some(r) + } + } + }; + } + } + + // Read number, failing if max_digits of number value exceeded + fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { + do self.read_atomically |p| { + p.read_number_impl(radix, max_digits, upto) + } + } + + fn read_ipv4_addr_impl(&mut self) -> Option { + let mut bs = [0u8, ..4]; + let mut i = 0; + while i < 4 { + if i != 0 && self.read_given_char('.').is_none() { + return None; + } + + let octet = self.read_number(10, 3, 0x100).map(|&n| n as u8); + match octet { + Some(d) => bs[i] = d, + None => return None, + }; + i += 1; + } + Some(Ipv4Addr(bs[0], bs[1], bs[2], bs[3])) + } + + // Read IPv4 address + fn read_ipv4_addr(&mut self) -> Option { + do self.read_atomically |p| { + p.read_ipv4_addr_impl() + } + } + + fn read_ipv6_addr_impl(&mut self) -> Option { + fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr { + assert!(head.len() + tail.len() <= 8); + let mut gs = [0u16, ..8]; + gs.copy_from(head); + gs.mut_slice(8 - tail.len(), 8).copy_from(tail); + Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) + } + + fn read_groups(p: &mut Parser, groups: &mut [u16, ..8], limit: uint) -> (uint, bool) { + let mut i = 0; + while i < limit { + if i < limit - 1 { + let ipv4 = do p.read_atomically |p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_ipv4_addr() + } else { + None + } + }; + match ipv4 { + Some(Ipv4Addr(a, b, c, d)) => { + groups[i + 0] = (a as u16 << 8) | (b as u16); + groups[i + 1] = (c as u16 << 8) | (d as u16); + return (i + 2, true); + } + _ => {} + } + } + + let group = do p.read_atomically |p| { + if i == 0 || p.read_given_char(':').is_some() { + p.read_number(16, 4, 0x10000).map(|&n| n as u16) + } else { + None + } + }; + match group { + Some(g) => groups[i] = g, + None => return (i, false) + } + i += 1; + } + (i, false) + } + + let mut head = [0u16, ..8]; + let (head_size, head_ipv4) = read_groups(self, &mut head, 8); + + if head_size == 8 { + return Some(Ipv6Addr( + head[0], head[1], head[2], head[3], + head[4], head[5], head[6], head[7])) + } + + // IPv4 part is not allowed before `::` + if head_ipv4 { + return None + } + + // read `::` if previous code parsed less than 8 groups + if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { + return None; + } + + let mut tail = [0u16, ..8]; + let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size); + Some(ipv6_addr_from_head_tail(head.slice(0, head_size), tail.slice(0, tail_size))) + } + + fn read_ipv6_addr(&mut self) -> Option { + do self.read_atomically |p| { + p.read_ipv6_addr_impl() + } + } + + fn read_ip_addr(&mut self) -> Option { + let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr(); + let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr(); + self.read_or([ipv4_addr, ipv6_addr]) + } + + fn read_socket_addr(&mut self) -> Option { + let ip_addr = |p: &mut Parser| { + let ipv4_p = |p: &mut Parser| p.read_ip_addr(); + let ipv6_p = |p: &mut Parser| { + let open_br = |p: &mut Parser| p.read_given_char('['); + let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); + let clos_br = |p: &mut Parser| p.read_given_char(']'); + p.read_seq_3::(open_br, ip_addr, clos_br) + .map(|&t| match t { (_, ip, _) => ip }) + }; + p.read_or([ipv4_p, ipv6_p]) + }; + let colon = |p: &mut Parser| p.read_given_char(':'); + let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|&n| n as u16); + + // host, colon, port + self.read_seq_3::(ip_addr, colon, port) + .map(|&t| match t { (ip, _, port) => SocketAddr { ip: ip, port: port } }) + } +} + +impl FromStr for IpAddr { + fn from_str(s: &str) -> Option { + do Parser::new(s).read_till_eof |p| { + p.read_ip_addr() + } + } +} + +impl FromStr for SocketAddr { + fn from_str(s: &str) -> Option { + do Parser::new(s).read_till_eof |p| { + p.read_socket_addr() + } + } +} + + +#[cfg(test)] +mod test { + use super::*; + use from_str::FromStr; + use option::{Some, None}; + + #[test] + fn test_from_str_ipv4() { + assert_eq!(Some(Ipv4Addr(127, 0, 0, 1)), FromStr::from_str("127.0.0.1")); + assert_eq!(Some(Ipv4Addr(255, 255, 255, 255)), FromStr::from_str("255.255.255.255")); + assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0")); + + // out of range + assert_eq!(None, FromStr::from_str::("256.0.0.1")); + // too short + assert_eq!(None, FromStr::from_str::("255.0.0")); + // too long + assert_eq!(None, FromStr::from_str::("255.0.0.1.2")); + // no number between dots + assert_eq!(None, FromStr::from_str::("255.0..1")); + } + + #[test] + fn test_from_str_ipv6() { + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("0:0:0:0:0:0:0:0")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("0:0:0:0:0:0:0:1")); + + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("::1")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("::")); + + assert_eq!(Some(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), + FromStr::from_str("2a02:6b8::11:11")); + + // too long group + assert_eq!(None, FromStr::from_str::("::00000")); + // too short + assert_eq!(None, FromStr::from_str::("1:2:3:4:5:6:7")); + // too long + assert_eq!(None, FromStr::from_str::("1:2:3:4:5:6:7:8:9")); + // triple colon + assert_eq!(None, FromStr::from_str::("1:2:::6:7:8")); + // two double colons + assert_eq!(None, FromStr::from_str::("1:2::6::8")); + } + + #[test] + fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)), + FromStr::from_str("::192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), + FromStr::from_str("::FFFF:192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + FromStr::from_str("64:ff9b::192.0.2.33")); + assert_eq!(Some(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33")); + + // colon after v4 + assert_eq!(None, FromStr::from_str::("::127.0.0.1:")); + // not enought groups + assert_eq!(None, FromStr::from_str::("1.2.3.4.5:127.0.0.1")); + // too many groups + assert_eq!(None, FromStr::from_str::("1.2.3.4.5:6:7:127.0.0.1")); + } + + #[test] + fn test_from_str_socket_addr() { + assert_eq!(Some(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }), + FromStr::from_str("77.88.21.11:80")); + assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }), + FromStr::from_str("[2a02:6b8:0:1::1]:53")); + assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }), + FromStr::from_str("[::127.0.0.1]:22")); + + // without port + assert_eq!(None, FromStr::from_str::("127.0.0.1")); + // without port + assert_eq!(None, FromStr::from_str::("127.0.0.1:")); + // wrong brackets around v4 + assert_eq!(None, FromStr::from_str::("[127.0.0.1]:22")); + // port out of range + assert_eq!(None, FromStr::from_str::("127.0.0.1:123456")); + } +} diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index 3372c13b877..e07cb1425bf 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -402,10 +402,10 @@ pub fn reparent_children_to(self, parent: &mut KillHandle) { || { // Prefer to check tombstones that were there first, // being "more fair" at the expense of tail-recursion. - others.take().map_consume_default(true, |f| f()) && { + others.take().map_move_default(true, |f| f()) && { let mut inner = this.take().unwrap(); (!inner.any_child_failed) && - inner.child_tombstones.take_map_default(true, |f| f()) + inner.child_tombstones.take().map_move_default(true, |f| f()) } } } @@ -424,7 +424,7 @@ pub fn reparent_children_to(self, parent: &mut KillHandle) { let others = Cell::new(other_tombstones); // :( || { // Prefer fairness to tail-recursion, as in above case. - others.take().map_consume_default(true, |f| f()) && + others.take().map_move_default(true, |f| f()) && f.take()() } } @@ -493,7 +493,7 @@ pub fn collect_failure(&mut self, mut success: bool, group: Option) { { use util; util::ignore(group); } // Step 1. Decide if we need to collect child failures synchronously. - do self.on_exit.take_map |on_exit| { + do self.on_exit.take().map_move |on_exit| { if success { // We succeeded, but our children might not. Need to wait for them. let mut inner = self.kill_handle.take_unwrap().unwrap(); @@ -501,7 +501,7 @@ pub fn collect_failure(&mut self, mut success: bool, group: Option) { success = false; } else { // Lockless access to tombstones protected by unwrap barrier. - success = inner.child_tombstones.take_map_default(true, |f| f()); + success = inner.child_tombstones.take().map_move_default(true, |f| f()); } } on_exit(success); @@ -510,12 +510,12 @@ pub fn collect_failure(&mut self, mut success: bool, group: Option) { // Step 2. Possibly alert possibly-watching parent to failure status. // Note that as soon as parent_handle goes out of scope, the parent // can successfully unwrap its handle and collect our reported status. - do self.watching_parent.take_map |mut parent_handle| { + do self.watching_parent.take().map_move |mut parent_handle| { if success { // Our handle might be None if we had an exit callback, and // already unwrapped it. But 'success' being true means no // child failed, so there's nothing to do (see below case). - do self.kill_handle.take_map |own_handle| { + do self.kill_handle.take().map_move |own_handle| { own_handle.reparent_children_to(&mut parent_handle); }; } else { @@ -590,7 +590,8 @@ pub fn allow_yield(&mut self) { #[inline] pub fn assert_may_sleep(&self) { if self.wont_sleep != 0 { - rtabort!("illegal atomic-sleep: can't deschedule inside atomically()"); + rtabort!("illegal atomic-sleep: attempt to reschedule while \ + using an Exclusive or LittleLock"); } } } @@ -614,6 +615,7 @@ mod test { // Test cases don't care about the spare killed flag. fn make_kill_handle() -> KillHandle { let (h,_) = KillHandle::new(); h } + #[ignore(reason = "linked failure")] #[test] fn no_tombstone_success() { do run_in_newsched_task { @@ -819,6 +821,7 @@ fn block_and_wake() { } } + #[ignore(reason = "linked failure")] #[test] fn block_and_get_killed() { do with_test_task |mut task| { @@ -830,6 +833,7 @@ fn block_and_get_killed() { } } + #[ignore(reason = "linked failure")] #[test] fn block_already_killed() { do with_test_task |mut task| { @@ -839,6 +843,7 @@ fn block_already_killed() { } } + #[ignore(reason = "linked failure")] #[test] fn block_unkillably_and_get_killed() { do with_test_task |mut task| { @@ -856,6 +861,7 @@ fn block_unkillably_and_get_killed() { } } + #[ignore(reason = "linked failure")] #[test] fn block_on_pipe() { // Tests the "killable" path of casting to/from uint. @@ -869,6 +875,7 @@ fn block_on_pipe() { } } + #[ignore(reason = "linked failure")] #[test] fn block_unkillably_on_pipe() { // Tests the "indestructible" path of casting to/from uint. diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index 131507196b1..7154066e7b7 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -126,6 +126,7 @@ unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl #[cfg(test)] mod test { + use option::None; use unstable::run_in_bare_thread; use rt::test::*; use super::*; @@ -137,7 +138,7 @@ fn thread_local_task_smoke_test() { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let task: ~Task = Local::take(); cleanup_task(task); @@ -149,11 +150,11 @@ fn thread_local_task_two_instances() { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let task: ~Task = Local::take(); cleanup_task(task); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let task: ~Task = Local::take(); cleanup_task(task); @@ -166,7 +167,7 @@ fn borrow_smoke_test() { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); unsafe { @@ -182,7 +183,7 @@ fn borrow_with_return() { do run_in_bare_thread { local_ptr::init_tls_key(); let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); + let task = ~Task::new_root(&mut sched.stack_pool, None, || {}); Local::put(task); let res = do Local::borrow:: |_task| { diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 760ca8a9ada..01a52892f63 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -63,8 +63,7 @@ use cell::Cell; use clone::Clone; use container::Container; -use iter::Times; -use iterator::{Iterator, IteratorUtil}; +use iterator::{Iterator, IteratorUtil, range}; use option::{Some, None}; use ptr::RawPtr; use rt::local::Local; @@ -212,6 +211,7 @@ pub fn init(argc: int, argv: **u8, crate_map: *u8) { // Need to propagate the unsafety to `start`. unsafe { args::init(argc, argv); + env::init(); logging::init(crate_map); rust_update_gc_metadata(crate_map); } @@ -246,11 +246,16 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let main = Cell::new(main); - // The shared list of sleeping schedulers. Schedulers wake each other - // occassionally to do new work. + // The shared list of sleeping schedulers. let sleepers = SleeperList::new(); - // The shared work queue. Temporary until work stealing is implemented. - let work_queue = WorkQueue::new(); + + // Create a work queue for each scheduler, ntimes. Create an extra + // for the main thread if that flag is set. We won't steal from it. + let mut work_queues = ~[]; + for _ in range(0u, nscheds) { + let work_queue: WorkQueue<~Task> = WorkQueue::new(); + work_queues.push(work_queue); + } // The schedulers. let mut scheds = ~[]; @@ -258,12 +263,15 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // sent the Shutdown message to terminate the schedulers. let mut handles = ~[]; - do nscheds.times { + for i in range(0u, nscheds) { rtdebug!("inserting a regular scheduler"); // Every scheduler is driven by an I/O event loop. let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone()); + let mut sched = ~Scheduler::new(loop_, + work_queues[i].clone(), + work_queues.clone(), + sleepers.clone()); let handle = sched.make_handle(); scheds.push(sched); @@ -279,9 +287,14 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let friend_handle = friend_sched.make_handle(); scheds.push(friend_sched); + // This scheduler needs a queue that isn't part of the stealee + // set. + let work_queue = WorkQueue::new(); + let main_loop = ~UvEventLoop::new(); let mut main_sched = ~Scheduler::new_special(main_loop, - work_queue.clone(), + work_queue, + work_queues.clone(), sleepers.clone(), false, Some(friend_handle)); @@ -330,8 +343,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // In the case where we do not use a main_thread scheduler we // run the main task in one of our threads. - let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, - main.take()); + let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, main.take()); main_task.death.on_exit = Some(on_exit.take()); let main_task_cell = Cell::new(main_task); @@ -351,7 +363,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let sched_cell = Cell::new(sched); let thread = do Thread::start { let mut sched = sched_cell.take(); - let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || { + let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || { rtdebug!("boostraping a non-primary scheduler"); }; sched.bootstrap(bootstrap_task); @@ -368,10 +380,10 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { let mut main_sched = main_sched.unwrap(); let home = Sched(main_sched.make_handle()); - let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, + let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None, home, main.take()); main_task.death.on_exit = Some(on_exit.take()); - rtdebug!("boostrapping main_task"); + rtdebug!("bootstrapping main_task"); main_sched.bootstrap(main_task); } diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 1a75f2569b5..ce4e64c47d2 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -13,7 +13,6 @@ use cast::{transmute, transmute_mut_region, transmute_mut_unsafe}; use clone::Clone; use unstable::raw; - use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; use super::stack::{StackPool}; @@ -28,6 +27,9 @@ use rt::metrics::SchedMetrics; use borrow::{to_uint}; use cell::Cell; +use rand::{XorShiftRng, RngUtil}; +use iterator::{range}; +use vec::{OwnedVector}; /// The Scheduler is responsible for coordinating execution of Coroutines /// on a single thread. When the scheduler is running it is owned by @@ -37,9 +39,11 @@ /// XXX: This creates too many callbacks to run_sched_once, resulting /// in too much allocation and too many events. pub struct Scheduler { - /// A queue of available work. Under a work-stealing policy there - /// is one per Scheduler. - work_queue: WorkQueue<~Task>, + /// There are N work queues, one per scheduler. + priv work_queue: WorkQueue<~Task>, + /// Work queues for the other schedulers. These are created by + /// cloning the core work queues. + work_queues: ~[WorkQueue<~Task>], /// The queue of incoming messages from other schedulers. /// These are enqueued by SchedHandles after which a remote callback /// is triggered to handle the message. @@ -70,7 +74,10 @@ pub struct Scheduler { run_anything: bool, /// If the scheduler shouldn't run some tasks, a friend to send /// them to. - friend_handle: Option + friend_handle: Option, + /// A fast XorShift rng for scheduler use + rng: XorShiftRng + } pub struct SchedHandle { @@ -97,10 +104,13 @@ pub fn sched_id(&self) -> uint { to_uint(self) } pub fn new(event_loop: ~EventLoopObject, work_queue: WorkQueue<~Task>, + work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList) -> Scheduler { - Scheduler::new_special(event_loop, work_queue, sleeper_list, true, None) + Scheduler::new_special(event_loop, work_queue, + work_queues, + sleeper_list, true, None) } @@ -108,6 +118,7 @@ pub fn new(event_loop: ~EventLoopObject, // task field is None. pub fn new_special(event_loop: ~EventLoopObject, work_queue: WorkQueue<~Task>, + work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList, run_anything: bool, friend: Option) @@ -120,12 +131,14 @@ pub fn new_special(event_loop: ~EventLoopObject, no_sleep: false, event_loop: event_loop, work_queue: work_queue, + work_queues: work_queues, stack_pool: StackPool::new(), sched_task: None, cleanup_job: None, metrics: SchedMetrics::new(), run_anything: run_anything, - friend_handle: friend + friend_handle: friend, + rng: XorShiftRng::new() } } @@ -248,7 +261,7 @@ fn run_sched_once() { // Second activity is to try resuming a task from the queue. - let result = sched.resume_task_from_queue(); + let result = sched.do_work(); let mut sched = match result { Some(sched) => { // Failed to dequeue a task, so we return. @@ -325,7 +338,7 @@ pub fn enqueue_task(&mut self, task: ~Task) { /// As enqueue_task, but with the possibility for the blocked task to /// already have been killed. pub fn enqueue_blocked_task(&mut self, blocked_task: BlockedTask) { - do blocked_task.wake().map_consume |task| { + do blocked_task.wake().map_move |task| { self.enqueue_task(task); }; } @@ -415,47 +428,98 @@ fn send_to_friend(&mut self, task: ~Task) { } } - // Resume a task from the queue - but also take into account that - // it might not belong here. + // Workstealing: In this iteration of the runtime each scheduler + // thread has a distinct work queue. When no work is available + // locally, make a few attempts to steal work from the queues of + // other scheduler threads. If a few steals fail we end up in the + // old "no work" path which is fine. + + // First step in the process is to find a task. This function does + // that by first checking the local queue, and if there is no work + // there, trying to steal from the remote work queues. + fn find_work(&mut self) -> Option<~Task> { + rtdebug!("scheduler looking for work"); + match self.work_queue.pop() { + Some(task) => { + rtdebug!("found a task locally"); + return Some(task) + } + None => { + // Our naive stealing, try kinda hard. + rtdebug!("scheduler trying to steal"); + let _len = self.work_queues.len(); + return self.try_steals(2); + } + } + } + + // With no backoff try stealing n times from the queues the + // scheduler knows about. This naive implementation can steal from + // our own queue or from other special schedulers. + fn try_steals(&mut self, n: uint) -> Option<~Task> { + for _ in range(0, n) { + let index = self.rng.gen_uint_range(0, self.work_queues.len()); + let work_queues = &mut self.work_queues; + match work_queues[index].steal() { + Some(task) => { + rtdebug!("found task by stealing"); return Some(task) + } + None => () + } + }; + rtdebug!("giving up on stealing"); + return None; + } - // If we perform a scheduler action we give away the scheduler ~ - // pointer, if it is still available we return it. + // Given a task, execute it correctly. + fn process_task(~self, task: ~Task) -> Option<~Scheduler> { + let mut this = self; + let mut task = task; - fn resume_task_from_queue(~self) -> Option<~Scheduler> { + rtdebug!("processing a task"); + let home = task.take_unwrap_home(); + match home { + Sched(home_handle) => { + if home_handle.sched_id != this.sched_id() { + rtdebug!("sending task home"); + task.give_home(Sched(home_handle)); + Scheduler::send_task_home(task); + return Some(this); + } else { + rtdebug!("running task here"); + task.give_home(Sched(home_handle)); + this.resume_task_immediately(task); + return None; + } + } + AnySched if this.run_anything => { + rtdebug!("running anysched task here"); + task.give_home(AnySched); + this.resume_task_immediately(task); + return None; + } + AnySched => { + rtdebug!("sending task to friend"); + task.give_home(AnySched); + this.send_to_friend(task); + return Some(this); + } + } + } + + // Bundle the helpers together. + fn do_work(~self) -> Option<~Scheduler> { let mut this = self; - match this.work_queue.pop() { + rtdebug!("scheduler calling do work"); + match this.find_work() { Some(task) => { - let mut task = task; - let home = task.take_unwrap_home(); - match home { - Sched(home_handle) => { - if home_handle.sched_id != this.sched_id() { - task.give_home(Sched(home_handle)); - Scheduler::send_task_home(task); - return Some(this); - } else { - this.event_loop.callback(Scheduler::run_sched_once); - task.give_home(Sched(home_handle)); - this.resume_task_immediately(task); - return None; - } - } - AnySched if this.run_anything => { - this.event_loop.callback(Scheduler::run_sched_once); - task.give_home(AnySched); - this.resume_task_immediately(task); - return None; - } - AnySched => { - task.give_home(AnySched); - this.send_to_friend(task); - return Some(this); - } - } + rtdebug!("found some work! processing the task"); + return this.process_task(task); } None => { + rtdebug!("no work was found, returning the scheduler struct"); return Some(this); } } @@ -533,7 +597,7 @@ pub fn run_task(task: ~Task) { sched.enqueue_blocked_task(last_task); } }; - opt.map_consume(Local::put); + opt.map_move(Local::put); } // The primary function for changing contexts. In the current @@ -711,7 +775,6 @@ pub fn run_cleanup_job(&mut self) { GiveTask(task, f) => f.to_fn()(self, task) } } - } // The cases for the below function. @@ -745,6 +808,8 @@ fn to_fn(self) -> &fn(&mut Scheduler, ~Task) { unsafe { transmute(self) } } #[cfg(test)] mod test { + extern mod extra; + use prelude::*; use rt::test::*; use unstable::run_in_bare_thread; @@ -833,7 +898,7 @@ fn test_home_sched() { let mut sched = ~new_test_uv_sched(); let sched_handle = sched.make_handle(); - let mut task = ~do Task::new_root_homed(&mut sched.stack_pool, + let mut task = ~do Task::new_root_homed(&mut sched.stack_pool, None, Sched(sched_handle)) { unsafe { *task_ran_ptr = true }; assert!(Task::on_appropriate_sched()); @@ -862,12 +927,15 @@ fn test_schedule_home_states() { do run_in_bare_thread { let sleepers = SleeperList::new(); - let work_queue = WorkQueue::new(); + let normal_queue = WorkQueue::new(); + let special_queue = WorkQueue::new(); + let queues = ~[normal_queue.clone(), special_queue.clone()]; // Our normal scheduler let mut normal_sched = ~Scheduler::new( ~UvEventLoop::new(), - work_queue.clone(), + normal_queue, + queues.clone(), sleepers.clone()); let normal_handle = Cell::new(normal_sched.make_handle()); @@ -877,7 +945,8 @@ fn test_schedule_home_states() { // Our special scheduler let mut special_sched = ~Scheduler::new_special( ~UvEventLoop::new(), - work_queue.clone(), + special_queue.clone(), + queues.clone(), sleepers.clone(), false, Some(friend_handle)); @@ -893,21 +962,21 @@ fn test_schedule_home_states() { // 3) task not homed, sched requeues // 4) task not home, send home - let task1 = ~do Task::new_root_homed(&mut special_sched.stack_pool, + let task1 = ~do Task::new_root_homed(&mut special_sched.stack_pool, None, Sched(t1_handle)) || { rtassert!(Task::on_appropriate_sched()); }; rtdebug!("task1 id: **%u**", borrow::to_uint(task1)); - let task2 = ~do Task::new_root(&mut normal_sched.stack_pool) { + let task2 = ~do Task::new_root(&mut normal_sched.stack_pool, None) { rtassert!(Task::on_appropriate_sched()); }; - let task3 = ~do Task::new_root(&mut normal_sched.stack_pool) { + let task3 = ~do Task::new_root(&mut normal_sched.stack_pool, None) { rtassert!(Task::on_appropriate_sched()); }; - let task4 = ~do Task::new_root_homed(&mut special_sched.stack_pool, + let task4 = ~do Task::new_root_homed(&mut special_sched.stack_pool, None, Sched(t4_handle)) { rtassert!(Task::on_appropriate_sched()); }; @@ -923,7 +992,7 @@ fn test_schedule_home_states() { let port = Cell::new(port); let chan = Cell::new(chan); - let normal_task = ~do Task::new_root(&mut normal_sched.stack_pool) { + let normal_task = ~do Task::new_root(&mut normal_sched.stack_pool, None) { rtdebug!("*about to submit task2*"); Scheduler::run_task(task2.take()); rtdebug!("*about to submit task4*"); @@ -938,7 +1007,7 @@ fn test_schedule_home_states() { rtdebug!("normal task: %u", borrow::to_uint(normal_task)); - let special_task = ~do Task::new_root(&mut special_sched.stack_pool) { + let special_task = ~do Task::new_root(&mut special_sched.stack_pool, None) { rtdebug!("*about to submit task1*"); Scheduler::run_task(task1.take()); rtdebug!("*about to submit task3*"); diff --git a/src/libstd/rt/select.rs b/src/libstd/rt/select.rs index 006b777b71b..0e8d26e9482 100644 --- a/src/libstd/rt/select.rs +++ b/src/libstd/rt/select.rs @@ -182,6 +182,7 @@ fn select_a_lot() { fn select_stream() { use util; use comm::GenericChan; + use iter::Times; // Sends 10 buffered packets, and uses select to retrieve them all. // Puts the port in a different spot in the vector each time. @@ -199,9 +200,7 @@ fn select_stream() { // get it back out util::swap(port.get_mut_ref(), &mut ports[index]); // NB. Not recv(), because optimistic_check randomly fails. - let (data, new_port) = port.take_unwrap().recv_ready().unwrap(); - assert!(data == 31337); - port = Some(new_port); + assert!(port.get_ref().recv_ready().unwrap() == 31337); } } } @@ -265,6 +264,7 @@ fn select_racing_senders() { fn select_racing_senders_helper(killable: bool, send_on_chans: ~[uint]) { use rt::test::spawntask_random; + use iter::Times; do run_in_newsched_task { // A bit of stress, since ordinarily this is just smoke and mirrors. diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 4c5e4bdc3c1..364439a4526 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -20,6 +20,7 @@ use ptr; use prelude::*; use option::{Option, Some, None}; +use rt::env; use rt::kill::Death; use rt::local::Local; use rt::logging::StdErrLogger; @@ -85,12 +86,13 @@ impl Task { // A helper to build a new task using the dynamically found // scheduler and task. Only works in GreenTask context. - pub fn build_homed_child(f: ~fn(), home: SchedHome) -> ~Task { + pub fn build_homed_child(stack_size: Option, f: ~fn(), home: SchedHome) -> ~Task { let f = Cell::new(f); let home = Cell::new(home); do Local::borrow:: |running_task| { let mut sched = running_task.sched.take_unwrap(); let new_task = ~running_task.new_child_homed(&mut sched.stack_pool, + stack_size, home.take(), f.take()); running_task.sched = Some(sched); @@ -98,25 +100,26 @@ pub fn build_homed_child(f: ~fn(), home: SchedHome) -> ~Task { } } - pub fn build_child(f: ~fn()) -> ~Task { - Task::build_homed_child(f, AnySched) + pub fn build_child(stack_size: Option, f: ~fn()) -> ~Task { + Task::build_homed_child(stack_size, f, AnySched) } - pub fn build_homed_root(f: ~fn(), home: SchedHome) -> ~Task { + pub fn build_homed_root(stack_size: Option, f: ~fn(), home: SchedHome) -> ~Task { let f = Cell::new(f); let home = Cell::new(home); do Local::borrow:: |running_task| { let mut sched = running_task.sched.take_unwrap(); let new_task = ~Task::new_root_homed(&mut sched.stack_pool, - home.take(), - f.take()); + stack_size, + home.take(), + f.take()); running_task.sched = Some(sched); new_task } } - pub fn build_root(f: ~fn()) -> ~Task { - Task::build_homed_root(f, AnySched) + pub fn build_root(stack_size: Option, f: ~fn()) -> ~Task { + Task::build_homed_root(stack_size, f, AnySched) } pub fn new_sched_task() -> Task { @@ -137,17 +140,20 @@ pub fn new_sched_task() -> Task { } pub fn new_root(stack_pool: &mut StackPool, + stack_size: Option, start: ~fn()) -> Task { - Task::new_root_homed(stack_pool, AnySched, start) + Task::new_root_homed(stack_pool, stack_size, AnySched, start) } pub fn new_child(&mut self, stack_pool: &mut StackPool, + stack_size: Option, start: ~fn()) -> Task { - self.new_child_homed(stack_pool, AnySched, start) + self.new_child_homed(stack_pool, stack_size, AnySched, start) } pub fn new_root_homed(stack_pool: &mut StackPool, + stack_size: Option, home: SchedHome, start: ~fn()) -> Task { Task { @@ -160,7 +166,7 @@ pub fn new_root_homed(stack_pool: &mut StackPool, death: Death::new(), destroyed: false, name: None, - coroutine: Some(Coroutine::new(stack_pool, start)), + coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, task_type: GreenTask(Some(~home)) } @@ -168,6 +174,7 @@ pub fn new_root_homed(stack_pool: &mut StackPool, pub fn new_child_homed(&mut self, stack_pool: &mut StackPool, + stack_size: Option, home: SchedHome, start: ~fn()) -> Task { Task { @@ -181,7 +188,7 @@ pub fn new_child_homed(&mut self, death: self.death.new_child(), destroyed: false, name: None, - coroutine: Some(Coroutine::new(stack_pool, start)), + coroutine: Some(Coroutine::new(stack_pool, stack_size, start)), sched: None, task_type: GreenTask(Some(~home)) } @@ -325,11 +332,13 @@ fn drop(&self) { impl Coroutine { - pub fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { - static MIN_STACK_SIZE: uint = 3000000; // XXX: Too much stack - + pub fn new(stack_pool: &mut StackPool, stack_size: Option, start: ~fn()) -> Coroutine { + let stack_size = match stack_size { + Some(size) => size, + None => env::min_stack() + }; let start = Coroutine::build_start_wrapper(start); - let mut stack = stack_pool.take_segment(MIN_STACK_SIZE); + let mut stack = stack_pool.take_segment(stack_size); let initial_context = Context::new(start, &mut stack); Coroutine { current_stack_segment: stack, @@ -465,10 +474,10 @@ fn tls() { do run_in_newsched_task() { static key: local_data::Key<@~str> = &local_data::Key; local_data::set(key, @~"data"); - assert!(*local_data::get(key, |k| k.map(|&k| *k)).unwrap() == ~"data"); + assert!(*local_data::get(key, |k| k.map_move(|k| *k)).unwrap() == ~"data"); static key2: local_data::Key<@~str> = &local_data::Key; local_data::set(key2, @~"data"); - assert!(*local_data::get(key2, |k| k.map(|&k| *k)).unwrap() == ~"data"); + assert!(*local_data::get(key2, |k| k.map_move(|k| *k)).unwrap() == ~"data"); } } diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 8b5215ae969..92366d5187f 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -15,8 +15,8 @@ use clone::Clone; use container::Container; use iterator::{Iterator, range}; -use vec::{OwnedVector, MutableVector}; use super::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; +use vec::{OwnedVector, MutableVector, ImmutableVector}; use rt::sched::Scheduler; use unstable::run_in_bare_thread; use rt::thread::Thread; @@ -29,8 +29,12 @@ pub fn new_test_uv_sched() -> Scheduler { + let queue = WorkQueue::new(); + let queues = ~[queue.clone()]; + let mut sched = Scheduler::new(~UvEventLoop::new(), - WorkQueue::new(), + queue, + queues, SleeperList::new()); // Don't wait for the Shutdown message @@ -57,7 +61,7 @@ pub fn run_in_newsched_task_core(f: ~fn()) { exit_handle.take().send(Shutdown); rtassert!(exit_status); }; - let mut task = ~Task::new_root(&mut sched.stack_pool, f); + let mut task = ~Task::new_root(&mut sched.stack_pool, None, f); task.death.on_exit = Some(on_exit); sched.bootstrap(task); @@ -164,15 +168,21 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { }; let sleepers = SleeperList::new(); - let work_queue = WorkQueue::new(); let mut handles = ~[]; let mut scheds = ~[]; + let mut work_queues = ~[]; for _ in range(0u, nthreads) { + let work_queue = WorkQueue::new(); + work_queues.push(work_queue); + } + + for i in range(0u, nthreads) { let loop_ = ~UvEventLoop::new(); let mut sched = ~Scheduler::new(loop_, - work_queue.clone(), + work_queues[i].clone(), + work_queues.clone(), sleepers.clone()); let handle = sched.make_handle(); @@ -190,8 +200,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { rtassert!(exit_status); }; - let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, - f.take()); + let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, f.take()); main_task.death.on_exit = Some(on_exit); let mut threads = ~[]; @@ -209,7 +218,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { while !scheds.is_empty() { let mut sched = scheds.pop(); - let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || { + let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || { rtdebug!("bootstrapping non-primary scheduler"); }; let bootstrap_task_cell = Cell::new(bootstrap_task); @@ -232,12 +241,12 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { /// Test tasks will abort on failure instead of unwinding pub fn spawntask(f: ~fn()) { - Scheduler::run_task(Task::build_child(f)); + Scheduler::run_task(Task::build_child(None, f)); } /// Create a new task and run it right now. Aborts on failure pub fn spawntask_later(f: ~fn()) { - Scheduler::run_task_later(Task::build_child(f)); + Scheduler::run_task_later(Task::build_child(None, f)); } pub fn spawntask_random(f: ~fn()) { @@ -259,7 +268,7 @@ pub fn spawntask_try(f: ~fn()) -> Result<(),()> { let chan = Cell::new(chan); let on_exit: ~fn(bool) = |exit_status| chan.take().send(exit_status); - let mut new_task = Task::build_root(f); + let mut new_task = Task::build_root(None, f); new_task.death.on_exit = Some(on_exit); Scheduler::run_task(new_task); @@ -285,7 +294,7 @@ pub fn spawntask_thread(f: ~fn()) -> Thread { pub fn with_test_task(blk: ~fn(~Task) -> ~Task) { do run_in_bare_thread { let mut sched = ~new_test_uv_sched(); - let task = blk(~Task::new_root(&mut sched.stack_pool, ||{})); + let task = blk(~Task::new_root(&mut sched.stack_pool, None, ||{})); cleanup_task(task); } } diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index fd3042899f6..c8b3d41a78d 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -20,7 +20,6 @@ use vec; use str; use from_str::{FromStr}; -use num; pub enum UvSocketAddr { UvIpv4SocketAddr(*sockaddr_in), @@ -85,77 +84,10 @@ fn uv_socket_addr_as_socket_addr(addr: UvSocketAddr, f: &fn(SocketAddr) -> T) port as u16 }; let ip_str = str::from_bytes_slice(ip_name).trim_right_chars(&'\x00'); - let ip = match addr { - UvIpv4SocketAddr(*) => { - let ip: ~[u8] = - ip_str.split_iter('.') - .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) - .collect(); - assert_eq!(ip.len(), 4); - SocketAddr { - ip: Ipv4Addr(ip[0], ip[1], ip[2], ip[3]), - port: ip_port - } - }, - UvIpv6SocketAddr(*) => { - let ip: ~[u16] = { - let expand_shorthand_and_convert = |s: &str| -> ~[~[u16]] { - let convert_each_segment = |s: &str| -> ~[u16] { - let read_hex_segment = |s: &str| -> u16 { - num::FromStrRadix::from_str_radix(s, 16u).unwrap() - }; - match s { - "" => ~[], - // IPv4-Mapped/Compatible IPv6 Address? - s if s.find('.').is_some() => { - let i = s.rfind(':').unwrap_or_default(-1); - - let b = s.slice(i + 1, s.len()); // the ipv4 part - - let h = b.split_iter('.') - .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() }) - .transform(|s: u8| -> ~str { fmt!("%02x", s as uint) }) - .collect::<~[~str]>(); - - if i == -1 { - // Ipv4 Compatible Address (::x.x.x.x) - // first 96 bits are zero leaving 32 bits - // for the ipv4 part - // (i.e ::127.0.0.1 == ::7F00:1) - ~[num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), - num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] - } else { - // Ipv4-Mapped Address (::FFFF:x.x.x.x) - // first 80 bits are zero, followed by all ones - // for the next 16 bits, leaving 32 bits for - // the ipv4 part - // (i.e ::FFFF:127.0.0.1 == ::FFFF:7F00:1) - ~[1, - num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(), - num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()] - } - }, - s => s.split_iter(':').transform(read_hex_segment).collect() - } - }; - s.split_str_iter("::").transform(convert_each_segment).collect() - }; - match expand_shorthand_and_convert(ip_str) { - [x] => x, // no shorthand found - [l, r] => l + vec::from_elem(8 - l.len() - r.len(), 0u16) + r, // fill the gap - _ => fail!(), // impossible. only one shorthand allowed. - } - }; - assert_eq!(ip.len(), 8); - SocketAddr { - ip: Ipv6Addr(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]), - port: ip_port - } - }, - }; + let ip_addr = FromStr::from_str(ip_str).unwrap(); // finally run the closure - f(ip) + f(SocketAddr { ip: ip_addr, port: ip_port }) } pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index ef3d881c5fe..99cf96eaae2 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -632,7 +632,6 @@ fn spawn_process_os(prog: &str, args: &[~str], use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; use libc::funcs::bsd44::getdtablesize; - use int; mod rustrt { use libc::c_void; @@ -665,10 +664,9 @@ mod rustrt { fail!("failure in dup3(err_fd, 2): %s", os::last_os_error()); } // close all other fds - do int::range_rev(getdtablesize() as int, 3) |fd| { + for fd in range(3, getdtablesize()).invert() { close(fd as c_int); - true - }; + } do with_dirp(dir) |dirp| { if !dirp.is_null() && chdir(dirp) == -1 { @@ -763,14 +761,14 @@ fn with_dirp(d: Option<&Path>, } #[cfg(windows)] -priv fn free_handle(handle: *()) { +fn free_handle(handle: *()) { unsafe { libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle)); } } #[cfg(unix)] -priv fn free_handle(_handle: *()) { +fn free_handle(_handle: *()) { // unix has no process handle object, just a pid } @@ -825,7 +823,7 @@ pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput { * operate on a none-existant process or, even worse, on a newer process * with the same id. */ -priv fn waitpid(pid: pid_t) -> int { +fn waitpid(pid: pid_t) -> int { return waitpid_os(pid); #[cfg(windows)] diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 568709c89da..7000b56069d 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -177,6 +177,7 @@ pub mod linkhack { pub mod run; pub mod sys; pub mod cast; +pub mod fmt; pub mod repr; pub mod cleanup; pub mod reflect; @@ -216,4 +217,6 @@ mod std { pub use unstable; pub use str; pub use os; + pub use fmt; + pub use to_bytes; } diff --git a/src/libstd/str.rs b/src/libstd/str.rs index b4057b85cbf..fa75916fb86 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -738,7 +738,7 @@ pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { } // https://tools.ietf.org/html/rfc3629 -priv static UTF8_CHAR_WIDTH: [u8, ..256] = [ +static UTF8_CHAR_WIDTH: [u8, ..256] = [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, @@ -781,15 +781,15 @@ macro_rules! utf8_acc_cont_byte( ) // UTF-8 tags and ranges -priv static TAG_CONT_U8: u8 = 128u8; -priv static TAG_CONT: uint = 128u; -priv static MAX_ONE_B: uint = 128u; -priv static TAG_TWO_B: uint = 192u; -priv static MAX_TWO_B: uint = 2048u; -priv static TAG_THREE_B: uint = 224u; -priv static MAX_THREE_B: uint = 65536u; -priv static TAG_FOUR_B: uint = 240u; -priv static MAX_UNICODE: uint = 1114112u; +static TAG_CONT_U8: u8 = 128u8; +static TAG_CONT: uint = 128u; +static MAX_ONE_B: uint = 128u; +static TAG_TWO_B: uint = 192u; +static MAX_TWO_B: uint = 2048u; +static TAG_THREE_B: uint = 224u; +static MAX_THREE_B: uint = 65536u; +static TAG_FOUR_B: uint = 240u; +static MAX_UNICODE: uint = 1114112u; /// Unsafe operations pub mod raw { @@ -1849,7 +1849,7 @@ fn find_str(&self, needle: &str) -> Option { } else { self.matches_index_iter(needle) .next() - .map_consume(|(start, _end)| start) + .map_move(|(start, _end)| start) } } @@ -3304,19 +3304,22 @@ fn test_char_range_at_reverse_underflow() { fn test_add() { #[allow(unnecessary_allocation)]; macro_rules! t ( - ($s1:expr, $s2:expr, $e:expr) => { - assert_eq!($s1 + $s2, $e); - assert_eq!($s1.to_owned() + $s2, $e); - assert_eq!($s1.to_managed() + $s2, $e); - } + ($s1:expr, $s2:expr, $e:expr) => { { + let s1 = $s1; + let s2 = $s2; + let e = $e; + assert_eq!(s1 + s2, e.to_owned()); + assert_eq!(s1.to_owned() + s2, e.to_owned()); + assert_eq!(s1.to_managed() + s2, e.to_owned()); + } } ); - t!("foo", "bar", ~"foobar"); - t!("foo", @"bar", ~"foobar"); - t!("foo", ~"bar", ~"foobar"); - t!("ศไทย中", "华Việt Nam", ~"ศไทย中华Việt Nam"); - t!("ศไทย中", @"华Việt Nam", ~"ศไทย中华Việt Nam"); - t!("ศไทย中", ~"华Việt Nam", ~"ศไทย中华Việt Nam"); + t!("foo", "bar", "foobar"); + t!("foo", @"bar", "foobar"); + t!("foo", ~"bar", "foobar"); + t!("ศไทย中", "华Việt Nam", "ศไทย中华Việt Nam"); + t!("ศไทย中", @"华Việt Nam", "ศไทย中华Việt Nam"); + t!("ศไทย中", ~"华Việt Nam", "ศไทย中华Việt Nam"); } #[test] diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index dd730f20689..6ededb02107 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -13,7 +13,10 @@ use to_str::{ToStr,ToStrConsume}; use str; use str::StrSlice; +use str::OwnedStr; +use container::Container; use cast; +use ptr; use iterator::{Iterator, IteratorUtil}; use vec::{CopyableVector, ImmutableVector, OwnedVector}; use to_bytes::IterBytes; @@ -39,27 +42,19 @@ pub fn to_char(self) -> char { /// Convert to lowercase. #[inline] pub fn to_lower(self) -> Ascii { - if self.chr >= 65 && self.chr <= 90 { - Ascii{chr: self.chr | 0x20 } - } else { - self - } + Ascii{chr: ASCII_LOWER_MAP[self.chr]} } /// Convert to uppercase. #[inline] pub fn to_upper(self) -> Ascii { - if self.chr >= 97 && self.chr <= 122 { - Ascii{chr: self.chr & !0x20 } - } else { - self - } + Ascii{chr: ASCII_UPPER_MAP[self.chr]} } /// Compares two ascii characters of equality, ignoring case. #[inline] pub fn eq_ignore_case(self, other: Ascii) -> bool { - self.to_lower().chr == other.to_lower().chr + ASCII_LOWER_MAP[self.chr] == ASCII_LOWER_MAP[other.chr] } } @@ -261,10 +256,124 @@ fn into_bytes(self) -> ~[u8] { } } + +/// Convert the string to ASCII upper case: +/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', +/// but non-ASCII letters are unchanged. +#[inline] +pub fn to_ascii_upper(string: &str) -> ~str { + map_bytes(string, ASCII_UPPER_MAP) +} + +/// Convert the string to ASCII lower case: +/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', +/// but non-ASCII letters are unchanged. +#[inline] +pub fn to_ascii_lower(string: &str) -> ~str { + map_bytes(string, ASCII_LOWER_MAP) +} + +#[inline] +fn map_bytes(string: &str, map: &'static [u8]) -> ~str { + let len = string.len(); + let mut result = str::with_capacity(len); + unsafe { + do result.as_mut_buf |mut buf, _| { + for c in string.as_bytes().iter() { + *buf = map[*c]; + buf = ptr::mut_offset(buf, 1) + } + } + str::raw::set_len(&mut result, len); + } + result +} + +/// Check that two strings are an ASCII case-insensitive match. +/// Same as `to_ascii_lower(a) == to_ascii_lower(b)`, +/// but without allocating and copying temporary strings. +#[inline] +pub fn eq_ignore_ascii_case(a: &str, b: &str) -> bool { + a.len() == b.len() && a.as_bytes().iter().zip(b.as_bytes().iter()).all( + |(byte_a, byte_b)| ASCII_LOWER_MAP[*byte_a] == ASCII_LOWER_MAP[*byte_b]) +} + +static ASCII_LOWER_MAP: &'static [u8] = &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +]; + +static ASCII_UPPER_MAP: &'static [u8] = &[ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +]; + + #[cfg(test)] mod tests { use super::*; use to_bytes::ToBytes; + use str::from_char; macro_rules! v2ascii ( ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]); @@ -347,4 +456,53 @@ fn test_ascii_to_bytes() { #[test] #[should_fail] fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); } + + #[test] + fn test_to_ascii_upper() { + assert_eq!(to_ascii_upper("url()URL()uRl()ürl"), ~"URL()URL()URL()üRL"); + assert_eq!(to_ascii_upper("hıKß"), ~"HıKß"); + + let mut i = 0; + while i <= 500 { + let c = i as char; + let upper = if 'a' <= c && c <= 'z' { c + 'A' - 'a' } else { c }; + assert_eq!(to_ascii_upper(from_char(i as char)), from_char(upper)) + i += 1; + } + } + + #[test] + fn test_to_ascii_lower() { + assert_eq!(to_ascii_lower("url()URL()uRl()Ürl"), ~"url()url()url()Ürl"); + // Dotted capital I, Kelvin sign, Sharp S. + assert_eq!(to_ascii_lower("HİKß"), ~"hİKß"); + + let mut i = 0; + while i <= 500 { + let c = i as char; + let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c }; + assert_eq!(to_ascii_lower(from_char(i as char)), from_char(lower)) + i += 1; + } + } + + + #[test] + fn test_eq_ignore_ascii_case() { + assert!(eq_ignore_ascii_case("url()URL()uRl()Ürl", "url()url()url()Ürl")); + assert!(!eq_ignore_ascii_case("Ürl", "ürl")); + // Dotted capital I, Kelvin sign, Sharp S. + assert!(eq_ignore_ascii_case("HİKß", "hİKß")); + assert!(!eq_ignore_ascii_case("İ", "i")); + assert!(!eq_ignore_ascii_case("K", "k")); + assert!(!eq_ignore_ascii_case("ß", "s")); + + let mut i = 0; + while i <= 500 { + let c = i as char; + let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c }; + assert!(eq_ignore_ascii_case(from_char(i as char), from_char(lower))); + i += 1; + } + } } diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index 225a4b8cfd2..2e0c9c1d1ad 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -142,7 +142,8 @@ pub struct TaskOpts { indestructible: bool, notify_chan: Option>, name: Option<~str>, - sched: SchedOpts + sched: SchedOpts, + stack_size: Option } /** @@ -197,7 +198,8 @@ fn consume(&mut self) -> TaskBuilder { indestructible: self.opts.indestructible, notify_chan: notify_chan, name: name, - sched: self.opts.sched + sched: self.opts.sched, + stack_size: self.opts.stack_size }, gen_body: gen_body, can_not_copy: None, @@ -351,7 +353,8 @@ pub fn spawn(&mut self, f: ~fn()) { indestructible: x.opts.indestructible, notify_chan: notify_chan, name: name, - sched: x.opts.sched + sched: x.opts.sched, + stack_size: x.opts.stack_size }; let f = match gen_body { Some(gen) => { @@ -422,7 +425,8 @@ pub fn default_task_opts() -> TaskOpts { name: None, sched: SchedOpts { mode: DefaultScheduler, - } + }, + stack_size: None } } @@ -655,6 +659,7 @@ pub unsafe fn rekillable(f: &fn() -> U) -> U { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_kill_unkillable_task() { use rt::test::*; @@ -675,6 +680,7 @@ fn test_kill_unkillable_task() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_kill_rekillable_task() { use rt::test::*; @@ -716,6 +722,7 @@ fn test_cant_dup_task_builder() { #[cfg(test)] fn block_forever() { let (po, _ch) = stream::<()>(); po.recv(); } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port use rt::test::run_in_newsched_task; @@ -734,6 +741,7 @@ fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port po.recv(); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails use rt::test::run_in_newsched_task; @@ -741,6 +749,7 @@ fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails do spawn_unlinked { fail!(); } } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_sup_no_fail_up() { // child unlinked fails use rt::test::run_in_newsched_task; @@ -750,6 +759,7 @@ fn test_spawn_unlinked_sup_no_fail_up() { // child unlinked fails do 16.times { task::yield(); } } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_sup_fail_down() { use rt::test::run_in_newsched_task; @@ -762,6 +772,7 @@ fn test_spawn_unlinked_sup_fail_down() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_up() { // child fails; parent fails use rt::test::run_in_newsched_task; @@ -782,6 +793,7 @@ fn test_spawn_unlinked_sup_fail_down() { assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_down() { // parent fails; child fails use rt::test::run_in_newsched_task; @@ -798,6 +810,7 @@ fn test_spawn_unlinked_sup_fail_down() { assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails use rt::test::run_in_newsched_task; @@ -810,6 +823,7 @@ fn test_spawn_unlinked_sup_fail_down() { assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails use rt::test::run_in_newsched_task; @@ -822,6 +836,7 @@ fn test_spawn_unlinked_sup_fail_down() { assert!(result.is_err()); } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails use rt::test::run_in_newsched_task; @@ -840,6 +855,7 @@ fn test_spawn_unlinked_sup_fail_down() { // A couple bonus linked failure tests - testing for failure propagation even // when the middle task exits successfully early before kill signals are sent. +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_failure_propagate_grandchild() { use rt::test::run_in_newsched_task; @@ -856,6 +872,7 @@ fn test_spawn_failure_propagate_grandchild() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_failure_propagate_secondborn() { use rt::test::run_in_newsched_task; @@ -872,6 +889,7 @@ fn test_spawn_failure_propagate_secondborn() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_failure_propagate_nephew_or_niece() { use rt::test::run_in_newsched_task; @@ -888,6 +906,7 @@ fn test_spawn_failure_propagate_nephew_or_niece() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_linked_sup_propagate_sibling() { use rt::test::run_in_newsched_task; @@ -1191,6 +1210,7 @@ fn test_avoid_copying_the_body_unlinked() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] #[should_fail] @@ -1226,6 +1246,7 @@ fn test_unkillable() { po.recv(); } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] #[should_fail] @@ -1292,6 +1313,7 @@ fn test_simple_newsched_spawn() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_spawn_watched() { use rt::test::run_in_newsched_task; @@ -1314,6 +1336,7 @@ fn test_spawn_watched() { } } +#[ignore(reason = "linked failure")] #[test] #[ignore(cfg(windows))] fn test_indestructible() { use rt::test::run_in_newsched_task; diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 527b20b0e90..05a17f8539c 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -98,6 +98,7 @@ use rt::sched::Scheduler; use rt::uv::uvio::UvEventLoop; use rt::thread::Thread; +use rt::work_queue::WorkQueue; #[cfg(test)] use task::default_task_opts; #[cfg(test)] use comm; @@ -500,7 +501,7 @@ unsafe fn kill_task(task: TaskHandle) { OldTask(ptr) => rt::rust_task_kill_other(ptr), NewTask(handle) => { let mut handle = handle; - do handle.kill().map_consume |killed_task| { + do handle.kill().map_move |killed_task| { let killed_task = Cell::new(killed_task); do Local::borrow:: |sched| { sched.enqueue_task(killed_task.take()); @@ -682,7 +683,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { // Child task runs this code. // If child data is 'None', the enlist is vacuously successful. - let enlist_success = do child_data.take().map_consume_default(true) |child_data| { + let enlist_success = do child_data.take().map_move_default(true) |child_data| { let child_data = Cell::new(child_data); // :( do Local::borrow:: |me| { let (child_tg, ancestors, is_main) = child_data.take(); @@ -713,19 +714,25 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let mut task = unsafe { if opts.sched.mode != SingleThreaded { if opts.watched { - Task::build_child(child_wrapper) + Task::build_child(opts.stack_size, child_wrapper) } else { - Task::build_root(child_wrapper) + Task::build_root(opts.stack_size, child_wrapper) } } else { // Creating a 1:1 task:thread ... let sched = Local::unsafe_borrow::(); let sched_handle = (*sched).make_handle(); + // Since this is a 1:1 scheduler we create a queue not in + // the stealee set. The run_anything flag is set false + // which will disable stealing. + let work_queue = WorkQueue::new(); + // Create a new scheduler to hold the new task let new_loop = ~UvEventLoop::new(); let mut new_sched = ~Scheduler::new_special(new_loop, - (*sched).work_queue.clone(), + work_queue, + (*sched).work_queues.clone(), (*sched).sleeper_list.clone(), false, Some(sched_handle)); @@ -736,16 +743,16 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { // Pin the new task to the new scheduler let new_task = if opts.watched { - Task::build_homed_child(child_wrapper, Sched(new_sched_handle)) + Task::build_homed_child(opts.stack_size, child_wrapper, Sched(new_sched_handle)) } else { - Task::build_homed_root(child_wrapper, Sched(new_sched_handle)) + Task::build_homed_root(opts.stack_size, child_wrapper, Sched(new_sched_handle)) }; // Create a task that will later be used to join with the new scheduler // thread when it is ready to terminate let (thread_port, thread_chan) = oneshot(); let thread_port_cell = Cell::new(thread_port); - let join_task = do Task::build_child() { + let join_task = do Task::build_child(None) { rtdebug!("running join task"); let thread_port = thread_port_cell.take(); let thread: Thread = thread_port.recv(); @@ -762,8 +769,8 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let mut orig_sched_handle = orig_sched_handle_cell.take(); let join_task = join_task_cell.take(); - let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool) || { - rtdebug!("bootstrapping a 1:1 scheduler"); + let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool, None) || { + rtdebug!("boostrapping a 1:1 scheduler"); }; new_sched.bootstrap(bootstrap_task); @@ -854,7 +861,7 @@ fn make_child_wrapper(child: *rust_task, child_arc: TaskGroupArc, // Even if the below code fails to kick the child off, we must // send Something on the notify channel. - let notifier = notify_chan.map_consume(|c| AutoNotify(c)); + let notifier = notify_chan.map_move(|c| AutoNotify(c)); if enlist_many(OldTask(child), &child_arc, &mut ancestors) { let group = @@mut Taskgroup(child_arc, ancestors, is_main, notifier); diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 6f61d29780f..5ef5526e516 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -271,8 +271,8 @@ fn new() -> TrieNode { impl TrieNode { fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - for idx in range(0u, self.children.len()) { - match self.children[idx] { + for elt in self.children.iter() { + match *elt { Internal(ref x) => if !x.each(|i,t| f(i,t)) { return false }, External(k, ref v) => if !f(&k, v) { return false }, Nothing => () @@ -282,13 +282,14 @@ fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { } fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - do uint::range_rev(self.children.len(), 0) |idx| { - match self.children[idx] { - Internal(ref x) => x.each_reverse(|i,t| f(i,t)), - External(k, ref v) => f(&k, v), - Nothing => true + for elt in self.children.rev_iter() { + match *elt { + Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false }, + External(k, ref v) => if !f(&k, v) { return false }, + Nothing => () } } + true } fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { @@ -539,10 +540,9 @@ fn test_each() { fn test_each_break() { let mut m = TrieMap::new(); - do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { + for x in range(uint::max_value - 10000, uint::max_value).invert() { m.insert(x, x / 2); - true - }; + } let mut n = uint::max_value - 10000; do m.each |k, v| { @@ -580,10 +580,9 @@ fn test_each_reverse() { fn test_each_reverse_break() { let mut m = TrieMap::new(); - do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { + for x in range(uint::max_value - 10000, uint::max_value).invert() { m.insert(x, x / 2); - true - }; + } let mut n = uint::max_value - 1; do m.each_reverse |k, v| { @@ -634,10 +633,9 @@ fn test_iteration() { let last = uint::max_value; let mut map = TrieMap::new(); - do uint::range_rev(last, first) |x| { + for x in range(first, last).invert() { map.insert(x, x / 2); - true - }; + } let mut i = 0; for (k, &v) in map.iter() { diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 1270a80c354..c60edad3dbd 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -317,12 +317,21 @@ fn visit_leave_fn(&self, purity: uint, proto: uint, /// Get the address of the `__morestack` stack growth function. pub fn morestack_addr() -> *(); - /// Adjust a pointer by an offset. + /// Calculates the offset from a pointer. /// /// This is implemented as an intrinsic to avoid converting to and from an /// integer, since the conversion would throw away aliasing information. pub fn offset(dst: *T, offset: int) -> *T; + /// Calculates the offset from a pointer. The offset *must* be in-bounds of + /// the object, or one-byte-past-the-end. An arithmetic overflow is also + /// undefined behaviour. + /// + /// This intrinsic should be preferred over `offset` when the guarantee can + /// be satisfied, to enable better optimization. + #[cfg(not(stage0))] + pub fn offset_inbounds(dst: *T, offset: int) -> *T; + /// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of /// `count` * `size_of::()` and an alignment of `min_align_of::()` pub fn memcpy32(dst: *mut T, src: *T, count: u32); diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index e0c4950b38e..98c0fe254b6 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -135,7 +135,7 @@ pub fn start(main: *u8, argc: int, argv: **c_char, use os; unsafe { - let use_old_rt = os::getenv("RUST_NEWRT").is_none(); + let use_old_rt = os::getenv("RUST_OLDRT").is_some(); if use_old_rt { return rust_start(main as *c_void, argc as c_int, argv, crate_map as *c_void) as int; diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 0259b547ab3..0f6d94bb771 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -849,10 +849,15 @@ fn slice_to(&self, end: uint) -> &'self [T] { fn iter(self) -> VecIterator<'self, T> { unsafe { let p = vec::raw::to_ptr(self); - VecIterator{ptr: p, - end: (p as uint + self.len() * - sys::nonzero_size_of::()) as *T, - lifetime: cast::transmute(p)} + if sys::size_of::() == 0 { + VecIterator{ptr: p, + end: (p as uint + self.len()) as *T, + lifetime: cast::transmute(p)} + } else { + VecIterator{ptr: p, + end: p.offset_inbounds(self.len() as int), + lifetime: cast::transmute(p)} + } } } @@ -1597,8 +1602,8 @@ fn push_all(&mut self, rhs: &[T]) { let new_len = self.len() + rhs.len(); self.reserve(new_len); - for i in range(0u, rhs.len()) { - self.push(unsafe { raw::get(rhs, i) }) + for elt in rhs.iter() { + self.push((*elt).clone()) } } @@ -1826,10 +1831,15 @@ fn mut_split(self, mid: uint) -> (&'self mut [T], &'self mut [T]) { fn mut_iter(self) -> VecMutIterator<'self, T> { unsafe { let p = vec::raw::to_mut_ptr(self); - VecMutIterator{ptr: p, - end: (p as uint + self.len() * - sys::nonzero_size_of::()) as *mut T, - lifetime: cast::transmute(p)} + if sys::size_of::() == 0 { + VecMutIterator{ptr: p, + end: (p as uint + self.len()) as *mut T, + lifetime: cast::transmute(p)} + } else { + VecMutIterator{ptr: p, + end: p.offset_inbounds(self.len() as int), + lifetime: cast::transmute(p)} + } } } @@ -2183,7 +2193,7 @@ fn next(&mut self) -> Option<$elem> { // same pointer. cast::transmute(self.ptr as uint + 1) } else { - self.ptr.offset(1) + self.ptr.offset_inbounds(1) }; Some(cast::transmute(old)) @@ -2215,7 +2225,7 @@ fn next_back(&mut self) -> Option<$elem> { // See above for why 'ptr.offset' isn't used cast::transmute(self.end as uint - 1) } else { - self.end.offset(-1) + self.end.offset_inbounds(-1) }; Some(cast::transmute(self.end)) } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 84e6544f780..ba167fe6714 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -888,7 +888,7 @@ pub fn new_sctable_internal() -> SCTable { // fetch the SCTable from TLS, create one if it doesn't yet exist. pub fn get_sctable() -> @mut SCTable { static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key; - match local_data::get(sctable_key, |k| k.map(|&k| *k)) { + match local_data::get(sctable_key, |k| k.map_move(|k| *k)) { None => { let new_table = @@mut new_sctable_internal(); local_data::set(sctable_key,new_table); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index d39cb2f507c..9edd41152f7 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -83,7 +83,7 @@ fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> { } pub fn name_str_pair(&self) -> Option<(@str, @str)> { - self.value_str().map_consume(|s| (self.name(), s)) + self.value_str().map_move(|s| (self.name(), s)) } } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 8b501436641..2b6cb91a5df 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -192,7 +192,7 @@ fn print_maybe_styled(msg: &str, color: term::attr::Attr) { let stderr = io::stderr(); if stderr.get_type() == io::Screen { - let t = match local_data::get(tls_terminal, |v| v.map_consume(|&k|k)) { + let t = match local_data::get(tls_terminal, |v| v.map_move(|k| *k)) { None => { let t = term::Terminal::new(stderr); let tls = @match t { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6ed5ca3e402..dc20994b49f 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -139,6 +139,8 @@ fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer { ext::tt::macro_rules::add_new_extension)); syntax_expanders.insert(intern(&"fmt"), builtin_normal_tt(ext::fmt::expand_syntax_ext)); + syntax_expanders.insert(intern(&"ifmt"), + builtin_normal_tt(ext::ifmt::expand_syntax_ext)); syntax_expanders.insert( intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); @@ -479,7 +481,7 @@ fn find_in_topmost_frame(&self, key: &K) -> Option<@V> { ConsMapChain(ref map,_) => map }; // strip one layer of indirection off the pointer. - map.find(key).map(|r| {**r}) + map.find(key).map_move(|r| {*r}) } // insert the binding into the top-level map diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index c373a389488..d81dca005b0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -591,7 +591,7 @@ fn expr_match(&self, span: span, arg: @ast::expr, arms: ~[ast::arm]) -> @expr { fn expr_if(&self, span: span, cond: @ast::expr, then: @ast::expr, els: Option<@ast::expr>) -> @ast::expr { - let els = els.map(|x| self.expr_block(self.block_expr(*x))); + let els = els.map_move(|x| self.expr_block(self.block_expr(x))); self.expr(span, ast::expr_if(cond, self.block_expr(then), els)) } diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs index 01dacdfe453..001e9235528 100644 --- a/src/libsyntax/ext/deriving/cmp/totalord.rs +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use ast; use ast::{MetaItem, item, expr}; use codemap::span; use ext::base::ExtCtxt; @@ -40,40 +41,70 @@ pub fn expand_deriving_totalord(cx: @ExtCtxt, } -pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> @expr { +pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> ast::Path { let cnst = match cnst { Less => "Less", Equal => "Equal", Greater => "Greater" }; - cx.expr_path( - cx.path_global(span, - ~[cx.ident_of("std"), - cx.ident_of("cmp"), - cx.ident_of(cnst)])) + cx.path_global(span, + ~[cx.ident_of("std"), + cx.ident_of("cmp"), + cx.ident_of(cnst)]) } pub fn cs_cmp(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr { + let test_id = cx.ident_of("__test"); + let equals_path = ordering_const(cx, span, Equal); + /* + Builds: + + let __test = self_field1.cmp(&other_field2); + if other == ::std::cmp::Equal { + let __test = self_field2.cmp(&other_field2); + if __test == ::std::cmp::Equal { + ... + } else { + __test + } + } else { + __test + } + + FIXME #6449: These `if`s could/should be `match`es. + */ cs_same_method_fold( - // foldr (possibly) nests the matches in lexical_ordering better + // foldr nests the if-elses correctly, leaving the first field + // as the outermost one, and the last as the innermost. false, |cx, span, old, new| { - cx.expr_call_global(span, - ~[cx.ident_of("std"), - cx.ident_of("cmp"), - cx.ident_of("lexical_ordering")], - ~[old, new]) + // let __test = new; + // if __test == ::std::cmp::Equal { + // old + // } else { + // __test + // } + + let assign = cx.stmt_let(span, false, test_id, new); + + let cond = cx.expr_binary(span, ast::eq, + cx.expr_ident(span, test_id), + cx.expr_path(equals_path.clone())); + let if_ = cx.expr_if(span, + cond, + old, Some(cx.expr_ident(span, test_id))); + cx.expr_block(cx.block(span, ~[assign], Some(if_))) }, - ordering_const(cx, span, Equal), + cx.expr_path(equals_path.clone()), |cx, span, list, _| { match list { // an earlier nonmatching variant is Less than a - // later one + // later one. [(self_var, _, _), - (other_var, _, _)] => ordering_const(cx, span, - self_var.cmp(&other_var)), + (other_var, _, _)] => cx.expr_path(ordering_const(cx, span, + self_var.cmp(&other_var))), _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`") } }, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c7020b990bf..a928680e093 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1014,7 +1014,9 @@ pub fn expand_crate(parse_sess: @mut parse::ParseSess, .. *afp}; let f = make_fold(f_pre); - @f.fold_crate(c) + let ret = @f.fold_crate(c); + parse_sess.span_diagnostic.handler().abort_if_errors(); + return ret; } // given a function from idents to idents, produce diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs new file mode 100644 index 00000000000..5cf5fdba632 --- /dev/null +++ b/src/libsyntax/ext/ifmt.rs @@ -0,0 +1,720 @@ +// Copyright 2012 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. + +use ast; +use codemap::{span, respan}; +use ext::base::*; +use ext::base; +use ext::build::AstBuilder; +use rsparse = parse; +use parse::token; + +use std::fmt::parse; +use std::hashmap::{HashMap, HashSet}; +use std::vec; + +#[deriving(Eq)] +enum ArgumentType { + Unknown, + Known(@str), + Unsigned, + String, +} + +struct Context { + ecx: @ExtCtxt, + fmtsp: span, + + // Parsed argument expressions and the types that we've found so far for + // them. + args: ~[@ast::expr], + arg_types: ~[Option], + // Parsed named expressions and the types that we've found for them so far + names: HashMap<@str, @ast::expr>, + name_types: HashMap<@str, ArgumentType>, + + // Collection of the compiled `rt::Piece` structures + pieces: ~[@ast::expr], + name_positions: HashMap<@str, uint>, + method_statics: ~[@ast::item], + + // Updated as arguments are consumed or methods are entered + nest_level: uint, + next_arg: uint, +} + +impl Context { + /// Parses the arguments from the given list of tokens, returning None if + /// there's a parse error so we can continue parsing other fmt! expressions. + fn parse_args(&mut self, sp: span, + tts: &[ast::token_tree]) -> Option<@ast::expr> { + let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(), + self.ecx.cfg(), + tts.to_owned()); + if *p.token == token::EOF { + self.ecx.span_err(sp, "ifmt! expects at least one argument"); + return None; + } + let fmtstr = p.parse_expr(); + let mut named = false; + while *p.token != token::EOF { + if !p.eat(&token::COMMA) { + self.ecx.span_err(sp, "expected token: `,`"); + return None; + } + if named || (token::is_ident(p.token) && + p.look_ahead(1, |t| *t == token::EQ)) { + named = true; + let ident = match *p.token { + token::IDENT(i, _) => { + p.bump(); + i + } + _ if named => { + self.ecx.span_err(*p.span, + "expected ident, positional arguments \ + cannot follow named arguments"); + return None; + } + _ => { + self.ecx.span_err(*p.span, + fmt!("expected ident for named \ + argument, but found `%s`", + p.this_token_to_str())); + return None; + } + }; + let name = self.ecx.str_of(ident); + p.expect(&token::EQ); + let e = p.parse_expr(); + match self.names.find(&name) { + None => {} + Some(prev) => { + self.ecx.span_err(e.span, fmt!("duplicate argument \ + named `%s`", name)); + self.ecx.parse_sess.span_diagnostic.span_note( + prev.span, "previously here"); + loop + } + } + self.names.insert(name, e); + } else { + self.args.push(p.parse_expr()); + self.arg_types.push(None); + } + } + return Some(fmtstr); + } + + /// Verifies one piece of a parse string. All errors are not emitted as + /// fatal so we can continue giving errors about this and possibly other + /// format strings. + fn verify_piece(&mut self, p: &parse::Piece) { + match *p { + parse::String(*) => {} + parse::CurrentArgument => { + if self.nest_level == 0 { + self.ecx.span_err(self.fmtsp, + "`#` reference used with nothing to \ + reference back to"); + } + } + parse::Argument(ref arg) => { + // argument first (it's first in the format string) + let pos = match arg.position { + parse::ArgumentNext => { + let i = self.next_arg; + if self.check_positional_ok() { + self.next_arg += 1; + } + Left(i) + } + parse::ArgumentIs(i) => Left(i), + parse::ArgumentNamed(s) => Right(s.to_managed()), + }; + let ty = if arg.format.ty == "" { + Unknown + } else { Known(arg.format.ty.to_managed()) }; + self.verify_arg_type(pos, ty); + + // width/precision next + self.verify_count(arg.format.width); + self.verify_count(arg.format.precision); + + // and finally the method being applied + match arg.method { + None => {} + Some(ref method) => { self.verify_method(pos, *method); } + } + } + } + } + + fn verify_pieces(&mut self, pieces: &[parse::Piece]) { + for piece in pieces.iter() { + self.verify_piece(piece); + } + } + + fn verify_count(&mut self, c: parse::Count) { + match c { + parse::CountImplied | parse::CountIs(*) => {} + parse::CountIsParam(i) => { + self.verify_arg_type(Left(i), Unsigned); + } + parse::CountIsNextParam => { + if self.check_positional_ok() { + self.verify_arg_type(Left(self.next_arg), Unsigned); + self.next_arg += 1; + } + } + } + } + + fn check_positional_ok(&mut self) -> bool { + if self.nest_level != 0 { + self.ecx.span_err(self.fmtsp, "cannot use implicit positional \ + arguments nested inside methods"); + false + } else { + true + } + } + + fn verify_method(&mut self, pos: Either, m: &parse::Method) { + self.nest_level += 1; + match *m { + parse::Plural(_, ref arms, ref default) => { + let mut seen_cases = HashSet::new(); + self.verify_arg_type(pos, Unsigned); + for arm in arms.iter() { + if !seen_cases.insert(arm.selector) { + match arm.selector { + Left(name) => { + self.ecx.span_err(self.fmtsp, + fmt!("duplicate selector \ + `%?`", name)); + } + Right(idx) => { + self.ecx.span_err(self.fmtsp, + fmt!("duplicate selector \ + `=%u`", idx)); + } + } + } + self.verify_pieces(arm.result); + } + self.verify_pieces(*default); + } + parse::Select(ref arms, ref default) => { + self.verify_arg_type(pos, String); + let mut seen_cases = HashSet::new(); + for arm in arms.iter() { + if !seen_cases.insert(arm.selector) { + self.ecx.span_err(self.fmtsp, + fmt!("duplicate selector `%s`", + arm.selector)); + } else if arm.selector == "" { + self.ecx.span_err(self.fmtsp, + "empty selector in `select`"); + } + self.verify_pieces(arm.result); + } + self.verify_pieces(*default); + } + } + self.nest_level -= 1; + } + + fn verify_arg_type(&mut self, arg: Either, ty: ArgumentType) { + match arg { + Left(arg) => { + if arg < 0 || self.args.len() <= arg { + let msg = fmt!("invalid reference to argument `%u` (there \ + are %u arguments)", arg, self.args.len()); + self.ecx.span_err(self.fmtsp, msg); + return; + } + self.verify_same(self.args[arg].span, ty, self.arg_types[arg]); + if ty != Unknown || self.arg_types[arg].is_none() { + self.arg_types[arg] = Some(ty); + } + } + + Right(name) => { + let span = match self.names.find(&name) { + Some(e) => e.span, + None => { + let msg = fmt!("There is no argument named `%s`", name); + self.ecx.span_err(self.fmtsp, msg); + return; + } + }; + self.verify_same(span, ty, + self.name_types.find(&name).map(|&x| *x)); + if ty != Unknown || !self.name_types.contains_key(&name) { + self.name_types.insert(name, ty); + } + // Assign this named argument a slot in the arguments array if + // it hasn't already been assigned a slot. + if !self.name_positions.contains_key(&name) { + let slot = self.name_positions.len(); + self.name_positions.insert(name, slot); + } + } + } + } + + /// When we're keeping track of the types that are declared for certain + /// arguments, we assume that `None` means we haven't seen this argument + /// yet, `Some(None)` means that we've seen the argument, but no format was + /// specified, and `Some(Some(x))` means that the argument was declared to + /// have type `x`. + /// + /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true + /// that: `Some(None) == Some(Some(x))` + fn verify_same(&self, sp: span, ty: ArgumentType, + before: Option) { + if ty == Unknown { return } + let cur = match before { + Some(Unknown) | None => return, + Some(t) => t, + }; + if ty == cur { return } + match (cur, ty) { + (Known(cur), Known(ty)) => { + self.ecx.span_err(sp, + fmt!("argument redeclared with type `%s` when \ + it was previously `%s`", ty, cur)); + } + (Known(cur), _) => { + self.ecx.span_err(sp, + fmt!("argument used to format with `%s` was \ + attempted to not be used for formatting", + cur)); + } + (_, Known(ty)) => { + self.ecx.span_err(sp, + fmt!("argument previously used as a format \ + argument attempted to be used as `%s`", + ty)); + } + (_, _) => { + self.ecx.span_err(sp, "argument declared with multiple formats"); + } + } + } + + /// Translate a `parse::Piece` to a static `rt::Piece` + fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::expr { + let sp = self.fmtsp; + let rtpath = |s: &str| { + ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), + self.ecx.ident_of("rt"), self.ecx.ident_of(s)] + }; + let ctpath = |s: &str| { + ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), + self.ecx.ident_of("parse"), self.ecx.ident_of(s)] + }; + let none = || { + let p = self.ecx.path(sp, ~[self.ecx.ident_of("None")]); + self.ecx.expr_path(p) + }; + let some = |e: @ast::expr| { + self.ecx.expr_call_ident(sp, self.ecx.ident_of("Some"), ~[e]) + }; + let trans_count = |c: parse::Count| { + match c { + parse::CountIs(i) => { + self.ecx.expr_call_global(sp, ctpath("CountIs"), + ~[self.ecx.expr_uint(sp, i)]) + } + parse::CountIsParam(i) => { + self.ecx.expr_call_global(sp, ctpath("CountIsParam"), + ~[self.ecx.expr_uint(sp, i)]) + } + parse::CountImplied => { + let path = self.ecx.path_global(sp, ctpath("CountImplied")); + self.ecx.expr_path(path) + } + parse::CountIsNextParam => { + let path = self.ecx.path_global(sp, ctpath("CountIsNextParam")); + self.ecx.expr_path(path) + } + } + }; + let trans_method = |method: &parse::Method| { + let method = match *method { + parse::Select(ref arms, ref default) => { + let arms = arms.iter().transform(|arm| { + let p = self.ecx.path_global(sp, rtpath("SelectArm")); + let result = arm.result.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + let s = arm.selector.to_managed(); + let selector = self.ecx.expr_str(sp, s); + self.ecx.expr_struct(sp, p, ~[ + self.ecx.field_imm(sp, + self.ecx.ident_of("selector"), + selector), + self.ecx.field_imm(sp, self.ecx.ident_of("result"), + self.ecx.expr_vec_slice(sp, result)), + ]) + }).collect(); + let default = default.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + self.ecx.expr_call_global(sp, rtpath("Select"), ~[ + self.ecx.expr_vec_slice(sp, arms), + self.ecx.expr_vec_slice(sp, default), + ]) + } + parse::Plural(offset, ref arms, ref default) => { + let offset = match offset { + Some(i) => { some(self.ecx.expr_uint(sp, i)) } + None => { none() } + }; + let arms = arms.iter().transform(|arm| { + let p = self.ecx.path_global(sp, rtpath("PluralArm")); + let result = arm.result.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + let (lr, selarg) = match arm.selector { + Left(t) => { + let p = ctpath(fmt!("%?", t)); + let p = self.ecx.path_global(sp, p); + (self.ecx.ident_of("Left"), + self.ecx.expr_path(p)) + } + Right(i) => { + (self.ecx.ident_of("Right"), + self.ecx.expr_uint(sp, i)) + } + }; + let selector = self.ecx.expr_call_ident(sp, + lr, ~[selarg]); + self.ecx.expr_struct(sp, p, ~[ + self.ecx.field_imm(sp, + self.ecx.ident_of("selector"), + selector), + self.ecx.field_imm(sp, self.ecx.ident_of("result"), + self.ecx.expr_vec_slice(sp, result)), + ]) + }).collect(); + let default = default.iter().transform(|p| { + self.trans_piece(p) + }).collect(); + self.ecx.expr_call_global(sp, rtpath("Plural"), ~[ + offset, + self.ecx.expr_vec_slice(sp, arms), + self.ecx.expr_vec_slice(sp, default), + ]) + } + }; + let life = self.ecx.lifetime(sp, self.ecx.ident_of("static")); + let ty = self.ecx.ty_path(self.ecx.path_all( + sp, + true, + rtpath("Method"), + Some(life), + ~[] + ), None); + let st = ast::item_static(ty, ast::m_imm, method); + let static_name = self.ecx.ident_of(fmt!("__static_method_%u", + self.method_statics.len())); + let item = self.ecx.item(sp, static_name, ~[], st); + self.method_statics.push(item); + self.ecx.expr_ident(sp, static_name) + }; + + match *piece { + parse::String(s) => { + self.ecx.expr_call_global(sp, rtpath("String"), + ~[self.ecx.expr_str(sp, s.to_managed())]) + } + parse::CurrentArgument => { + let nil = self.ecx.expr_lit(sp, ast::lit_nil); + self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil]) + } + parse::Argument(ref arg) => { + // Translate the position + let pos = match arg.position { + // These two have a direct mapping + parse::ArgumentNext => { + let path = self.ecx.path_global(sp, + rtpath("ArgumentNext")); + self.ecx.expr_path(path) + } + parse::ArgumentIs(i) => { + self.ecx.expr_call_global(sp, rtpath("ArgumentIs"), + ~[self.ecx.expr_uint(sp, i)]) + } + // Named arguments are converted to positional arguments at + // the end of the list of arguments + parse::ArgumentNamed(n) => { + let n = n.to_managed(); + let i = match self.name_positions.find_copy(&n) { + Some(i) => i, + None => 0, // error already emitted elsewhere + }; + let i = i + self.args.len(); + self.ecx.expr_call_global(sp, rtpath("ArgumentIs"), + ~[self.ecx.expr_uint(sp, i)]) + } + }; + + // Translate the format + let fill = match arg.format.fill { Some(c) => c, None => ' ' }; + let fill = self.ecx.expr_lit(sp, ast::lit_int(fill as i64, + ast::ty_char)); + let align = match arg.format.align { + None | Some(parse::AlignLeft) => { + self.ecx.expr_bool(sp, true) + } + Some(parse::AlignRight) => { + self.ecx.expr_bool(sp, false) + } + }; + let flags = self.ecx.expr_uint(sp, arg.format.flags); + let prec = trans_count(arg.format.precision); + let width = trans_count(arg.format.width); + let path = self.ecx.path_global(sp, rtpath("FormatSpec")); + let fmt = self.ecx.expr_struct(sp, path, ~[ + self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill), + self.ecx.field_imm(sp, self.ecx.ident_of("alignleft"), align), + self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags), + self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec), + self.ecx.field_imm(sp, self.ecx.ident_of("width"), width), + ]); + + // Translate the method (if any) + let method = match arg.method { + None => { none() } + Some(ref m) => { + let m = trans_method(*m); + some(self.ecx.expr_addr_of(sp, m)) + } + }; + let path = self.ecx.path_global(sp, rtpath("Argument")); + let s = self.ecx.expr_struct(sp, path, ~[ + self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos), + self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt), + self.ecx.field_imm(sp, self.ecx.ident_of("method"), method), + ]); + self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s]) + } + } + } + + /// Actually builds the expression which the ifmt! block will be expanded + /// to + fn to_expr(&self) -> @ast::expr { + let mut lets = ~[]; + let mut locals = ~[]; + let mut names = vec::from_fn(self.name_positions.len(), |_| None); + + // First, declare all of our methods that are statics + for &method in self.method_statics.iter() { + let decl = respan(self.fmtsp, ast::decl_item(method)); + lets.push(@respan(self.fmtsp, + ast::stmt_decl(@decl, self.ecx.next_id()))); + } + + // Next, build up the static array which will become our precompiled + // format "string" + let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone()); + let ty = ast::ty_fixed_length_vec( + self.ecx.ty_mt( + self.ecx.ty_path(self.ecx.path_all( + self.fmtsp, + true, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("rt"), + self.ecx.ident_of("Piece"), + ], + Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), + ~[] + ), None), + ast::m_imm + ), + self.ecx.expr_uint(self.fmtsp, self.pieces.len()) + ); + let ty = self.ecx.ty(self.fmtsp, ty); + let st = ast::item_static(ty, ast::m_imm, fmt); + let static_name = self.ecx.ident_of("__static_fmtstr"); + let item = self.ecx.item(self.fmtsp, static_name, ~[], st); + let decl = respan(self.fmtsp, ast::decl_item(item)); + lets.push(@respan(self.fmtsp, ast::stmt_decl(@decl, self.ecx.next_id()))); + + // Right now there is a bug such that for the expression: + // foo(bar(&1)) + // the lifetime of `1` doesn't outlast the call to `bar`, so it's not + // vald for the call to `foo`. To work around this all arguments to the + // fmt! string are shoved into locals. + for (i, &e) in self.args.iter().enumerate() { + if self.arg_types[i].is_none() { loop } // error already generated + + let name = self.ecx.ident_of(fmt!("__arg%u", i)); + lets.push(self.ecx.stmt_let(e.span, false, name, e)); + locals.push(self.format_arg(e.span, Left(i), name)); + } + for (&name, &e) in self.names.iter() { + if !self.name_types.contains_key(&name) { loop } + + let lname = self.ecx.ident_of(fmt!("__arg%s", name)); + lets.push(self.ecx.stmt_let(e.span, false, lname, e)); + names[*self.name_positions.get(&name)] = + Some(self.format_arg(e.span, Right(name), lname)); + } + + let args = names.consume_iter().transform(|a| a.unwrap()); + let mut args = locals.consume_iter().chain_(args); + + // Next, build up the actual call to the sprintf function. + let result = self.ecx.expr_call_global(self.fmtsp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("sprintf"), + ], ~[ + self.ecx.expr_ident(self.fmtsp, static_name), + self.ecx.expr_vec(self.fmtsp, args.collect()), + ]); + + // sprintf is unsafe, but we just went through a lot of work to + // validate that our call is save, so inject the unsafe block for the + // user. + let result = self.ecx.expr_block(ast::Block { + view_items: ~[], + stmts: ~[], + expr: Some(result), + id: self.ecx.next_id(), + rules: ast::UnsafeBlock, + span: self.fmtsp, + }); + + self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, Some(result))) + } + + fn format_arg(&self, sp: span, arg: Either, + ident: ast::ident) -> @ast::expr { + let mut ty = match arg { + Left(i) => self.arg_types[i].unwrap(), + Right(s) => *self.name_types.get(&s) + }; + // Default types to '?' if nothing else is specified. + if ty == Unknown { + ty = Known(@"?"); + } + let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident)); + match ty { + Known(tyname) => { + let fmt_trait = match tyname.as_slice() { + "?" => "Poly", + "d" | "i" => "Signed", + "u" => "Unsigned", + "b" => "Bool", + "c" => "Char", + "o" => "Octal", + "x" => "LowerHex", + "X" => "UpperHex", + "s" => "String", + "p" => "Pointer", + _ => { + self.ecx.span_err(sp, fmt!("unknown format trait \ + `%s`", tyname)); + "Dummy" + } + }; + let format_fn = self.ecx.path_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of(fmt_trait), + self.ecx.ident_of("fmt"), + ]); + self.ecx.expr_call_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("argument"), + ], ~[self.ecx.expr_path(format_fn), argptr]) + } + String => { + self.ecx.expr_call_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("argumentstr"), + ], ~[argptr]) + } + Unsigned => { + self.ecx.expr_call_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("argumentuint"), + ], ~[argptr]) + } + Unknown => { fail!() } + } + } +} + +pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span, + tts: &[ast::token_tree]) -> base::MacResult { + let mut cx = Context { + ecx: ecx, + args: ~[], + arg_types: ~[], + names: HashMap::new(), + name_positions: HashMap::new(), + name_types: HashMap::new(), + nest_level: 0, + next_arg: 0, + pieces: ~[], + method_statics: ~[], + fmtsp: sp, + }; + let efmt = match cx.parse_args(sp, tts) { + Some(e) => e, + None => { return MRExpr(ecx.expr_uint(sp, 2)); } + }; + cx.fmtsp = efmt.span; + let fmt = expr_to_str(ecx, efmt, + ~"first argument to ifmt! must be a string literal."); + + let mut err = false; + do parse::parse_error::cond.trap(|m| { + if !err { + err = true; + ecx.span_err(efmt.span, m); + } + }).inside { + for piece in parse::Parser::new(fmt) { + if !err { + cx.verify_piece(&piece); + let piece = cx.trans_piece(&piece); + cx.pieces.push(piece); + } + } + } + if err { return MRExpr(efmt) } + + // Make sure that all arguments were used and all arguments have types. + for (i, ty) in cx.arg_types.iter().enumerate() { + if ty.is_none() { + ecx.span_err(cx.args[i].span, "argument never used"); + } + } + for (name, e) in cx.names.iter() { + if !cx.name_types.contains_key(name) { + ecx.span_err(e.span, "named argument never used"); + } + } + + MRExpr(cx.to_expr()) +} diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 7ffed13940e..0a5bc000720 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -417,7 +417,7 @@ fn noop_fold_stmt(s: &stmt_, fld: @ast_fold) -> Option { fn noop_fold_arm(a: &arm, fld: @ast_fold) -> arm { arm { pats: a.pats.map(|x| fld.fold_pat(*x)), - guard: a.guard.map(|x| fld.fold_expr(*x)), + guard: a.guard.map_move(|x| fld.fold_expr(x)), body: fld.fold_block(&a.body), } } @@ -429,7 +429,7 @@ pub fn noop_fold_pat(p: &pat_, fld: @ast_fold) -> pat_ { pat_ident( binding_mode, fld.fold_path(pth), - sub.map(|x| fld.fold_pat(*x)) + sub.map_move(|x| fld.fold_pat(x)) ) } pat_lit(e) => pat_lit(fld.fold_expr(e)), @@ -459,7 +459,7 @@ pub fn noop_fold_pat(p: &pat_, fld: @ast_fold) -> pat_ { pat_vec(ref before, ref slice, ref after) => { pat_vec( before.map(|x| fld.fold_pat(*x)), - slice.map(|x| fld.fold_pat(*x)), + slice.map_move(|x| fld.fold_pat(x)), after.map(|x| fld.fold_pat(*x)) ) } @@ -551,7 +551,7 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field { expr_if( fld.fold_expr(cond), fld.fold_block(tr), - fl.map(|x| fld.fold_expr(*x)) + fl.map_move(|x| fld.fold_expr(x)) ) } expr_while(cond, ref body) => { @@ -565,7 +565,7 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field { expr_loop(ref body, opt_ident) => { expr_loop( fld.fold_block(body), - opt_ident.map(|x| fld.fold_ident(*x)) + opt_ident.map_move(|x| fld.fold_ident(x)) ) } expr_match(expr, ref arms) => { @@ -608,13 +608,13 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field { expr_path(ref pth) => expr_path(fld.fold_path(pth)), expr_self => expr_self, expr_break(ref opt_ident) => { - expr_break(opt_ident.map(|x| fld.fold_ident(*x))) + expr_break(opt_ident.map_move(|x| fld.fold_ident(x))) } expr_again(ref opt_ident) => { - expr_again(opt_ident.map(|x| fld.fold_ident(*x))) + expr_again(opt_ident.map_move(|x| fld.fold_ident(x))) } expr_ret(ref e) => { - expr_ret(e.map(|x| fld.fold_expr(*x))) + expr_ret(e.map_move(|x| fld.fold_expr(x))) } expr_log(lv, e) => { expr_log( @@ -634,7 +634,7 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field { expr_struct( fld.fold_path(path), fields.map(|x| fold_field(*x)), - maybe_expr.map(|x| fld.fold_expr(*x)) + maybe_expr.map_move(|x| fld.fold_expr(x)) ) }, expr_paren(ex) => expr_paren(fld.fold_expr(ex)) @@ -731,7 +731,7 @@ fn fold_variant_arg_(va: variant_arg, fld: @ast_fold) -> variant_arg { fold_variant_arg(/*bad*/ (*x).clone()) }) } - struct_variant_kind(struct_def) => { + struct_variant_kind(ref struct_def) => { kind = struct_variant_kind(@ast::struct_def { fields: struct_def.fields.iter() .transform(|f| fld.fold_struct_field(*f)).collect(), @@ -776,7 +776,7 @@ fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local { is_mutbl: l.is_mutbl, ty: fld.fold_ty(&l.ty), pat: fld.fold_pat(l.pat), - init: l.init.map(|e| fld.fold_expr(*e)), + init: l.init.map_move(|e| fld.fold_expr(e)), id: fld.new_id(l.id), span: fld.new_span(l.span), } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index ec956f61863..dda5e990221 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -64,6 +64,7 @@ pub enum ObsoleteSyntax { ObsoleteMutWithMultipleBindings, ObsoleteExternVisibility, ObsoleteUnsafeExternFn, + ObsoletePrivVisibility, } impl to_bytes::IterBytes for ObsoleteSyntax { @@ -253,6 +254,10 @@ pub fn obsolete(&self, sp: span, kind: ObsoleteSyntax) { "external functions are always unsafe; remove the `unsafe` \ keyword" ), + ObsoletePrivVisibility => ( + "`priv` not necessary", + "an item without a visibility qualifier is private by default" + ), }; self.report(sp, kind, kind_str, desc); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a0932729930..7d6dce22fb7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -85,7 +85,7 @@ use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl}; use parse::obsolete::{ObsoleteMutWithMultipleBindings}; use parse::obsolete::{ObsoleteExternVisibility, ObsoleteUnsafeExternFn}; -use parse::obsolete::{ParserObsoleteMethods}; +use parse::obsolete::{ParserObsoleteMethods, ObsoletePrivVisibility}; use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; use parse::token::{is_ident_or_path}; use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; @@ -814,7 +814,7 @@ pub fn parse_trait_methods(&self) -> ~[trait_method] { let attrs = p.parse_outer_attributes(); let lo = p.span.lo; - let vis = p.parse_visibility(); + let vis = p.parse_non_priv_visibility(); let pur = p.parse_fn_purity(); // NB: at the moment, trait methods are public by default; this // could change. @@ -1313,7 +1313,7 @@ pub fn parse_bounded_path_with_tps(&self, colons: bool, // If the path might have bounds on it, they should be parsed before // the parameters, e.g. module::TraitName:B1+B2 - before_tps.map_consume(|callback| callback()); + before_tps.map_move(|callback| callback()); // Parse the (obsolete) trailing region parameter, if any, which will // be written "foo/&x" @@ -3608,7 +3608,7 @@ fn parse_method(&self) -> @method { let attrs = self.parse_outer_attributes(); let lo = self.span.lo; - let visa = self.parse_visibility(); + let visa = self.parse_non_priv_visibility(); let pur = self.parse_fn_purity(); let ident = self.parse_ident(); let generics = self.parse_generics(); @@ -3871,6 +3871,18 @@ fn parse_visibility(&self) -> visibility { else { inherited } } + // parse visibility, but emits an obsolete error if it's private + fn parse_non_priv_visibility(&self) -> visibility { + match self.parse_visibility() { + public => public, + inherited => inherited, + private => { + self.obsolete(*self.last_span, ObsoletePrivVisibility); + inherited + } + } + } + fn parse_staticness(&self) -> bool { if self.eat_keyword(keywords::Static) { self.obsolete(*self.last_span, ObsoleteStaticMethod); @@ -4063,7 +4075,7 @@ fn eval_src_mod_from_path(&self, // parse a function declaration from a foreign module fn parse_item_foreign_fn(&self, attrs: ~[Attribute]) -> @foreign_item { let lo = self.span.lo; - let vis = self.parse_visibility(); + let vis = self.parse_non_priv_visibility(); // Parse obsolete purity. let purity = self.parse_fn_purity(); @@ -4443,7 +4455,7 @@ fn parse_item_or_view_item(&self, maybe_whole!(iovi self, nt_item); let lo = self.span.lo; - let visibility = self.parse_visibility(); + let visibility = self.parse_non_priv_visibility(); // must be a view item: if self.eat_keyword(keywords::Use) { @@ -4575,7 +4587,7 @@ fn parse_foreign_item(&self, maybe_whole!(iovi self, nt_item); let lo = self.span.lo; - let visibility = self.parse_visibility(); + let visibility = self.parse_non_priv_visibility(); if (self.is_keyword(keywords::Const) || self.is_keyword(keywords::Static)) { // FOREIGN CONST ITEM diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 39668e5c8b2..fd491c1e890 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -486,7 +486,7 @@ fn mk_fresh_ident_interner() -> @ident_interner { pub fn get_ident_interner() -> @ident_interner { static key: local_data::Key<@@::parse::token::ident_interner> = &local_data::Key; - match local_data::get(key, |k| k.map(|&k| *k)) { + match local_data::get(key, |k| k.map_move(|k| *k)) { Some(interner) => *interner, None => { let interner = mk_fresh_ident_interner(); diff --git a/src/libsyntax/syntax.rs b/src/libsyntax/syntax.rs index e0f5aa848a2..a5feb0483d8 100644 --- a/src/libsyntax/syntax.rs +++ b/src/libsyntax/syntax.rs @@ -73,6 +73,7 @@ pub mod tt { pub mod cfg; pub mod fmt; + pub mod ifmt; pub mod env; pub mod bytes; pub mod concat_idents; diff --git a/src/test/auxiliary/cci_class_5.rs b/src/test/auxiliary/cci_class_5.rs index 7cdfcf64bb9..5b8bebda924 100644 --- a/src/test/auxiliary/cci_class_5.rs +++ b/src/test/auxiliary/cci_class_5.rs @@ -17,7 +17,7 @@ pub struct cat { } impl cat { - priv fn nap(&self) {} + fn nap(&self) {} } pub fn cat(in_x : uint, in_y : int) -> cat { diff --git a/src/test/auxiliary/xcrate_unit_struct.rs b/src/test/auxiliary/xcrate_unit_struct.rs new file mode 100644 index 00000000000..a72bf307e5d --- /dev/null +++ b/src/test/auxiliary/xcrate_unit_struct.rs @@ -0,0 +1,31 @@ +// 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. + +#[crate_type = "lib"]; + +// used by the rpass test + +pub struct Struct; + +pub enum Unit { + Unit, + Argument(Struct) +} + +// used by the cfail test + +pub struct StructWithFields { + foo: int, +} + +pub enum EnumWithVariants { + EnumVariant, + EnumVariantArg(int) +} diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index cf160ca31c6..6475012e009 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -53,24 +53,21 @@ fn descending>(map: &mut M, n_keys: uint) { io::println(" Descending integers:"); do timed("insert") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys).invert() { map.insert(i, i + 1); - true - }; + } } do timed("search") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys).invert() { assert_eq!(map.find(&i).unwrap(), &(i + 1)); - true - }; + } } do timed("remove") { - do uint::range_rev(n_keys, 0) |i| { + for i in range(0, n_keys) { assert!(map.remove(&i)); - true - }; + } } } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 4fbe00622aa..70fe6f706f7 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -59,7 +59,7 @@ pub fn bench_int, { let mut set = f(); do timed(&mut self.random_ints) { - do num_keys.times { + for _ in range(0, num_keys) { set.insert((rng.next() as uint) % rand_cap); } } @@ -103,7 +103,7 @@ pub fn bench_str, { let mut set = f(); do timed(&mut self.random_strings) { - do num_keys.times { + for _ in range(0, num_keys) { let s = uint::to_str(rng.next() as uint); set.insert(s); } diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 19380feea6d..8503b188b2f 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -105,7 +105,7 @@ fn main() { let symbols = [" ", "░", "▒", "▓", "█", "█"]; let mut pixels = [0f32, ..256*256]; let n2d = ~Noise2DContext::new(); - do 100.times { + for _ in range(0, 100u) { for y in range(0, 256) { for x in range(0, 256) { let v = n2d.get( diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs new file mode 100644 index 00000000000..3d38d61bc2e --- /dev/null +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -0,0 +1,82 @@ +// 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 extra; + +use std::task::spawn; +use std::os; +use std::uint; +use std::rt::test::spawntask_later; +use std::cell::Cell; + +// This is a simple bench that creates M pairs of of tasks. These +// tasks ping-pong back and forth over a pair of streams. This is a +// cannonical message-passing benchmark as it heavily strains message +// passing and almost nothing else. + +fn ping_pong_bench(n: uint, m: uint) { + + // Create pairs of tasks that pingpong back and forth. + fn run_pair(n: uint) { + // Create a stream A->B + let (pa,ca) = stream::<()>(); + // Create a stream B->A + let (pb,cb) = stream::<()>(); + + let pa = Cell::new(pa); + let ca = Cell::new(ca); + let pb = Cell::new(pb); + let cb = Cell::new(cb); + + do spawntask_later() || { + let chan = ca.take(); + let port = pb.take(); + do n.times { + chan.send(()); + port.recv(); + } + } + + do spawntask_later() || { + let chan = cb.take(); + let port = pa.take(); + do n.times { + port.recv(); + chan.send(()); + } + } + } + + do m.times { + run_pair(n) + } + +} + + + +fn main() { + + let args = os::args(); + let n = if args.len() == 3 { + uint::from_str(args[1]).unwrap() + } else { + 10000 + }; + + let m = if args.len() == 3 { + uint::from_str(args[2]).unwrap() + } else { + 4 + }; + + ping_pong_bench(n, m); + +} diff --git a/src/test/bench/rt-parfib.rs b/src/test/bench/rt-parfib.rs new file mode 100644 index 00000000000..6669342f511 --- /dev/null +++ b/src/test/bench/rt-parfib.rs @@ -0,0 +1,49 @@ +// 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 extra; + +use std::task::spawn; +use std::os; +use std::uint; +use std::rt::test::spawntask_later; +use std::cell::Cell; +use std::comm::*; + +// A simple implementation of parfib. One subtree is found in a new +// task and communicated over a oneshot pipe, the other is found +// locally. There is no sequential-mode threshold. + +fn parfib(n: uint) -> uint { + if(n == 0 || n == 1) { + return 1; + } + + let (port,chan) = oneshot::(); + let chan = Cell::new(chan); + do spawntask_later { + chan.take().send(parfib(n-1)); + }; + let m2 = parfib(n-2); + return (port.recv() + m2); +} + +fn main() { + + let args = os::args(); + let n = if args.len() == 2 { + uint::from_str(args[1]).unwrap() + } else { + 10 + }; + + parfib(n); + +} diff --git a/src/test/bench/rt-spawn-rate.rs b/src/test/bench/rt-spawn-rate.rs new file mode 100644 index 00000000000..ff578ed70b9 --- /dev/null +++ b/src/test/bench/rt-spawn-rate.rs @@ -0,0 +1,33 @@ +// 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 extra; + +use std::task::spawn; +use std::os; +use std::uint; + +// Very simple spawn rate test. Spawn N tasks that do nothing and +// return. + +fn main() { + + let args = os::args(); + let n = if args.len() == 2 { + uint::from_str(args[1]).unwrap() + } else { + 100000 + }; + + do n.times { + do spawn || {}; + } + +} diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 190ad62d6e1..2b177ccb98f 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -169,7 +169,7 @@ fn rendezvous(nn: uint, set: ~[color]) { let mut creatures_met = 0; // set up meetings... - do nn.times { + for _ in range(0, nn) { let fst_creature: CreatureInfo = from_creatures.recv(); let snd_creature: CreatureInfo = from_creatures.recv(); diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 9d4d31b8969..48372c6d03b 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::from_str::FromStr; use std::os; use std::vec::MutableVector; diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 579b88a7e0e..1f1ce86404b 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::cast::transmute; use std::from_str::FromStr; use std::libc::{FILE, STDOUT_FILENO, c_int, fdopen, fputc, fputs, fwrite, size_t}; @@ -164,7 +166,7 @@ fn make(&mut self, n: uint) { let chars_left = n % LINE_LEN; let mut buf = [0, ..LINE_LEN + 1]; - do lines.times { + for _ in range(0, lines) { for i in range(0u, LINE_LEN) { buf[i] = self.nextc(); } diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 96fd4d7e604..2b5b4ded947 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -54,7 +54,7 @@ fn pack(string: &str) -> Code { fn unpack(&self, frame: i32) -> ~str { let mut key = **self; let mut result = ~[]; - do (frame as uint).times { + for _ in range(0, frame) { result.push(unpack_symbol((key as u8) & 3)); key >>= 2; } @@ -251,7 +251,7 @@ fn generate_frequencies(frequencies: &mut Table, let mut code = Code(0); // Pull first frame. - do (frame as uint).times { + for _ in range(0, frame) { code = code.push_char(input[0]); input = next_char(input); } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index cf43f470e71..72007d2b50a 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::cast::transmute; use std::from_str::FromStr; use std::libc::{STDOUT_FILENO, c_int, fdopen, fputc}; diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 115607d0a99..0f43d5027a9 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -1,3 +1,5 @@ +// xfail-test reading from os::args()[1] - bogus! + use std::from_str::FromStr; use std::os; @@ -79,7 +81,7 @@ struct Planet { fn advance(bodies: &mut [Planet, ..N_BODIES], dt: f64, steps: i32) { let mut d = [ 0.0, ..3 ]; - do (steps as uint).times { + for _ in range(0, steps) { for i in range(0u, N_BODIES) { for j in range(i + 1, N_BODIES) { d[0] = bodies[i].x[0] - bodies[j].x[0]; diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index aef22bc2b84..d7f5e5781e0 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test reading from os::args()[1] - bogus! + use std::from_str::FromStr; use std::os; use std::vec; @@ -56,7 +58,7 @@ fn main() { let mut u = vec::from_elem(n, 1f64); let mut v = u.clone(); let mut tmp = u.clone(); - do 8.times { + for _ in range(0, 8u) { mult_AtAv(u, v, tmp); mult_AtAv(v, u, tmp); } diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index ca539d712fd..114c7e997a2 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -32,7 +32,7 @@ fn main() { } fn run(repeat: int, depth: int) { - do (repeat as uint).times { + for _ in range(0, repeat) { info!("starting %.4f", precise_time_s()); do task::try { recurse_or_fail(depth, None) diff --git a/src/test/bench/task-perf-linked-failure.rs b/src/test/bench/task-perf-linked-failure.rs index 95dd803af81..7788005775f 100644 --- a/src/test/bench/task-perf-linked-failure.rs +++ b/src/test/bench/task-perf-linked-failure.rs @@ -32,16 +32,19 @@ fn grandchild_group(num_tasks: uint) { let (po, ch) = stream(); let ch = SharedChan::new(ch); - do num_tasks.times { + for _ in range(0, num_tasks) { let ch = ch.clone(); - do task::spawn { // linked + let mut t = task::task(); + t.linked(); + t.unwatched(); + do t.spawn { // linked ch.send(()); let (p, _c) = stream::<()>(); p.recv(); // block forever } } error!("Grandchild group getting started"); - do num_tasks.times { + for _ in range(0, num_tasks) { // Make sure all above children are fully spawned; i.e., enlisted in // their ancestor groups. po.recv(); diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs new file mode 100644 index 00000000000..875ad0d2b62 --- /dev/null +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -0,0 +1,74 @@ +// 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 main() { + // bad arguments to the ifmt! call + + ifmt!(); //~ ERROR: expects at least one + ifmt!("{}"); //~ ERROR: invalid reference to argument + + ifmt!("{1}", 1); //~ ERROR: invalid reference to argument `1` + //~^ ERROR: argument never used + ifmt!("{foo}"); //~ ERROR: no argument named `foo` + + ifmt!("{}", 1, 2); //~ ERROR: argument never used + ifmt!("{1}", 1, 2); //~ ERROR: argument never used + ifmt!("{}", 1, foo=2); //~ ERROR: named argument never used + ifmt!("{foo}", 1, foo=2); //~ ERROR: argument never used + ifmt!("", foo=2); //~ ERROR: named argument never used + + ifmt!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s` + ifmt!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s` + + ifmt!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument + ifmt!("#"); //~ ERROR: `#` reference used + ifmt!("", foo=1, 2); //~ ERROR: positional arguments cannot follow + ifmt!("" 1); //~ ERROR: expected token: `,` + ifmt!("", 1 1); //~ ERROR: expected token: `,` + + ifmt!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector + ifmt!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector + ifmt!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector + + // bad syntax of the format string + + ifmt!("{"); //~ ERROR: unterminated format string + ifmt!("\\ "); //~ ERROR: invalid escape + ifmt!("\\"); //~ ERROR: expected an escape + + ifmt!("{0, }", 1); //~ ERROR: expected method + ifmt!("{0, foo}", 1); //~ ERROR: unknown method + ifmt!("{0, select}", "a"); //~ ERROR: must be followed by + ifmt!("{0, plural}", 1); //~ ERROR: must be followed by + + ifmt!("{0, select, a{{}", 1); //~ ERROR: must be terminated + ifmt!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector + ifmt!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other` + ifmt!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer + ifmt!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:` + ifmt!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer + ifmt!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural + ifmt!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other` + ifmt!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other` + + ifmt!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as + ifmt!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to + ifmt!("{0, select, other{}} \ + {0, plural, other{}}", "a"); + //~^ ERROR: declared with multiple formats + + // It should be illegal to use implicit placement arguments nested inside of + // format strings because otherwise the "internal pointer of which argument + // is next" would be invalidated if different cases had different numbers of + // arguments. + ifmt!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit + ifmt!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit + ifmt!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit +} diff --git a/src/test/compile-fail/ifmt-bad-plural.rs b/src/test/compile-fail/ifmt-bad-plural.rs new file mode 100644 index 00000000000..76a697b174f --- /dev/null +++ b/src/test/compile-fail/ifmt-bad-plural.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. + +fn main() { + ifmt!("{0, plural, other{}}", "a"); + //~^ ERROR: expected uint but found +} diff --git a/src/test/compile-fail/ifmt-bad-select.rs b/src/test/compile-fail/ifmt-bad-select.rs new file mode 100644 index 00000000000..abe3b6ed65a --- /dev/null +++ b/src/test/compile-fail/ifmt-bad-select.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. + +fn main() { + ifmt!("{0, select, other{}}", 2); + //~^ ERROR: expected &str but found integral +} diff --git a/src/test/compile-fail/ifmt-unimpl.rs b/src/test/compile-fail/ifmt-unimpl.rs new file mode 100644 index 00000000000..427f5ea562c --- /dev/null +++ b/src/test/compile-fail/ifmt-unimpl.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. + +fn main() { + ifmt!("{:d}", "3"); + //~^ ERROR: failed to find an implementation of trait std::fmt::Signed +} diff --git a/src/test/compile-fail/ifmt-unknown-trait.rs b/src/test/compile-fail/ifmt-unknown-trait.rs new file mode 100644 index 00000000000..85556f9501a --- /dev/null +++ b/src/test/compile-fail/ifmt-unknown-trait.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. + +fn main() { + ifmt!("{:notimplemented}", "3"); + //~^ ERROR: unknown format trait `notimplemented` +} diff --git a/src/test/compile-fail/issue-3763.rs b/src/test/compile-fail/issue-3763.rs index 9647d412d2c..7097615b87e 100644 --- a/src/test/compile-fail/issue-3763.rs +++ b/src/test/compile-fail/issue-3763.rs @@ -16,7 +16,7 @@ pub fn MyStruct () -> MyStruct { MyStruct {priv_field: 4} } impl MyStruct { - priv fn happyfun(&self) {} + fn happyfun(&self) {} } } diff --git a/src/test/compile-fail/issue-3993-3.rs b/src/test/compile-fail/issue-3993-3.rs index ccda6f158ed..cab999f621d 100644 --- a/src/test/compile-fail/issue-3993-3.rs +++ b/src/test/compile-fail/issue-3993-3.rs @@ -12,8 +12,8 @@ //~^ ERROR unresolved import: found `fly` in `zoo` but it is private mod zoo { - priv type fly = (); - priv fn fly() {} + type fly = (); + fn fly() {} } diff --git a/src/test/compile-fail/issue-3993.rs b/src/test/compile-fail/issue-3993.rs index 450ea023bcb..53a56ad2774 100644 --- a/src/test/compile-fail/issue-3993.rs +++ b/src/test/compile-fail/issue-3993.rs @@ -12,7 +12,7 @@ //~^ ERROR unresolved import: found `fly` in `zoo` but it is private mod zoo { - priv fn fly() {} + fn fly() {} } diff --git a/src/test/compile-fail/private-impl-method.rs b/src/test/compile-fail/private-impl-method.rs index 26b7d73ab2a..42da53e9890 100644 --- a/src/test/compile-fail/private-impl-method.rs +++ b/src/test/compile-fail/private-impl-method.rs @@ -14,7 +14,7 @@ pub struct Foo { } impl Foo { - priv fn foo(&self) {} + fn foo(&self) {} } } diff --git a/src/test/compile-fail/private-item-simple.rs b/src/test/compile-fail/private-item-simple.rs index 8776739db2d..a31d0030f67 100644 --- a/src/test/compile-fail/private-item-simple.rs +++ b/src/test/compile-fail/private-item-simple.rs @@ -9,7 +9,7 @@ // except according to those terms. mod a { - priv fn f() {} + fn f() {} } fn main() { diff --git a/src/test/compile-fail/private-method.rs b/src/test/compile-fail/private-method.rs index 1cde50cc15e..85822765595 100644 --- a/src/test/compile-fail/private-method.rs +++ b/src/test/compile-fail/private-method.rs @@ -18,7 +18,7 @@ pub struct cat { } impl cat { - priv fn nap(&self) {} + fn nap(&self) {} } pub fn cat(in_x : uint, in_y : int) -> cat { diff --git a/src/test/compile-fail/xcrate-unit-struct.rs b/src/test/compile-fail/xcrate-unit-struct.rs new file mode 100644 index 00000000000..e71a0f05dff --- /dev/null +++ b/src/test/compile-fail/xcrate-unit-struct.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:xcrate_unit_struct.rs + +// Make sure that when we have cross-crate unit structs we don't accidentally +// make values out of cross-crate structs that aren't unit. + +extern mod xcrate_unit_struct; + +fn main() { + let _ = xcrate_unit_struct::StructWithFields; //~ ERROR: unresolved name + let _ = xcrate_unit_struct::Struct; +} diff --git a/src/test/debug-info/option-like-enum.rs b/src/test/debug-info/option-like-enum.rs index 6d3b157d63e..3bf3507faba 100644 --- a/src/test/debug-info/option-like-enum.rs +++ b/src/test/debug-info/option-like-enum.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 +// xfail-test broken in newrt? // compile-flags:-Z extra-debug-info // debugger:break zzz diff --git a/src/test/run-fail/assert-eq-macro-fail b/src/test/run-fail/assert-eq-macro-fail new file mode 100755 index 00000000000..2841756d4a0 Binary files /dev/null and b/src/test/run-fail/assert-eq-macro-fail differ diff --git a/src/test/run-fail/extern-fail.rs b/src/test/run-fail/extern-fail.rs index a281e986364..a65db3ee515 100644 --- a/src/test/run-fail/extern-fail.rs +++ b/src/test/run-fail/extern-fail.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // error-pattern:explicit failure // Testing that runtime failure doesn't cause callbacks to abort abnormally. // Instead the failure will be delivered after the callbacks return. diff --git a/src/test/run-fail/linked-failure.rs b/src/test/run-fail/linked-failure.rs index 41a9d7ddcea..52dfb8aef13 100644 --- a/src/test/run-fail/linked-failure.rs +++ b/src/test/run-fail/linked-failure.rs @@ -10,6 +10,7 @@ // except according to those terms. +// xfail-test linked failure // error-pattern:1 == 2 extern mod extra; diff --git a/src/test/run-fail/linked-failure2.rs b/src/test/run-fail/linked-failure2.rs index 0269e395986..d4049f6753e 100644 --- a/src/test/run-fail/linked-failure2.rs +++ b/src/test/run-fail/linked-failure2.rs @@ -10,6 +10,7 @@ // except according to those terms. +// xfail-test linked failure // error-pattern:fail use std::comm; diff --git a/src/test/run-fail/linked-failure3.rs b/src/test/run-fail/linked-failure3.rs index 1203f74322f..f40eae20bc0 100644 --- a/src/test/run-fail/linked-failure3.rs +++ b/src/test/run-fail/linked-failure3.rs @@ -10,6 +10,7 @@ // except according to those terms. +// xfail-test linked failure // error-pattern:fail use std::comm; diff --git a/src/test/run-fail/linked-failure4.rs b/src/test/run-fail/linked-failure4.rs index 766b43f211f..94e41f1ae68 100644 --- a/src/test/run-fail/linked-failure4.rs +++ b/src/test/run-fail/linked-failure4.rs @@ -9,6 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // error-pattern:1 == 2 use std::comm; diff --git a/src/test/run-fail/spawnfail.rs b/src/test/run-fail/spawnfail.rs index de085a6f3ad..12dab8e25b7 100644 --- a/src/test/run-fail/spawnfail.rs +++ b/src/test/run-fail/spawnfail.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 // error-pattern:explicit extern mod extra; diff --git a/src/test/run-fail/task-comm-recv-block.rs b/src/test/run-fail/task-comm-recv-block.rs index 8302b96ca3e..bd51ce38ec0 100644 --- a/src/test/run-fail/task-comm-recv-block.rs +++ b/src/test/run-fail/task-comm-recv-block.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // error-pattern:goodfail use std::comm; diff --git a/src/test/run-pass/class-cast-to-trait-multiple-types.rs b/src/test/run-pass/class-cast-to-trait-multiple-types.rs index a5d7ba2c1aa..a134ffe49fd 100644 --- a/src/test/run-pass/class-cast-to-trait-multiple-types.rs +++ b/src/test/run-pass/class-cast-to-trait-multiple-types.rs @@ -21,7 +21,7 @@ struct dog { } impl dog { - priv fn bark(&self) -> int { + fn bark(&self) -> int { info!("Woof %u %d", *self.barks, *self.volume); *self.barks += 1u; if *self.barks % 3u == 0u { diff --git a/src/test/run-pass/class-impl-parameterized-trait.rs b/src/test/run-pass/class-impl-parameterized-trait.rs deleted file mode 100644 index 93e9eac1dd9..00000000000 --- a/src/test/run-pass/class-impl-parameterized-trait.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2012 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 FIXME #7307 -// xfail-fast - -extern mod extra; -use extra::oldmap::*; - -class cat : map { - priv { - // Yes, you can have negative meows - let mut meows : int; - fn meow() { - self.meows += 1; - error!("Meow %d", self.meows); - if self.meows % 5 == 0 { - self.how_hungry += 1; - } - } - } - - let mut how_hungry : int; - let name : str; - - new(in_x : int, in_y : int, in_name: str) - { self.meows = in_x; self.how_hungry = in_y; self.name = in_name; } - - fn speak() { self.meow(); } - - fn eat() -> bool { - if self.how_hungry > 0 { - error!("OM NOM NOM"); - self.how_hungry -= 2; - return true; - } - else { - error!("Not hungry!"); - return false; - } - } - - fn size() -> uint { self.meows as uint } - fn insert(+k: int, +v: bool) -> bool { - if v { self.meows += k; } else { self.meows -= k; }; - true - } - fn contains_key(&&k: int) -> bool { k <= self.meows } - fn get(&&k:int) -> bool { k <= self.meows } - fn [](&&k:int) -> bool { k <= self.meows } - fn find(&&k:int) -> Option { Some(self.get(k)) } - fn remove(&&k:int) -> Option { self.meows -= k; Some(true) } - fn each(f: &fn(&&int, &&bool) -> bool) { - let mut n = num::abs(self.meows); - while n > 0 { - if !f(n, true) { break; } - n -= 1; - } - } - fn each_key(&&f: &fn(&&int) -> bool) { - for self.each |k, _v| { if !f(k) { break; } again;}; - } - fn each_value(&&f: &fn(&&bool) -> bool) { - for self.each |_k, v| { if !f(v) { break; } again;}; - } - fn clear() { } -} - -pub fn main() { - let nyan : cat = cat(0, 2, "nyan"); - for _ in range(1u, 5u) { nyan.speak(); } - // cat returns true if uint input is greater than - // the number of meows so far - assert!((nyan.get(1))); - assert!((!nyan.get(10))); -} diff --git a/src/test/run-pass/class-implements-multiple-traits.rs b/src/test/run-pass/class-implements-multiple-traits.rs deleted file mode 100644 index 4fccc45a753..00000000000 --- a/src/test/run-pass/class-implements-multiple-traits.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2012 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 FIXME #7305 - -extern mod extra; -use extra::oldmap::*; -use vec::*; -use dvec::{dvec, extensions}; - -enum furniture { chair, couch, bed } -enum body_part { finger, toe, nose, ear } - -trait noisy { - fn speak() -> int; -} - -trait scratchy { - fn scratch() -> Option; -} - -trait bitey { - fn bite() -> body_part; -} - -fn vec_includes(xs: ~[T], x: T) -> bool { - for each(xs) |y| { if y == x { return true; }} - return false; -} - -// vtables other than the 1st one don't seem to work -class cat : noisy, scratchy, bitey { - priv { - let meows : @mut uint; - let scratched : dvec; - let bite_counts : hashmap; - - fn meow() -> uint { - info!("Meow: %u", *self.meows); - *self.meows += 1u; - if *self.meows % 5u == 0u { - *self.how_hungry += 1; - } - *self.meows - } - } - - let how_hungry : @mut int; - let name : str; - - new(in_x : uint, in_y : int, in_name: str) - { self.meows = @mut in_x; self.how_hungry = @mut in_y; - self.name = in_name; self.scratched = dvec(); - let hsher: hashfn = |p| int::hash(p as int); - let eqer : eqfn = |p, q| p == q; - let t : hashmap = - hashmap::(hsher, eqer); - self.bite_counts = t; - do iter(~[finger, toe, nose, ear]) |p| { - self.bite_counts.insert(p, 0u); - }; - } - - fn speak() -> int { self.meow() as int } - fn meow_count() -> uint { *self.meows } - fn scratch() -> Option { - let all = ~[chair, couch, bed]; - log(error, self.scratched); - let mut rslt = None; - for each(all) |thing| { if !self.scratched.contains(thing) { - self.scratched.push(thing); - return Some(thing); }} - rslt - } - fn bite() -> body_part { - error!("In bite()"); - let all = ~[toe, nose, ear]; - let mut min = finger; - do iter(all) |next| { - info!("min = %?", min); - if self.bite_counts.get(next) < self.bite_counts.get(min) { - min = next; - }}; - self.bite_counts.insert(min, self.bite_counts.get(min) + 1u); - info!("Bit %?", min); - min - } -} - -fn annoy_neighbors(critter: T) { - for i in range(0u, 10u) { - let what = critter.speak(); - info!("%u %d", i, what); - } -} - -fn bite_everything(critter: T) -> bool { - let mut left : ~[body_part] = ~[finger, toe, nose, ear]; - while left.len() > 0u { - let part = critter.bite(); - info!("%? %?", left, part); - if vec_includes(left, part) { - left = vec::filter(left, |p| p != part ); - } - else { - return false; - } - } - true -} - -fn scratched_something(critter: T) -> bool { - option::is_some(critter.scratch()) -} - -pub fn main() { - let nyan : cat = cat(0u, 2, "nyan"); - annoy_neighbors(nyan as noisy); - assert_eq!(nyan.meow_count(), 10u); - assert!((bite_everything(nyan as bitey))); - assert!((scratched_something(nyan as scratchy))); -} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs index 7fb01006844..b31f0eab2e2 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs @@ -12,10 +12,4 @@ fn sum_imm(y: &[int]) -> int { sum(y) } -/* FIXME #7304 -fn sum_const(y: &const [int]) -> int { - sum(y) -} -*/ - pub fn main() {} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs index 590cd825020..8a271a4d65f 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -1,9 +1,3 @@ -/* FIXME #7302 -fn foo(v: &const [uint]) -> ~[uint] { - v.to_owned() -} -*/ - fn bar(v: &mut [uint]) -> ~[uint] { v.to_owned() } @@ -14,7 +8,6 @@ fn bip(v: &[uint]) -> ~[uint] { pub fn main() { let mut the_vec = ~[1u, 2, 3, 100]; -// assert_eq!(the_vec.clone(), foo(the_vec)); assert_eq!(the_vec.clone(), bar(the_vec)); assert_eq!(the_vec.clone(), bip(the_vec)); } diff --git a/src/test/run-pass/deriving-cmp-shortcircuit.rs b/src/test/run-pass/deriving-cmp-shortcircuit.rs new file mode 100644 index 00000000000..7f5c78cf602 --- /dev/null +++ b/src/test/run-pass/deriving-cmp-shortcircuit.rs @@ -0,0 +1,46 @@ +// 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. + +// check that the derived impls for the comparison traits shortcircuit +// where possible, by having a type that fails when compared as the +// second element, so this passes iff the instances shortcircuit. + +pub struct FailCmp; +impl Eq for FailCmp { + fn eq(&self, _: &FailCmp) -> bool { fail!("eq") } +} + +impl Ord for FailCmp { + fn lt(&self, _: &FailCmp) -> bool { fail!("lt") } +} + +impl TotalEq for FailCmp { + fn equals(&self, _: &FailCmp) -> bool { fail!("equals") } +} + +impl TotalOrd for FailCmp { + fn cmp(&self, _: &FailCmp) -> Ordering { fail!("cmp") } +} + +#[deriving(Eq,Ord,TotalEq,TotalOrd)] +struct ShortCircuit { + x: int, + y: FailCmp +} + +fn main() { + let a = ShortCircuit { x: 1, y: FailCmp }; + let b = ShortCircuit { x: 2, y: FailCmp }; + + assert!(a != b); + assert!(a < b); + assert!(!a.equals(&b)); + assert_eq!(a.cmp(&b), ::std::cmp::Less); +} diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs new file mode 100644 index 00000000000..562642453fd --- /dev/null +++ b/src/test/run-pass/ifmt.rs @@ -0,0 +1,71 @@ +// 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. + +use std::fmt; + +struct A; +struct B; + +#[fmt="foo"] +impl fmt::Signed for A { + fn fmt(_: &A, f: &mut fmt::Formatter) { f.buf.write("aloha".as_bytes()); } +} +impl fmt::Signed for B { + fn fmt(_: &B, f: &mut fmt::Formatter) { f.buf.write("adios".as_bytes()); } +} + +pub fn main() { + fn t(a: ~str, b: &str) { assert_eq!(a, b.to_owned()); } + + // Make sure there's a poly formatter that takes anything + t(ifmt!("{}", 1), "1"); + t(ifmt!("{}", A), "{}"); + t(ifmt!("{}", ()), "()"); + t(ifmt!("{}", @(~1, "foo")), "@(~1, \"foo\")"); + + // Various edge cases without formats + t(ifmt!(""), ""); + t(ifmt!("hello"), "hello"); + t(ifmt!("hello \\{"), "hello {"); + + // At least exercise all the formats + t(ifmt!("{:b}", true), "true"); + t(ifmt!("{:c}", '☃'), "☃"); + t(ifmt!("{:d}", 10), "10"); + t(ifmt!("{:i}", 10), "10"); + t(ifmt!("{:u}", 10u), "10"); + t(ifmt!("{:o}", 10u), "12"); + t(ifmt!("{:x}", 10u), "a"); + t(ifmt!("{:X}", 10u), "A"); + t(ifmt!("{:s}", "foo"), "foo"); + t(ifmt!("{:p}", 0x1234 as *int), "0x1234"); + t(ifmt!("{:p}", 0x1234 as *mut int), "0x1234"); + t(ifmt!("{:d}", A), "aloha"); + t(ifmt!("{:d}", B), "adios"); + t(ifmt!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t(ifmt!("{1} {0}", 0, 1), "1 0"); + t(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1"); + t(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0"); + t(ifmt!("{} {0:s}", "a"), "a a"); + t(ifmt!("{} {0}", "a"), "\"a\" \"a\""); + + // Methods should probably work + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0"); + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1"); + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2"); + t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc"); + t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd"); + t(ifmt!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab"); + t(ifmt!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb"); +} + diff --git a/src/test/run-pass/issue-3168.rs b/src/test/run-pass/issue-3168.rs index 609849bffb4..f4e2a9f36a0 100644 --- a/src/test/run-pass/issue-3168.rs +++ b/src/test/run-pass/issue-3168.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-fast // xfail-win32 #7999 diff --git a/src/test/run-pass/lots-a-fail.rs b/src/test/run-pass/lots-a-fail.rs index cec0a7a756c..13296131236 100644 --- a/src/test/run-pass/lots-a-fail.rs +++ b/src/test/run-pass/lots-a-fail.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 leaks extern mod extra; diff --git a/src/test/run-pass/num-range-rev.rs b/src/test/run-pass/num-range-rev.rs index 5eecbe7e03a..ea7d4a651f7 100644 --- a/src/test/run-pass/num-range-rev.rs +++ b/src/test/run-pass/num-range-rev.rs @@ -20,11 +20,11 @@ fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool { } fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool { - uint::range_rev(hi, lo, it) + range(lo, hi).invert().advance(it) } fn int_range_rev(hi: int, lo: int, it: &fn(int) -> bool) -> bool { - int::range_rev(hi, lo, it) + range(lo, hi).invert().advance(it) } fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool { diff --git a/src/test/run-pass/rcvr-borrowed-to-region.rs b/src/test/run-pass/rcvr-borrowed-to-region.rs index 28396119596..46819027dad 100644 --- a/src/test/run-pass/rcvr-borrowed-to-region.rs +++ b/src/test/run-pass/rcvr-borrowed-to-region.rs @@ -12,7 +12,9 @@ trait get { fn get(self) -> int; } -// FIXME #7302: Note: impl on a slice +// Note: impl on a slice; we're checking that the pointers below +// correctly get borrowed to `&`. (similar to impling for `int`, with +// `&self` instead of `self`.) impl<'self> get for &'self int { fn get(self) -> int { return *self; @@ -34,11 +36,6 @@ pub fn main() { info!("y=%d", y); assert_eq!(y, 6); - let x = ~6; - let y = x.get(); - info!("y=%d", y); - assert_eq!(y, 6); - let x = &6; let y = x.get(); info!("y=%d", y); diff --git a/src/test/run-pass/send-iloop.rs b/src/test/run-pass/send-iloop.rs index e27f35d1851..a647e5849a8 100644 --- a/src/test/run-pass/send-iloop.rs +++ b/src/test/run-pass/send-iloop.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 extern mod extra; diff --git a/src/test/run-pass/task-killjoin-rsrc.rs b/src/test/run-pass/task-killjoin-rsrc.rs index c811e548f3f..b8a1aa433a3 100644 --- a/src/test/run-pass/task-killjoin-rsrc.rs +++ b/src/test/run-pass/task-killjoin-rsrc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 // A port of task-killjoin to use a class with a dtor to manage diff --git a/src/test/run-pass/task-killjoin.rs b/src/test/run-pass/task-killjoin.rs index c94e00251d2..5382ac77671 100644 --- a/src/test/run-pass/task-killjoin.rs +++ b/src/test/run-pass/task-killjoin.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test linked failure // xfail-win32 // Create a task that is supervised by another task, join the supervised task diff --git a/src/test/run-pass/xcrate-unit-struct.rs b/src/test/run-pass/xcrate-unit-struct.rs new file mode 100644 index 00000000000..d6522231f65 --- /dev/null +++ b/src/test/run-pass/xcrate-unit-struct.rs @@ -0,0 +1,35 @@ +// 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. + +// aux-build:xcrate_unit_struct.rs +// xfail-fast +extern mod xcrate_unit_struct; + +use std::util; + +static s1: xcrate_unit_struct::Struct = xcrate_unit_struct::Struct; +static s2: xcrate_unit_struct::Unit = xcrate_unit_struct::Unit; +static s3: xcrate_unit_struct::Unit = + xcrate_unit_struct::Argument(xcrate_unit_struct::Struct); +static s4: xcrate_unit_struct::Unit = xcrate_unit_struct::Argument(s1); + +fn f1(_: xcrate_unit_struct::Struct) {} +fn f2(_: xcrate_unit_struct::Unit) {} + +fn main() { + f1(xcrate_unit_struct::Struct); + f2(xcrate_unit_struct::Unit); + f2(xcrate_unit_struct::Argument(xcrate_unit_struct::Struct)); + + f1(s1); + f2(s2); + f2(s3); + f2(s4); +}