]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #8350 : dim-an/rust/fix-struct-match, r=pcwalton
authorbors <bors@rust-lang.org>
Fri, 9 Aug 2013 04:41:05 +0000 (21:41 -0700)
committerbors <bors@rust-lang.org>
Fri, 9 Aug 2013 04:41:05 +0000 (21:41 -0700)
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.

188 files changed:
Makefile.in
doc/tutorial-ffi.md
doc/tutorial-tasks.md
doc/tutorial.md
src/compiletest/compiletest.rs
src/compiletest/runtest.rs
src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang
src/libextra/arc.rs
src/libextra/base64.rs
src/libextra/bitv.rs
src/libextra/dlist.rs
src/libextra/extra.rs
src/libextra/fileinput.rs
src/libextra/flate.rs
src/libextra/future.rs
src/libextra/getopts.rs
src/libextra/hex.rs [new file with mode: 0644]
src/libextra/iter.rs [deleted file]
src/libextra/num/bigint.rs
src/libextra/ringbuf.rs
src/libextra/smallintmap.rs
src/libextra/sort.rs
src/libextra/stats.rs
src/libextra/sync.rs
src/libextra/term.rs
src/libextra/terminfo/parm.rs
src/libextra/test.rs
src/libextra/time.rs
src/libextra/treemap.rs
src/libextra/workcache.rs
src/librust/rust.rs
src/librustc/driver/driver.rs
src/librustc/front/config.rs
src/librustc/lib/llvm.rs
src/librustc/metadata/cstore.rs
src/librustc/metadata/decoder.rs
src/librustc/middle/borrowck/check_loans.rs
src/librustc/middle/borrowck/mod.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/dataflow.rs
src/librustc/middle/graph.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/liveness.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/cabi_mips.rs
src/librustc/middle/trans/cabi_x86_64.rs
src/librustc/middle/trans/common.rs
src/librustc/middle/trans/context.rs
src/librustc/middle/trans/foreign.rs
src/librustc/middle/trans/meth.rs
src/librustc/middle/trans/type_use.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionmanip.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/collect.rs
src/librustc/middle/typeck/infer/mod.rs
src/librustc/middle/typeck/infer/region_inference/mod.rs
src/librustc/middle/typeck/rscope.rs
src/librustc/rustc.rs
src/librustdoc/config.rs
src/librustdoc/doc.rs
src/librustdoc/extract.rs
src/librustdoc/fold.rs
src/librustdoc/markdown_pass.rs
src/librustdoc/prune_private_pass.rs
src/librustdoc/sort_item_type_pass.rs
src/librustdoc/tystr_pass.rs
src/librusti/rusti.rs
src/librustpkg/tests.rs
src/libstd/at_vec.rs
src/libstd/borrow.rs
src/libstd/cmp.rs
src/libstd/comm.rs
src/libstd/either.rs
src/libstd/fmt/mod.rs [new file with mode: 0644]
src/libstd/fmt/parse.rs [new file with mode: 0644]
src/libstd/fmt/rt.rs [new file with mode: 0644]
src/libstd/hashmap.rs
src/libstd/iterator.rs
src/libstd/local_data.rs
src/libstd/managed.rs
src/libstd/num/f64.rs
src/libstd/num/int_macros.rs
src/libstd/num/num.rs
src/libstd/num/strconv.rs
src/libstd/num/uint_macros.rs
src/libstd/option.rs
src/libstd/os.rs
src/libstd/owned.rs
src/libstd/prelude.rs
src/libstd/ptr.rs
src/libstd/rand.rs
src/libstd/result.rs
src/libstd/rt/comm.rs
src/libstd/rt/env.rs
src/libstd/rt/io/mem.rs
src/libstd/rt/io/net/ip.rs
src/libstd/rt/kill.rs
src/libstd/rt/local.rs
src/libstd/rt/mod.rs
src/libstd/rt/sched.rs
src/libstd/rt/select.rs
src/libstd/rt/task.rs
src/libstd/rt/test.rs
src/libstd/rt/uv/net.rs
src/libstd/run.rs
src/libstd/std.rs
src/libstd/str.rs
src/libstd/str/ascii.rs
src/libstd/task/mod.rs
src/libstd/task/spawn.rs
src/libstd/trie.rs
src/libstd/unstable/intrinsics.rs
src/libstd/unstable/lang.rs
src/libstd/vec.rs
src/libsyntax/ast_util.rs
src/libsyntax/attr.rs
src/libsyntax/diagnostic.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/deriving/cmp/totalord.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/ifmt.rs [new file with mode: 0644]
src/libsyntax/fold.rs
src/libsyntax/parse/obsolete.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/syntax.rs
src/test/auxiliary/cci_class_5.rs
src/test/auxiliary/xcrate_unit_struct.rs [new file with mode: 0644]
src/test/bench/core-map.rs
src/test/bench/core-set.rs
src/test/bench/noise.rs
src/test/bench/rt-messaging-ping-pong.rs [new file with mode: 0644]
src/test/bench/rt-parfib.rs [new file with mode: 0644]
src/test/bench/rt-spawn-rate.rs [new file with mode: 0644]
src/test/bench/shootout-chameneos-redux.rs
src/test/bench/shootout-fannkuch-redux.rs
src/test/bench/shootout-fasta-redux.rs
src/test/bench/shootout-k-nucleotide.rs
src/test/bench/shootout-mandelbrot.rs
src/test/bench/shootout-nbody.rs
src/test/bench/shootout-spectralnorm.rs
src/test/bench/task-perf-alloc-unwind.rs
src/test/bench/task-perf-linked-failure.rs
src/test/compile-fail/ifmt-bad-arg.rs [new file with mode: 0644]
src/test/compile-fail/ifmt-bad-plural.rs [new file with mode: 0644]
src/test/compile-fail/ifmt-bad-select.rs [new file with mode: 0644]
src/test/compile-fail/ifmt-unimpl.rs [new file with mode: 0644]
src/test/compile-fail/ifmt-unknown-trait.rs [new file with mode: 0644]
src/test/compile-fail/issue-3763.rs
src/test/compile-fail/issue-3993-3.rs
src/test/compile-fail/issue-3993.rs
src/test/compile-fail/private-impl-method.rs
src/test/compile-fail/private-item-simple.rs
src/test/compile-fail/private-method.rs
src/test/compile-fail/xcrate-unit-struct.rs [new file with mode: 0644]
src/test/debug-info/option-like-enum.rs
src/test/run-fail/assert-eq-macro-fail [new file with mode: 0755]
src/test/run-fail/extern-fail.rs
src/test/run-fail/linked-failure.rs
src/test/run-fail/linked-failure2.rs
src/test/run-fail/linked-failure3.rs
src/test/run-fail/linked-failure4.rs
src/test/run-fail/spawnfail.rs
src/test/run-fail/task-comm-recv-block.rs
src/test/run-pass/class-cast-to-trait-multiple-types.rs
src/test/run-pass/class-impl-parameterized-trait.rs [deleted file]
src/test/run-pass/class-implements-multiple-traits.rs [deleted file]
src/test/run-pass/coerce-reborrow-imm-vec-arg.rs
src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs
src/test/run-pass/deriving-cmp-shortcircuit.rs [new file with mode: 0644]
src/test/run-pass/ifmt.rs [new file with mode: 0644]
src/test/run-pass/issue-3168.rs
src/test/run-pass/lots-a-fail.rs
src/test/run-pass/num-range-rev.rs
src/test/run-pass/rcvr-borrowed-to-region.rs
src/test/run-pass/send-iloop.rs
src/test/run-pass/task-killjoin-rsrc.rs
src/test/run-pass/task-killjoin.rs
src/test/run-pass/xcrate-unit-struct.rs [new file with mode: 0644]

index d78176e569999ad162b0f03b0f59c0522454f744..a9a41a073d03366291a404187213a417cd608de6 100644 (file)
@@ -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
 
index 047b57e56a61aa950e1e93228a217c72a9608c6d..d1aa793e5fc1b83d0501baea22f99cbf542b66c8 100644 (file)
@@ -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
index b2ef624d1ac3e6b1c90cb17a3c9dbfecfafe7637..d190c332e6633ade92d1a9ac944aef034caca1db 100644 (file)
@@ -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<int>, Chan<int>) = 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::<int> {
 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;
index a5f2001eaf515b2f624d101c8860f60f0f0f9f39..40e276ae04a158e92ecaf413bfbb12734f7d42a2 100644 (file)
@@ -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) { ... }
     }
 
