]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #9504 : brson/rust/continue, r=alexcrichton
authorbors <bors@rust-lang.org>
Fri, 27 Sep 2013 01:46:10 +0000 (18:46 -0700)
committerbors <bors@rust-lang.org>
Fri, 27 Sep 2013 01:46:10 +0000 (18:46 -0700)
30 files changed:
.gitattributes
RELEASES.txt
src/etc/pkg/rust-logo.ico
src/libextra/bitv.rs
src/libextra/crypto/md5.rs
src/libextra/crypto/sha2.rs
src/libextra/ringbuf.rs
src/libextra/url.rs
src/librustc/middle/trans/controlflow.rs
src/librustc/middle/typeck/check/method.rs
src/libstd/libc.rs
src/libstd/logging.rs
src/libstd/result.rs
src/libstd/rt/comm.rs
src/libstd/rt/io/mem.rs
src/libstd/rt/local_ptr.rs
src/libstd/rt/logging.rs
src/libstd/rt/sched.rs
src/libstd/std.rs
src/libstd/str.rs
src/libstd/sys.rs
src/libstd/task/mod.rs
src/libsyntax/ext/expand.rs
src/test/auxiliary/cfg_inner_static.rs [new file with mode: 0644]
src/test/compile-fail/issue-2823.rs
src/test/compile-fail/issue-5153.rs [new file with mode: 0644]
src/test/run-fail/rt-log-trunc.rs [deleted file]
src/test/run-pass/cfg_inner_static.rs [new file with mode: 0644]
src/test/run-pass/issue-9394-inherited-trait-calls.rs [new file with mode: 0644]
src/test/run-pass/logging_before_rt_started.rs [new file with mode: 0644]

index 39221d3928ee3c681eeb753107c6facf9ae918b3..57f8083a5568ab249f88315c2c4c3fbe6f2b92c9 100644 (file)
@@ -4,6 +4,7 @@
 *.cpp rust
 *.h rust
 *.rs rust
+src/etc/pkg/rust-logo.ico binary
 src/rt/msvc/* -whitespace
 src/rt/vg/* -whitespace
 src/rt/linenoise/* -whitespace
index e4d7086658d1b2747acd3eecc856f432d68ec1ee..9aea24dd22d886214ba2df08c339103a05f3f206 100644 (file)
@@ -1,7 +1,7 @@
-Version 0.8 (October 2013)
+Version 0.8 (September 2013)
 --------------------------
 
-   * ~2100 changes, numerous bugfixes
+   * ~2200 changes, numerous bugfixes
 
    * Language
       * The `for` loop syntax has changed to work with the `Iterator` trait.
index 4de8f87ae269c423b08cab18c5e98b5c23496e87..4749b398c2d2c063219f8e5b5c99bf1547ec0d99 100644 (file)
Binary files a/src/etc/pkg/rust-logo.ico and b/src/etc/pkg/rust-logo.ico differ
index 780527e4532cce04a2c849c81b2c7a36ffebd3c5..1ff54772f397ff81d1254fbc3287115e266354e8 100644 (file)
@@ -523,7 +523,7 @@ pub fn ones(&self, f: &fn(uint) -> bool) -> bool {
  * with the most significant bits of each byte coming first. Each
  * bit becomes true if equal to 1 or false if equal to 0.
  */