index 4e4261e8b2bbda8b8dd19dfc6a3d3704a941dd6d..4262aba9a85946c2f30ee8dc6bdfa4be5dc75d5e 100644 (file)
@@ -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"),
index 5c1cc78d678f361f1525226fbcb8e1bf7f807f34..9c176b504b2ee61fcb7440687d91412b294f0fad 100644 (file)
@@ -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);
index a6415beab36cf7a9f62c08541291ed0939376c5f..b1180098bd2acc3ce7ed618888548b25de7acb9c 100644 (file)
@@ -50,6 +50,7 @@
                <keyword>for</keyword>
                <keyword>if</keyword>
                <keyword>impl</keyword>
+               <keyword>in</keyword>
                <keyword>let</keyword>
                <keyword>log</keyword>
                <keyword>loop</keyword>
index cb4468f48ecb1473b65c3805ff15e22a2581c69f..69203b753cdc5c0159bf7be6e83092771b2e721a 100644 (file)
@@ -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);
index 550b891a4db16c22356d20be362f55ca7b06e6cb..b4431004bd74cff0dd38693c5093d4b590c479be 100644 (file)
@@ -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();
         }
index 6dedd9ee4dd266f95da9777cf67bd7737e8edc18..20a3add3e7b3d64e7a79d6b03daaa9af6ada9ec3 100644 (file)
@@ -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;
             }
         }
index 75487a44f2600253e4d50091eaccc1517c299e06..b0839a55795b760ccf0efdaba987c0d9edf6df35 100644 (file)
@@ -164,7 +164,7 @@ fn push_front_node(&mut self, mut new_head: ~Node<T>) {
     /// Remove the first Node and return it, or None if the list is empty
     #[inline]
     fn pop_front_node(&mut self) -> Option<~Node<T>> {
-        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<T>) {
     /// Remove the last Node and return it, or None if the list is empty
     #[inline]
     fn pop_back_node(&mut self) -> Option<~Node<T>> {
-        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<T> {
-        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<T> {
-        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<T> {
     /// 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)
     }
 }
 
index 58929778a59e20f6afb11105979894b771755207..44781a1fd19b632f0794802ae3d9ee8cbae167ce 100644 (file)
 pub mod semver;
 pub mod fileinput;
 pub mod flate;
+pub mod hex;
 
 #[cfg(unicode)]
 mod unicode;
index 7a36b25eac57a53b32bb877c21e69bb60e97c109..14b02688cffcfc1481ff2927727b3ab5c0981a1e 100644 (file)
@@ -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<Path>],
+    files: ~[Option<Path>],
     /**
     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) => {
index 8024b9aa1596cddbbff48c25cf0a11ae78f06334..ed8cbcd0663f3f9874afc34e6ef92a827c76eeae 100644 (file)
@@ -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);
+    }
 }
index 7d2a0658969ab7cc62ea8273fc0c5d3d85c61432..cc65c49d73a9c2b569619591a145df84c8036d3f 100644 (file)
@@ -46,7 +46,7 @@ impl<A> Drop for Future<A> {
     fn drop(&self) {}
 }
 
-priv enum FutureState<A> {
+enum FutureState<A> {
     Pending(~fn() -> A),
     Evaluating,
     Forced(A)
index 15aac8ef47c9e660dd59ac98ab0e947f0951b1c9..1b65528923a100c16a5c50108447d92dd1a637e1 100644 (file)
@@ -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<uint> {
-    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 (file)
index 0000000..d5345cb
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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 (file)
index 7fd47fd..0000000
+++ /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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*! 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<T> {
-    /// 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<T>(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<T>(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<T>(predicate: &fn(&T) -> bool,
-               iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
-    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<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
-    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<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
-    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<T, U>(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<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
- *     fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
- * }
- * ~~~
- */
-#[inline]
-pub fn fold_ref<T, U>(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<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
-    fold_ref(Zero::zero::<T>(), 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<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
-    fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
-}
-
-impl<T> FromIter<T> 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);
-    }
-}
index bced00902c95f5abdcc62dee20adb3b42f14d372..0c8701bd0b515b1db16a6dc7dc5f0b958cdb0558 100644 (file)
@@ -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<int>) {
-            let ans = ans.map(|&n| IntConvertible::from_int::<BigInt>(n));
+            let ans = ans.map_move(|n| IntConvertible::from_int::<BigInt>(n));
             assert_eq!(FromStrRadix::from_str_radix(s, 10), ans);
         }
         check("10", Some(10));
index 9833bd5d1cbf2cebe758fe7213832681d2bba76c..da8089250b34587a24cd3191031c87c286b40f1d 100644 (file)
@@ -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<uint> = seq.collect();
         for (i, &x) in deq.iter().enumerate() {
             assert_eq!(2*i, x);
index 3f62317eb8908ca7b083f91b7edfee1e0b08af3c..a601270e8ece16c80c27031c966ed22b69578daa 100644 (file)
@@ -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<T> {
 impl<V> Container for SmallIntMap<V> {
     /// 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<V> SmallIntMap<V> {
     /// Create an empty SmallIntMap
     pub fn new() -> SmallIntMap<V> { 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))
         })
     }
 }
index 8090dd26ef20a88e79de83dc632eee747feae6b0..daafdbc37182d581a8fc82c4c36ab2939f70daa2 100644 (file)
@@ -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;
index 68d5af43688a241f9ff827ff6ebe31253f3a1976..881d931fe0acc21749287991d5826564c8ded3c8 100644 (file)
@@ -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<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
+    let mut map = hashmap::HashMap::new::<U, uint>();
+    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)]
index 63e371899a9bdbf8ed6c34ed4dbca5ec09eac33f..4172c715adb96309701da1228c37f66eb4f492b9 100644 (file)
@@ -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;
index 1cfb4f4afa6277b6df7b3b64b4c570fe070b720a..d0412b8954db2abc963e43f87979ca96503709c8 100644 (file)
@@ -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<Terminal, ~str> {
         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 }
index b619e0f33b644663bb43ba781c3688411f3f1679..0929575ee9e70bc1eb089e56b0d248d0f70f360c 100644 (file)
@@ -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 {
index e87be1462267468dc8cc3b6772c41b191da6895e..761cb1bd76f929198e5011cd8595f3840fe30996 100644 (file)
@@ -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,
index efc3dc87adc00f02887a3980fb20c7931cae69f6..f6a5fd98234b58aabab5898bdc13b9137c500ee3 100644 (file)
@@ -254,7 +254,7 @@ pub fn rfc3339(&self) -> ~str {
     }
 }
 
-priv fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> {
+fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> {
     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);
index 487ad050e78643bf5bd759c7180d88a8375dd05c..4d898dfb2b4f082d6d8be4cee9562785b3e5db72 100644 (file)
@@ -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<K, V> {
 
 impl<K: Eq + TotalOrd, V: Eq> Eq for TreeMap<K, V> {
     fn eq(&self, other: &TreeMap<K, V>) -> 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<K, V>) -> bool { !self.eq(other) }
 }
 
 // Lexicographical comparison
 fn lt<K: Ord + TotalOrd, V: Ord>(a: &TreeMap<K, V>,
                                  b: &TreeMap<K, V>) -> 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<K: Ord + TotalOrd, V: Ord> Ord for TreeMap<K, V> {
@@ -151,36 +134,11 @@ impl<K: TotalOrd, V> TreeMap<K, V> {
     /// Create an empty TreeMap
     pub fn new() -> TreeMap<K, V> { 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<uint>) {
@@ -301,6 +272,25 @@ fn size_hint(&self) -> (uint, Option<uint>) {
     }
 }
 
+/// 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<uint>) {
+        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<uint>) {
 }
 
 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<T>) -> 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<T>) -> 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<T>, 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<T>)
+        -> 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<T>)
+        -> 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<T>) -> 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<A, T> {
+    priv iter: T,
+    priv focus: Option<A>,
+}
 
-    /// Visit the values (in-order) representing the symmetric difference
-    pub fn symmetric_difference(&self, other: &TreeSet<T>,
-                            f: &fn(&T) -> bool) -> bool {
-        let mut x = self.iter();
-        let mut y = other.iter();
+impl<A, T: Iterator<A>> Focus<A, T> {
+    fn new(mut it: T) -> Focus<A, T> {
+        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<T>, 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<T>, 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<K, V> {
     }
 }
 
-fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>,
-                            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<K, V>>,
-                                    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<K, V>>,
                                      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([], [], []);
index 0256519abb7e835c257cd29943140cfdfa4aeb42..b4ba8acae476974cff76b27e2945718900e12350 100644 (file)
@@ -221,7 +221,7 @@ fn digest<T:Encodable<json::Encoder>>(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"))),
index 1ac8146bb589aab17141eddb25a67090331fe0d4..010486cdf855c7747df7c33c46362d3b1cd69f95 100644 (file)
@@ -130,7 +130,7 @@ fn rustc_help() {
 fn find_cmd(command_string: &str) -> Option<Command> {
     do COMMANDS.iter().find_ |command| {
         command.cmd == command_string
-    }.map_consume(|x| *x)
+    }.map_move(|x| *x)
 }
 
 fn cmd_help(args: &[~str]) -> ValidUsage {
index c3c100a89f1357fc6f021907b7284cfe1041e4df..28c7df4b33a869e7f999d59db95d931ac637b18a 100644 (file)
@@ -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");
index d8b59d579c8154ece425d0be7d5f0d0c7c28afbd..d6584846655d2db01bc28f9cbfdabfcc699a7ce8 100644 (file)
@@ -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,
index 356cdaf754eebe7b199bf20870b46568e552d317..90db3f8edb0a6eec5ba033ecafd0d6d57190262d 100644 (file)
@@ -2159,7 +2159,7 @@ pub fn find_name<'r>(&'r self, ty: &Type) -> Option<&'r str> {
     }
 
     pub fn find_type(&self, s: &str) -> Option<Type> {
-        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.
index 33623a40cfb2ac6a1f34b2b743b892dfb454444a..a5f541412ded9b84715b777e58f1c4aabdc093eb 100644 (file)
@@ -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<ast::CrateNum> {
-    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)]
index c3097d1aa66577c85ff5d71324ccf208e85c4c6c..8d3571260184b679ec621756110ac3230e021c0c 100644 (file)
@@ -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<ast::def_id> {
-    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<ty::region_variance> {
-    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)
     }
 }
index c3bb2000447f7fe6ae8f17694282738d72753b04..88e168db5584f7baabcd24290976f35e9a92cfb5 100644 (file)
@@ -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);
             }
         }
index 3db90ed5d74948981544249b1e153be66905128b..d410021063c238496b76f4ce94ce296d7468a7b6 100644 (file)
@@ -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) |
index 77e81709a03d73370f51043a5a45ba9bc08840c4..3b56764f2fcad1afb0f38f41df22a46f744d794c 100644 (file)
@@ -493,9 +493,9 @@ pub fn compare_lit_exprs(tcx: middle::ty::ctxt, a: &expr, b: &expr) -> Option<in
 }
 
 pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: &expr, b: &expr) -> Option<bool> {
-    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<bool> {
-    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)
 }
index 008add975d490abf8193c37c184fa7e49fdd55a2..46b6d2214ae49dac47703d4c1de09fe3bb957171 100644 (file)
@@ -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
index 28d24b169ca4ab187752b60505645de2dc7f3cfc..46394454d006f80e8f3d84cc2b58cc8c7b4cf1e2 100644 (file)
@@ -187,12 +187,12 @@ pub fn next_adjacent(&self, edge: EdgeIndex, dir: Direction) -> EdgeIndex {
 
     pub fn each_node(&self, f: &fn(NodeIndex, &Node<N>) -> 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<E>) -> 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,
index 0dfad430f4d656389ecb175cf347e41c67f510ad..42bc435a58a944c48c30bf1b914a4a677c82784f 100644 (file)
@@ -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)
 
index 0387f344796e26b4f9c58cd05edabe2571262e2d..b39616304906bb4a02a4936c74091446bff12a57 100644 (file)
@@ -607,9 +607,9 @@ pub fn variable_from_path(&self, expr: &expr) -> Option<Variable> {
         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<Variable> {
         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(
index 2d121209118f8dc28bb8ac69ec3eb6063035cce2..4da22be4428e271f60b8de66ad1da2f1c440a853 100644 (file)
@@ -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<ast::NodeId> {
         //! 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)
index 625dcd5d9cc49d1a5adb75fea9bd225e150c1cff..f55fdd22c9a9f8bcd91889887db598a33fc367da 100644 (file)
@@ -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
                     }
index 2efed8f36d7fff216b0f26bbefc0e1f3ed5acff2..db8a86fe948dff3d38bb9fafcbd811ef2e0d9219 100644 (file)
@@ -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
index fe1c288d1773f3e3e7125a1055de9358d99ca7bb..f5fb68a70578c2fcf60536019877e5f00e07d236 100644 (file)
@@ -159,7 +159,7 @@ fn struct_ty(ty: Type,
              padding: Option<Type>,
              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));
index 530e1ff8e5baa77a22b51e4eaaf4e9ce8cf6d4eb..dd24ec3ff1ac198222cecf77cb54afb0b97cfa1d 100644 (file)
@@ -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;
         }
     }
 
index f303e7b82759769696c95b0c9856d28c89cf0341..240696ec1908b5a706b5b1da79ef34308b87bf8f 100644 (file)
@@ -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<typeck::vtable_res> {
     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)
index 802163583d6a1dacb8ee552cbf392403f5d7ca27..56ba1ae1694b6684f3a02681c69318032d7abb36 100644 (file)
@@ -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!")
 }
 
index 5153296337daed25055c7751d7d680c61abc37f5..b1e600b9d7376f5466d53ba06a500a948fe8e90d 100644 (file)
@@ -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),
index b67d88c07e1e6207dae5da20f96ed72150f33ff7..9be01ef1db94f639da751f44bb3ed3ef253e31bd 100644 (file)
@@ -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,
               })
index 42d5527ee43bc39bced200bcb0eed0737d7e792f..f25bf011f5d062f56c2130bb570bc725dc40e3d8 100644 (file)
@@ -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);
     }
 }
 
index a53bdff85f9dc2cb4903f2ef47d67b2b69969ce0..849c35cdd2c038eec2662fbf09c77466a2edcfb0 100644 (file)
@@ -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<ast::def_id> {
-    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<ast::def_id> {
         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<t, ~str> {
-    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<t, ~str> {
-    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")
     }
 }
index 53853e4fe1a78be01dedd8e7e1256cb521214e7b..750bd506f3e48583a66c7740b1aeb1806dba6d57 100644 (file)
@@ -621,9 +621,9 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:region_scope + Clone + 'static>(
         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));
 
index 7caed39060159bd2c1d321c9466a1a9b20ba5a1d..d8a9350e695d70404f3250bb904ab818d0eebb49 100644 (file)
@@ -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",
index e1e7d10db0abd5ba07481b5a9d505e08f8221319..ae0a95688ed20dfef1b5c1607283f9518d0cd8b3 100644 (file)
@@ -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);
             }
         }
 
index ea8a11fc7b3821b425f4ee3fac59c6927a712bb6..da0e219310fde2b64b3f325b892d7cd5d028acc5 100644 (file)
@@ -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,
                ~[
index 2685055bd84aa6083376511dd2c9098f780ef84a..cb4827104b6275e7f63506060f1146cac7430ec1 100644 (file)
@@ -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);
index abb97f0d1c7b9d7ed10c1a8cc4b532fa4dacad51..700d96727eae2f9a0f3700e0a9f4c91b09c379df 100644 (file)
@@ -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.
 
index bc8de29b78bcd54d30c4bdd4511ebbfb2bde8d6b..c3df0d06f83dd5bd78499100c1b9093f962e8e45 100644 (file)
@@ -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);
index 2bef2c08bb22d983e3fa5ea398f981b44bfed85a..907a076b1a1efce000e622877195440379157c62 100644 (file)
@@ -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 = {
index 854ee835cc7dce534006f1787ea4eb07d52ce212..7fa7daf614901006d54b2cc334c962752007d925 100644 (file)
@@ -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)),
index 63503f3e6b6c6c94d0039003747647204fc360c7..91b6a4ce3bce3820b8c26eeece0d95338d548c76 100644 (file)
@@ -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),
                     _ => ()
                 }