-pub fn from_utf8(bytes: &[u8]) -> Bitv {
+pub fn from_bytes(bytes: &[u8]) -> Bitv {
     from_fn(bytes.len() * 8, |i| {
         let b = bytes[i / 8] as uint;
         let offset = i % 8;
@@ -1275,8 +1275,8 @@ fn test_equal_sneaky_big() {
     }
 
     #[test]
-    fn test_from_utf8() {
-        let bitv = from_utf8([0b10110110, 0b00000000, 0b11111111]);
+    fn test_from_bytes() {
+        let bitv = from_bytes([0b10110110, 0b00000000, 0b11111111]);
         let str = ~"10110110" + "00000000" + "11111111";
         assert_eq!(bitv.to_str(), str);
     }
@@ -1302,7 +1302,7 @@ fn test_from_bools() {
     #[test]
     fn test_to_bools() {
         let bools = ~[false, false, true, false, false, true, true, false];
-        assert_eq!(from_utf8([0b00100110]).to_bools(), bools);
+        assert_eq!(from_bytes([0b00100110]).to_bools(), bools);
     }
 
     #[test]
index 8e07c7ee1c7cac43a4903a382022ce6d867e4350..5ef113971abb0e0672cc5aadcec0fa9c7d85298d 100644 (file)
@@ -156,7 +156,7 @@ fn op_i(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
 
 
 /// The MD5 Digest algorithm
-struct Md5 {
+pub struct Md5 {
     priv length_bytes: u64,
     priv buffer: FixedBuffer64,
     priv state: Md5State,
index 10289fb8b976465ebde8557f07746ddd25ff7994..4a8b62ffd114193de34635cd54786ed5fa3ef416 100644 (file)
@@ -230,7 +230,8 @@ fn finish(&mut self) {
 }
 
 
-struct Sha512 {
+/// The SHA-512 hash algorithm
+pub struct Sha512 {
     priv engine: Engine512
 }
 
@@ -282,7 +283,8 @@ fn output_bits(&self) -> uint { 512 }
 ];
 
 
-struct Sha384 {
+/// The SHA-384 hash algorithm
+pub struct Sha384 {
     priv engine: Engine512
 }
 
@@ -332,7 +334,8 @@ fn output_bits(&self) -> uint { 384 }
 ];
 
 
-struct Sha512Trunc256 {
+/// The SHA-512 hash algorithm with digest truncated to 256 bits
+pub struct Sha512Trunc256 {
     priv engine: Engine512
 }
 
@@ -380,7 +383,8 @@ fn output_bits(&self) -> uint { 256 }
 ];
 
 
-struct Sha512Trunc224 {
+/// The SHA-512 hash algorithm with digest truncated to 224 bits
+pub struct Sha512Trunc224 {
     priv engine: Engine512
 }
 
@@ -635,7 +639,8 @@ fn finish(&mut self) {
 }
 
 
-struct Sha256 {
+/// The SHA-256 hash algorithm
+pub struct Sha256 {
     priv engine: Engine256
 }
 
@@ -687,7 +692,8 @@ fn output_bits(&self) -> uint { 256 }
 ];
 
 
-struct Sha224 {
+/// The SHA-224 hash algorithm
+pub struct Sha224 {
     priv engine: Engine256
 }
 
index ea8537caeb5a19f0ba6d57f5814de380dce1b3f8..1e3962914057a5e1785c0f71711cab012dc36b2e 100644 (file)
@@ -143,6 +143,19 @@ pub fn get_mut<'a>(&'a mut self, i: uint) -> &'a mut T {
         }
     }
 
+    /// Swap elements at indices `i` and `j`
+    ///
+    /// `i` and `j` may be equal.
+    ///
+    /// Fails if there is no element with the given index
+    pub fn swap(&mut self, i: uint, j: uint) {
+        assert!(i < self.len());
+        assert!(j < self.len());
+        let ri = self.raw_index(i);
+        let rj = self.raw_index(j);
+        self.elts.swap(ri, rj);
+    }
+
     /// Return index in underlying vec for a given logical element index
     fn raw_index(&self, idx: uint) -> uint {
         raw_index(self.lo, self.elts.len(), idx)
@@ -604,6 +617,14 @@ fn test_reserve_at_least() {
         assert_eq!(d.elts.capacity(), 64);
     }
 
+    #[test]
+    fn test_swap() {
+        let mut d: RingBuf<int> = range(0, 5).collect();
+        d.pop_front();
+        d.swap(0, 3);
+        assert_eq!(d.iter().map(|&x|x).collect::<~[int]>(), ~[4, 2, 3, 1]);
+    }
+
     #[test]
     fn test_iter() {
         let mut d = RingBuf::new();
index ca1ce752faa1712420089563ab032f848a9eb7ce..451b410833f0f82e1e100b4b39900ea1b49024c7 100644 (file)
@@ -21,7 +21,7 @@
 use std::uint;
 
 #[deriving(Clone, Eq)]
-struct Url {
+pub struct Url {
     scheme: ~str,
     user: Option<UserInfo>,
     host: ~str,
@@ -32,7 +32,7 @@ struct Url {
 }
 
 #[deriving(Clone, Eq)]
-struct UserInfo {
+pub struct UserInfo {
     user: ~str,
     pass: Option<~str>
 }
index 2bf4e5c2bc6b0432dcf2b5fd68ee7e26b87d8cca..bfa7beace8ced7c2c4a388b760c6acf1251ebbf4 100644 (file)
@@ -25,6 +25,7 @@
 use syntax::ast::Name;
 use syntax::ast_util;
 use syntax::codemap::Span;
+use syntax::visit::Visitor;
 
 pub fn trans_block(bcx: @mut Block, b: &ast::Block, dest: expr::Dest) -> @mut Block {
     let _icx = push_ctxt("trans_block");
@@ -64,12 +65,22 @@ pub fn trans_if(bcx: @mut Block,
     // Drop branches that are known to be impossible
     if is_const(cond_val) && !is_undef(cond_val) {
         if const_to_uint(cond_val) == 1 {
+            match els {
+                Some(elexpr) => {
+                    let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
+                    trans.visit_expr(elexpr, ());
+                }
+                None => {}
+            }
             // if true { .. } [else { .. }]
             return do with_scope(bcx, thn.info(), "if_true_then") |bcx| {
                 let bcx_out = trans_block(bcx, thn, dest);
                 trans_block_cleanups(bcx_out, block_cleanups(bcx))
             }
         } else {
+            let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
+            trans.visit_block(thn, ());
+
             match els {
                 // if false { .. } else { .. }
                 Some(elexpr) => {
index 48d630b4aa93d57dcc508a1e64588da54f19598e..60712769de5b89164e599fa98648114d18556bc7 100644 (file)
@@ -372,7 +372,7 @@ fn push_extension_candidates(&self) {
     // to a trait and its supertraits.
     fn get_method_index(&self,
                         trait_ref: @TraitRef,
-                        subtrait_id: ast::DefId,
+                        subtrait: @TraitRef,
                         n_method: uint) -> uint {
         let tcx = self.tcx();
 
@@ -382,15 +382,14 @@ fn get_method_index(&self,
         // we find the trait the method came from, counting up the
         // methods from them.
         let mut method_count = 0;
-        do ty::each_bound_trait_and_supertraits(tcx, &[trait_ref])
+        do ty::each_bound_trait_and_supertraits(tcx, &[subtrait])
             |bound_ref| {
-            if bound_ref.def_id == subtrait_id { false }
+            if bound_ref.def_id == trait_ref.def_id { false }
                 else {
                 method_count += ty::trait_methods(tcx, bound_ref.def_id).len();
                 true
             }
         };
-
         return method_count + n_method;
     }
 
@@ -418,9 +417,9 @@ fn push_inherent_candidates_from_object(&self,
         let trait_ref = @TraitRef { def_id: did, substs: rcvr_substs.clone() };
 
         do self.push_inherent_candidates_from_bounds_inner(&[trait_ref])
-            |trait_ref, m, method_num, _bound_num| {
+            |new_trait_ref, m, method_num, _bound_num| {
             let vtable_index =
-                self.get_method_index(trait_ref, trait_ref.def_id, method_num);
+                self.get_method_index(new_trait_ref, trait_ref, method_num);
             // We need to fix up the transformed self type.
             let transformed_self_ty =
                 self.construct_transformed_self_ty_for_object(
index a5a2def450e8a0f33dce48a034c86f4027f81b38..e772ade135ec346047f553ab6a2eefd7e60e5003 100644 (file)
@@ -3224,14 +3224,14 @@ pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int)
         #[nolink]
         #[abi = "cdecl"]
         pub mod glob {
-            use libc::types::common::c95::{c_void};
             use libc::types::os::arch::c95::{c_char, c_int};
             use libc::types::os::common::posix01::{glob_t};
+            use option::Option;
 
             extern {
                 pub fn glob(pattern: *c_char,
                             flags: c_int,
-                            errfunc: *c_void, // XXX callback
+                            errfunc: Option<extern "C" fn(epath: *c_char, errno: int) -> int>,
                             pglob: *mut glob_t);
                 pub fn globfree(pglob: *mut glob_t);
             }
index 1a463a499cb41bedee4d31e88e58094bea708b08..342d0828f82f1972f36b72ab4f6b223bd3c97869 100644 (file)
 
 //! Logging
 
+use fmt;
 use option::*;
 use os;
 use rt;
 use rt::logging::{Logger, StdErrLogger};
-use send_str::SendStrOwned;
 
 /// Turns on logging to stdout globally
 pub fn console_on() {
@@ -37,7 +37,17 @@ pub fn console_off() {
     rt::logging::console_off();
 }
 
-fn newsched_log_str(msg: ~str) {
+#[cfg(stage0)]
+#[doc(hidden)]
+pub fn log(_level: u32, s: ~str) {
+    // this is a terrible approximation, but it gets the job done (for stage0 at
+    // least)
+    ::io::println(s);
+}
+
+#[allow(missing_doc)]
+#[cfg(not(stage0))]
+pub fn log(_level: u32, args: &fmt::Arguments) {
     use rt::task::Task;
     use rt::local::Local;
 
@@ -46,20 +56,13 @@ fn newsched_log_str(msg: ~str) {
         match optional_task {
             Some(local) => {
                 // Use the available logger
-                (*local).logger.log(SendStrOwned(msg));
+                (*local).logger.log(args);
             }
             None => {
                 // There is no logger anywhere, just write to stderr
                 let mut logger = StdErrLogger;
-                logger.log(SendStrOwned(msg));
+                logger.log(args);
             }
         }
     }
 }
-
-// XXX: This will change soon to not require an allocation. This is an unstable
-//      api which should not be used outside of the macros in ext/expand.
-#[doc(hidden)]
-pub fn log(_level: u32, msg: ~str) {
-    newsched_log_str(msg);
-}
index 3811f34cec43c1d5f0d4ebe32501dfdfd5eaa18b..a1980aa70e34449404079c601d7cb5c34650f2b3 100644 (file)
@@ -366,19 +366,6 @@ fn as_either<'a>(&'a self)-> either::Either<&'a E, &'a T> {
     }
 }
 
-#[inline]
-#[allow(missing_doc)]
-pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>,
-                               op: &fn(&T) -> Result<V,U>) -> Result<Option<V>,U> {
-    match *o_t {
-        None => Ok(None),
-        Some(ref t) => match op(t) {
-            Ok(v) => Ok(Some(v)),
-            Err(e) => Err(e)
-        }
-    }
-}
-
 /// Takes each element in the iterator: if it is an error, no further
 /// elements are taken, and the error is returned.
 /// Should no error occur, a vector containing the values of each Result
index 6336b1cbe2e783dab3c9c4993ae9f5c8f8fc0ce8..d7b444691776805d78728d295095d1809ed62bd3 100644 (file)
@@ -118,6 +118,17 @@ fn try_send_inner(self, val: T, do_resched: bool) -> bool {
             rtassert!(!rt::in_sched_context());
         }
 
+        // In order to prevent starvation of other tasks in situations
+        // where a task sends repeatedly without ever receiving, we
+        // occassionally yield instead of doing a send immediately.
+        // Only doing this if we're doing a rescheduling send,
+        // otherwise the caller is expecting not to context switch.
+        if do_resched {
+            // XXX: This TLS hit should be combined with other uses of the scheduler below
+            let sched: ~Scheduler = Local::take();
+            sched.maybe_yield();
+        }
+
         let mut this = self;
         let mut recvr_active = true;
         let packet = this.packet();
index 808e9f3a383e1f03eb03d5dc6428e9daf2bf803a..6d2a8a0d7e51f5c396bd045dea96d578b1a090ef 100644 (file)
@@ -128,7 +128,7 @@ fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
 
 
 /// Writes to a fixed-size byte slice
-struct BufWriter<'self> {
+pub struct BufWriter<'self> {
     buf: &'self mut [u8],
     pos: uint
 }
@@ -156,7 +156,7 @@ fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
 
 
 /// Reads from a fixed-size byte slice
-struct BufReader<'self> {
+pub struct BufReader<'self> {
     buf: &'self [u8],
     pos: uint
 }
index 3f9b7fc83df9822b618ff658f97db38f4cad4999..33384594c575ff4bab120fbd3f3a6e48afa8ceb6 100644 (file)
@@ -129,12 +129,16 @@ pub unsafe fn unsafe_borrow<T>() -> *mut T {
 }
 
 pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
-    let key = tls_key();
-    let void_ptr = tls::get(key);
-    if void_ptr.is_null() {
-        None
-    } else {
-        Some(void_ptr as *mut T)
+    match maybe_tls_key() {
+        Some(key) => {
+            let void_ptr = tls::get(key);
+            if void_ptr.is_null() {
+                None
+            } else {
+                Some(void_ptr as *mut T)
+            }
+        }
+        None => None
     }
 }
 
index 3dbf7a918b7a84a06abb0e626964a30ebf59b30c..cfbc53ad34e00c8fbf82c7e7f49500f0592edc59 100644 (file)
@@ -7,9 +7,12 @@
 // <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 fmt;
 use from_str::from_str;
-use libc::{uintptr_t, exit, STDERR_FILENO};
+use libc::{uintptr_t, exit};
 use option::{Some, None, Option};
+use rt;
 use rt::util::dumb_println;
 use rt::crate_map::{ModEntry, iter_crate_map};
 use rt::crate_map::get_crate_map;
@@ -18,7 +21,6 @@
 use u32;
 use vec::ImmutableVector;
 use cast::transmute;
-use send_str::{SendStr, SendStrOwned, SendStrStatic};
 
 struct LogDirective {
     name: Option<~str>,
@@ -171,44 +173,33 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
 }
 
 pub trait Logger {
-    fn log(&mut self, msg: SendStr);
+    fn log(&mut self, args: &fmt::Arguments);
 }
 
 pub struct StdErrLogger;
 
 impl Logger for StdErrLogger {
-    fn log(&mut self, msg: SendStr) {
-        use io::{Writer, WriterUtil};
-
-        if !should_log_console() {
-            return;
+    fn log(&mut self, args: &fmt::Arguments) {
+        if should_log_console() {
+            fmt::write(self as &mut rt::io::Writer, args);
         }
+    }
+}
 
-        let s: &str = match msg {
-            SendStrOwned(ref s) => {
-                let slc: &str = *s;
-                slc
-            },
-            SendStrStatic(s) => s,
-        };
-
-        // Truncate the string
-        let buf_bytes = 2048;
-        if s.len() > buf_bytes {
-            let s = s.slice(0, buf_bytes) + "[...]";
-            print(s);
-        } else {
-            print(s)
-        };
-
-        fn print(s: &str) {
-            let dbg = STDERR_FILENO as ::io::fd_t;
-            dbg.write_str(s);
-            dbg.write_str("\n");
-            dbg.flush();
-        }
+impl rt::io::Writer for StdErrLogger {
+    fn write(&mut self, buf: &[u8]) {
+        // Nothing like swapping between I/O implementations! In theory this
+        // could use the libuv bindings for writing to file descriptors, but
+        // that may not necessarily be desirable because logging should work
+        // outside of the uv loop. (modify with caution)
+        use io::Writer;
+        let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
+        dbg.write(buf);
     }
+
+    fn flush(&mut self) {}
 }
+
 /// Configure logging by traversing the crate map and setting the
 /// per-module global logging flags based on the logging spec
 pub fn init() {
index c3841760de3512c4552deaaea9995fed4a207df7..a62d3335644573a43462fd54865aca5300bb9556 100644 (file)
@@ -26,7 +26,7 @@
 use rt::rtio::{RemoteCallback, PausibleIdleCallback};
 use borrow::{to_uint};
 use cell::Cell;
-use rand::{XorShiftRng, Rng};
+use rand::{XorShiftRng, Rng, Rand};
 use iter::range;
 use vec::{OwnedVector};
 
@@ -78,7 +78,14 @@ pub struct Scheduler {
     /// A fast XorShift rng for scheduler use
     rng: XorShiftRng,
     /// A toggleable idle callback
-    idle_callback: Option<~PausibleIdleCallback>
+    idle_callback: Option<~PausibleIdleCallback>,
+    /// A countdown that starts at a random value and is decremented
+    /// every time a yield check is performed. When it hits 0 a task
+    /// will yield.
+    yield_check_count: uint,
+    /// A flag to tell the scheduler loop it needs to do some stealing
+    /// in order to introduce randomness as part of a yield
+    steal_for_yield: bool
 }
 
 /// An indication of how hard to work on a given operation, the difference
@@ -89,6 +96,13 @@ enum EffortLevel {
     GiveItYourBest
 }
 
+static MAX_YIELD_CHECKS: uint = 200;
+
+fn reset_yield_check(rng: &mut XorShiftRng) -> uint {
+    let r: uint = Rand::rand(rng);
+    r % MAX_YIELD_CHECKS + 1
+}
+
 impl Scheduler {
 
     // * Initialization Functions
@@ -113,7 +127,7 @@ pub fn new_special(event_loop: ~EventLoopObject,
                        friend: Option<SchedHandle>)
         -> Scheduler {
 
-        Scheduler {
+        let mut sched = Scheduler {
             sleeper_list: sleeper_list,
             message_queue: MessageQueue::new(),
             sleepy: false,
@@ -127,8 +141,14 @@ pub fn new_special(event_loop: ~EventLoopObject,
             run_anything: run_anything,
             friend_handle: friend,
             rng: XorShiftRng::new(),
-            idle_callback: None
-        }
+            idle_callback: None,
+            yield_check_count: 0,
+            steal_for_yield: false
+        };
+
+        sched.yield_check_count = reset_yield_check(&mut sched.rng);
+
+        return sched;
     }
 
     // XXX: This may eventually need to be refactored so that
@@ -307,8 +327,7 @@ fn interpret_message_queue(~self, effort: EffortLevel) -> Option<~Scheduler> {
             }
             Some(TaskFromFriend(task)) => {
                 rtdebug!("got a task from a friend. lovely!");
-                this.process_task(task,
-                                  Scheduler::resume_task_immediately_cl).map_move(Local::put);
+                this.process_task(task, Scheduler::resume_task_immediately_cl);
                 return None;
             }
             Some(Wake) => {
@@ -352,8 +371,8 @@ fn do_work(~self) -> Option<~Scheduler> {
         match this.find_work() {
             Some(task) => {
                 rtdebug!("found some work! processing the task");
-                return this.process_task(task,
-                                         Scheduler::resume_task_immediately_cl);
+                this.process_task(task, Scheduler::resume_task_immediately_cl);
+                return None;
             }
             None => {
                 rtdebug!("no work was found, returning the scheduler struct");
@@ -373,14 +392,35 @@ fn do_work(~self) -> Option<~Scheduler> {
     // 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)
+        if !self.steal_for_yield {
+            match self.work_queue.pop() {
+                Some(task) => {
+                    rtdebug!("found a task locally");
+                    return Some(task)
+                }
+                None => {
+                    rtdebug!("scheduler trying to steal");
+                    return self.try_steals();
+                }
             }
-            None => {
-                rtdebug!("scheduler trying to steal");
-                return self.try_steals();
+        } else {
+            // During execution of the last task, it performed a 'yield',
+            // so we're doing some work stealing in order to introduce some
+            // scheduling randomness. Otherwise we would just end up popping
+            // that same task again. This is pretty lame and is to work around
+            // the problem that work stealing is not designed for 'non-strict'
+            // (non-fork-join) task parallelism.
+            self.steal_for_yield = false;
+            match self.try_steals() {
+                Some(task) => {
+                    rtdebug!("stole a task after yielding");
+                    return Some(task);
+                }
+                None => {
+                    rtdebug!("did not steal a task after yielding");
+                    // Back to business
+                    return self.find_work();
+                }
             }
         }
     }
@@ -409,7 +449,7 @@ fn try_steals(&mut self) -> Option<~Task> {
     // place.
 
     fn process_task(~self, task: ~Task,
-                    schedule_fn: SchedulingFn) -> Option<~Scheduler> {
+                    schedule_fn: SchedulingFn) {
         let mut this = self;
         let mut task = task;
 
@@ -422,23 +462,23 @@ fn process_task(~self, task: ~Task,
                     rtdebug!("sending task home");
                     task.give_home(Sched(home_handle));
                     Scheduler::send_task_home(task);
-                    return Some(this);
+                    Local::put(this);
                 } else {
                     rtdebug!("running task here");
                     task.give_home(Sched(home_handle));
-                    return schedule_fn(this, task);
+                    schedule_fn(this, task);
                 }
             }
             AnySched if this.run_anything => {
                 rtdebug!("running anysched task here");
                 task.give_home(AnySched);
-                return schedule_fn(this, task);
+                schedule_fn(this, task);
             }
             AnySched => {
                 rtdebug!("sending task to friend");
                 task.give_home(AnySched);
                 this.send_to_friend(task);
-                return Some(this);
+                Local::put(this);
             }
         }
     }
@@ -607,15 +647,14 @@ pub fn get_contexts<'a>(current_task: &mut Task, next_task: &mut Task) ->
 
     // * Context Swapping Helpers - Here be ugliness!
 
-    pub fn resume_task_immediately(~self, task: ~Task) -> Option<~Scheduler> {
+    pub fn resume_task_immediately(~self, task: ~Task) {
         do self.change_task_context(task) |sched, stask| {
             sched.sched_task = Some(stask);
         }
-        return None;
     }
 
     fn resume_task_immediately_cl(sched: ~Scheduler,
-                                  task: ~Task) -> Option<~Scheduler> {
+                                  task: ~Task) {
         sched.resume_task_immediately(task)
     }
 
@@ -662,11 +701,10 @@ pub fn switch_running_tasks_and_then(~self, next_task: ~Task,
         }
     }
 
-    fn switch_task(sched: ~Scheduler, task: ~Task) -> Option<~Scheduler> {
+    fn switch_task(sched: ~Scheduler, task: ~Task) {
         do sched.switch_running_tasks_and_then(task) |sched, last_task| {
             sched.enqueue_blocked_task(last_task);
         };
-        return None;
     }
 
     // * Task Context Helpers
@@ -686,7 +724,7 @@ pub fn terminate_current_task(~self) {
 
     pub fn run_task(task: ~Task) {
         let sched: ~Scheduler = Local::take();
-        sched.process_task(task, Scheduler::switch_task).map_move(Local::put);
+        sched.process_task(task, Scheduler::switch_task);
     }
 
     pub fn run_task_later(next_task: ~Task) {
@@ -696,6 +734,33 @@ pub fn run_task_later(next_task: ~Task) {
         };
     }
 
+    /// Yield control to the scheduler, executing another task. This is guaranteed
+    /// to introduce some amount of randomness to the scheduler. Currently the
+    /// randomness is a result of performing a round of work stealing (which
+    /// may end up stealing from the current scheduler).
+    pub fn yield_now(~self) {
+        let mut this = self;
+        this.yield_check_count = reset_yield_check(&mut this.rng);
+        // Tell the scheduler to start stealing on the next iteration
+        this.steal_for_yield = true;
+        do this.deschedule_running_task_and_then |sched, task| {
+            sched.enqueue_blocked_task(task);
+        }
+    }
+
+    pub fn maybe_yield(~self) {
+        // The number of times to do the yield check before yielding, chosen arbitrarily.
+        let mut this = self;
+        rtassert!(this.yield_check_count > 0);
+        this.yield_check_count -= 1;
+        if this.yield_check_count == 0 {
+            this.yield_now();
+        } else {
+            Local::put(this);
+        }
+    }
+
+
     // * Utility Functions
 
     pub fn sched_id(&self) -> uint { to_uint(self) }
@@ -718,7 +783,7 @@ pub fn make_handle(&mut self) -> SchedHandle {
 
 // Supporting types
 
-type SchedulingFn = ~fn(~Scheduler, ~Task) -> Option<~Scheduler>;
+type SchedulingFn = ~fn(~Scheduler, ~Task);
 
 pub enum SchedMessage {
     Wake,
@@ -1231,4 +1296,40 @@ fn dont_starve_1() {
             }
         }
     }
+
+    #[test]
+    fn dont_starve_2() {
+        use rt::comm::oneshot;
+
+        do stress_factor().times {
+            do run_in_newsched_task {
+                let (port, chan) = oneshot();
+                let (_port2, chan2) = stream();
+
+                // This task should not be able to starve the other task.
+                // The sends should eventually yield.
+                do spawntask {
+                    while !port.peek() {
+                        chan2.send(());
+                    }
+                }
+
+                chan.send(());
+            }
+        }
+    }
+
+    // Regression test for a logic bug that would cause single-threaded schedulers
+    // to sleep forever after yielding and stealing another task.
+    #[test]
+    fn single_threaded_yield() {
+        use task::{spawn, spawn_sched, SingleThreaded, deschedule};
+        use num::Times;
+
+        do spawn_sched(SingleThreaded) {
+            do 5.times { deschedule(); }
+        }
+        do spawn { }
+        do spawn { }
+    }
 }
index 46d655e6379f7840132d9cd3bb15d5af13208104..39f71d78ff63524b3c38ed96b99ee69d577924b5 100644 (file)
@@ -223,4 +223,5 @@ mod std {
     pub use os;
     pub use fmt;
     pub use to_bytes;
+    pub use logging;
 }
index 8dc6f783fbea76235d5daf1249c0bfcfd0793bac..9562346c70d8a12d37757f5a1a3cc757d5565b6b 100644 (file)
@@ -246,14 +246,16 @@ pub fn push_str(lhs: &mut ~str, rhs: &str) {
     lhs.push_str(rhs)
 }
 
-#[allow(missing_doc)]
+/// Methods for vectors of strings
 pub trait StrVector {
+    /// Concatenate a vector of strings.
     fn concat(&self) -> ~str;
+
+    /// Concatenate a vector of strings, placing a given separator between each.
     fn connect(&self, sep: &str) -> ~str;
 }
 
 impl<'self, S: Str> StrVector for &'self [S] {
-    /// Concatenate a vector of strings.
     fn concat(&self) -> ~str {
         if self.is_empty() { return ~""; }
 
@@ -268,7 +270,6 @@ fn concat(&self) -> ~str {
         result
     }
 
-    /// Concatenate a vector of strings, placing a given separator between each.
     fn connect(&self, sep: &str) -> ~str {
         if self.is_empty() { return ~""; }
 
@@ -990,9 +991,15 @@ pub fn utf8_char_width(b: u8) -> uint {
     return UTF8_CHAR_WIDTH[b] as uint;
 }
 
-#[allow(missing_doc)]
+/// Struct that contains a `char` and
+/// the index of the first byte of the next `char` in a string.
+/// This is being used as a datastructure for iterating over
+/// the utf8 bytes of a string.
 pub struct CharRange {
+    /// Current `char`
     ch: char,
+
+    /// Index of the first byte of the next `char`
     next: uint
 }
 
@@ -1417,96 +1424,21 @@ fn clear(&mut self) {
     }
 }
 
-#[allow(missing_doc)]
+/// Methods for string slices
 pub trait StrSlice<'self> {
-    fn contains<'a>(&self, needle: &'a str) -> bool;
-    fn contains_char(&self, needle: char) -> bool;
-    fn iter(&self) -> CharIterator<'self>;
-    fn rev_iter(&self) -> CharRevIterator<'self>;
-    fn byte_iter(&self) -> ByteIterator<'self>;
-    fn byte_rev_iter(&self) -> ByteRevIterator<'self>;
-    fn char_offset_iter(&self) -> CharOffsetIterator<'self>;
-    fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self>;
-    fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
-    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
-    fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
-    fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep>;
-    fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
-    fn matches_index_iter(&self, sep: &'self str) -> MatchesIndexIterator<'self>;
-    fn split_str_iter(&self, &'self str) -> StrSplitIterator<'self>;
-    fn line_iter(&self) -> CharSplitIterator<'self, char>;
-    fn any_line_iter(&self) -> AnyLineIterator<'self>;
-    fn word_iter(&self) -> WordIterator<'self>;
-    fn nfd_iter(&self) -> NormalizationIterator<'self>;
-    fn nfkd_iter(&self) -> NormalizationIterator<'self>;
-    fn ends_with(&self, needle: &str) -> bool;
-    fn is_whitespace(&self) -> bool;
-    fn is_alphanumeric(&self) -> bool;
-    fn char_len(&self) -> uint;
-
-    fn slice(&self, begin: uint, end: uint) -> &'self str;
-    fn slice_from(&self, begin: uint) -> &'self str;
-    fn slice_to(&self, end: uint) -> &'self str;
-
-    fn slice_chars(&self, begin: uint, end: uint) -> &'self str;
-
-    fn starts_with(&self, needle: &str) -> bool;
-    fn escape_default(&self) -> ~str;
-    fn escape_unicode(&self) -> ~str;
-    fn trim(&self) -> &'self str;
-    fn trim_left(&self) -> &'self str;
-    fn trim_right(&self) -> &'self str;
-    fn trim_chars<C: CharEq>(&self, to_trim: &C) -> &'self str;
-    fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'self str;
-    fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'self str;
-    fn replace(&self, from: &str, to: &str) -> ~str;
-    fn to_owned(&self) -> ~str;
-    fn to_managed(&self) -> @str;
-    fn to_utf16(&self) -> ~[u16];
-    fn to_send_str(&self) -> SendStr;
-    fn is_char_boundary(&self, index: uint) -> bool;
-    fn char_range_at(&self, start: uint) -> CharRange;
-    fn char_at(&self, i: uint) -> char;
-    fn char_range_at_reverse(&self, start: uint) -> CharRange;
-    fn char_at_reverse(&self, i: uint) -> char;
-    fn as_bytes(&self) -> &'self [u8];
-
-    fn find<C: CharEq>(&self, search: C) -> Option<uint>;
-    fn rfind<C: CharEq>(&self, search: C) -> Option<uint>;
-    fn find_str(&self, &str) -> Option<uint>;
-
-    fn repeat(&self, nn: uint) -> ~str;
-
-    fn slice_shift_char(&self) -> (char, &'self str);
-
-    fn lev_distance(&self, t: &str) -> uint;
-
-    fn subslice_offset(&self, inner: &str) -> uint;
-
-    fn as_imm_buf<T>(&self, f: &fn(*u8, uint) -> T) -> T;
-}
-
-/// Extension methods for strings
-impl<'self> StrSlice<'self> for &'self str {
     /// Returns true if one string contains another
     ///
     /// # Arguments
     ///
-    /// * needle - The string to look for
-    #[inline]
-    fn contains<'a>(&self, needle: &'a str) -> bool {
-        self.find_str(needle).is_some()
-    }
+    /// - needle - The string to look for
+    fn contains<'a>(&self, needle: &'a str) -> bool;
 
     /// Returns true if a string contains a char.
     ///
     /// # Arguments
     ///
-    /// * needle - The char to look for
-    #[inline]
-    fn contains_char(&self, needle: char) -> bool {
-        self.find(needle).is_some()
-    }
+    /// - needle - The char to look for
+    fn contains_char(&self, needle: char) -> bool;
 
     /// An iterator over the characters of `self`. Note, this iterates
     /// over unicode code-points, not unicode graphemes.
@@ -1517,41 +1449,23 @@ fn contains_char(&self, needle: char) -> bool {
     /// let v: ~[char] = "abc åäö".iter().collect();
     /// assert_eq!(v, ~['a', 'b', 'c', ' ', 'å', 'ä', 'ö']);
     /// ```
-    #[inline]
-    fn iter(&self) -> CharIterator<'self> {
-        CharIterator{string: *self}
-    }
+    fn iter(&self) -> CharIterator<'self>;
 
     /// An iterator over the characters of `self`, in reverse order.
-    #[inline]
-    fn rev_iter(&self) -> CharRevIterator<'self> {
-        self.iter().invert()
-    }
+    fn rev_iter(&self) -> CharRevIterator<'self>;
 
     /// An iterator over the bytes of `self`
-    #[inline]
-    fn byte_iter(&self) -> ByteIterator<'self> {
-        self.as_bytes().iter().map(|&b| b)
-    }
+    fn byte_iter(&self) -> ByteIterator<'self>;
 
     /// An iterator over the bytes of `self`, in reverse order
-    #[inline]
-    fn byte_rev_iter(&self) -> ByteRevIterator<'self> {
-        self.byte_iter().invert()
-    }
+    fn byte_rev_iter(&self) -> ByteRevIterator<'self>;
 
     /// An iterator over the characters of `self` and their byte offsets.
-    #[inline]
-    fn char_offset_iter(&self) -> CharOffsetIterator<'self> {
-        CharOffsetIterator{string: *self, iter: self.iter()}
-    }
+    fn char_offset_iter(&self) -> CharOffsetIterator<'self>;
 
     /// An iterator over the characters of `self` and their byte offsets,
     /// in reverse order.
-    #[inline]
-    fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self> {
-        self.char_offset_iter().invert()
-    }
+    fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self>;
 
     /// An iterator over substrings of `self`, separated by characters
     /// matched by `sep`.
@@ -1565,29 +1479,12 @@ fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self> {
     /// let v: ~[&str] = "abc1def2ghi".split_iter(|c: char| c.is_digit()).collect();
     /// assert_eq!(v, ~["abc", "def", "ghi"]);
     /// ```
-    #[inline]
-    fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep> {
-        CharSplitIterator {
-            string: *self,
-            only_ascii: sep.only_ascii(),
-            sep: sep,
-            allow_trailing_empty: true,
-            finished: false,
-        }
-    }
+    fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
 
     /// An iterator over substrings of `self`, separated by characters
     /// matched by `sep`, restricted to splitting at most `count`
     /// times.
-    #[inline]
-    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
-        -> CharSplitNIterator<'self, Sep> {
-        CharSplitNIterator {
-            iter: self.split_iter(sep),
-            count: count,
-            invert: false,
-        }
-    }
+    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
 
     /// An iterator over substrings of `self`, separated by characters
     /// matched by `sep`.
@@ -1601,14 +1498,7 @@ fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
     /// let v: ~[&str] = "A.B.".split_terminator_iter('.').collect();
     /// assert_eq!(v, ~["A", "B"]);
     /// ```
-    #[inline]
-    fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep)
-        -> CharSplitIterator<'self, Sep> {
-        CharSplitIterator {
-            allow_trailing_empty: false,
-            ..self.split_iter(sep)
-        }
-    }
+    fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep>;
 
     /// An iterator over substrings of `self`, separated by characters
     /// matched by `sep`, in reverse order
@@ -1619,37 +1509,16 @@ fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep)
     /// let v: ~[&str] = "Mary had a little lamb".rsplit_iter(' ').collect();
     /// assert_eq!(v, ~["lamb", "little", "a", "had", "Mary"]);
     /// ```
-    #[inline]
-    fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep> {
-        self.split_iter(sep).invert()
-    }
+    fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep>;
 
     /// An iterator over substrings of `self`, separated by characters
     /// matched by `sep`, starting from the end of the string.
     /// Restricted to splitting at most `count` times.
-    #[inline]
-    fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
-        -> CharSplitNIterator<'self, Sep> {
-        CharSplitNIterator {
-            iter: self.split_iter(sep),
-            count: count,
-            invert: true,
-        }
-    }
-
-
+    fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> CharSplitNIterator<'self, Sep>;
 
     /// An iterator over the start and end indices of each match of
     /// `sep` within `self`.
-    #[inline]
-    fn matches_index_iter(&self, sep: &'self str) -> MatchesIndexIterator<'self> {
-        assert!(!sep.is_empty())
-        MatchesIndexIterator {
-            haystack: *self,
-            needle: sep,
-            position: 0
-        }
-    }
+    fn matches_index_iter(&self, sep: &'self str) -> MatchesIndexIterator<'self>;
 
     /// An iterator over the substrings of `self` separated by `sep`.
     ///
@@ -1659,125 +1528,475 @@ fn matches_index_iter(&self, sep: &'self str) -> MatchesIndexIterator<'self> {
     /// let v: ~[&str] = "abcXXXabcYYYabc".split_str_iter("abc").collect()
     /// assert_eq!(v, ["", "XXX", "YYY", ""]);
     /// ```
-    #[inline]
-    fn split_str_iter(&self, sep: &'self str) -> StrSplitIterator<'self> {
-        StrSplitIterator {
-            it: self.matches_index_iter(sep),
-            last_end: 0,
-            finished: false
-        }
-    }
+    fn split_str_iter(&self, &'self str) -> StrSplitIterator<'self>;
 
     /// An iterator over the lines of a string (subsequences separated
     /// by `\n`).
-    #[inline]
-    fn line_iter(&self) -> CharSplitIterator<'self, char> {
-        self.split_terminator_iter('\n')
-    }
+    fn line_iter(&self) -> CharSplitIterator<'self, char>;
 
     /// An iterator over the lines of a string, separated by either
     /// `\n` or (`\r\n`).
-    fn any_line_iter(&self) -> AnyLineIterator<'self> {
-        do self.line_iter().map |line| {
-            let l = line.len();
-            if l > 0 && line[l - 1] == '\r' as u8 { line.slice(0, l - 1) }
-            else { line }
-        }
-    }
+    fn any_line_iter(&self) -> AnyLineIterator<'self>;
 
     /// An iterator over the words of a string (subsequences separated
     /// by any sequence of whitespace).
-    #[inline]
-    fn word_iter(&self) -> WordIterator<'self> {
-        self.split_iter(char::is_whitespace).filter(|s| !s.is_empty())
-    }
+    fn word_iter(&self) -> WordIterator<'self>;
 
-    /// Returns the string in Unicode Normalization Form D (canonical decomposition)
-    fn nfd_iter(&self) -> NormalizationIterator<'self> {
-        NormalizationIterator {
-            iter: self.iter(),
-            buffer: ~[],
-            sorted: false,
-            kind: NFD
-        }
-    }
+    /// An Iterator over the string in Unicode Normalization Form D (canonical decomposition)
+    fn nfd_iter(&self) -> NormalizationIterator<'self>;
 
-    /// Returns the string in Unicode Normalization Form KD (compatibility decomposition)
-    fn nfkd_iter(&self) -> NormalizationIterator<'self> {
-        NormalizationIterator {
-            iter: self.iter(),
-            buffer: ~[],
-            sorted: false,
-            kind: NFKD
-        }
-    }
+    /// An Iterator over the string in Unicode Normalization Form KD (compatibility decomposition)
+    fn nfkd_iter(&self) -> NormalizationIterator<'self>;
 
     /// Returns true if the string contains only whitespace
     ///
     /// Whitespace characters are determined by `char::is_whitespace`
-    #[inline]
-    fn is_whitespace(&self) -> bool { self.iter().all(char::is_whitespace) }
+    fn is_whitespace(&self) -> bool;
 
     /// Returns true if the string contains only alphanumerics
     ///
     /// Alphanumeric characters are determined by `char::is_alphanumeric`
-    #[inline]
-    fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) }
+    fn is_alphanumeric(&self) -> bool;
 
     /// Returns the number of characters that a string holds
-    #[inline]
-    fn char_len(&self) -> uint { self.iter().len() }
+    fn char_len(&self) -> uint;
 
     /// Returns a slice of the given string from the byte range
     /// [`begin`..`end`)
     ///
     /// Fails when `begin` and `end` do not point to valid characters or
     /// beyond the last character of the string
-    #[inline]
-    fn slice(&self, begin: uint, end: uint) -> &'self str {
-        assert!(self.is_char_boundary(begin) && self.is_char_boundary(end));
-        unsafe { raw::slice_bytes(*self, begin, end) }
-    }
+    fn slice(&self, begin: uint, end: uint) -> &'self str;
 
     /// Returns a slice of the string from `begin` to its end.
     ///
     /// Fails when `begin` does not point to a valid character, or is
     /// out of bounds.
-    #[inline]
-    fn slice_from(&self, begin: uint) -> &'self str {
-        self.slice(begin, self.len())
-    }
+    fn slice_from(&self, begin: uint) -> &'self str;
 
     /// Returns a slice of the string from the beginning to byte
     /// `end`.
     ///
     /// Fails when `end` does not point to a valid character, or is
     /// out of bounds.
-    #[inline]
-    fn slice_to(&self, end: uint) -> &'self str {
-        assert!(self.is_char_boundary(end));
-        unsafe { raw::slice_bytes(*self, 0, end) }
-    }
+    fn slice_to(&self, end: uint) -> &'self str;
 
     /// Returns a slice of the string from the char range
     /// [`begin`..`end`).
     ///
     /// Fails if `begin` > `end` or the either `begin` or `end` are
     /// beyond the last character of the string.
-    fn slice_chars(&self, begin: uint, end: uint) -> &'self str {
-        assert!(begin <= end);
-        let mut count = 0;
-        let mut begin_byte = None;
-        let mut end_byte = None;
+    fn slice_chars(&self, begin: uint, end: uint) -> &'self str;
 
-        // This could be even more efficient by not decoding,
-        // only finding the char boundaries
-        for (idx, _) in self.char_offset_iter() {
-            if count == begin { begin_byte = Some(idx); }
-            if count == end { end_byte = Some(idx); break; }
-            count += 1;
-        }
-        if begin_byte.is_none() && count == begin { begin_byte = Some(self.len()) }
+    /// Returns true if `needle` is a prefix of the string.
+    fn starts_with(&self, needle: &str) -> bool;
+
+    /// Returns true if `needle` is a suffix of the string.
+    fn ends_with(&self, needle: &str) -> bool;
+
+    /// Escape each char in `s` with char::escape_default.
+    fn escape_default(&self) -> ~str;
+
+    /// Escape each char in `s` with char::escape_unicode.
+    fn escape_unicode(&self) -> ~str;
+
+    /// Returns a string with leading and trailing whitespace removed
+    fn trim(&self) -> &'self str;
+
+    /// Returns a string with leading whitespace removed
+    fn trim_left(&self) -> &'self str;
+
+    /// Returns a string with trailing whitespace removed
+    fn trim_right(&self) -> &'self str;
+
+    /// Returns a string with characters that match `to_trim` removed.
+    ///
+    /// # Arguments
+    ///
+    /// * to_trim - a character matcher
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// assert_eq!("11foo1bar11".trim_chars(&'1'), "foo1bar")
+    /// assert_eq!("12foo1bar12".trim_chars(& &['1', '2']), "foo1bar")
+    /// assert_eq!("123foo1bar123".trim_chars(&|c: char| c.is_digit()), "foo1bar")
+    /// ```
+    fn trim_chars<C: CharEq>(&self, to_trim: &C) -> &'self str;
+
+    /// Returns a string with leading `chars_to_trim` removed.
+    ///
+    /// # Arguments
+    ///
+    /// * to_trim - a character matcher
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// assert_eq!("11foo1bar11".trim_left_chars(&'1'), "foo1bar11")
+    /// assert_eq!("12foo1bar12".trim_left_chars(& &['1', '2']), "foo1bar12")
+    /// assert_eq!("123foo1bar123".trim_left_chars(&|c: char| c.is_digit()), "foo1bar123")
+    /// ```
+    fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'self str;
+
+    /// Returns a string with trailing `chars_to_trim` removed.
+    ///
+    /// # Arguments
+    ///
+    /// * to_trim - a character matcher
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// assert_eq!("11foo1bar11".trim_right_chars(&'1'), "11foo1bar")
+    /// assert_eq!("12foo1bar12".trim_right_chars(& &['1', '2']), "12foo1bar")
+    /// assert_eq!("123foo1bar123".trim_right_chars(&|c: char| c.is_digit()), "123foo1bar")
+    /// ```
+    fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'self str;
+
+    /// Replace all occurrences of one string with another
+    ///
+    /// # Arguments
+    ///
+    /// * from - The string to replace
+    /// * to - The replacement string
+    ///
+    /// # Return value
+    ///
+    /// The original string with all occurances of `from` replaced with `to`
+    fn replace(&self, from: &str, to: &str) -> ~str;
+
+    /// Copy a slice into a new owned str
+    fn to_owned(&self) -> ~str;
+
+    /// Copy a slice into a new managed str
+    fn to_managed(&self) -> @str;
+
+    /// Converts to a vector of `u16` encoded as UTF-16.
+    fn to_utf16(&self) -> ~[u16];
+
+    /// Copy a slice into a new `SendStr`
+    fn to_send_str(&self) -> SendStr;
+
+    /// Returns false if the index points into the middle of a multi-byte
+    /// character sequence.
+    fn is_char_boundary(&self, index: uint) -> bool;
+
+    /// Pluck a character out of a string and return the index of the next
+    /// character.
+    ///
+    /// This function can be used to iterate over the unicode characters of a
+    /// string.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let s = "中华Việt Nam";
+    /// let i = 0u;
+    /// while i < s.len() {
+    ///     let CharRange {ch, next} = s.char_range_at(i);
+    ///     printfln!("%u: %c", i, ch);
+    ///     i = next;
+    /// }
+    /// ```
+    ///
+    /// # Example output
+    ///
+    /// ```
+    /// 0: 中
+    /// 3: 华
+    /// 6: V
+    /// 7: i
+    /// 8: ệ
+    /// 11: t
+    /// 12:
+    /// 13: N
+    /// 14: a
+    /// 15: m
+    /// ```
+    ///
+    /// # Arguments
+    ///
+    /// * s - The string
+    /// * i - The byte offset of the char to extract
+    ///
+    /// # Return value
+    ///
+    /// A record {ch: char, next: uint} containing the char value and the byte
+    /// index of the next unicode character.
+    ///
+    /// # Failure
+    ///
+    /// If `i` is greater than or equal to the length of the string.
+    /// If `i` is not the index of the beginning of a valid UTF-8 character.
+    fn char_range_at(&self, start: uint) -> CharRange;
+
+    /// Given a byte position and a str, return the previous char and its position.
+    ///
+    /// This function can be used to iterate over a unicode string in reverse.
+    ///
+    /// Returns 0 for next index if called on start index 0.
+    fn char_range_at_reverse(&self, start: uint) -> CharRange;
+
+    /// Plucks the character starting at the `i`th byte of a string
+    fn char_at(&self, i: uint) -> char;
+
+    /// Plucks the character ending at the `i`th byte of a string
+    fn char_at_reverse(&self, i: uint) -> char;
+
+    /// Work with the byte buffer of a string as a byte slice.
+    fn as_bytes(&self) -> &'self [u8];
+
+    /// Returns the byte index of the first character of `self` that matches `search`
+    ///
+    /// # Return value
+    ///
+    /// `Some` containing the byte index of the last matching character
+    /// or `None` if there is no match
+    fn find<C: CharEq>(&self, search: C) -> Option<uint>;
+
+    /// Returns the byte index of the last character of `self` that matches `search`
+    ///
+    /// # Return value
+    ///
+    /// `Some` containing the byte index of the last matching character
+    /// or `None` if there is no match
+    fn rfind<C: CharEq>(&self, search: C) -> Option<uint>;
+
+    /// Returns the byte index of the first matching substring
+    ///
+    /// # Arguments
+    ///
+    /// * `needle` - The string to search for
+    ///
+    /// # Return value
+    ///
+    /// `Some` containing the byte index of the first matching substring
+    /// or `None` if there is no match
+    fn find_str(&self, &str) -> Option<uint>;
+
+    /// Given a string, make a new string with repeated copies of it.
+    fn repeat(&self, nn: uint) -> ~str;
+
+    /// Retrieves the first character from a string slice and returns
+    /// it. This does not allocate a new string; instead, it returns a
+    /// slice that point one character beyond the character that was
+    /// shifted.
+    ///
+    /// # Failure
+    ///
+    /// If the string does not contain any characters
+    fn slice_shift_char(&self) -> (char, &'self str);
+
+    /// Levenshtein Distance between two strings.
+    fn lev_distance(&self, t: &str) -> uint;
+
+    /// Returns the byte offset of an inner slice relative to an enclosing outer slice.
+    ///
+    /// Fails if `inner` is not a direct slice contained within self.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// let string = "a\nb\nc";
+    /// let mut lines = ~[];
+    /// for line in string.line_iter() { lines.push(line) }
+    ///
+    /// assert!(string.subslice_offset(lines[0]) == 0); // &"a"
+    /// assert!(string.subslice_offset(lines[1]) == 2); // &"b"
+    /// assert!(string.subslice_offset(lines[2]) == 4); // &"c"
+    /// ```
+    fn subslice_offset(&self, inner: &str) -> uint;
+
+    /// Work with the byte buffer and length of a slice.
+    ///
+    /// The buffer does not have a null terminator.
+    fn as_imm_buf<T>(&self, f: &fn(*u8, uint) -> T) -> T;
+}
+
+impl<'self> StrSlice<'self> for &'self str {
+    #[inline]
+    fn contains<'a>(&self, needle: &'a str) -> bool {
+        self.find_str(needle).is_some()
+    }
+
+    #[inline]
+    fn contains_char(&self, needle: char) -> bool {
+        self.find(needle).is_some()
+    }
+
+    #[inline]
+    fn iter(&self) -> CharIterator<'self> {
+        CharIterator{string: *self}
+    }
+
+    #[inline]
+    fn rev_iter(&self) -> CharRevIterator<'self> {
+        self.iter().invert()
+    }
+
+    #[inline]
+    fn byte_iter(&self) -> ByteIterator<'self> {
+        self.as_bytes().iter().map(|&b| b)
+    }
+
+    #[inline]
+    fn byte_rev_iter(&self) -> ByteRevIterator<'self> {
+        self.byte_iter().invert()
+    }
+
+    #[inline]
+    fn char_offset_iter(&self) -> CharOffsetIterator<'self> {
+        CharOffsetIterator{string: *self, iter: self.iter()}
+    }
+
+    #[inline]
+    fn char_offset_rev_iter(&self) -> CharOffsetRevIterator<'self> {
+        self.char_offset_iter().invert()
+    }
+
+    #[inline]
+    fn split_iter<Sep: CharEq>(&self, sep: Sep) -> CharSplitIterator<'self, Sep> {
+        CharSplitIterator {
+            string: *self,
+            only_ascii: sep.only_ascii(),
+            sep: sep,
+            allow_trailing_empty: true,
+            finished: false,
+        }
+    }
+
+    #[inline]
+    fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
+        -> CharSplitNIterator<'self, Sep> {
+        CharSplitNIterator {
+            iter: self.split_iter(sep),
+            count: count,
+            invert: false,
+        }
+    }
+
+    #[inline]
+    fn split_terminator_iter<Sep: CharEq>(&self, sep: Sep)
+        -> CharSplitIterator<'self, Sep> {
+        CharSplitIterator {
+            allow_trailing_empty: false,
+            ..self.split_iter(sep)
+        }
+    }
+
+    #[inline]
+    fn rsplit_iter<Sep: CharEq>(&self, sep: Sep) -> CharRSplitIterator<'self, Sep> {
+        self.split_iter(sep).invert()
+    }
+
+    #[inline]
+    fn rsplitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint)
+        -> CharSplitNIterator<'self, Sep> {
+        CharSplitNIterator {
+            iter: self.split_iter(sep),
+            count: count,
+            invert: true,
+        }
+    }
+
+    #[inline]
+    fn matches_index_iter(&self, sep: &'self str) -> MatchesIndexIterator<'self> {
+        assert!(!sep.is_empty())
+        MatchesIndexIterator {
+            haystack: *self,
+            needle: sep,
+            position: 0
+        }
+    }
+
+    #[inline]
+    fn split_str_iter(&self, sep: &'self str) -> StrSplitIterator<'self> {
+        StrSplitIterator {
+            it: self.matches_index_iter(sep),
+            last_end: 0,
+            finished: false
+        }
+    }
+
+    #[inline]
+    fn line_iter(&self) -> CharSplitIterator<'self, char> {
+        self.split_terminator_iter('\n')
+    }
+
+    fn any_line_iter(&self) -> AnyLineIterator<'self> {
+        do self.line_iter().map |line| {
+            let l = line.len();
+            if l > 0 && line[l - 1] == '\r' as u8 { line.slice(0, l - 1) }
+            else { line }
+        }
+    }
+
+    #[inline]
+    fn word_iter(&self) -> WordIterator<'self> {
+        self.split_iter(char::is_whitespace).filter(|s| !s.is_empty())
+    }
+
+    #[inline]
+    fn nfd_iter(&self) -> NormalizationIterator<'self> {
+        NormalizationIterator {
+            iter: self.iter(),
+            buffer: ~[],
+            sorted: false,
+            kind: NFD
+        }
+    }
+
+    #[inline]
+    fn nfkd_iter(&self) -> NormalizationIterator<'self> {
+        NormalizationIterator {
+            iter: self.iter(),
+            buffer: ~[],
+            sorted: false,
+            kind: NFKD
+        }
+    }
+
+    #[inline]
+    fn is_whitespace(&self) -> bool { self.iter().all(char::is_whitespace) }
+
+    #[inline]
+    fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) }
+
+    #[inline]
+    fn char_len(&self) -> uint { self.iter().len() }
+
+    #[inline]
+    fn slice(&self, begin: uint, end: uint) -> &'self str {
+        assert!(self.is_char_boundary(begin) && self.is_char_boundary(end));
+        unsafe { raw::slice_bytes(*self, begin, end) }
+    }
+
+    #[inline]
+    fn slice_from(&self, begin: uint) -> &'self str {
+        self.slice(begin, self.len())
+    }
+
+    #[inline]
+    fn slice_to(&self, end: uint) -> &'self str {
+        assert!(self.is_char_boundary(end));
+        unsafe { raw::slice_bytes(*self, 0, end) }
+    }
+
+    fn slice_chars(&self, begin: uint, end: uint) -> &'self str {
+        assert!(begin <= end);
+        let mut count = 0;
+        let mut begin_byte = None;
+        let mut end_byte = None;
+
+        // This could be even more efficient by not decoding,
+        // only finding the char boundaries
+        for (idx, _) in self.char_offset_iter() {
+            if count == begin { begin_byte = Some(idx); }
+            if count == end { end_byte = Some(idx); break; }
+            count += 1;
+        }
+        if begin_byte.is_none() && count == begin { begin_byte = Some(self.len()) }
         if end_byte.is_none() && count == end { end_byte = Some(self.len()) }
 
         match (begin_byte, end_byte) {
@@ -1787,7 +2006,6 @@ fn slice_chars(&self, begin: uint, end: uint) -> &'self str {
         }
     }
 
-    /// Returns true if `needle` is a prefix of the string.
     fn starts_with<'a>(&self, needle: &'a str) -> bool {
         let (self_len, needle_len) = (self.len(), needle.len());
         if needle_len == 0u { true }
@@ -1795,7 +2013,6 @@ fn starts_with<'a>(&self, needle: &'a str) -> bool {
         else { match_at(*self, needle, 0u) }
     }
 
-    /// Returns true if `needle` is a suffix of the string.
     fn ends_with(&self, needle: &str) -> bool {
         let (self_len, needle_len) = (self.len(), needle.len());
         if needle_len == 0u { true }
@@ -1803,7 +2020,6 @@ fn ends_with(&self, needle: &str) -> bool {
         else { match_at(*self, needle, self_len - needle_len) }
     }
 
-    /// Escape each char in `s` with char::escape_default.
     fn escape_default(&self) -> ~str {
         let mut out: ~str = ~"";
         out.reserve_at_least(self.len());
@@ -1815,7 +2031,6 @@ fn escape_default(&self) -> ~str {
         out
     }
 
-    /// Escape each char in `s` with char::escape_unicode.
     fn escape_unicode(&self) -> ~str {
         let mut out: ~str = ~"";
         out.reserve_at_least(self.len());
@@ -1827,55 +2042,26 @@ fn escape_unicode(&self) -> ~str {
         out
     }
 
-    /// Returns a string with leading and trailing whitespace removed
     #[inline]
     fn trim(&self) -> &'self str {
         self.trim_left().trim_right()
     }
 
-    /// Returns a string with leading whitespace removed
     #[inline]
     fn trim_left(&self) -> &'self str {
         self.trim_left_chars(&char::is_whitespace)
     }
 
-    /// Returns a string with trailing whitespace removed
     #[inline]
     fn trim_right(&self) -> &'self str {
         self.trim_right_chars(&char::is_whitespace)
-    }
-
-    /// Returns a string with characters that match `to_trim` removed.
-    ///
-    /// # Arguments
-    ///
-    /// * to_trim - a character matcher
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// assert_eq!("11foo1bar11".trim_chars(&'1'), "foo1bar")
-    /// assert_eq!("12foo1bar12".trim_chars(& &['1', '2']), "foo1bar")
-    /// assert_eq!("123foo1bar123".trim_chars(&|c: char| c.is_digit()), "foo1bar")
-    /// ```
-    #[inline]
-    fn trim_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
-        self.trim_left_chars(to_trim).trim_right_chars(to_trim)
-    }
-
-    /// Returns a string with leading `chars_to_trim` removed.
-    ///
-    /// # Arguments
-    ///
-    /// * to_trim - a character matcher
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// assert_eq!("11foo1bar11".trim_left_chars(&'1'), "foo1bar11")
-    /// assert_eq!("12foo1bar12".trim_left_chars(& &['1', '2']), "foo1bar12")
-    /// assert_eq!("123foo1bar123".trim_left_chars(&|c: char| c.is_digit()), "foo1bar123")
-    /// ```
+    }
+
+    #[inline]
+    fn trim_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
+        self.trim_left_chars(to_trim).trim_right_chars(to_trim)
+    }
+
     #[inline]
     fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
         match self.find(|c: char| !to_trim.matches(c)) {
@@ -1884,19 +2070,6 @@ fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
         }
     }
 