index bbcf42b1c5d321b600eb4a1be6fa0f7411990c5b..c9e2b8dd37b9dfb02d6a3fdc83bccc19ea0b9cfa 100644 (file)
@@ -215,7 +215,7 @@ fn named_region(&self, span: span, id: ast::ident)
 pub struct type_rscope(Option<RegionParameterization>);
 
 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 {
index 46414a7a5e23e0cc13e0e886d94db7c872a2c20c..5bc22db0ca1a76700fc93d12394c72ed7d0699d0 100644 (file)
@@ -136,7 +136,7 @@ pub fn usage(argv0: &str) {
 
 pub fn describe_warnings() {
     use extra::sort::Sort;
-    printfln!("
+    println("
 Available lint options:
     -W <foo>           Warn about <foo>
     -A <foo>           Allow <foo>
@@ -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::<pp_mode>(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
index d387bbea592d36374231a4e59a4572d00d177fef..3598eb7c0fb9b217d8af908ae888c112567382b1 100644 (file)
@@ -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()
index d24fd1f5bfe54fb59cc90ecb61fc482976938154..aba7ea1f0d753f807e7b30021f2f9724ce942533 100644 (file)
@@ -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<Index>
 }
 
-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(),
index f849cfade9bdafe89ac7553793abb528c14b9027..2cab62296a4ddbdec2d051013ee1dde305bca2fd 100644 (file)
@@ -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]
index ad0dabdc3a4b5437ddab8519bc620a1107a91150..589232f6e2f2f3cc447c2df44d5c770f8e0b6bf3 100644 (file)
@@ -21,7 +21,7 @@ pub struct Fold<T> {
     fold_mod: FoldMod<T>,
     fold_nmod: FoldNmod<T>,
     fold_fn: FoldFn<T>,
-    fold_const: FoldConst<T>,
+    fold_static: FoldStatic<T>,
     fold_enum: FoldEnum<T>,
     fold_trait: FoldTrait<T>,
     fold_impl: FoldImpl<T>,
@@ -39,7 +39,7 @@ fn clone(&self) -> Fold<T> {
             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<T> {
 type FoldMod<T> = @fn(fold: &Fold<T>, doc: doc::ModDoc) -> doc::ModDoc;
 type FoldNmod<T> = @fn(fold: &Fold<T>, doc: doc::NmodDoc) -> doc::NmodDoc;
 type FoldFn<T> = @fn(fold: &Fold<T>, doc: doc::FnDoc) -> doc::FnDoc;
-type FoldConst<T> = @fn(fold: &Fold<T>, doc: doc::ConstDoc) -> doc::ConstDoc;
+type FoldStatic<T> = @fn(fold: &Fold<T>, doc: doc::StaticDoc) -> doc::StaticDoc;
 type FoldEnum<T> = @fn(fold: &Fold<T>, doc: doc::EnumDoc) -> doc::EnumDoc;
 type FoldTrait<T> = @fn(fold: &Fold<T>, doc: doc::TraitDoc) -> doc::TraitDoc;
 type FoldImpl<T> = @fn(fold: &Fold<T>, doc: doc::ImplDoc) -> doc::ImplDoc;
@@ -73,7 +73,7 @@ fn mk_fold<T>(
     fold_mod: FoldMod<T>,
     fold_nmod: FoldNmod<T>,
     fold_fn: FoldFn<T>,
-    fold_const: FoldConst<T>,
+    fold_static: FoldStatic<T>,
     fold_enum: FoldEnum<T>,
     fold_trait: FoldTrait<T>,
     fold_impl: FoldImpl<T>,
@@ -88,7 +88,7 @@ fn mk_fold<T>(
         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<T:Clone>(ctxt: T) -> Fold<T> {
         |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<T:Clone>(ctxt: T) -> Fold<T> {
         |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<T:Clone>(ctxt: T) -> Fold<T> {
         |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<T>(fold: &Fold<T>, 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<T>(
     }
 }
 
-pub fn default_seq_fold_const<T>(
+pub fn default_seq_fold_static<T>(
     fold: &Fold<T>,
-    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, ~"");
index 85c360a9e0dfdd8153fa103791365235687276f3..7d07b4864f50e1b57e6a50e11ef4a51bd0bd238d 100644 (file)
@@ -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;");
index 6f3f91f3c65de66cb9de4f1bcd82146115ee371b..3e380732d0f07e87aaff5be5ff76c00d5813524d 100644 (file)
@@ -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);
     }
index 366cc83df2728846f30a8b30c289ac7170e59e49..ba8f37601fd567cb64660ccaf81a635f0c6d995d 100644 (file)
@@ -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");
index 684b4e9d198d4d1551e05418143f33b469485ce5..196c7e892a8801e90b04cceb87eac3d3af7d636e 100644 (file)
@@ -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<astsrv::Srv>,
-    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]
index 5d5518997f68f0252ab8e9c3acd276c0dec417f7..bb863df33481211c354b5519fb223be17cd2fe06 100644 (file)
@@ -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();
index 828be5dce12788c0495e010b1d784f15f5127ed0..9fea866212975c02335ead93f4121c9fb039d5ee 100644 (file)
@@ -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);
index a84f3137bbd5bfb022f2ac93a6982472c59b3064..f2470bed7329e81fcd1df99620574989f49607cd 100644 (file)
@@ -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<T:Clone>(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());
         }
     }
 }
index 9e3a3a28fe8cef39aa0b1020d8f548ca37e8cfdb..6c3d4c5f1fbeab4d82dec81c1543d7e4eeb74939 100644 (file)
@@ -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) }
+}
index 43a632562b2b71b5db5697bf28a051c62df185e5..b66f89e83415e1b22ad0a575f950f1855057460f 100644 (file)
@@ -153,7 +153,6 @@ pub fn cmp2<A:TotalOrd,B:TotalOrd>(
 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 {
index 4356f1143da4668f760d598aa1f1d34d50cb8120..a4de10f8c7760aae76a718f95a74aab086ad7cb7 100644 (file)
@@ -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<T: Send>() -> (server::Oneshot<T>, client::Oneshot<T>) {
@@ -341,7 +341,7 @@ pub struct __Buffer<T> {
         #[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<T: Send>(pipe: Oneshot<T>, x_0: T) ->
@@ -489,7 +489,7 @@ pub fn try_send_one<T: Send>(chan: ChanOne<T>, data: T) -> bool {
 
     #[allow(non_camel_case_types)]
     pub mod streamp {
-        priv use std::kinds::Send;
+        use std::kinds::Send;
 
         pub fn init<T: Send>() -> (server::Open<T>, client::Open<T>) {
             pub use std::pipes::HasBuffer;
@@ -501,7 +501,7 @@ pub enum Open<T> { pub data(T, server::Open<T>), }
 
         #[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<T: Send>(pipe: Open<T>, x_0: T) ->
index cfaef550c6fa74072a2cd64413d7aa612e044a06..bb74d9b3ec484b1d3730d74837359891c03ef4f5 100644 (file)
@@ -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<L, R> {
     Left(L),
     Right(R)
diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs
new file mode 100644 (file)
index 0000000..2b8807b
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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<uint>,
+    /// Optionally specified precision for numeric types
+    precision: Option<uint>,
+
+    /// 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<uint>, 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<T> 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<T> 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 (file)
index 0000000..673ea1d
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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<char>,
+    /// Optionally specified alignment
+    align: Option<Alignment>,
+    /// 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<uint>, ~[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<PluralKeyword, uint>,
+    /// 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<Piece<'self>> for Parser<'self> {
+    fn next(&mut self) -> Option<Piece<'self>> {
+        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<uint> {
+        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:*<abcd}", ~[Argument(Argument {
+            position: ArgumentIs(3),
+            format: FormatSpec {
+                fill: Some('*'),
+                align: Some(AlignLeft),
+                flags: 0,
+                precision: CountImplied,
+                width: CountImplied,
+                ty: "abcd",
+            },
+            method: None,
+        })]);
+    }
+    #[test]
+    fn format_counts() {
+        same("{:10s}", ~[Argument(Argument {
+            position: ArgumentNext,
+            format: FormatSpec {
+                fill: None,
+                align: None,
+                flags: 0,
+                precision: CountImplied,
+                width: CountIs(10),
+                ty: "s",
+            },
+            method: None,
+        })]);
+        same("{:10$.10s}", ~[Argument(Argument {
+            position: ArgumentNext,
+            format: FormatSpec {
+                fill: None,
+                align: None,
+                flags: 0,
+                precision: CountIs(10),
+                width: CountIsParam(10),
+                ty: "s",
+            },
+            method: None,
+        })]);
+        same("{:.*s}", ~[Argument(Argument {
+            position: ArgumentNext,
+            format: FormatSpec {
+                fill: None,
+                align: None,
+                flags: 0,
+                precision: CountIsNextParam,
+                width: CountImplied,
+                ty: "s",
+            },
+            method: None,
+        })]);
+        same("{:.10$s}", ~[Argument(Argument {
+            position: ArgumentNext,
+            format: FormatSpec {
+                fill: None,
+                align: None,
+                flags: 0,
+                precision: CountIsParam(10),
+                width: CountImplied,
+                ty: "s",
+            },
+            method: None,
+        })]);
+    }
+    #[test]
+    fn format_flags() {
+        same("{:-}", ~[Argument(Argument {
+            position: ArgumentNext,
+            format: FormatSpec {
+                fill: None,
+                align: None,
+                flags: (1 << FlagSignMinus as uint),
+                precision: CountImplied,
+                width: CountImplied,
+                ty: "",
+            },
+            method: None,
+        })]);
+        same("{:+#}", ~[Argument(Argument {
+            position: ArgumentNext,
+            format: FormatSpec {
+                fill: None,
+                align: None,
+                flags: (1 << FlagSignPlus as uint) | (1 << FlagAlternate as uint),
+                precision: CountImplied,
+                width: CountImplied,
+                ty: "",
+            },
+            method: None,
+        })]);
+    }
+    #[test]
+    fn format_mixture() {
+        same("abcd {3:a} efg", ~[String("abcd "), Argument(Argument {
+            position: ArgumentIs(3),
+            format: FormatSpec {
+                fill: None,
+                align: None,
+                flags: 0,
+                precision: CountImplied,
+                width: CountImplied,
+                ty: "a",
+            },
+            method: None,
+        }), String(" efg")]);
+    }
+
+    #[test]
+    fn select_simple() {
+        same("{, select, other { haha } }", ~[Argument(Argument{
+            position: ArgumentNext,
+            format: fmtdflt(),
+            method: Some(~Select(~[], ~[String(" haha ")]))
+        })]);
+        same("{1, select, other { haha } }", ~[Argument(Argument{
+            position: ArgumentIs(1),
+            format: fmtdflt(),
+            method: Some(~Select(~[], ~[String(" haha ")]))
+        })]);
+        same("{1, select, other {#} }", ~[Argument(Argument{
+            position: ArgumentIs(1),
+            format: fmtdflt(),
+            method: Some(~Select(~[], ~[CurrentArgument]))
+        })]);
+        same("{1, select, other {{2, select, other {lol}}} }", ~[Argument(Argument{
+            position: ArgumentIs(1),
+            format: fmtdflt(),
+            method: Some(~Select(~[], ~[Argument(Argument{
+                position: ArgumentIs(2),
+                format: fmtdflt(),
+                method: Some(~Select(~[], ~[String("lol")]))
+            })])) // wat
+        })]);
+    }
+
+    #[test]
+    fn select_cases() {
+        same("{1, select, a{1} b{2} c{3} other{4} }", ~[Argument(Argument{
+            position: ArgumentIs(1),
+            format: fmtdflt(),
+            method: Some(~Select(~[
+                SelectArm{ selector: "a", result: ~[String("1")] },
+                SelectArm{ selector: "b", result: ~[String("2")] },
+                SelectArm{ selector: "c", result: ~[String("3")] },
+            ], ~[String("4")]))
+        })]);
+    }
+
+    #[test] #[should_fail] fn badselect01() {
+        musterr("{select, }")
+    }
+    #[test] #[should_fail] fn badselect02() {
+        musterr("{1, select}")
+    }
+    #[test] #[should_fail] fn badselect03() {
+        musterr("{1, select, }")
+    }
+    #[test] #[should_fail] fn badselect04() {
+        musterr("{1, select, a {}}")
+    }
+    #[test] #[should_fail] fn badselect05() {
+        musterr("{1, select, other }}")
+    }
+    #[test] #[should_fail] fn badselect06() {
+        musterr("{1, select, other {}")
+    }
+    #[test] #[should_fail] fn badselect07() {
+        musterr("{select, other {}")
+    }
+    #[test] #[should_fail] fn badselect08() {
+        musterr("{1 select, other {}")
+    }
+    #[test] #[should_fail] fn badselect09() {
+        musterr("{:d select, other {}")
+    }
+    #[test] #[should_fail] fn badselect10() {
+        musterr("{1:d select, other {}")
+    }
+
+    #[test]
+    fn plural_simple() {
+        same("{, plural, other { haha } }", ~[Argument(Argument{
+            position: ArgumentNext,
+            format: fmtdflt(),
+            method: Some(~Plural(None, ~[], ~[String(" haha ")]))
+        })]);
+        same("{:, plural, other { haha } }", ~[Argument(Argument{
+            position: ArgumentNext,
+            format: fmtdflt(),
+            method: Some(~Plural(None, ~[], ~[String(" haha ")]))
+        })]);
+        same("{, plural, offset:1 =2{2} =3{3} many{yes} other{haha} }",
+        ~[Argument(Argument{
+            position: ArgumentNext,
+            format: fmtdflt(),
+            method: Some(~Plural(Some(1), ~[
+                PluralArm{ selector: Right(2), result: ~[String("2")] },
+                PluralArm{ selector: Right(3), result: ~[String("3")] },
+                PluralArm{ selector: Left(Many), result: ~[String("yes")] }
+            ], ~[String("haha")]))
+        })]);
+    }
+}
diff --git a/src/libstd/fmt/rt.rs b/src/libstd/fmt/rt.rs
new file mode 100644 (file)
index 0000000..6feb1d7
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! 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<uint>, &'self [PluralArm<'self>], &'self [Piece<'self>]),
+    Select(&'self [SelectArm<'self>], &'self [Piece<'self>]),
+}
+
+pub struct PluralArm<'self> {
+    selector: Either<parse::PluralKeyword, uint>,
+    result: &'self [Piece<'self>],
+}
+
+pub struct SelectArm<'self> {
+    selector: &'self str,
+    result: &'self [Piece<'self>],
+}
index fbc471c0ae05d4b289235134ec8366d040459437..84cba254dcf23599258f50f64fdbfdc1637cff30 100644 (file)
@@ -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<V> {
         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<K:Hash + Eq,V> Mutable for HashMap<K, V> {
     /// 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<K, V> {
 impl<K: Hash + Eq, V: Clone> HashMap<K, V> {
     /// Like `find`, but returns a copy of the value.
     pub fn find_copy(&self, k: &K) -> Option<V> {
-        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.
index 56a0dca56679ccf3a34d89038944614d0c497263..d10a5541e41a683fef643f9c02aa2957abf2a15c 100644 (file)
@@ -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<B>)
     /// ~~~ {.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<B>>(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<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> {
                     Some((y, y_val))
                 }
             }
-        }).map_consume(|(x, _)| x)
+        }).map_move(|(x, _)| x)
     }
 
     #[inline]