-    /// Returns a string with trailing `chars_to_trim` removed.
-    ///
-    /// # Arguments
-    ///
-    /// * to_trim - a character matcher
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// assert_eq!("11foo1bar11".trim_right_chars(&'1'), "11foo1bar")
-    /// assert_eq!("12foo1bar12".trim_right_chars(& &['1', '2']), "12foo1bar")
-    /// assert_eq!("123foo1bar123".trim_right_chars(&|c: char| c.is_digit()), "123foo1bar")
-    /// ```
     #[inline]
     fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
         match self.rfind(|c: char| !to_trim.matches(c)) {
@@ -1908,16 +2081,6 @@ fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'self str {
         }
     }
 
-    /// Replace all occurrences of one string with another
-    ///
-    /// # Arguments
-    ///
-    /// * from - The string to replace
-    /// * to - The replacement string
-    ///
-    /// # Return value
-    ///
-    /// The original string with all occurances of `from` replaced with `to`
     fn replace(&self, from: &str, to: &str) -> ~str {
         let mut result = ~"";
         let mut last_end = 0;
@@ -1930,7 +2093,6 @@ fn replace(&self, from: &str, to: &str) -> ~str {
         result
     }
 
-    /// Copy a slice into a new unique str
     #[inline]
     fn to_owned(&self) -> ~str {
         do self.as_imm_buf |src, len| {
@@ -1954,7 +2116,6 @@ fn to_managed(&self) -> @str {
         }
     }
 
-    /// Converts to a vector of `u16` encoded as UTF-16.
     fn to_utf16(&self) -> ~[u16] {
         let mut u = ~[];
         for ch in self.iter() {
@@ -1983,8 +2144,6 @@ fn to_send_str(&self) -> SendStr {
         SendStrOwned(self.to_owned())
     }
 
-    /// Returns false if the index points into the middle of a multi-byte
-    /// character sequence.
     #[inline]
     fn is_char_boundary(&self, index: uint) -> bool {
         if index == self.len() { return true; }
@@ -1992,53 +2151,6 @@ fn is_char_boundary(&self, index: uint) -> bool {
         return b < 128u8 || b >= 192u8;
     }
 
-    /// Pluck a character out of a string and return the index of the next
-    /// character.
-    ///
-    /// This function can be used to iterate over the unicode characters of a
-    /// string.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let s = "中华Việt Nam";
-    /// let i = 0u;
-    /// while i < s.len() {
-    ///     let CharRange {ch, next} = s.char_range_at(i);
-    ///     printfln!("%u: %c", i, ch);
-    ///     i = next;
-    /// }
-    /// ```
-    ///
-    /// # Example output
-    ///
-    /// ```
-    /// 0: 中
-    /// 3: 华
-    /// 6: V
-    /// 7: i
-    /// 8: ệ
-    /// 11: t
-    /// 12:
-    /// 13: N
-    /// 14: a
-    /// 15: m
-    /// ```
-    ///
-    /// # Arguments
-    ///
-    /// * s - The string
-    /// * i - The byte offset of the char to extract
-    ///
-    /// # Return value
-    ///
-    /// A record {ch: char, next: uint} containing the char value and the byte
-    /// index of the next unicode character.
-    ///
-    /// # Failure
-    ///
-    /// If `i` is greater than or equal to the length of the string.
-    /// If `i` is not the index of the beginning of a valid UTF-8 character.
     #[inline]
     fn char_range_at(&self, i: uint) -> CharRange {
         if (self[i] < 128u8) {
@@ -2062,15 +2174,9 @@ fn multibyte_char_range_at(s: &str, i: uint) -> CharRange {
         return multibyte_char_range_at(*self, i);
     }
 
-    /// Plucks the character starting at the `i`th byte of a string
     #[inline]
     fn char_at(&self, i: uint) -> char { self.char_range_at(i).ch }
 
-    /// Given a byte position and a str, return the previous char and its position.
-    ///
-    /// This function can be used to iterate over a unicode string in reverse.
-    ///
-    /// Returns 0 for next index if called on start index 0.
     #[inline]
     fn char_range_at_reverse(&self, start: uint) -> CharRange {
         let mut prev = start;
@@ -2079,7 +2185,7 @@ fn char_range_at_reverse(&self, start: uint) -> CharRange {
         if self[prev] < 128 { return CharRange{ch: self[prev] as char, next: prev} }
 
         // Multibyte case is a fn to allow char_range_at_reverse to inline cleanly
-        fn multibyte_char_range_at_rev(s: &str, mut i: uint) -> CharRange {
+        fn multibyte_char_range_at_reverse(s: &str, mut i: uint) -> CharRange {
             // while there is a previous byte == 10......
             while i > 0 && s[i] & 192u8 == TAG_CONT_U8 {
                 i -= 1u;
@@ -2097,26 +2203,24 @@ fn multibyte_char_range_at_rev(s: &str, mut i: uint) -> CharRange {
             return CharRange {ch: unsafe { transmute(val as u32) }, next: i};
         }
 
-        return multibyte_char_range_at_rev(*self, prev);
+        return multibyte_char_range_at_reverse(*self, prev);
+    }
+
+    #[inline]
+    fn char_at(&self, i: uint) -> char {
+        self.char_range_at(i).ch
     }
 
-    /// Plucks the character ending at the `i`th byte of a string
     #[inline]
     fn char_at_reverse(&self, i: uint) -> char {
         self.char_range_at_reverse(i).ch
     }
 
-    /// Work with the byte buffer of a string as a byte slice.
+    #[inline]
     fn as_bytes(&self) -> &'self [u8] {
         unsafe { cast::transmute(*self) }
     }
 
-    /// Returns the byte index of the first character of `self` that matches `search`
-    ///
-    /// # Return value
-    ///
-    /// `Some` containing the byte index of the last matching character
-    /// or `None` if there is no match
     fn find<C: CharEq>(&self, search: C) -> Option<uint> {
         if search.only_ascii() {
             self.byte_iter().position(|b| search.matches(b as char))
@@ -2128,12 +2232,6 @@ fn find<C: CharEq>(&self, search: C) -> Option<uint> {
         }
     }
 
-    /// Returns the byte index of the last character of `self` that matches `search`
-    ///
-    /// # Return value
-    ///
-    /// `Some` containing the byte index of the last matching character
-    /// or `None` if there is no match
     fn rfind<C: CharEq>(&self, search: C) -> Option<uint> {
         if search.only_ascii() {
             self.byte_iter().rposition(|b| search.matches(b as char))
@@ -2145,16 +2243,6 @@ fn rfind<C: CharEq>(&self, search: C) -> Option<uint> {
         }
     }
 
-    /// Returns the byte index of the first matching substring
-    ///
-    /// # Arguments
-    ///
-    /// * `needle` - The string to search for
-    ///
-    /// # Return value
-    ///
-    /// `Some` containing the byte index of the first matching substring
-    /// or `None` if there is no match
     fn find_str(&self, needle: &str) -> Option<uint> {
         if needle.is_empty() {
             Some(0)
@@ -2165,7 +2253,6 @@ fn find_str(&self, needle: &str) -> Option<uint> {
         }
     }
 
-    /// Given a string, make a new string with repeated copies of it.
     fn repeat(&self, nn: uint) -> ~str {
         let mut ret = with_capacity(nn * self.len());
         for _ in range(0, nn) {
@@ -2174,14 +2261,6 @@ fn repeat(&self, nn: uint) -> ~str {
         ret
     }
 
-    /// Retrieves the first character from a string slice and returns
-    /// it. This does not allocate a new string; instead, it returns a
-    /// slice that point one character beyond the character that was
-    /// shifted.
-    ///
-    /// # Failure
-    ///
-    /// If the string does not contain any characters
     #[inline]
     fn slice_shift_char(&self) -> (char, &'self str) {
         let CharRange {ch, next} = self.char_range_at(0u);
@@ -2189,7 +2268,6 @@ fn slice_shift_char(&self) -> (char, &'self str) {
         return (ch, next_s);
     }
 
-    /// Levenshtein Distance between two strings.
     fn lev_distance(&self, t: &str) -> uint {
         let slen = self.len();
         let tlen = t.len();
@@ -2222,22 +2300,6 @@ fn lev_distance(&self, t: &str) -> uint {
         return dcol[tlen];
     }
 
-    /// Returns the byte offset of an inner slice relative to an enclosing outer slice.
-    ///
-    /// Fails if `inner` is not a direct slice contained within self.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let string = "a\nb\nc";
-    /// let mut lines = ~[];
-    /// for line in string.line_iter() { lines.push(line) }
-    ///
-    /// assert!(string.subslice_offset(lines[0]) == 0); // &"a"
-    /// assert!(string.subslice_offset(lines[1]) == 2); // &"b"
-    /// assert!(string.subslice_offset(lines[2]) == 4); // &"c"
-    /// ```
-    #[inline]
     fn subslice_offset(&self, inner: &str) -> uint {
         do self.as_imm_buf |a, a_len| {
             do inner.as_imm_buf |b, b_len| {
@@ -2256,9 +2318,6 @@ fn subslice_offset(&self, inner: &str) -> uint {
         }
     }
 
-    /// Work with the byte buffer and length of a slice.
-    ///
-    /// The buffer does not have a null terminator.
     #[inline]
     fn as_imm_buf<T>(&self, f: &fn(*u8, uint) -> T) -> T {
         let v: &[u8] = unsafe { cast::transmute(*self) };
@@ -2266,19 +2325,79 @@ fn as_imm_buf<T>(&self, f: &fn(*u8, uint) -> T) -> T {
     }
 }
 
-#[allow(missing_doc)]
+/// Methods for owned strings
 pub trait OwnedStr {
+    /// Appends a string slice to the back of a string, without overallocating
     fn push_str_no_overallocate(&mut self, rhs: &str);
+
+    /// Appends a string slice to the back of a string
     fn push_str(&mut self, rhs: &str);
+
+    /// Appends a character to the back of a string
     fn push_char(&mut self, c: char);
+
+    /// Remove the final character from a string and return it
+    ///
+    /// # Failure
+    ///
+    /// If the string does not contain any characters
     fn pop_char(&mut self) -> char;
+
+    /// Remove the first character from a string and return it
+    ///
+    /// # Failure
+    ///
+    /// If the string does not contain any characters
     fn shift_char(&mut self) -> char;
+
+    /// Prepend a char to a string
     fn unshift_char(&mut self, ch: char);
+
+    /// Concatenate two strings together.
     fn append(self, rhs: &str) -> ~str;
+
+    /// Reserves capacity for exactly `n` bytes in the given string.
+    ///
+    /// Assuming single-byte characters, the resulting string will be large
+    /// enough to hold a string of length `n`.
+    ///
+    /// If the capacity for `s` is already equal to or greater than the requested
+    /// capacity, then no action is taken.
+    ///
+    /// # Arguments
+    ///
+    /// * s - A string
+    /// * n - The number of bytes to reserve space for
     fn reserve(&mut self, n: uint);
+
+    /// Reserves capacity for at least `n` bytes in the given string.
+    ///
+    /// Assuming single-byte characters, the resulting string will be large
+    /// enough to hold a string of length `n`.
+    ///
+    /// This function will over-allocate in order to amortize the allocation costs
+    /// in scenarios where the caller may need to repeatedly reserve additional
+    /// space.
+    ///
+    /// If the capacity for `s` is already equal to or greater than the requested
+    /// capacity, then no action is taken.
+    ///
+    /// # Arguments
+    ///
+    /// * s - A string
+    /// * n - The number of bytes to reserve space for
     fn reserve_at_least(&mut self, n: uint);
+
+    /// Returns the number of single-byte characters the string can hold without
+    /// reallocating
     fn capacity(&self) -> uint;
+
+    /// Shorten a string to the specified length (which must be <= the current length)
     fn truncate(&mut self, len: uint);
+
+    /// Consumes the string, returning the underlying byte buffer.
+    ///
+    /// The buffer does not have a null terminator.
     fn into_bytes(self) -> ~[u8];
 
     /// Work with the mutable byte buffer and length of a slice.
@@ -2291,7 +2410,6 @@ pub trait OwnedStr {
 }
 
 impl OwnedStr for ~str {
-    /// Appends a string slice to the back of a string, without overallocating
     #[inline]
     fn push_str_no_overallocate(&mut self, rhs: &str) {
         let new_cap = self.len() + rhs.len();
@@ -2299,7 +2417,6 @@ fn push_str_no_overallocate(&mut self, rhs: &str) {
         self.push_str(rhs);
     }
 
-    /// Appends a string slice to the back of a string
     #[inline]
     fn push_str(&mut self, rhs: &str) {
         unsafe {
@@ -2307,7 +2424,6 @@ fn push_str(&mut self, rhs: &str) {
         }
     }
 
-    /// Appends a character to the back of a string
     #[inline]
     fn push_char(&mut self, c: char) {
         let cur_len = self.len();
@@ -2326,11 +2442,7 @@ fn push_char(&mut self, c: char) {
         }
     }
 
-    /// Remove the final character from a string and return it
-    ///
-    /// # Failure
-    ///
-    /// If the string does not contain any characters
+    #[inline]
     fn pop_char(&mut self) -> char {
         let end = self.len();
         assert!(end > 0u);
@@ -2339,18 +2451,14 @@ fn pop_char(&mut self) -> char {
         return ch;
     }
 
-    /// Remove the first character from a string and return it
-    ///
-    /// # Failure
-    ///
-    /// If the string does not contain any characters
+    #[inline]
     fn shift_char(&mut self) -> char {
         let CharRange {ch, next} = self.char_range_at(0u);
         *self = self.slice(next, self.len()).to_owned();
         return ch;
     }
 
-    /// Prepend a char to a string
+    #[inline]
     fn unshift_char(&mut self, ch: char) {
         // This could be more efficient.
         let mut new_str = ~"";
@@ -2359,7 +2467,6 @@ fn unshift_char(&mut self, ch: char) {
         *self = new_str;
     }
 
-    /// Concatenate two strings together.
     #[inline]
     fn append(self, rhs: &str) -> ~str {
         let mut new_str = self;
@@ -2367,18 +2474,6 @@ fn append(self, rhs: &str) -> ~str {
         new_str
     }
 
-    /// Reserves capacity for exactly `n` bytes in the given string.
-    ///
-    /// Assuming single-byte characters, the resulting string will be large
-    /// enough to hold a string of length `n`.
-    ///
-    /// If the capacity for `s` is already equal to or greater than the requested
-    /// capacity, then no action is taken.
-    ///
-    /// # Arguments
-    ///
-    /// * s - A string
-    /// * n - The number of bytes to reserve space for
     #[inline]
     fn reserve(&mut self, n: uint) {
         unsafe {
@@ -2386,29 +2481,12 @@ fn reserve(&mut self, n: uint) {
         }
     }
 
-    /// Reserves capacity for at least `n` bytes in the given string.
-    ///
-    /// Assuming single-byte characters, the resulting string will be large
-    /// enough to hold a string of length `n`.
-    ///
-    /// This function will over-allocate in order to amortize the allocation costs
-    /// in scenarios where the caller may need to repeatedly reserve additional
-    /// space.
-    ///
-    /// If the capacity for `s` is already equal to or greater than the requested
-    /// capacity, then no action is taken.
-    ///
-    /// # Arguments
-    ///
-    /// * s - A string
-    /// * n - The number of bytes to reserve space for
     #[inline]
     fn reserve_at_least(&mut self, n: uint) {
         self.reserve(uint::next_power_of_two_opt(n).unwrap_or(n))
     }
 
-    /// Returns the number of single-byte characters the string can hold without
-    /// reallocating
+    #[inline]
     fn capacity(&self) -> uint {
         unsafe {
             let buf: &~[u8] = cast::transmute(self);
@@ -2416,7 +2494,6 @@ fn capacity(&self) -> uint {
         }
     }
 
-    /// Shorten a string to the specified length (which must be <= the current length)
     #[inline]
     fn truncate(&mut self, len: uint) {
         assert!(len <= self.len());
@@ -2424,9 +2501,6 @@ fn truncate(&mut self, len: uint) {
         unsafe { raw::set_len(self, len); }
     }
 
-    /// Consumes the string, returning the underlying byte buffer.
-    ///
-    /// The buffer does not have a null terminator.
     #[inline]
     fn into_bytes(self) -> ~[u8] {
         unsafe { cast::transmute(self) }
index c315c3f9dfc5e1f87257e83e6ebbe29bf43517df..c38f3525867cc4ca0e10663d67973c897335ff59 100644 (file)
@@ -125,14 +125,41 @@ fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
     }
 }
 
-// FIXME #4427: Temporary until rt::rt_fail_ goes away
+// This stage0 version is incredibly wrong.
+#[cfg(stage0)]
 pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
     use option::{Some, None};
     use rt::in_green_task_context;
     use rt::task::Task;
     use rt::local::Local;
     use rt::logging::Logger;
-    use send_str::SendStrOwned;
+    use str::Str;
+
+    unsafe {
+        let msg = str::raw::from_c_str(msg);
+        let file = str::raw::from_c_str(file);
+        if in_green_task_context() {
+            rterrln!("task failed at '%s', %s:%i", msg, file, line as int);
+        } else {
+            rterrln!("failed in non-task context at '%s', %s:%i",
+                     msg, file, line as int);
+        }
+
+        let task: *mut Task = Local::unsafe_borrow();
+        if (*task).unwinder.unwinding {
+            rtabort!("unwinding again");
+        }
+        (*task).unwinder.begin_unwind();
+    }
+}
+
+// FIXME #4427: Temporary until rt::rt_fail_ goes away
+#[cfg(not(stage0))]
+pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
+    use rt::in_green_task_context;
+    use rt::task::Task;
+    use rt::local::Local;
+    use rt::logging::Logger;
     use str::Str;
 
     unsafe {
@@ -140,22 +167,14 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
         let msg = str::raw::from_c_str(msg);
         let file = str::raw::from_c_str(file);
 
-        // XXX: Logging doesn't work correctly in non-task context because it
-        // invokes the local heap
         if in_green_task_context() {
-            // XXX: Logging doesn't work here - the check to call the log
-            // function never passes - so calling the log function directly.
+            // Be careful not to allocate in this block, if we're failing we may
+            // have been failing due to a lack of memory in the first place...
             do Local::borrow |task: &mut Task| {
-                let msg = match task.name {
-                    Some(ref name) =>
-                    fmt!("task '%s' failed at '%s', %s:%i",
-                         name.as_slice(), msg, file, line as int),
-                    None =>
-                    fmt!("task <unnamed> failed at '%s', %s:%i",
-                         msg, file, line as int)
-                };
-
-                task.logger.log(SendStrOwned(msg));
+                let n = task.name.map(|n| n.as_slice()).unwrap_or("<unnamed>");
+                format_args!(|args| { task.logger.log(args) },
+                             "task '{}' failed at '{}', {}:{}",
+                             n, msg.as_slice(), file.as_slice(), line);
             }
         } else {
             rterrln!("failed in non-task context at '%s', %s:%i",
index 1dbc644c8e5ce165b46cc05aba6d977adb49fab4..e6f6536956c9ff077789e109a7226f69e2cc3741 100644 (file)
@@ -542,12 +542,9 @@ pub fn deschedule() {
     use rt::local::Local;
     use rt::sched::Scheduler;
 
-    // FIXME #6842: What does yield really mean in newsched?
     // FIXME(#7544): Optimize this, since we know we won't block.
     let sched: ~Scheduler = Local::take();
-    do sched.deschedule_running_task_and_then |sched, task| {
-        sched.enqueue_blocked_task(task);
-    }
+    sched.yield_now();
 }
 
 pub fn failing() -> bool {
index 61c9ea7be14a27c3c7008836957d461f32895c6d..9771f7dadcab5675f57ced164b7c24d0ca8fd5f4 100644 (file)
@@ -813,13 +813,17 @@ macro_rules! log(
         ($lvl:expr, $arg:expr) => ({
             let lvl = $lvl;
             if lvl <= __log_level() {
-                ::std::logging::log(lvl, fmt!(\"%?\", $arg))
+                format_args!(|args| {
+                    ::std::logging::log(lvl, args)
+                }, \"{}\", fmt!(\"%?\", $arg))
             }
         });
         ($lvl:expr, $($arg:expr),+) => ({
             let lvl = $lvl;
             if lvl <= __log_level() {
-                ::std::logging::log(lvl, fmt!($($arg),+))
+                format_args!(|args| {
+                    ::std::logging::log(lvl, args)
+                }, \"{}\", fmt!($($arg),+))
             }
         })
     )
@@ -834,7 +838,9 @@ macro_rules! log2(
         ($lvl:expr, $($arg:tt)+) => ({
             let lvl = $lvl;
             if lvl <= __log_level() {
-                ::std::logging::log(lvl, format!($($arg)+))
+                format_args!(|args| {
+                    ::std::logging::log(lvl, args)
+                }, $($arg)+)
             }
         })
     )
diff --git a/src/test/auxiliary/cfg_inner_static.rs b/src/test/auxiliary/cfg_inner_static.rs
new file mode 100644 (file)
index 0000000..4331a1d
--- /dev/null
@@ -0,0 +1,17 @@
+// 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 used to just ICE on compiling
+pub fn foo() {
+    if cfg!(foo) {
+        static a: int = 3;
+        a
+    } else { 3 };
+}
index bf00dc139d0f594ce248cfc4af7b74024a27be48..58b216e8d119b8d3b78b83bedbcb31fd062debbc 100644 (file)
@@ -20,6 +20,5 @@ fn drop(&mut self) {
 
 fn main() {
     let c = C{ x: 2};
-    let d = c.clone(); //~ ERROR does not implement any method in scope
-    error!("%?", d.x);
+    let _d = c.clone(); //~ ERROR does not implement any method in scope
 }
diff --git a/src/test/compile-fail/issue-5153.rs b/src/test/compile-fail/issue-5153.rs
new file mode 100644 (file)
index 0000000..37d2cce
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+
+// error-pattern: type `@Foo:'static` does not implement any method in scope named `foo`
+
+trait Foo {
+    fn foo(~self);
+}
+
+impl Foo for int {
+    fn foo(~self) { }
+}
+
+fn main() {
+    (@5 as @Foo).foo();
+}
diff --git a/src/test/run-fail/rt-log-trunc.rs b/src/test/run-fail/rt-log-trunc.rs
deleted file mode 100644 (file)
index 1dd27d7..0000000
+++ /dev/null
@@ -1,74 +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.
-
-// Test that logs add `[...]` to truncated lines
-// error-pattern:[...]
-
-fn main() {
-    fail!("\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
-          ");
-}
diff --git a/src/test/run-pass/cfg_inner_static.rs b/src/test/run-pass/cfg_inner_static.rs
new file mode 100644 (file)
index 0000000..2d06a10
--- /dev/null
@@ -0,0 +1,18 @@
+// 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:cfg_inner_static.rs
+// xfail-fast
+
+extern mod cfg_inner_static;
+
+fn main() {
+    cfg_inner_static::foo();
+}
diff --git a/src/test/run-pass/issue-9394-inherited-trait-calls.rs b/src/test/run-pass/issue-9394-inherited-trait-calls.rs
new file mode 100644 (file)
index 0000000..e60f8d4
--- /dev/null
@@ -0,0 +1,61 @@
+// 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.
+
+trait Base: Base2 + Base3{
+    fn foo(&self) -> ~str;
+}
+
+trait Base2: Base3{
+    fn baz(&self) -> ~str;
+}
+
+trait Base3{
+    fn root(&self) -> ~str;
+}
+
+trait Super: Base{
+    fn bar(&self) -> ~str;
+}
+
+struct X;
+
+impl Base for X {
+    fn foo(&self) -> ~str{
+        ~"base foo"
+    }
+
+}
+
+impl Base2 for X {
+    fn baz(&self) -> ~str{
+        ~"base2 baz"
+    }
+}
+
+impl Base3 for X {
+    fn root(&self) -> ~str{
+        ~"base3 root"
+    }
+}
+
+impl Super for X {
+    fn bar(&self) -> ~str{
+        ~"super bar"
+    }
+}
+
+pub fn main() {
+    let n = X;
+    let s = &n as &Super;
+    assert_eq!(s.bar(),~"super bar");
+    assert_eq!(s.foo(),~"base foo");
+    assert_eq!(s.baz(),~"base2 baz");
+    assert_eq!(s.root(),~"base3 root");
+}
diff --git a/src/test/run-pass/logging_before_rt_started.rs b/src/test/run-pass/logging_before_rt_started.rs
new file mode 100644 (file)
index 0000000..cdf3882
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// exec-env:RUST_LOG=std::ptr
+// xfail-fast this would cause everything to print forever on windows...
+
+// In issue #9487, it was realized that std::ptr was invoking the logging
+// infrastructure, and when std::ptr was used during runtime initialization,
+// this caused some serious problems. The problems have since been fixed, but
+// this test will trigger "output during runtime initialization" to make sure
+// that the bug isn't re-introduced.
+
+fn main() {}