@@ -689,7 +689,7 @@ fn min_by<B: Ord>(&mut self, f: &fn(&A) -> B) -> Option<A> {
                     Some((y, y_val))
                 }
             }
-        }).map_consume(|(x, _)| x)
+        }).map_move(|(x, _)| x)
     }
 }
 
@@ -723,7 +723,7 @@ pub trait MultiplicativeIterator<A> {
     /// 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<uint>) {
         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<A, T: RandomAccessIterator<A>, U: RandomAccessIterator<A>> 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<A> {
     fn size_hint(&self) -> (uint, Option<uint>) {
         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<uint>) {
 impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {
     #[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<T> {
 impl<A, T: Iterator<A>> Iterator<A> for Take<T> {
     #[inline]
     fn next(&mut self) -> Option<A> {
-        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<B> {
                     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<B> {
     fn size_hint(&self) -> (uint, Option<uint>) {
         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<B> {
                     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<A> {
     step: A
 }
 
-impl<A> Counter<A> {
-    /// Creates a new counter with the specified start/step
-    #[inline]
-    pub fn new(start: A, step: A) -> Counter<A> {
-        Counter{state: start, step: step}
-    }
+/// Creates a new counter with the specified start/step
+#[inline]
+pub fn count<A>(start: A, step: A) -> Counter<A> {
+    Counter{state: start, step: step}
 }
 
 /// A range of numbers from [0, N)
@@ -1549,7 +1531,7 @@ pub fn range<A: Add<A, A> + Ord + Clone + One>(start: A, stop: A) -> Range<A> {
     Range{state: start, stop: stop, one: One::one()}
 }
 
-impl<A: Add<A, A> + Ord + Clone + One> Iterator<A> for Range<A> {
+impl<A: Add<A, A> + Ord + Clone> Iterator<A> for Range<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
         if self.state < self.stop {
@@ -1562,6 +1544,22 @@ fn next(&mut self) -> Option<A> {
     }
 }
 
+impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        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<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
     #[inline]
     fn next(&mut self) -> Option<A> {
@@ -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<float> {
     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<uint> {
     #[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");
+        }
+    }
 }
index c2a60e1c0e9c01891dd97a56a2abb09c80bf06d2..a73809d202c44c7eb64a47be72c228bc159f7e47 100644 (file)
@@ -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]
index bd4dc69537cb10c9969e19c0b5dc942af3383197..57230b2fd247d4e86d9a844dc6bc39c798056378 100644 (file)
@@ -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<T: TotalOrd> TotalOrd for @T {
+    #[inline]
+    fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for @mut T {
+    #[inline]
+    fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @T {
+    #[inline]
+    fn equals(&self, other: &@T) -> bool { (**self).equals(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @mut T {
+    #[inline]
+    fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) }
+}
 #[test]
 fn test() {
     let x = @3;
index c7db60e6fd2649e772758ee26666c6eac513cfe1..60527905779f035296e8a126b7dfbe9b037677a0 100644 (file)
@@ -278,18 +278,22 @@ fn one() -> f64 { 1.0 }
 
 #[cfg(not(test))]
 impl Add<f64,f64> for f64 {
+    #[inline]
     fn add(&self, other: &f64) -> f64 { *self + *other }
 }
 #[cfg(not(test))]
 impl Sub<f64,f64> for f64 {
+    #[inline]
     fn sub(&self, other: &f64) -> f64 { *self - *other }
 }
 #[cfg(not(test))]
 impl Mul<f64,f64> for f64 {
+    #[inline]
     fn mul(&self, other: &f64) -> f64 { *self * *other }
 }
 #[cfg(not(test))]
 impl Div<f64,f64> for f64 {
+    #[inline]
     fn div(&self, other: &f64) -> f64 { *self / *other }
 }
 #[cfg(not(test))]
index 9842a570d7ea7e3c405245d5af9f9e4a17857bf7..b692bedebfd54f0ed17b39f5fcc99701abec5d32 100644 (file)
@@ -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");
         };
index 8b61a8a8734b9fb8f8df49193bc51db5756c5e56..bbadf1caca2413c4570460ac9040d28cc1940554 100644 (file)
@@ -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::<Self>()
+            } else { x }
+        } else {
+            if x > self {
+                // underflow
+                Bounded::min_value::<Self>()
+            } 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::<Self>()
+            } else { x }
+        } else {
+            if x < self {
+                // overflow
+                Bounded::max_value::<Self>()
+            } 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<T:Num + NumCast>(ten: T, two: T) {
@@ -482,64 +532,111 @@ pub fn test_num<T:Num + NumCast>(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);
+    }
+}
index 7ab3c81b61f7abd4e134e8f66ecafbff0187bf26..1f22343ad9c36063b8dc392120a4b3c451c15e45 100644 (file)
@@ -422,9 +422,9 @@ pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+Round+
 
 // Some constants for from_str_bytes_common's input validation,
 // they define minimum radix values for which the character is a valid digit.
-priv static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
-priv static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
-priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
+static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
+static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
+static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
 
 /**
  * Parses a byte slice as a number. This is meant to
index a2874c9670390816c034777c231aa4d0179b048a..29b8f29d87d3f866a37bff576ea9e408be768687 100644 (file)
@@ -125,13 +125,6 @@ pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) ->
     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");
         };
index ea1bddcdb4b9d60aba0138494219519e120d5317..66b30d8dd031c288eb2200fd4f35d69553f5a35b 100644 (file)
@@ -208,6 +208,12 @@ pub fn map_mut<'a, U>(&'a mut self, f: &fn(&'a mut T) -> U) -> Option<U> {
         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<U>(self, f: &fn(v: T) -> U) -> Option<U> {
-        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<U>(self, f: &fn(T) -> U) -> Option<U> {
+        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<U>(self, def: U, f: &fn(v: T) -> U) -> U {
-        match self { None => def, Some(v) => f(v) }
+    pub fn map_move_default<U>(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<T> {
         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<U>(&mut self, blk: &fn(T) -> U) -> Option<U> {
-        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<U> (&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 {
index b0e1f35b4a018a6c8237b29b7ca4b06c15741306..f246a61a4d580d8308aaa93e0885a37a6842a7f5 100644 (file)
@@ -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())
 }
 
 
index e7a6e38fdb08874d5474806d66f346a9167e75ca..424c4fd6b2f44d0e4f4102e04e1827a62f667670 100644 (file)
@@ -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<T:Eq> 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<T: TotalOrd> TotalOrd for ~T {
+    #[inline]
+    fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for ~T {
+    #[inline]
+    fn equals(&self, other: &~T) -> bool { (**self).equals(*other) }
+}
index 517bc4a441a68df454edf042fe1209404c434abd..65db55297b3b70e673146e74b19f2c58d3121d52 100644 (file)
@@ -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};
index dfd11f9227d413e5b37725b91a34e54d024f3eea..5a2bd0c4de9cea8e88cd256c87100c1eb42650d0 100644 (file)
@@ -272,6 +272,7 @@ pub trait RawPtr<T> {
     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
index 4ef524d77152bb224021d3ef7dc3b8a8e253906c..5f8fa9fddbcf7c2808f06ea9247590d49d4fa297 100644 (file)
@@ -610,15 +610,32 @@ fn shuffle_mut<T>(&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,
index 91f42edf0aecd46e33efafc41fa7fccf43032be4..3e429c6116d4c60d2c7aa191170405433b158593 100644 (file)
@@ -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<U>(self, op: &fn(T) -> U) -> Result<U,E> {
+        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<F>(self, op: &fn(E) -> F) -> Result<T,F> {
+        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<S, T, U: ToStr>(ss: &[S], ts: &[T],
 #[cfg(test)]
 mod tests {
     use super::*;
+
     use either;
+    use str::OwnedStr;
 
     pub fn op1() -> Result<int, ~str> { 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]
index a060059f5fc9339b9ba2af58288d8a5a461c6358..936a6526508a93f4c47cf5fdf2d69f4b15c4586f 100644 (file)
@@ -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::<Scheduler, bool> |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<T> Select for Port<T> {
+// XXX: Kind of gross. A Port<T> should be selectable so you can make an array
+// of them, but a &Port<T> should also be selectable so you can select2 on it
+// alongside a PortOne<U> without passing the port by value in recv_ready.
+
+impl<'self, T> Select for &'self Port<T> {
     #[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<T> SelectPort<(T, Port<T>)> for Port<T> {
-    fn recv_ready(self) -> Option<(T, Port<T>)> {
+impl<T> Select for Port<T> {
+    #[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<T> for &'self Port<T> {
+    fn recv_ready(self) -> Option<T> {
         match self.next.take().recv_ready() {
             Some(StreamPayload { val, next }) => {
                 self.next.put_back(next);
-                Some((val, self))
+                Some(val)
             }
             None => None
         }
index 1d7ff17314901bf50093e8cdeecef254c22a3017..6e671742fb6fdfa7fd8c8c71b8ed58fcbd34faca 100644 (file)
 
 //! 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 }
+}
index c93945a6a9aa9eeddba2784b6b6b2c050122470b..277897e5d2e27b80587309d16a7ef48475939560 100644 (file)
@@ -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 {
index 815ec9b5c61ec56284ba436caa1a35af611af5b8..81269d197d501ea6dc5dbd1b15b444fbe3fc8357 100644 (file)
@@ -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<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> {
+        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<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> {
+        do self.read_atomically |p| {
+            cb(p).filtered(|_| p.is_eof())
+        }
+    }
+
+    // Return result of first successful parser
+    fn read_or<T>(&mut self, parsers: &[&fn(&mut Parser) -> Option<T>]) -> Option<T> {
+        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<A, B, C>(&mut self,
+            pa: &fn(&mut Parser) -> Option<A>,
+            pb: &fn(&mut Parser) -> Option<B>,
+            pc: &fn(&mut Parser) -> Option<C>
+        ) -> 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<char> {
+        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<char> {
+        do self.read_atomically |p| {
+            p.read_char().filtered(|&next| next == c)
+        }
+    }
+
+    // Read digit
+    fn read_digit(&mut self, radix: u8) -> Option<u8> {
+        fn parse_digit(c: char, radix: u8) -> Option<u8> {
+            // 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<u32> {
+        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<u32> {
+        do self.read_atomically |p| {
+            p.read_number_impl(radix, max_digits, upto)
+        }
+    }
+
+    fn read_ipv4_addr_impl(&mut self) -> Option<IpAddr> {
+        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<IpAddr> {
+        do self.read_atomically |p| {
+            p.read_ipv4_addr_impl()
+        }
+    }
+
+    fn read_ipv6_addr_impl(&mut self) -> Option<IpAddr> {
+        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<IpAddr> {
+        do self.read_atomically |p| {
+            p.read_ipv6_addr_impl()
+        }
+    }
+
+    fn read_ip_addr(&mut self) -> Option<IpAddr> {
+        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<SocketAddr> {
+        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::<char, IpAddr, char>(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::<IpAddr, char, u16>(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<IpAddr> {
+        do Parser::new(s).read_till_eof |p| {
+            p.read_ip_addr()
+        }
+    }
+}
+
+impl FromStr for SocketAddr {
+    fn from_str(s: &str) -> Option<SocketAddr> {
+        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::<IpAddr>("256.0.0.1"));
+        // too short
+        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0"));
+        // too long
+        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0.1.2"));
+        // no number between dots
+        assert_eq!(None, FromStr::from_str::<IpAddr>("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::<IpAddr>("::00000"));
+        // too short
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7"));
+        // too long
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7:8:9"));
+        // triple colon
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:::6:7:8"));
+        // two double colons
+        assert_eq!(None, FromStr::from_str::<IpAddr>("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::<IpAddr>("::127.0.0.1:"));
+        // not enought groups
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:127.0.0.1"));
+        // too many groups
+        assert_eq!(None, FromStr::from_str::<IpAddr>("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::<SocketAddr>("127.0.0.1"));
+        // without port
+        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:"));
+        // wrong brackets around v4
+        assert_eq!(None, FromStr::from_str::<SocketAddr>("[127.0.0.1]:22"));
+        // port out of range
+        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:123456"));
+    }
+}
index 3372c13b87703a72cdef5af13fa5b651cc2379fc..e07cb1425bf75819efa2dfc1a58568e5518fe0f3 100644 (file)
@@ -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<Taskgroup>) {
         { 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<Taskgroup>) {
                     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<Taskgroup>) {
         // 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.
index 131507196b1f2558e61d6d7276ba1ca613f827c3..7154066e7b748f4e6196567301986c766755e2bd 100644 (file)
@@ -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,bool> |_task| {
index 760ca8a9adadcbae741cce4423728ffd6ea3e75e..01a52892f633b95eb71484d218fbf18f43dab314 100644 (file)
@@ -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);
     }
index 1a75f2569b59ea073303e18ca98451ac2cae0004..ce4e64c47d2ef5cb3faefd7cd5ead4bf9400d9e3 100644 (file)
@@ -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
 /// 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<SchedHandle>
+    friend_handle: Option<SchedHandle>,
+    /// 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<SchedHandle>)
@@ -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*");
index 006b777b71b1486168ae54c36a002adbefa4c61f..0e8d26e9482bac99761e536d5a16da8c5867195c 100644 (file)
@@ -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.
index 4c5e4bdc3c1d9b8b984642686428527ec1f40d38..364439a452601e490e5f2580d629f21c6caeb40f 100644 (file)
@@ -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<uint>, f: ~fn(), home: SchedHome) -> ~Task {
         let f = Cell::new(f);
         let home = Cell::new(home);
         do Local::borrow::<Task, ~Task> |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<uint>, 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<uint>, f: ~fn(), home: SchedHome) -> ~Task {
         let f = Cell::new(f);
         let home = Cell::new(home);
         do Local::borrow::<Task, ~Task> |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<uint>, 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<uint>,
                     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<uint>,
                      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<uint>,
                           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<uint>,
                            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<uint>, 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");
         }
     }
 
index 8b5215ae9694aedc4d0549b1c8f184e14d00edb5..92366d5187fe23cae6bc7aa3126d2bda464af8e5 100644 (file)
@@ -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;
 
 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);
     }
 }
index fd3042899f6bca5e28dadc366b1ed0e0208ea8d3..c8b3d41a78d79b65e8b5316e77dcc98aa38cd529 100644 (file)
@@ -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<T>(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 {
index ef3d881c5fead58be610146747508263d37b2472..99cf96eaae2fff4be0fcdd9d72a4714c5ff2f06b 100644 (file)
@@ -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<T>(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)]
index 568709c89da73d73039ac9eb042b346803382671..7000b56069df624333ba6bed60dde795a395a648 100644 (file)
@@ -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;
 }
index b4057b85cbfef5cbfae74b54555c359c3e9f5376..fa75916fb8640e10785c53b3e70c6c69aab93a89 100644 (file)
@@ -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<uint> {
         } 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]
index dd730f2068973d67534586d69d03c4bacb99446e..6ededb02107d497bb77a2d0b91e1b11d70b84978 100644 (file)
 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;
+        }
+    }
 }
index 225a4b8cfd294eacb0fddb4ad2b5058b5dd0edab..2e0c9c1d1ad1e01bf3b75f18e48ebee8c6820d1d 100644 (file)
@@ -142,7 +142,8 @@ pub struct TaskOpts {
     indestructible: bool,
     notify_chan: Option<Chan<TaskResult>>,
     name: Option<~str>,
-    sched: SchedOpts
+    sched: SchedOpts,
+    stack_size: Option<uint>
 }
 
 /**
@@ -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<U>(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;
index 527b20b0e9027312afc5d66244365fa54b5cb28f..05a17f8539c216b93dce541651ceffa47b62cbb8 100644 (file)
@@ -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::<Scheduler, ()> |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::<Task, bool> |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::<Scheduler>();
             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);
index 6f61d29780f044307d048aff29d1ae0de826a547..5ef5526e5162d4833c3aeff09056c9d94fdc80d4 100644 (file)
@@ -271,8 +271,8 @@ fn new() -> TrieNode<T> {
 
 impl<T> TrieNode<T> {
     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() {
index 1270a80c354990aeee037520b1fe4f1221faf192..c60edad3dbd5683e6ec69cae281376a950089a6c 100644 (file)
@@ -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<T>(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<T>(dst: *T, offset: int) -> *T;
+
     /// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
     /// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
     pub fn memcpy32<T>(dst: *mut T, src: *T, count: u32);
index e0c4950b38eaa8a0cb1d4cc742838b3493486bc2..98c0fe254b697643325efbe9dff7fb6a9f514991 100644 (file)
@@ -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;
index 0259b547ab3f06040f812deaa55144fbb5bded3e..0f6d94bb77107786bfff531ad73645ea73d8f380 100644 (file)
@@ -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::<T>()) as *T,
-                        lifetime: cast::transmute(p)}
+            if sys::size_of::<T>() == 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::<T>()) as *mut T,
-                           lifetime: cast::transmute(p)}
+            if sys::size_of::<T>() == 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))
                     }
index 84e6544f78092b56ca51416548ae9b03c1c47947..ba167fe67148ef5df984fbdf00e50495fb7f6f39 100644 (file)
@@ -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);
index d39cb2f507ca957ae57d1ec7d45332487ddcfd88..9edd41152f7f288ef090b2b94f555fabf4edf0b7 100644 (file)
@@ -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))
     }
 }
 
index 8b5014366413527ef93381f22b4b7f02e6c98880..2b6cb91a5df1759771fb7e4567c270f8806a0535 100644 (file)
@@ -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 {
index 6ed5ca3e402a8dc4ac5e69ada83f9255c30bc75f..dc20994b49facbb70d3d7ed0dd87d981c99985b4 100644 (file)
@@ -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
index c373a3894884e50bc2286db265bf254a739e2577..d81dca005b0a41dc99bdef621159eea0face4e9a 100644 (file)
@@ -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))
     }
 
index 01dacdfe453ee7cec2a5b186698b48468ba9442a..001e92355282f9d5f095dfab787c3afa9dd779d4 100644 (file)
@@ -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)`")
             }
         },
index c7020b990bf005695341846d0b0ecd49f773fa0a..a928680e093929f041c275f12dc8951e77801261 100644 (file)
@@ -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 (file)
index 0000000..5cf5fdb
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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<ArgumentType>],
+    // 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<uint, @str>, 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<uint, @str>, 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<ArgumentType>) {
+        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<uint, @str>,
+                  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())
+}
index 7ffed13940e8a6f144c3a9a92c7ce9efe0f6c28a..0a5bc00072034a052bd9a2d865d81aabfbb4f5a5 100644 (file)
@@ -417,7 +417,7 @@ fn noop_fold_stmt(s: &stmt_, fld: @ast_fold) -> Option<stmt_> {
 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),
     }
index ec956f61863765a56b25558b174fb8d7db965b97..dda5e990221eccf066d42a502637108f17bad179 100644 (file)
@@ -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);
index a0932729930e3c7fcc3da3da356b6b23251b3efd..7d6dce22fb7b423553d034f8f718c373860d68c8 100644 (file)
@@ -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<T>
-        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
index 39668e5c8b29b22613e30ab034fd5fcbd5b7e198..fd491c1e890a0d8f140d56d06bd2a29e5ea34791 100644 (file)
@@ -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();
index e0f5aa848a29bfd25b4cb7b8d6810411a20f6978..a5feb0483d894a24dbd75bcfa9b2a5c9818c6445 100644 (file)
@@ -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;
index 7cdfcf64bb9db17dc4f273bfaf9d5b1dc74ea0d4..5b8bebda9248eba37bfa25ec2f750990aaf2c4e5 100644 (file)
@@ -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 (file)
index 0000000..a72bf30
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[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)
+}
index cf160ca31c6f185d3ae38b5a06ef6edda527674d..6475012e0097e9e7180f7eb55fce18ed49fe012e 100644 (file)
@@ -53,24 +53,21 @@ fn descending<M: MutableMap<uint, uint>>(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
-        };
+        }
     }
 }
 
index 4fbe00622aa26fdded3c4d32bf8a6d4b7f0824e3..70fe6f706f79a763683fdc6556f09c765e2a86f0 100644 (file)
@@ -59,7 +59,7 @@ pub fn bench_int<T:MutableSet<uint>,
         {
             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<T:MutableSet<~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);
                 }
index 19380feea6df4beca237cfa16e6033ea27cecb39..8503b188b2f25a27dd7d21bc6d01e5d991373abd 100644 (file)
@@ -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 (file)
index 0000000..3d38d61
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern mod 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 (file)
index 0000000..6669342
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern mod 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::<uint>();
+    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 (file)
index 0000000..ff578ed
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern mod 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 || {};
+    }
+
+}
index 190ad62d6e17ff771ecb81900a8cdd2767479a3b..2b177ccb98fcc194a0dbf743619ac82764b6a447 100644 (file)
@@ -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();
 
index 9d4d31b8969205a3b0b7a911dd9648897c3d8214..48372c6d03b2fc3410b7ec34aaac3237d1883ece 100644 (file)
@@ -1,3 +1,5 @@
+// xfail-test reading from os::args()[1] - bogus!
+
 use std::from_str::FromStr;
 use std::os;
 use std::vec::MutableVector;
index 579b88a7e0e72c0231fb22f17a8c7a407cbfb83b..1f1ce86404b69347896cee3050b49d0be120a2e2 100644 (file)
@@ -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();
                 }
index 96fd4d7e604e7888c803b6b0a1285b1757fa8026..2b5b4ded94774690913cd7136db00954f26a387d 100644 (file)
@@ -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);
     }
index cf43f470e7177d55e2fcf77b0c57061fc03d02a7..72007d2b50a98029c4260233407733ebbe4bee7a 100644 (file)
@@ -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};
index 115607d0a992c14896d3d227799dee2dbc611bbf..0f43d5027a9133e6a331146ece4cafb105d6874b 100644 (file)
@@ -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];
index aef22bc2b8426f056a4047abb81092e288f9ece6..d7f5e5781e0ebc6659000b389d15c79bc2d27c59 100644 (file)
@@ -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);
     }
index ca539d712fdefb726cc41082f7524fe2a4d53d89..114c7e997a24f67cd22b4195ae6d4221c126d776 100644 (file)
@@ -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)
index 95dd803af8183221f00bbc21ee6a2c56bbabd3e9..7788005775f7897e20fbede324d5fb0318432326 100644 (file)
@@ -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 (file)
index 0000000..875ad0d
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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 (file)
index 0000000..76a697b
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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 (file)
index 0000000..abe3b6e
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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 (file)
index 0000000..427f5ea
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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 (file)
index 0000000..85556f9
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    ifmt!("{:notimplemented}", "3");
+    //~^ ERROR: unknown format trait `notimplemented`
+}
index 9647d412d2cdb8e70857cac782090e729c10959f..7097615b87e74ff963b59ac0b1837b31ce21ca7d 100644 (file)
@@ -16,7 +16,7 @@ pub fn MyStruct () -> MyStruct {
         MyStruct {priv_field: 4}
     }
     impl MyStruct {
-        priv fn happyfun(&self) {}
+        fn happyfun(&self) {}
     }
 }
 
index ccda6f158eda283ea35603cefc2abdd5dc67b4f7..cab999f621de8f37b7637f61261f3784c4b2238f 100644 (file)
@@ -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() {}
 }
 
 
index 450ea023bcbe6760100e7dfbe9f85e1852a8ade4..53a56ad2774235357000e824e86daf9f2e656979 100644 (file)
@@ -12,7 +12,7 @@
               //~^ ERROR unresolved import: found `fly` in `zoo` but it is private
 
 mod zoo {
-    priv fn fly() {}
+    fn fly() {}
 }
 
 
index 26b7d73ab2af2db19099f5665e157359a257a4dc..42da53e989036447b687fb645d0d0024aa14e296 100644 (file)
@@ -14,7 +14,7 @@ pub struct Foo {
     }
 
     impl Foo {
-        priv fn foo(&self) {}
+        fn foo(&self) {}
     }
 }
 
index 8776739db2d7629ce5ed84215afd739f591c4ea5..a31d0030f67e7be7066e6c640554070ad2a85a88 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 mod a {
-    priv fn f() {}
+    fn f() {}
 }
 
 fn main() {
index 1cde50cc15e9223e8b47dc8390c91640eba7a743..858227655955c614005dd4e23a08c5a84c571348 100644 (file)
@@ -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 (file)
index 0000000..e71a0f0
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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;
+}
index 6d3b157d63e802136c322e4c08cf55b9dd444c1e..3bf3507faba779d02ca9d63b3db56832d7846158 100644 (file)
@@ -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 (executable)
index 0000000..2841756
Binary files /dev/null and b/src/test/run-fail/assert-eq-macro-fail differ
index a281e9863649eb4455ea30c7496262dab4d02753..a65db3ee51543db658e8db9dc155658e0a491f1c 100644 (file)
@@ -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.
index 41a9d7ddcea1fc47445b0ee846783ac6e3488ebb..52dfb8aef13d56b484623c22b4250146ed8452c3 100644 (file)
@@ -10,6 +10,7 @@
 // except according to those terms.
 
 
+// xfail-test linked failure
 // error-pattern:1 == 2
 extern mod extra;
 
index 0269e3959868d9d899a1683ac45a30ebb9f5c43e..d4049f6753ee89204fd75c57be84b2dc9eac15c5 100644 (file)
@@ -10,6 +10,7 @@
 // except according to those terms.
 
 
+// xfail-test linked failure
 // error-pattern:fail
 
 use std::comm;
index 1203f74322febe0e0e5b6c9796916f15a69c0d9a..f40eae20bc0bc386b6e7276e009e22345914c2f0 100644 (file)
@@ -10,6 +10,7 @@
 // except according to those terms.
 
 
+// xfail-test linked failure
 // error-pattern:fail
 
 use std::comm;
index 766b43f211f46c52372376fed0b9c251cf8ad95c..94e41f1ae682565703aeb17bf725573209866b76 100644 (file)
@@ -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;
index de085a6f3addbc925639d524de97784e861b7788..12dab8e25b780755829b5d325667241f69600f0b 100644 (file)
@@ -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;
index 8302b96ca3ef7395e09cf41e099724a891d5192d..bd51ce38ec0e47bc03d38444eebc5d5437d1ec6a 100644 (file)
@@ -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;
index a5d7ba2c1aaa1bd1fee0783770f9d71d09bbc1e1..a134ffe49fd02f4f1ee2e75808ae0a8c2fbff2c5 100644 (file)
@@ -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 (file)
index 93e9eac..0000000
+++ /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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// xfail-test FIXME #7307
-// xfail-fast
-
-extern mod extra;
-use extra::oldmap::*;
-
-class cat : map<int, bool> {
-  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<bool> { Some(self.get(k)) }
-  fn remove(&&k:int) -> Option<bool> { 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 (file)
index 4fccc45..0000000
+++ /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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// 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<furniture>;
-}
-
-trait bitey {
-  fn bite() -> body_part;
-}
-
-fn vec_includes<T>(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<furniture>;
-    let bite_counts : hashmap<body_part, uint>;
-
-    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<body_part> = |p| int::hash(p as int);
-      let eqer : eqfn<body_part> = |p, q| p == q;
-      let t : hashmap<body_part, uint> =
-        hashmap::<body_part, uint>(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<furniture> {
-    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<T:noisy>(critter: T) {
-  for i in range(0u, 10u) {
-      let what = critter.speak();
-      info!("%u %d", i, what);
-  }
-}
-
-fn bite_everything<T:bitey>(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<T:scratchy>(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)));
-}
index 7fb01006844af5a7ee43b7e0c33b4865da993c51..b31f0eab2e2239494bef52c7d1464ecfd0a982ad 100644 (file)
@@ -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() {}
index 590cd8250208a7fbb221d477c589b4de5cc49644..8a271a4d65f3c06f5ac728c3c24464bf00cef97b 100644 (file)
@@ -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 (file)
index 0000000..7f5c78c
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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 (file)
index 0000000..5626424
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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");
+}
+
index 609849bffb4887b354af242e4fe0a3468d852d36..f4e2a9f36a072b5e34f6cdec6f0faeaa2e3dfb36 100644 (file)
@@ -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
 
index cec0a7a756c9fee8bfc77db20ba8a9cd3369fbab..13296131236ab25080245cf119baaa2f06e22461 100644 (file)
@@ -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;
 
index 5eecbe7e03afb207cec9f44a5a9a8cae76b33284..ea7d4a651f75d181b88bc80fa85fa9f771e9768d 100644 (file)
@@ -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 {
index 28396119596b0d94fbe1ee8cf2a5901019fda8e3..46819027dad649719e9ab9da908260a5800ab863 100644 (file)
@@ -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);
index e27f35d1851d52c743dab38ba5d78240113a62fb..a647e5849a8ee4036ab9eb63f7dda69904271b22 100644 (file)
@@ -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;
 
index c811e548f3fb18f0226b94baba937a32634ea43e..b8a1aa433a30a3e6492d7876dac1162a60168919 100644 (file)
@@ -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
index c94e00251d28a64f03b0936a0734fecf47fcfde5..5382ac77671392787232a58d60b1c4d8d1973f22 100644 (file)
@@ -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 (file)
index 0000000..d652223
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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);
+}