diff options
| author | Eric Reed <ereed@mozilla.com> | 2013-06-17 12:45:40 -0700 |
|---|---|---|
| committer | Eric Reed <ereed@mozilla.com> | 2013-06-17 12:45:40 -0700 |
| commit | 35f3fa6383b5ed278879bfe5c74a913b885a2d4f (patch) | |
| tree | be8ca61c0beccd0b4c5d1e486c5322c1181c49f5 /src/libstd | |
| parent | 33ae193a3c1a156e73bf6880366c9785dd4b7393 (diff) | |
| parent | 319cf6e465f203c794d71800808c2bd60a1e7613 (diff) | |
| download | rust-35f3fa6383b5ed278879bfe5c74a913b885a2d4f.tar.gz rust-35f3fa6383b5ed278879bfe5c74a913b885a2d4f.zip | |
Merge remote-tracking branch 'upstream/io' into io
Conflicts: src/libstd/rt/uvio.rs
Diffstat (limited to 'src/libstd')
98 files changed, 5705 insertions, 4550 deletions
diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 7a41c278fa3..a118e445fe2 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -101,6 +101,9 @@ pub fn build_sized_opt<A>(size: Option<uint>, } // Appending + +/// Iterates over the `rhs` vector, copying each element and appending it to the +/// `lhs`. Afterwards, the `lhs` is then returned for use again. #[inline(always)] pub fn append<T:Copy>(lhs: @[T], rhs: &const [T]) -> @[T] { do build_sized(lhs.len() + rhs.len()) |push| { @@ -211,6 +214,9 @@ pub mod raw { (**repr).unboxed.fill = new_len * sys::size_of::<T>(); } + /** + * Pushes a new value onto this vector. + */ #[inline(always)] pub unsafe fn push<T>(v: &mut @[T], initval: T) { let repr: **VecRepr = transmute_copy(&v); @@ -223,7 +229,7 @@ pub mod raw { } #[inline(always)] // really pretty please - pub unsafe fn push_fast<T>(v: &mut @[T], initval: T) { + unsafe fn push_fast<T>(v: &mut @[T], initval: T) { let repr: **mut VecRepr = ::cast::transmute(v); let fill = (**repr).unboxed.fill; (**repr).unboxed.fill += sys::size_of::<T>(); @@ -232,7 +238,7 @@ pub mod raw { move_val_init(&mut(*p), initval); } - pub unsafe fn push_slow<T>(v: &mut @[T], initval: T) { + unsafe fn push_slow<T>(v: &mut @[T], initval: T) { reserve_at_least(&mut *v, v.len() + 1u); push_fast(v, initval); } @@ -280,7 +286,7 @@ pub mod raw { #[cfg(test)] mod test { use super::*; - use prelude::*; + use uint; #[test] fn test() { diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index d91c09c99a2..66a5bfa944f 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -38,6 +38,7 @@ Finally, some inquries into the nature of truth: `is_true` and `is_false`. use cmp::{Eq, Ord, TotalOrd, Ordering}; use option::{None, Option, Some}; use from_str::FromStr; +use to_str::ToStr; /** * Negation of a boolean value. @@ -130,44 +131,6 @@ pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) } pub fn implies(a: bool, b: bool) -> bool { !a || b } /** -* Equality between two boolean values. -* -* Two booleans are equal if they have the same value. -* -* # Examples -* -* ~~~ {.rust} -* rusti> std::bool::eq(false, true) -* false -* ~~~ -* -* ~~~ {.rust} -* rusti> std::bool::eq(false, false) -* true -* ~~~ -*/ -pub fn eq(a: bool, b: bool) -> bool { a == b } - -/** -* Non-equality between two boolean values. -* -* Two booleans are not equal if they have different values. -* -* # Examples -* -* ~~~ {.rust} -* rusti> std::bool::ne(false, true) -* true -* ~~~ -* -* ~~~ {.rust} -* rusti> std::bool::ne(false, false) -* false -* ~~~ -*/ -pub fn ne(a: bool, b: bool) -> bool { a != b } - -/** * Is a given boolean value true? * * # Examples @@ -239,16 +202,21 @@ impl FromStr for bool { * # Examples * * ~~~ {.rust} -* rusti> std::bool::to_str(true) +* rusti> true.to_str() * "true" * ~~~ * * ~~~ {.rust} -* rusti> std::bool::to_str(false) +* rusti> false.to_str() * "false" * ~~~ */ -pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } } +impl ToStr for bool { + #[inline(always)] + fn to_str(&self) -> ~str { + if *self { ~"true" } else { ~"false" } + } +} /** * Iterates over all truth values, passing them to the given block. @@ -258,7 +226,7 @@ pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } } * # Examples * ~~~ * do std::bool::all_values |x: bool| { -* println(std::bool::to_str(x)); +* println(x.to_str()) * } * ~~~ */ @@ -303,6 +271,31 @@ impl TotalOrd for bool { fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) } } +/** +* Equality between two boolean values. +* +* Two booleans are equal if they have the same value. +* +* ~~~ {.rust} +* rusti> false.eq(&true) +* false +* ~~~ +* +* ~~~ {.rust} +* rusti> false == false +* true +* ~~~ +* +* ~~~ {.rust} +* rusti> false != true +* true +* ~~~ +* +* ~~~ {.rust} +* rusti> false.ne(&false) +* false +* ~~~ +*/ #[cfg(not(test))] impl Eq for bool { #[inline(always)] @@ -319,14 +312,14 @@ mod tests { #[test] fn test_bool_from_str() { do all_values |v| { - assert!(Some(v) == FromStr::from_str(to_str(v))) + assert!(Some(v) == FromStr::from_str(v.to_str())) } } #[test] fn test_bool_to_str() { - assert_eq!(to_str(false), ~"false"); - assert_eq!(to_str(true), ~"true"); + assert_eq!(false.to_str(), ~"false"); + assert_eq!(true.to_str(), ~"true"); } #[test] diff --git a/src/libstd/borrow.rs b/src/libstd/borrow.rs new file mode 100644 index 00000000000..703011aea7f --- /dev/null +++ b/src/libstd/borrow.rs @@ -0,0 +1,60 @@ +// Copyright 2012-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. + +//! Borrowed pointer utilities + +#[cfg(not(test))] +use prelude::*; + +/// Cast a region pointer - &T - to a uint. +#[inline(always)] +pub fn to_uint<T>(thing: &T) -> uint { + thing as *T as uint +} + +/// Determine if two borrowed pointers point to the same thing. +#[inline(always)] +pub fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool { + to_uint(thing) == to_uint(other) +} + +// Equality for region pointers +#[cfg(not(test))] +impl<'self, T: Eq> Eq for &'self T { + #[inline(always)] + fn eq(&self, other: & &'self T) -> bool { + *(*self) == *(*other) + } + #[inline(always)] + fn ne(&self, other: & &'self T) -> bool { + *(*self) != *(*other) + } +} + +// Comparison for region pointers +#[cfg(not(test))] +impl<'self, T: Ord> Ord for &'self T { + #[inline(always)] + fn lt(&self, other: & &'self T) -> bool { + *(*self) < *(*other) + } + #[inline(always)] + fn le(&self, other: & &'self T) -> bool { + *(*self) <= *(*other) + } + #[inline(always)] + fn ge(&self, other: & &'self T) -> bool { + *(*self) >= *(*other) + } + #[inline(always)] + fn gt(&self, other: & &'self T) -> bool { + *(*self) > *(*other) + } +} diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index 30ad41f0ca2..2109568a0a4 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -27,6 +27,7 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U { dest } +/// Casts the value at `src` to U. The two types must have the same length. #[cfg(target_word_size = "32", not(stage0))] #[inline(always)] pub unsafe fn transmute_copy<T, U>(src: &T) -> U { @@ -37,6 +38,7 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U { dest } +/// Casts the value at `src` to U. The two types must have the same length. #[cfg(target_word_size = "64", not(stage0))] #[inline(always)] pub unsafe fn transmute_copy<T, U>(src: &T) -> U { diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index d1fa9e697bf..e1d2b246dd3 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,6 +10,8 @@ //! A mutable, nullable memory location +#[missing_doc]; + use cast::transmute_mut; use prelude::*; use util::replace; @@ -22,22 +24,24 @@ Similar to a mutable option type, but friendlier. #[mutable] #[deriving(Clone, DeepClone, Eq)] +#[allow(missing_doc)] pub struct Cell<T> { priv value: Option<T> } -/// Creates a new full cell with the given value. -pub fn Cell<T>(value: T) -> Cell<T> { - Cell { value: Some(value) } -} +impl<T> Cell<T> { + /// Creates a new full cell with the given value. + pub fn new(value: T) -> Cell<T> { + Cell { value: Some(value) } + } -pub fn empty_cell<T>() -> Cell<T> { - Cell { value: None } -} + /// Creates a new empty cell with no value inside. + pub fn new_empty() -> Cell<T> { + Cell { value: None } + } -pub impl<T> Cell<T> { /// Yields the value, failing if the cell is empty. - fn take(&self) -> T { + pub fn take(&self) -> T { let this = unsafe { transmute_mut(self) }; if this.is_empty() { fail!("attempt to take an empty cell"); @@ -47,7 +51,7 @@ pub impl<T> Cell<T> { } /// Returns the value, failing if the cell is full. - fn put_back(&self, value: T) { + pub fn put_back(&self, value: T) { let this = unsafe { transmute_mut(self) }; if !this.is_empty() { fail!("attempt to put a value back into a full cell"); @@ -56,20 +60,20 @@ pub impl<T> Cell<T> { } /// Returns true if the cell is empty and false if the cell is full. - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.value.is_none() } - // Calls a closure with a reference to the value. - fn with_ref<R>(&self, op: &fn(v: &T) -> R) -> R { + /// Calls a closure with a reference to the value. + pub fn with_ref<R>(&self, op: &fn(v: &T) -> R) -> R { let v = self.take(); let r = op(&v); self.put_back(v); r } - // Calls a closure with a mutable reference to the value. - fn with_mut_ref<R>(&self, op: &fn(v: &mut T) -> R) -> R { + /// Calls a closure with a mutable reference to the value. + pub fn with_mut_ref<R>(&self, op: &fn(v: &mut T) -> R) -> R { let mut v = self.take(); let r = op(&mut v); self.put_back(v); @@ -79,7 +83,7 @@ pub impl<T> Cell<T> { #[test] fn test_basic() { - let value_cell = Cell(~10); + let value_cell = Cell::new(~10); assert!(!value_cell.is_empty()); let value = value_cell.take(); assert!(value == ~10); @@ -92,7 +96,7 @@ fn test_basic() { #[should_fail] #[ignore(cfg(windows))] fn test_take_empty() { - let value_cell = empty_cell::<~int>(); + let value_cell = Cell::new_empty::<~int>(); value_cell.take(); } @@ -100,14 +104,14 @@ fn test_take_empty() { #[should_fail] #[ignore(cfg(windows))] fn test_put_back_non_empty() { - let value_cell = Cell(~10); + let value_cell = Cell::new(~10); value_cell.put_back(~20); } #[test] fn test_with_ref() { let good = 6; - let c = Cell(~[1, 2, 3, 4, 5, 6]); + let c = Cell::new(~[1, 2, 3, 4, 5, 6]); let l = do c.with_ref() |v| { v.len() }; assert_eq!(l, good); } @@ -116,7 +120,7 @@ fn test_with_ref() { fn test_with_mut_ref() { let good = ~[1, 2, 3]; let v = ~[1, 2]; - let c = Cell(v); + let c = Cell::new(v); do c.with_mut_ref() |v| { v.push(3); } let v = c.take(); assert_eq!(v, good); diff --git a/src/libstd/char.rs b/src/libstd/char.rs index bd70f59212d..073ced8988a 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -53,8 +53,12 @@ use cmp::{Eq, Ord}; Cn Unassigned a reserved unassigned code point or a noncharacter */ +/// Returns whether the specified character is considered a unicode alphabetic +/// character pub fn is_alphabetic(c: char) -> bool { derived_property::Alphabetic(c) } +#[allow(missing_doc)] pub fn is_XID_start(c: char) -> bool { derived_property::XID_Start(c) } +#[allow(missing_doc)] pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) } /// @@ -256,6 +260,7 @@ pub fn len_utf8_bytes(c: char) -> uint { ) } +#[allow(missing_doc)] pub trait Char { fn is_alphabetic(&self) -> bool; fn is_XID_start(&self) -> bool; diff --git a/src/libstd/clone.rs b/src/libstd/clone.rs index 2965b31a8c3..266dd1a35e3 100644 --- a/src/libstd/clone.rs +++ b/src/libstd/clone.rs @@ -24,6 +24,7 @@ by convention implementing the `Clone` trait and calling the use core::kinds::Const; +/// A common trait for cloning an object. pub trait Clone { /// Returns a copy of the value. The contents of owned pointers /// are copied to maintain uniqueness, while the contents of @@ -85,10 +86,11 @@ clone_impl!(()) clone_impl!(bool) clone_impl!(char) +/// A trait distinct from `Clone` which represents "deep copies" of things like +/// managed boxes which would otherwise not be copied. pub trait DeepClone { /// Return a deep copy of the value. Unlike `Clone`, the contents of shared pointer types - /// *are* copied. Note that this is currently unimplemented for managed boxes, as - /// it would need to handle cycles, but it is implemented for other smart-pointer types. + /// *are* copied. fn deep_clone(&self) -> Self; } diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index ca9c49b2c06..ce6a04c3688 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -20,6 +20,8 @@ and `Eq` to overload the `==` and `!=` operators. */ +#[allow(missing_doc)]; + /** * Trait for values that can be compared for equality and inequality. * @@ -170,36 +172,6 @@ pub trait Ord { fn gt(&self, other: &Self) -> bool; } -#[inline(always)] -pub fn lt<T:Ord>(v1: &T, v2: &T) -> bool { - (*v1).lt(v2) -} - -#[inline(always)] -pub fn le<T:Ord>(v1: &T, v2: &T) -> bool { - (*v1).le(v2) -} - -#[inline(always)] -pub fn eq<T:Eq>(v1: &T, v2: &T) -> bool { - (*v1).eq(v2) -} - -#[inline(always)] -pub fn ne<T:Eq>(v1: &T, v2: &T) -> bool { - (*v1).ne(v2) -} - -#[inline(always)] -pub fn ge<T:Ord>(v1: &T, v2: &T) -> bool { - (*v1).ge(v2) -} - -#[inline(always)] -pub fn gt<T:Ord>(v1: &T, v2: &T) -> bool { - (*v1).gt(v2) -} - /// The equivalence relation. Two values may be equivalent even if they are /// of different types. The most common use case for this relation is /// container types; e.g. it is often desirable to be able to use `&str` diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 59eb915c239..f0c353c8d62 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -12,6 +12,8 @@ Message passing */ +#[allow(missing_doc)]; + use cast::{transmute, transmute_mut}; use container::Container; use either::{Either, Left, Right}; @@ -148,14 +150,14 @@ pub struct PortSet<T> { ports: ~[pipesy::Port<T>], } -pub impl<T: Owned> PortSet<T> { - fn new() -> PortSet<T> { +impl<T: Owned> PortSet<T> { + pub fn new() -> PortSet<T> { PortSet { ports: ~[] } } - fn add(&self, port: Port<T>) { + pub fn add(&self, port: Port<T>) { let Port { inner } = port; let port = match inner { Left(p) => p, @@ -167,7 +169,7 @@ pub impl<T: Owned> PortSet<T> { } } - fn chan(&self) -> Chan<T> { + pub fn chan(&self) -> Chan<T> { let (po, ch) = stream(); self.add(po); ch @@ -236,20 +238,24 @@ impl<T: Owned> SharedChan<T> { impl<T: Owned> GenericChan<T> for SharedChan<T> { fn send(&self, x: T) { - let mut xx = Some(x); - do self.ch.with_imm |chan| { - let x = replace(&mut xx, None); - chan.send(x.unwrap()) + unsafe { + let mut xx = Some(x); + do self.ch.with_imm |chan| { + let x = replace(&mut xx, None); + chan.send(x.unwrap()) + } } } } impl<T: Owned> GenericSmartChan<T> for SharedChan<T> { fn try_send(&self, x: T) -> bool { - let mut xx = Some(x); - do self.ch.with_imm |chan| { - let x = replace(&mut xx, None); - chan.try_send(x.unwrap()) + unsafe { + let mut xx = Some(x); + do self.ch.with_imm |chan| { + let x = replace(&mut xx, None); + chan.try_send(x.unwrap()) + } } } } @@ -370,7 +376,7 @@ mod pipesy { priv use core::kinds::Owned; use ptr::to_mut_unsafe_ptr; - pub fn init<T: Owned>() -> (client::Oneshot<T>, server::Oneshot<T>) { + pub fn init<T: Owned>() -> (server::Oneshot<T>, client::Oneshot<T>) { pub use core::pipes::HasBuffer; let buffer = ~::core::pipes::Buffer { @@ -460,24 +466,24 @@ mod pipesy { /// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair. pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { - let (chan, port) = oneshot::init(); + let (port, chan) = oneshot::init(); (PortOne::new(port), ChanOne::new(chan)) } - pub impl<T: Owned> PortOne<T> { - fn recv(self) -> T { recv_one(self) } - fn try_recv(self) -> Option<T> { try_recv_one(self) } - fn unwrap(self) -> oneshot::server::Oneshot<T> { + impl<T: Owned> PortOne<T> { + pub fn recv(self) -> T { recv_one(self) } + pub fn try_recv(self) -> Option<T> { try_recv_one(self) } + pub fn unwrap(self) -> oneshot::server::Oneshot<T> { match self { PortOne { contents: s } => s } } } - pub impl<T: Owned> ChanOne<T> { - fn send(self, data: T) { send_one(self, data) } - fn try_send(self, data: T) -> bool { try_send_one(self, data) } - fn unwrap(self) -> oneshot::client::Oneshot<T> { + impl<T: Owned> ChanOne<T> { + pub fn send(self, data: T) { send_one(self, data) } + pub fn try_send(self, data: T) -> bool { try_send_one(self, data) } + pub fn unwrap(self) -> oneshot::client::Oneshot<T> { match self { ChanOne { contents: s } => s } @@ -544,7 +550,7 @@ mod pipesy { pub mod streamp { priv use core::kinds::Owned; - pub fn init<T: Owned>() -> (client::Open<T>, server::Open<T>) { + pub fn init<T: Owned>() -> (server::Open<T>, client::Open<T>) { pub use core::pipes::HasBuffer; ::core::pipes::entangle() } @@ -561,7 +567,7 @@ mod pipesy { ::core::option::Option<Open<T>> { { use super::data; - let (c, s) = ::core::pipes::entangle(); + let (s, c) = ::core::pipes::entangle(); let message = data(x_0, s); if ::core::pipes::send(pipe, message) { ::core::pipes::rt::make_some(c) @@ -573,7 +579,7 @@ mod pipesy { pub fn data<T: Owned>(pipe: Open<T>, x_0: T) -> Open<T> { { use super::data; - let (c, s) = ::core::pipes::entangle(); + let (s, c) = ::core::pipes::entangle(); let message = data(x_0, s); ::core::pipes::send(pipe, message); c @@ -609,7 +615,7 @@ mod pipesy { */ pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { - let (c, s) = streamp::init(); + let (s, c) = streamp::init(); (Port { endp: Some(s) diff --git a/src/libstd/condition.rs b/src/libstd/condition.rs index baa6722b193..2f150a0d1b2 100644 --- a/src/libstd/condition.rs +++ b/src/libstd/condition.rs @@ -10,8 +10,11 @@ /*! Condition handling */ -use prelude::*; +#[allow(missing_doc)]; + use local_data::{local_data_pop, local_data_set}; +use local_data; +use prelude::*; // helper for transmutation, shown below. type RustClosure = (int, int); @@ -26,8 +29,8 @@ pub struct Condition<'self, T, U> { key: local_data::LocalDataKey<'self, Handler<T, U>> } -pub impl<'self, T, U> Condition<'self, T, U> { - fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> { +impl<'self, T, U> Condition<'self, T, U> { + pub fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> { unsafe { let p : *RustClosure = ::cast::transmute(&h); let prev = local_data::local_data_get(self.key); @@ -36,12 +39,12 @@ pub impl<'self, T, U> Condition<'self, T, U> { } } - fn raise(&self, t: T) -> U { + pub fn raise(&self, t: T) -> U { let msg = fmt!("Unhandled condition: %s: %?", self.name, t); self.raise_default(t, || fail!(copy msg)) } - fn raise_default(&self, t: T, default: &fn() -> U) -> U { + pub fn raise_default(&self, t: T, default: &fn() -> U) -> U { unsafe { match local_data_pop(self.key) { None => { @@ -70,8 +73,8 @@ struct Trap<'self, T, U> { handler: @Handler<T, U> } -pub impl<'self, T, U> Trap<'self, T, U> { - fn in<V>(&self, inner: &'self fn() -> V) -> V { +impl<'self, T, U> Trap<'self, T, U> { + pub fn in<V>(&self, inner: &'self fn() -> V) -> V { unsafe { let _g = Guard { cond: self.cond }; debug!("Trap: pushing handler to TLS"); diff --git a/src/libstd/container.rs b/src/libstd/container.rs index 505aa5881c5..065582e2e0d 100644 --- a/src/libstd/container.rs +++ b/src/libstd/container.rs @@ -12,6 +12,8 @@ use option::Option; +/// A trait to represent the abstract idea of a container. The only concrete +/// knowledge known is the number of elements contained within. pub trait Container { /// Return the number of elements in the container fn len(&const self) -> uint; @@ -20,16 +22,19 @@ pub trait Container { fn is_empty(&const self) -> bool; } +/// A trait to represent mutable containers pub trait Mutable: Container { /// Clear the container, removing all values. fn clear(&mut self); } +/// A map is a key-value store where values may be looked up by their keys. This +/// trait provides basic operations to operate on these stores. pub trait Map<K, V>: Mutable { /// Return true if the map contains a value for the specified key fn contains_key(&self, key: &K) -> bool; - // Visits all keys and values + /// Visits all keys and values fn each<'a>(&'a self, f: &fn(&K, &'a V) -> bool) -> bool; /// Visit all keys @@ -65,6 +70,9 @@ pub trait Map<K, V>: Mutable { fn pop(&mut self, k: &K) -> Option<V>; } +/// A set is a group of objects which are each distinct from one another. This +/// trait represents actions which can be performed on sets to manipulate and +/// iterate over them. pub trait Set<T>: Mutable { /// Return true if the set contains a value fn contains(&self, value: &T) -> bool; diff --git a/src/libstd/core.rc b/src/libstd/core.rc index 3d5f0fb8493..8e09a9b17fd 100644 --- a/src/libstd/core.rc +++ b/src/libstd/core.rc @@ -10,39 +10,39 @@ /*! -# The Rust core library +# The Rust standard library -The Rust core library provides runtime features required by the language, +The Rust standard library provides runtime features required by the language, including the task scheduler and memory allocators, as well as library support for Rust built-in types, platform abstractions, and other commonly used features. -`core` includes modules corresponding to each of the integer types, each of +`std` includes modules corresponding to each of the integer types, each of the floating point types, the `bool` type, tuples, characters, strings (`str`), vectors (`vec`), managed boxes (`managed`), owned boxes (`owned`), -and unsafe and borrowed pointers (`ptr`). Additionally, `core` provides +and unsafe and borrowed pointers (`ptr`). Additionally, `std` provides pervasive types (`option` and `result`), task creation and communication primitives (`task`, `comm`), platform abstractions (`os` and `path`), basic I/O abstractions (`io`), common traits (`kinds`, `ops`, `cmp`, `num`, `to_str`), and complete bindings to the C standard library (`libc`). -# Core injection and the Rust prelude +# Standard library injection and the Rust prelude -`core` is imported at the topmost level of every crate by default, as +`std` is imported at the topmost level of every crate by default, as if the first line of each crate was - extern mod core; + extern mod std; -This means that the contents of core can be accessed from from any context -with the `core::` path prefix, as in `use core::vec`, `use core::task::spawn`, +This means that the contents of std can be accessed from any context +with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`, etc. -Additionally, `core` contains a `prelude` module that reexports many of the -most common core modules, types and traits. The contents of the prelude are +Additionally, `std` contains a `prelude` module that reexports many of the +most common std modules, types and traits. The contents of the prelude are imported into every *module* by default. Implicitly, all modules behave as if they contained the following prologue: - use core::prelude::*; + use std::prelude::*; */ @@ -50,18 +50,21 @@ they contained the following prologue: #[link(name = "std", vers = "0.7-pre", uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8", - url = "https://github.com/mozilla/rust/tree/master/src/libcore")]; + url = "https://github.com/mozilla/rust/tree/master/src/libstd")]; -#[comment = "The Rust core library"]; +#[comment = "The Rust standard library"]; #[license = "MIT/ASL2"]; #[crate_type = "lib"]; +// NOTE: remove these two attributes after the next snapshot +#[no_core]; // for stage0 +#[allow(unrecognized_lint)]; // otherwise stage0 is seriously ugly // Don't link to std. We are std. -#[no_core]; // for stage0 #[no_std]; #[deny(non_camel_case_types)]; +#[deny(missing_doc)]; // Make core testable by not duplicating lang items. See #2912 #[cfg(test)] extern mod realstd(name = "std"); @@ -122,6 +125,7 @@ pub mod ascii; pub mod ptr; pub mod owned; pub mod managed; +pub mod borrow; /* Core language traits */ @@ -224,5 +228,7 @@ mod std { pub use kinds; pub use sys; pub use pipes; + pub use unstable; + pub use str; + pub use os; } - diff --git a/src/libstd/either.rs b/src/libstd/either.rs index f89bb3b2f90..fac0866f17e 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -10,6 +10,8 @@ //! A type that represents one of two alternatives +#[allow(missing_doc)]; + use container::Container; use cmp::Eq; use kinds::Copy; @@ -137,29 +139,29 @@ pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U { } } -pub impl<T, U> Either<T, U> { +impl<T, U> Either<T, U> { #[inline(always)] - fn either<V>(&self, f_left: &fn(&T) -> V, f_right: &fn(&U) -> V) -> V { + pub fn either<V>(&self, f_left: &fn(&T) -> V, f_right: &fn(&U) -> V) -> V { either(f_left, f_right, self) } #[inline(always)] - fn flip(self) -> Either<U, T> { flip(self) } + pub fn flip(self) -> Either<U, T> { flip(self) } #[inline(always)] - fn to_result(self) -> Result<U, T> { to_result(self) } + pub fn to_result(self) -> Result<U, T> { to_result(self) } #[inline(always)] - fn is_left(&self) -> bool { is_left(self) } + pub fn is_left(&self) -> bool { is_left(self) } #[inline(always)] - fn is_right(&self) -> bool { is_right(self) } + pub fn is_right(&self) -> bool { is_right(self) } #[inline(always)] - fn unwrap_left(self) -> T { unwrap_left(self) } + pub fn unwrap_left(self) -> T { unwrap_left(self) } #[inline(always)] - fn unwrap_right(self) -> U { unwrap_right(self) } + pub fn unwrap_right(self) -> U { unwrap_right(self) } } #[test] diff --git a/src/libstd/from_str.rs b/src/libstd/from_str.rs index ebf6d212466..d2f1a895e1e 100644 --- a/src/libstd/from_str.rs +++ b/src/libstd/from_str.rs @@ -12,6 +12,10 @@ use option::Option; +/// A trait to abstract the idea of creating a new instance of a type from a +/// string. pub trait FromStr { + /// Parses a string `s` to return an optional value of this type. If the + /// string is ill-formatted, the None is returned. fn from_str(s: &str) -> Option<Self>; } diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index 7eb2054a35d..e9022445786 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -19,6 +19,8 @@ * CPRNG like rand::rng. */ +#[allow(missing_doc)]; + use container::Container; use old_iter::BaseIter; use rt::io::Writer; @@ -387,6 +389,8 @@ mod tests { use super::*; use prelude::*; + use uint; + #[test] fn test_siphash() { let vecs : [[u8, ..8], ..64] = [ diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index e6ccb7a1d6b..85156d6996d 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -13,11 +13,14 @@ //! The tables use a keyed hash with new random keys generated for each container, so the ordering //! of a set of keys in a hash table is randomized. +#[mutable_doc]; + use container::{Container, Mutable, Map, Set}; use cmp::{Eq, Equiv}; use hash::Hash; use old_iter::BaseIter; use old_iter; +use iterator::{IteratorUtil}; use option::{None, Option, Some}; use rand::RngUtil; use rand; @@ -34,6 +37,14 @@ struct Bucket<K,V> { value: V, } +/// A hash map implementation which uses linear probing along with the SipHash +/// hash function for internal state. This means that the order of all hash maps +/// is randomized by keying each hash map randomly on creation. +/// +/// It is required that the keys implement the `Eq` and `Hash` traits, although +/// this can frequently be achieved by just implementing the `Eq` and +/// `IterBytes` traits as `Hash` is automatically implemented for types that +/// implement `IterBytes`. pub struct HashMap<K,V> { priv k0: u64, priv k1: u64, @@ -53,6 +64,7 @@ fn resize_at(capacity: uint) -> uint { ((capacity as float) * 3. / 4.) as uint } +/// Creates a new hash map with the specified capacity. pub fn linear_map_with_capacity<K:Eq + Hash,V>( initial_capacity: uint) -> HashMap<K, V> { let mut r = rand::task_rng(); @@ -63,15 +75,16 @@ pub fn linear_map_with_capacity<K:Eq + Hash,V>( fn linear_map_with_capacity_and_keys<K:Eq + Hash,V>( k0: u64, k1: u64, initial_capacity: uint) -> HashMap<K, V> { + let cap = uint::max(INITIAL_CAPACITY, initial_capacity); HashMap { k0: k0, k1: k1, - resize_at: resize_at(initial_capacity), + resize_at: resize_at(cap), size: 0, - buckets: vec::from_fn(initial_capacity, |_| None) + buckets: vec::from_fn(cap, |_| None) } } -priv impl<K:Hash + Eq,V> HashMap<K, V> { +impl<K:Hash + Eq,V> HashMap<K, V> { #[inline(always)] fn to_bucket(&self, h: uint) -> uint { // A good hash function with entropy spread over all of the @@ -81,9 +94,7 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> { #[inline(always)] fn next_bucket(&self, idx: uint, len_buckets: uint) -> uint { - let n = (idx + 1) % len_buckets; - debug!("next_bucket(%?, %?) = %?", idx, len_buckets, n); - n + (idx + 1) % len_buckets } #[inline(always)] @@ -202,16 +213,12 @@ priv impl<K:Hash + Eq,V> HashMap<K, V> { match self.bucket_for_key_with_hash(hash, &k) { TableFull => { fail!("Internal logic error"); } FoundHole(idx) => { - debug!("insert fresh (%?->%?) at idx %?, hash %?", - k, v, idx, hash); self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); self.size += 1; None } FoundEntry(idx) => { - debug!("insert overwrite (%?->%?) at idx %?, hash %?", - k, v, idx, hash); match self.buckets[idx] { None => { fail!("insert_internal: Internal logic error") } Some(ref mut b) => { @@ -304,7 +311,7 @@ impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> { /// Visit all key-value pairs fn each<'a>(&'a self, blk: &fn(&K, &'a V) -> bool) -> bool { for self.buckets.each |bucket| { - for bucket.each |pair| { + for bucket.iter().advance |pair| { if !blk(&pair.key, &pair.value) { return false; } @@ -393,29 +400,30 @@ impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> { } } -pub impl<K: Hash + Eq, V> HashMap<K, V> { +impl<K: Hash + Eq, V> HashMap<K, V> { /// Create an empty HashMap - fn new() -> HashMap<K, V> { + pub fn new() -> HashMap<K, V> { HashMap::with_capacity(INITIAL_CAPACITY) } /// Create an empty HashMap with space for at least `n` elements in /// the hash table. - fn with_capacity(capacity: uint) -> HashMap<K, V> { + pub fn with_capacity(capacity: uint) -> HashMap<K, V> { linear_map_with_capacity(capacity) } /// Reserve space for at least `n` elements in the hash table. - fn reserve_at_least(&mut self, n: uint) { + pub fn reserve_at_least(&mut self, n: uint) { if n > self.buckets.len() { let buckets = n * 4 / 3 + 1; self.resize(uint::next_power_of_two(buckets)); } } - /// Return the value corresponding to the key in the map, or insert - /// and return the value if it doesn't exist. - fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V { + /// Modify and return the value corresponding to the key in the map, or + /// insert and return a new value if it doesn't exist. + pub fn mangle<'a,A>(&'a mut self, k: K, a: A, not_found: &fn(&K, A) -> V, + found: &fn(&K, &mut V, A)) -> &'a mut V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so // that we do not resize if this call to insert is @@ -429,49 +437,44 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> { let hash = k.hash_keyed(self.k0, self.k1) as uint; let idx = match self.bucket_for_key_with_hash(hash, &k) { TableFull => fail!("Internal logic error"), - FoundEntry(idx) => idx, + FoundEntry(idx) => { found(&k, self.mut_value_for_bucket(idx), a); idx } FoundHole(idx) => { - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); + let v = not_found(&k, a); + self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); self.size += 1; idx - }, + } }; - self.value_for_bucket(idx) + self.mut_value_for_bucket(idx) + } + + /// Return the value corresponding to the key in the map, or insert + /// and return the value if it doesn't exist. + pub fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a mut V { + self.mangle(k, v, |_k, a| a, |_k,_v,_a| ()) } /// Return the value corresponding to the key in the map, or create, /// insert, and return a new value if it doesn't exist. - fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!("Internal logic error"), - FoundEntry(idx) => idx, - FoundHole(idx) => { - let v = f(&k); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; + pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) + -> &'a mut V { + self.mangle(k, (), |k,_a| f(k), |_k,_v,_a| ()) + } - self.value_for_bucket(idx) + /// Insert a key-value pair into the map if the key is not already present. + /// Otherwise, modify the existing value for the key. + /// Returns the new or modified value for the key. + pub fn insert_or_update_with<'a>(&'a mut self, k: K, v: V, + f: &fn(&K, &mut V)) -> &'a mut V { + self.mangle(k, v, |_k,a| a, |k,v,_a| f(k,v)) } - fn consume(&mut self, f: &fn(K, V)) { - let buckets = replace(&mut self.buckets, ~[]); + /// Calls a function on each element of a hash map, destroying the hash + /// map in the process. + pub fn consume(&mut self, f: &fn(K, V)) { + let buckets = replace(&mut self.buckets, + vec::from_fn(INITIAL_CAPACITY, |_| None)); self.size = 0; do vec::consume(buckets) |_, bucket| { @@ -484,16 +487,27 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> { } } - fn get<'a>(&'a self, k: &K) -> &'a V { + /// Retrieves a value for the given key, failing if the key is not + /// present. + pub fn get<'a>(&'a self, k: &K) -> &'a V { match self.find(k) { Some(v) => v, None => fail!("No entry found for key: %?", k), } } + /// Retrieves a (mutable) value for the given key, failing if the key + /// is not present. + pub fn get_mut<'a>(&'a mut self, k: &K) -> &'a mut V { + match self.find_mut(k) { + Some(v) => v, + None => fail!("No entry found for key: %?", k), + } + } + /// Return true if the map contains a value for the specified key, /// using equivalence - fn contains_key_equiv<Q:Hash + Equiv<K>>(&self, key: &Q) -> bool { + pub fn contains_key_equiv<Q:Hash + Equiv<K>>(&self, key: &Q) -> bool { match self.bucket_for_key_equiv(key) { FoundEntry(_) => {true} TableFull | FoundHole(_) => {false} @@ -502,7 +516,8 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> { /// Return the value corresponding to the key in the map, using /// equivalence - fn find_equiv<'a, Q:Hash + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> { + pub fn find_equiv<'a, Q:Hash + Equiv<K>>(&'a self, k: &Q) + -> Option<&'a V> { match self.bucket_for_key_equiv(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), TableFull | FoundHole(_) => None, @@ -510,14 +525,14 @@ pub impl<K: Hash + Eq, V> HashMap<K, V> { } } -pub impl<K: Hash + Eq, V: Copy> HashMap<K, V> { +impl<K: Hash + Eq, V: Copy> HashMap<K, V> { /// Like `find`, but returns a copy of the value. - fn find_copy(&self, k: &K) -> Option<V> { + pub fn find_copy(&self, k: &K) -> Option<V> { self.find(k).map_consume(|v| copy *v) } /// Like `get`, but returns a copy of the value. - fn get_copy(&self, k: &K) -> V { + pub fn get_copy(&self, k: &K) -> V { copy *self.get(k) } } @@ -539,6 +554,9 @@ impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> { fn ne(&self, other: &HashMap<K, V>) -> bool { !self.eq(other) } } +/// An implementation of a hash set using the underlying representation of a +/// HashMap where the value is (). As with the `HashMap` type, a `HashSet` +/// requires that the elements implement the `Eq` and `Hash` traits. pub struct HashSet<T> { priv map: HashMap<T, ()> } @@ -618,29 +636,31 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> { } } -pub impl <T:Hash + Eq> HashSet<T> { +impl<T:Hash + Eq> HashSet<T> { /// Create an empty HashSet - fn new() -> HashSet<T> { + pub fn new() -> HashSet<T> { HashSet::with_capacity(INITIAL_CAPACITY) } /// Create an empty HashSet with space for at least `n` elements in /// the hash table. - fn with_capacity(capacity: uint) -> HashSet<T> { + pub fn with_capacity(capacity: uint) -> HashSet<T> { HashSet { map: HashMap::with_capacity(capacity) } } /// Reserve space for at least `n` elements in the hash table. - fn reserve_at_least(&mut self, n: uint) { + pub fn reserve_at_least(&mut self, n: uint) { self.map.reserve_at_least(n) } /// Consumes all of the elements in the set, emptying it out - fn consume(&mut self, f: &fn(T)) { + pub fn consume(&mut self, f: &fn(T)) { self.map.consume(|k, _| f(k)) } - fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool { + /// Returns true if the hash set contains a value equivalent to the + /// given query value. + pub fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } } @@ -653,6 +673,12 @@ mod test_map { use uint; #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + assert!(m.insert(1, 1)); + } + + #[test] fn test_insert() { let mut m = HashMap::new(); assert!(m.insert(1, 2)); @@ -733,15 +759,22 @@ mod test_map { #[test] fn test_find_or_insert() { let mut m = HashMap::new::<int, int>(); - assert_eq!(m.find_or_insert(1, 2), &2); - assert_eq!(m.find_or_insert(1, 3), &2); + assert_eq!(*m.find_or_insert(1, 2), 2); + assert_eq!(*m.find_or_insert(1, 3), 2); } #[test] fn test_find_or_insert_with() { let mut m = HashMap::new::<int, int>(); - assert_eq!(m.find_or_insert_with(1, |_| 2), &2); - assert_eq!(m.find_or_insert_with(1, |_| 3), &2); + assert_eq!(*m.find_or_insert_with(1, |_| 2), 2); + assert_eq!(*m.find_or_insert_with(1, |_| 3), 2); + } + + #[test] + fn test_insert_or_update_with() { + let mut m = HashMap::new::<int, int>(); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3); } #[test] @@ -760,6 +793,14 @@ mod test_map { } #[test] + fn test_consume_still_usable() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2)); + do m.consume |_, _| {} + assert!(m.insert(1, 2)); + } + + #[test] fn test_iterate() { let mut m = linear_map_with_capacity(4); for uint::range(0, 32) |i| { @@ -819,6 +860,23 @@ mod test_map { assert_eq!(m.len(), i); assert!(!m.is_empty()); } + + #[test] + fn test_find_equiv() { + let mut m = HashMap::new(); + + let (foo, bar, baz) = (1,2,3); + m.insert(~"foo", foo); + m.insert(~"bar", bar); + m.insert(~"baz", baz); + + + assert_eq!(m.find_equiv(&("foo")), Some(&foo)); + assert_eq!(m.find_equiv(&("bar")), Some(&bar)); + assert_eq!(m.find_equiv(&("baz")), Some(&baz)); + + assert_eq!(m.find_equiv(&("qux")), None); + } } #[cfg(test)] diff --git a/src/libstd/io.rs b/src/libstd/io.rs index b97b0c70afc..6f065d74fa2 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -44,6 +44,8 @@ implement `Reader` and `Writer`, where appropriate. */ +#[allow(missing_doc)]; + use result::Result; use container::Container; @@ -670,7 +672,7 @@ impl<T:Reader> ReaderUtil for T { val <<= 6; val += (next & 63) as uint; } - // See str::char_at + // See str::StrSlice::char_at val += ((b0 << ((w + 1) as u8)) as uint) << (w - 1) * 6 - w - 1u; chars.push(val as char); @@ -746,7 +748,7 @@ impl<T:Reader> ReaderUtil for T { if self.eof() && line.is_empty() { break; } // trim the \n, so that each_line is consistent with read_line - let n = str::len(line); + let n = line.len(); if line[n-1] == '\n' as u8 { unsafe { str::raw::set_len(&mut line, n-1); } } @@ -769,7 +771,7 @@ impl<T:Reader> ReaderUtil for T { fn read_le_uint_n(&self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut val = 0u64, pos = 0, i = nbytes; + let mut (val, pos, i) = (0u64, 0, nbytes); while i > 0 { val += (self.read_u8() as u64) << pos; pos += 8; @@ -785,7 +787,7 @@ impl<T:Reader> ReaderUtil for T { fn read_be_uint_n(&self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut val = 0u64, i = nbytes; + let mut (val, i) = (0u64, nbytes); while i > 0 { i -= 1; val += (self.read_u8() as u64) << i * 8; @@ -980,6 +982,12 @@ pub struct FILERes { f: *libc::FILE, } +impl FILERes { + pub fn new(f: *libc::FILE) -> FILERes { + FILERes { f: f } + } +} + impl Drop for FILERes { fn finalize(&self) { unsafe { @@ -988,15 +996,9 @@ impl Drop for FILERes { } } -pub fn FILERes(f: *libc::FILE) -> FILERes { - FILERes { - f: f - } -} - pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader { if cleanup { - @Wrapper { base: f, cleanup: FILERes(f) } as @Reader + @Wrapper { base: f, cleanup: FILERes::new(f) } as @Reader } else { @f as @Reader } @@ -1089,7 +1091,7 @@ pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T { } pub fn with_str_reader<T>(s: &str, f: &fn(@Reader) -> T) -> T { - str::byte_slice(s, |bytes| with_bytes_reader(bytes, f)) + with_bytes_reader(s.as_bytes(), f) } // Writing @@ -1181,7 +1183,7 @@ impl Writer for *libc::FILE { pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer { if cleanup { - @Wrapper { base: f, cleanup: FILERes(f) } as @Writer + @Wrapper { base: f, cleanup: FILERes::new(f) } as @Writer } else { @f as @Writer } @@ -1225,6 +1227,12 @@ pub struct FdRes { fd: fd_t, } +impl FdRes { + pub fn new(fd: fd_t) -> FdRes { + FdRes { fd: fd } + } +} + impl Drop for FdRes { fn finalize(&self) { unsafe { @@ -1233,15 +1241,9 @@ impl Drop for FdRes { } } -pub fn FdRes(fd: fd_t) -> FdRes { - FdRes { - fd: fd - } -} - pub fn fd_writer(fd: fd_t, cleanup: bool) -> @Writer { if cleanup { - @Wrapper { base: fd, cleanup: FdRes(fd) } as @Writer + @Wrapper { base: fd, cleanup: FdRes::new(fd) } as @Writer } else { @fd as @Writer } @@ -1302,7 +1304,9 @@ pub fn u64_to_le_bytes<T>(n: u64, size: uint, (n >> 56) as u8]), _ => { - let mut bytes: ~[u8] = ~[], i = size, n = n; + let mut bytes: ~[u8] = ~[]; + let mut i = size; + let mut n = n; while i > 0u { bytes.push((n & 255_u64) as u8); n >>= 8_u64; @@ -1458,7 +1462,7 @@ impl<T:Writer> WriterUtil for T { self.write_str(str::from_char(ch)); } } - fn write_str(&self, s: &str) { str::byte_slice(s, |v| self.write(v)) } + fn write_str(&self, s: &str) { self.write(s.as_bytes()) } fn write_line(&self, s: &str) { self.write_str(s); self.write_str(&"\n"); @@ -1632,6 +1636,15 @@ pub struct BytesWriter { pos: @mut uint, } +impl BytesWriter { + pub fn new() -> BytesWriter { + BytesWriter { + bytes: @mut ~[], + pos: @mut 0 + } + } +} + impl Writer for BytesWriter { fn write(&self, v: &[u8]) { let v_len = v.len(); @@ -1671,15 +1684,8 @@ impl Writer for BytesWriter { } } -pub fn BytesWriter() -> BytesWriter { - BytesWriter { - bytes: @mut ~[], - pos: @mut 0 - } -} - pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] { - let wr = @BytesWriter(); + let wr = @BytesWriter::new(); f(wr as @Writer); let @BytesWriter { bytes, _ } = wr; copy *bytes @@ -1760,6 +1766,12 @@ pub mod fsync { arg: Arg<t>, } + impl <t: Copy> Res<t> { + pub fn new(arg: Arg<t>) -> Res<t> { + Res { arg: arg } + } + } + #[unsafe_destructor] impl<T:Copy> Drop for Res<T> { fn finalize(&self) { @@ -1774,12 +1786,6 @@ pub mod fsync { } } - pub fn Res<t: Copy>(arg: Arg<t>) -> Res<t>{ - Res { - arg: arg - } - } - pub struct Arg<t> { val: t, opt_level: Option<Level>, @@ -1791,7 +1797,7 @@ pub mod fsync { // outer res pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>, blk: &fn(v: Res<*libc::FILE>)) { - blk(Res(Arg { + blk(Res::new(Arg { val: file.f, opt_level: opt_level, fsync_fn: |file, l| { unsafe { @@ -1804,7 +1810,7 @@ pub mod fsync { // fsync fd after executing blk pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>, blk: &fn(v: Res<fd_t>)) { - blk(Res(Arg { + blk(Res::new(Arg { val: fd.fd, opt_level: opt_level, fsync_fn: |fd, l| os::fsync_fd(fd, l) as int })); @@ -1816,7 +1822,7 @@ pub mod fsync { // Call o.fsync after executing blk pub fn obj_sync(o: @FSyncable, opt_level: Option<Level>, blk: &fn(v: Res<@FSyncable>)) { - blk(Res(Arg { + blk(Res::new(Arg { val: o, opt_level: opt_level, fsync_fn: |o, l| o.fsync(l) })); @@ -1830,7 +1836,6 @@ mod tests { use io; use path::Path; use result; - use str; use u64; use vec; @@ -1931,7 +1936,7 @@ mod tests { #[test] fn file_reader_not_exist() { match io::file_reader(&Path("not a file")) { - result::Err(copy e) => { + result::Err(e) => { assert_eq!(e, ~"error opening not a file"); } result::Ok(_) => fail!() @@ -1972,8 +1977,8 @@ mod tests { #[test] fn file_writer_bad_name() { match io::file_writer(&Path("?/?"), []) { - result::Err(copy e) => { - assert!(str::starts_with(e, "error opening")); + result::Err(e) => { + assert!(e.starts_with("error opening")); } result::Ok(_) => fail!() } @@ -1982,8 +1987,8 @@ mod tests { #[test] fn buffered_file_writer_bad_name() { match io::buffered_file_writer(&Path("?/?")) { - result::Err(copy e) => { - assert!(str::starts_with(e, "error opening")); + result::Err(e) => { + assert!(e.starts_with("error opening")); } result::Ok(_) => fail!() } @@ -1991,7 +1996,7 @@ mod tests { #[test] fn bytes_buffer_overwrite() { - let wr = BytesWriter(); + let wr = BytesWriter::new(); wr.write([0u8, 1u8, 2u8, 3u8]); assert!(*wr.bytes == ~[0u8, 1u8, 2u8, 3u8]); wr.seek(-2, SeekCur); diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 800ce9f05dc..2197feea452 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -24,8 +24,6 @@ An external iterator object implementing the interface in the `iterator` module internal iterator by calling the `advance` method. For example: ~~~ {.rust} -use core::iterator::*; - let xs = [0u, 1, 2, 3, 4, 5]; let ys = [30, 40, 50, 60]; let mut it = xs.iter().chain(ys.iter()); @@ -42,30 +40,26 @@ much easier to implement. use cmp::Ord; use option::{Option, Some, None}; -use vec::OwnedVector; use num::{One, Zero}; use ops::{Add, Mul}; +#[allow(missing_doc)] pub trait Times { fn times(&self, it: &fn() -> bool) -> bool; } -/** - * Transform an internal iterator into an owned vector. - * - * # Example: - * - * ~~~ {.rust} - * let xs = ~[1, 2, 3]; - * let ys = do iter::to_vec |f| { xs.each(|x| f(*x)) }; - * assert_eq!(xs, ys); - * ~~~ - */ -#[inline(always)] -pub fn to_vec<T>(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] { - let mut v = ~[]; - for iter |x| { v.push(x) } - v +#[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.each(|x| f(*x)) }; + /// assert_eq!(xs, ys); + /// ~~~ + pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> Self; } /** @@ -257,10 +251,13 @@ mod tests { use super::*; use prelude::*; + use int; + use uint; + #[test] - fn test_to_vec() { + fn test_from_iter() { let xs = ~[1, 2, 3]; - let ys = do to_vec |f| { xs.each(|x| f(*x)) }; + let ys: ~[int] = do FromIter::from_iter |f| { xs.each(|x| f(*x)) }; assert_eq!(xs, ys); } diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index a5679e6dbff..e65904a6899 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -17,9 +17,17 @@ implementing the `Iterator` trait. */ -use prelude::*; +use cmp; +use iter::{FromIter, Times}; use num::{Zero, One}; - +use option::{Option, Some, None}; +use ops::{Add, Mul}; +use cmp::Ord; +use clone::Clone; + +/// An interface for dealing with "external iterators". These types of iterators +/// can be resumed at any time as all state is stored internally as opposed to +/// being located on the call stack. pub trait Iterator<A> { /// Advance the iterator and return the next value. Return `None` when the end is reached. fn next(&mut self) -> Option<A>; @@ -30,27 +38,276 @@ pub trait Iterator<A> { /// /// In the future these will be default methods instead of a utility trait. pub trait IteratorUtil<A> { - fn chain<U: Iterator<A>>(self, other: U) -> ChainIterator<Self, U>; - fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<Self, U>; + /// Chain this iterator with another, returning a new iterator which will + /// finish iterating over the current iterator, and then it will iterate + /// over the other specified iterator. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [0]; + /// let b = [1]; + /// let mut it = a.iter().chain_(b.iter()); + /// assert_eq!(it.next().get(), &0); + /// assert_eq!(it.next().get(), &1); + /// assert!(it.next().is_none()); + /// ~~~ + fn chain_<U: Iterator<A>>(self, other: U) -> ChainIterator<A, Self, U>; + + /// Creates an iterator which iterates over both this and the specified + /// iterators simultaneously, yielding the two elements as pairs. When + /// either iterator returns None, all further invocations of next() will + /// return None. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [0]; + /// let b = [1]; + /// let mut it = a.iter().zip(b.iter()); + /// assert_eq!(it.next().get(), (&0, &1)); + /// assert!(it.next().is_none()); + /// ~~~ + fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<A, Self, B, U>; + // FIXME: #5898: should be called map + /// Creates a new iterator which will apply the specified function to each + /// element returned by the first, yielding the mapped element instead. This + /// similar to the `vec::map` function. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2]; + /// let mut it = a.iter().transform(|&x| 2 * x); + /// assert_eq!(it.next().get(), 2); + /// assert_eq!(it.next().get(), 4); + /// assert!(it.next().is_none()); + /// ~~~ fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; + + /// Creates an iterator which applies the predicate to each element returned + /// by this iterator. Only elements which have the predicate evaluate to + /// `true` will be yielded. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2]; + /// let mut it = a.iter().filter(|&x| *x > 1); + /// assert_eq!(it.next().get(), &2); + /// assert!(it.next().is_none()); + /// ~~~ fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, Self>; + + /// Creates an iterator which both filters and maps elements. + /// If the specified function returns None, the element is skipped. + /// Otherwise the option is unwrapped and the new value is yielded. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2]; + /// let mut it = a.iter().filter_map(|&x| if x > 1 {Some(2 * x)} else {None}); + /// assert_eq!(it.next().get(), 4); + /// assert!(it.next().is_none()); + /// ~~~ fn filter_map<'r, B>(self, f: &'r fn(A) -> Option<B>) -> FilterMapIterator<'r, A, B, Self>; - fn enumerate(self) -> EnumerateIterator<Self>; + + /// Creates an iterator which yields a pair of the value returned by this + /// iterator plus the current index of iteration. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [100, 200]; + /// let mut it = a.iter().enumerate(); + /// assert_eq!(it.next().get(), (0, &100)); + /// assert_eq!(it.next().get(), (1, &200)); + /// assert!(it.next().is_none()); + /// ~~~ + fn enumerate(self) -> EnumerateIterator<A, Self>; + + /// Creates an iterator which invokes the predicate on elements until it + /// returns false. Once the predicate returns false, all further elements are + /// yielded. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 2, 1]; + /// let mut it = a.iter().skip_while(|&a| *a < 3); + /// assert_eq!(it.next().get(), &3); + /// assert_eq!(it.next().get(), &2); + /// assert_eq!(it.next().get(), &1); + /// assert!(it.next().is_none()); + /// ~~~ fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhileIterator<'r, A, Self>; + + /// Creates an iterator which yields elements so long as the predicate + /// returns true. After the predicate returns false for the first time, no + /// further elements will be yielded. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 2, 1]; + /// let mut it = a.iter().take_while(|&a| *a < 3); + /// assert_eq!(it.next().get(), &1); + /// assert_eq!(it.next().get(), &2); + /// assert!(it.next().is_none()); + /// ~~~ fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, Self>; - fn skip(self, n: uint) -> SkipIterator<Self>; - fn take(self, n: uint) -> TakeIterator<Self>; + + /// Creates an iterator which skips the first `n` elements of this iterator, + /// and then it yields all further items. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter().skip(3); + /// assert_eq!(it.next().get(), &4); + /// assert_eq!(it.next().get(), &5); + /// assert!(it.next().is_none()); + /// ~~~ + fn skip(self, n: uint) -> SkipIterator<A, Self>; + + // FIXME: #5898: should be called take + /// Creates an iterator which yields the first `n` elements of this + /// iterator, and then it will always return None. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter().take_(3); + /// assert_eq!(it.next().get(), &1); + /// assert_eq!(it.next().get(), &2); + /// assert_eq!(it.next().get(), &3); + /// assert!(it.next().is_none()); + /// ~~~ + fn take_(self, n: uint) -> TakeIterator<A, Self>; + + /// Creates a new iterator which behaves in a similar fashion to foldl. + /// There is a state which is passed between each iteration and can be + /// mutated as necessary. The yielded values from the closure are yielded + /// from the ScanIterator instance when not None. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter().scan(1, |fac, &x| { + /// *fac = *fac * x; + /// Some(*fac) + /// }); + /// assert_eq!(it.next().get(), 1); + /// assert_eq!(it.next().get(), 2); + /// assert_eq!(it.next().get(), 6); + /// assert_eq!(it.next().get(), 24); + /// assert_eq!(it.next().get(), 120); + /// assert!(it.next().is_none()); + /// ~~~ fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>) -> ScanIterator<'r, A, B, Self, St>; + + /// An adaptation of an external iterator to the for-loop protocol of rust. + /// + /// # Example + /// + /// ~~~ {.rust} + /// use std::iterator::Counter; + /// + /// for Counter::new(0, 10).advance |i| { + /// io::println(fmt!("%d", i)); + /// } + /// ~~~ fn advance(&mut self, f: &fn(A) -> bool) -> bool; - fn to_vec(&mut self) -> ~[A]; + + /// Loops through the entire iterator, collecting all of the elements into + /// a container implementing `FromIter`. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let b: ~[int] = a.iter().transform(|&x| x).collect(); + /// assert!(a == b); + /// ~~~ + fn collect<B: FromIter<A>>(&mut self) -> B; + + /// Loops through `n` iterations, returning the `n`th element of the + /// iterator. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter(); + /// assert!(it.nth(2).get() == &3); + /// assert!(it.nth(2) == None); + /// ~~~ fn nth(&mut self, n: uint) -> Option<A>; - fn last(&mut self) -> Option<A>; + + /// Loops through the entire iterator, returning the last element of the + /// iterator. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// assert!(a.iter().last().get() == &5); + /// ~~~ + // FIXME: #5898: should be called `last` + fn last_(&mut self) -> Option<A>; + + /// Performs a fold operation over the entire iterator, returning the + /// eventual state at the end of the iteration. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// assert!(a.iter().fold(0, |a, &b| a + b) == 15); + /// ~~~ fn fold<B>(&mut self, start: B, f: &fn(B, A) -> B) -> B; + + /// Counts the number of elements in this iterator. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter(); + /// assert!(it.count() == 5); + /// assert!(it.count() == 0); + /// ~~~ fn count(&mut self) -> uint; - fn all(&mut self, f: &fn(&A) -> bool) -> bool; - fn any(&mut self, f: &fn(&A) -> bool) -> bool; + + /// Tests whether the predicate holds true for all elements in the iterator. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// assert!(a.iter().all(|&x| *x > 0)); + /// assert!(!a.iter().all(|&x| *x > 2)); + /// ~~~ + fn all(&mut self, f: &fn(A) -> bool) -> bool; + + /// Tests whether any element of an iterator satisfies the specified + /// predicate. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter(); + /// assert!(it.any_(|&x| *x == 3)); + /// assert!(!it.any_(|&x| *x == 3)); + /// ~~~ + fn any_(&mut self, f: &fn(A) -> bool) -> bool; } /// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also @@ -59,12 +316,12 @@ pub trait IteratorUtil<A> { /// In the future these will be default methods instead of a utility trait. impl<A, T: Iterator<A>> IteratorUtil<A> for T { #[inline(always)] - fn chain<U: Iterator<A>>(self, other: U) -> ChainIterator<T, U> { + fn chain_<U: Iterator<A>>(self, other: U) -> ChainIterator<A, T, U> { ChainIterator{a: self, b: other, flag: false} } #[inline(always)] - fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> { + fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<A, T, B, U> { ZipIterator{a: self, b: other} } @@ -85,7 +342,7 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { } #[inline(always)] - fn enumerate(self) -> EnumerateIterator<T> { + fn enumerate(self) -> EnumerateIterator<A, T> { EnumerateIterator{iter: self, count: 0} } @@ -100,12 +357,13 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { } #[inline(always)] - fn skip(self, n: uint) -> SkipIterator<T> { + fn skip(self, n: uint) -> SkipIterator<A, T> { SkipIterator{iter: self, n: n} } + // FIXME: #5898: should be called take #[inline(always)] - fn take(self, n: uint) -> TakeIterator<T> { + fn take_(self, n: uint) -> TakeIterator<A, T> { TakeIterator{iter: self, n: n} } @@ -129,8 +387,8 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { } #[inline(always)] - fn to_vec(&mut self) -> ~[A] { - iter::to_vec::<A>(|f| self.advance(f)) + fn collect<B: FromIter<A>>(&mut self) -> B { + FromIter::from_iter::<A, B>(|f| self.advance(f)) } /// Return the `n`th item yielded by an iterator. @@ -147,7 +405,7 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { /// Return the last item yielded by an iterator. #[inline(always)] - fn last(&mut self) -> Option<A> { + fn last_(&mut self) -> Option<A> { let mut last = None; for self.advance |x| { last = Some(x); } last @@ -171,19 +429,29 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { fn count(&mut self) -> uint { self.fold(0, |cnt, _x| cnt + 1) } #[inline(always)] - fn all(&mut self, f: &fn(&A) -> bool) -> bool { - for self.advance |x| { if !f(&x) { return false; } } + fn all(&mut self, f: &fn(A) -> bool) -> bool { + for self.advance |x| { if !f(x) { return false; } } return true; } #[inline(always)] - fn any(&mut self, f: &fn(&A) -> bool) -> bool { - for self.advance |x| { if f(&x) { return true; } } + fn any_(&mut self, f: &fn(A) -> bool) -> bool { + for self.advance |x| { if f(x) { return true; } } return false; } } +/// A trait for iterators over elements which can be added together pub trait AdditiveIterator<A> { + /// Iterates over the entire iterator, summing up all the elements + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter().transform(|&x| x); + /// assert!(it.sum() == 15); + /// ~~~ fn sum(&mut self) -> A; } @@ -192,7 +460,23 @@ impl<A: Add<A, A> + Zero, T: Iterator<A>> AdditiveIterator<A> for T { fn sum(&mut self) -> A { self.fold(Zero::zero::<A>(), |s, x| s + x) } } +/// A trait for iterators over elements whose elements can be multiplied +/// together. pub trait MultiplicativeIterator<A> { + /// Iterates over the entire iterator, multiplying all the elements + /// + /// # Example + /// + /// ~~~ {.rust} + /// use std::iterator::Counter; + /// + /// fn factorial(n: uint) -> uint { + /// Counter::new(1u, 1).take_while(|&i| i <= n).product() + /// } + /// assert!(factorial(0) == 1); + /// assert!(factorial(1) == 1); + /// assert!(factorial(5) == 120); + /// ~~~ fn product(&mut self) -> A; } @@ -201,8 +485,27 @@ impl<A: Mul<A, A> + One, T: Iterator<A>> MultiplicativeIterator<A> for T { fn product(&mut self) -> A { self.fold(One::one::<A>(), |p, x| p * x) } } +/// A trait for iterators over elements which can be compared to one another. +/// The type of each element must ascribe to the `Ord` trait. pub trait OrdIterator<A> { + /// Consumes the entire iterator to return the maximum element. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// assert!(a.iter().max().get() == &5); + /// ~~~ fn max(&mut self) -> Option<A>; + + /// Consumes the entire iterator to return the minimum element. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// assert!(a.iter().min().get() == &1); + /// ~~~ fn min(&mut self) -> Option<A>; } @@ -228,13 +531,15 @@ impl<A: Ord, T: Iterator<A>> OrdIterator<A> for T { } } -pub struct ChainIterator<T, U> { +/// An iterator which strings two iterators together +// FIXME #6967: Dummy A parameter to get around type inference bug +pub struct ChainIterator<A, T, U> { priv a: T, priv b: U, priv flag: bool } -impl<A, T: Iterator<A>, U: Iterator<A>> Iterator<A> for ChainIterator<T, U> { +impl<A, T: Iterator<A>, U: Iterator<A>> Iterator<A> for ChainIterator<A, T, U> { #[inline] fn next(&mut self) -> Option<A> { if self.flag { @@ -250,12 +555,14 @@ impl<A, T: Iterator<A>, U: Iterator<A>> Iterator<A> for ChainIterator<T, U> { } } -pub struct ZipIterator<T, U> { +/// An iterator which iterates two other iterators simultaneously +// FIXME #6967: Dummy A & B parameters to get around type inference bug +pub struct ZipIterator<A, T, B, U> { priv a: T, priv b: U } -impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(A, B)> for ZipIterator<T, U> { +impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(A, B)> for ZipIterator<A, T, B, U> { #[inline] fn next(&mut self) -> Option<(A, B)> { match (self.a.next(), self.b.next()) { @@ -265,6 +572,7 @@ impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(A, B)> for ZipIterator<T, U } } +/// An iterator which maps the values of `iter` with `f` pub struct MapIterator<'self, A, B, T> { priv iter: T, priv f: &'self fn(A) -> B @@ -280,6 +588,7 @@ impl<'self, A, B, T: Iterator<A>> Iterator<B> for MapIterator<'self, A, B, T> { } } +/// An iterator which filters the elements of `iter` with `predicate` pub struct FilterIterator<'self, A, T> { priv iter: T, priv predicate: &'self fn(&A) -> bool @@ -299,6 +608,7 @@ impl<'self, A, T: Iterator<A>> Iterator<A> for FilterIterator<'self, A, T> { } } +/// An iterator which uses `f` to both filter and map elements from `iter` pub struct FilterMapIterator<'self, A, B, T> { priv iter: T, priv f: &'self fn(A) -> Option<B> @@ -317,12 +627,14 @@ impl<'self, A, B, T: Iterator<A>> Iterator<B> for FilterMapIterator<'self, A, B, } } -pub struct EnumerateIterator<T> { +/// An iterator which yields the current count and the element during iteration +// FIXME #6967: Dummy A parameter to get around type inference bug +pub struct EnumerateIterator<A, T> { priv iter: T, priv count: uint } -impl<A, T: Iterator<A>> Iterator<(uint, A)> for EnumerateIterator<T> { +impl<A, T: Iterator<A>> Iterator<(uint, A)> for EnumerateIterator<A, T> { #[inline] fn next(&mut self) -> Option<(uint, A)> { match self.iter.next() { @@ -336,6 +648,7 @@ impl<A, T: Iterator<A>> Iterator<(uint, A)> for EnumerateIterator<T> { } } +/// An iterator which rejects elements while `predicate` is true pub struct SkipWhileIterator<'self, A, T> { priv iter: T, priv flag: bool, @@ -367,6 +680,7 @@ impl<'self, A, T: Iterator<A>> Iterator<A> for SkipWhileIterator<'self, A, T> { } } +/// An iterator which only accepts elements while `predicate` is true pub struct TakeWhileIterator<'self, A, T> { priv iter: T, priv flag: bool, @@ -394,12 +708,14 @@ impl<'self, A, T: Iterator<A>> Iterator<A> for TakeWhileIterator<'self, A, T> { } } -pub struct SkipIterator<T> { +/// An iterator which skips over `n` elements of `iter`. +// FIXME #6967: Dummy A parameter to get around type inference bug +pub struct SkipIterator<A, T> { priv iter: T, priv n: uint } -impl<A, T: Iterator<A>> Iterator<A> for SkipIterator<T> { +impl<A, T: Iterator<A>> Iterator<A> for SkipIterator<A, T> { #[inline] fn next(&mut self) -> Option<A> { let mut next = self.iter.next(); @@ -425,12 +741,14 @@ impl<A, T: Iterator<A>> Iterator<A> for SkipIterator<T> { } } -pub struct TakeIterator<T> { +/// An iterator which only iterates over the first `n` iterations of `iter`. +// FIXME #6967: Dummy A parameter to get around type inference bug +pub struct TakeIterator<A, T> { priv iter: T, priv n: uint } -impl<A, T: Iterator<A>> Iterator<A> for TakeIterator<T> { +impl<A, T: Iterator<A>> Iterator<A> for TakeIterator<A, T> { #[inline] fn next(&mut self) -> Option<A> { let next = self.iter.next(); @@ -443,9 +761,12 @@ impl<A, T: Iterator<A>> Iterator<A> for TakeIterator<T> { } } +/// An iterator to maintain state while iterating another iterator pub struct ScanIterator<'self, A, B, T, St> { priv iter: T, priv f: &'self fn(&mut St, A) -> Option<B>, + + /// The current internal state to be passed to the closure next. state: St } @@ -456,14 +777,18 @@ impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for ScanIterator<'self, A, B, } } +/// An iterator which just modifies the contained state throughout iteration. pub struct UnfoldrIterator<'self, A, St> { priv f: &'self fn(&mut St) -> Option<A>, + /// Internal state that will be yielded on the next iteration state: St } -pub impl<'self, A, St> UnfoldrIterator<'self, A, St> { +impl<'self, A, St> UnfoldrIterator<'self, A, St> { + /// Creates a new iterator with the specified closure as the "iterator + /// function" and an initial state to eventually pass to the iterator #[inline] - fn new(f: &'self fn(&mut St) -> Option<A>, initial_state: St) + pub fn new(f: &'self fn(&mut St) -> Option<A>, initial_state: St) -> UnfoldrIterator<'self, A, St> { UnfoldrIterator { f: f, @@ -479,15 +804,19 @@ impl<'self, A, St> Iterator<A> for UnfoldrIterator<'self, A, St> { } } -/// An infinite iterator starting at `start` and advancing by `step` with each iteration +/// An infinite iterator starting at `start` and advancing by `step` with each +/// iteration pub struct Counter<A> { + /// The current state the counter is at (next value to be yielded) state: A, + /// The amount that this iterator is stepping by step: A } -pub impl<A> Counter<A> { +impl<A> Counter<A> { + /// Creates a new counter with the specified start/step #[inline(always)] - fn new(start: A, step: A) -> Counter<A> { + pub fn new(start: A, step: A) -> Counter<A> { Counter{state: start, step: step} } } @@ -506,10 +835,13 @@ mod tests { use super::*; use prelude::*; + use iter; + use uint; + #[test] - fn test_counter_to_vec() { - let mut it = Counter::new(0, 5).take(10); - let xs = iter::to_vec(|f| it.advance(f)); + fn test_counter_from_iter() { + let mut it = Counter::new(0, 5).take_(10); + let xs: ~[int] = iter::FromIter::from_iter::<int, ~[int]>(|f| it.advance(f)); assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); } @@ -518,18 +850,18 @@ mod tests { let xs = [0u, 1, 2, 3, 4, 5]; let ys = [30u, 40, 50, 60]; let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; - let mut it = xs.iter().chain(ys.iter()); + let mut it = xs.iter().chain_(ys.iter()); let mut i = 0; - for it.advance |&x: &uint| { + for it.advance |&x| { assert_eq!(x, expected[i]); i += 1; } assert_eq!(i, expected.len()); - let ys = Counter::new(30u, 10).take(4); - let mut it = xs.iter().transform(|&x| x).chain(ys); + let ys = Counter::new(30u, 10).take_(4); + let mut it = xs.iter().transform(|&x| x).chain_(ys); let mut i = 0; - for it.advance |x: uint| { + for it.advance |x| { assert_eq!(x, expected[i]); i += 1; } @@ -538,16 +870,16 @@ mod tests { #[test] fn test_filter_map() { - let mut it = Counter::new(0u, 1u).take(10) - .filter_map(|x: uint| if x.is_even() { Some(x*x) } else { None }); - assert_eq!(it.to_vec(), ~[0*0, 2*2, 4*4, 6*6, 8*8]); + let mut it = Counter::new(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]); } #[test] fn test_iterator_enumerate() { let xs = [0u, 1, 2, 3, 4, 5]; let mut it = xs.iter().enumerate(); - for it.advance |(i, &x): (uint, &uint)| { + for it.advance |(i, &x)| { assert_eq!(i, x); } } @@ -558,7 +890,7 @@ mod tests { let ys = [0u, 1, 2, 3, 5, 13]; let mut it = xs.iter().take_while(|&x| *x < 15u); let mut i = 0; - for it.advance |&x: &uint| { + for it.advance |&x| { assert_eq!(x, ys[i]); i += 1; } @@ -571,7 +903,7 @@ mod tests { let ys = [15, 16, 17, 19]; let mut it = xs.iter().skip_while(|&x| *x < 15u); let mut i = 0; - for it.advance |&x: &uint| { + for it.advance |&x| { assert_eq!(x, ys[i]); i += 1; } @@ -584,7 +916,7 @@ mod tests { let ys = [13, 15, 16, 17, 19, 20, 30]; let mut it = xs.iter().skip(5); let mut i = 0; - for it.advance |&x: &uint| { + for it.advance |&x| { assert_eq!(x, ys[i]); i += 1; } @@ -595,9 +927,9 @@ mod tests { fn test_iterator_take() { let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; let ys = [0u, 1, 2, 3, 5]; - let mut it = xs.iter().take(5); + let mut it = xs.iter().take_(5); let mut i = 0; - for it.advance |&x: &uint| { + for it.advance |&x| { assert_eq!(x, ys[i]); i += 1; } @@ -655,8 +987,8 @@ mod tests { #[test] fn test_iterator_last() { let v = &[0, 1, 2, 3, 4]; - assert_eq!(v.iter().last().unwrap(), &4); - assert_eq!(v.slice(0, 1).iter().last().unwrap(), &0); + assert_eq!(v.iter().last_().unwrap(), &4); + assert_eq!(v.slice(0, 1).iter().last_().unwrap(), &0); } #[test] @@ -700,20 +1032,27 @@ mod tests { } #[test] + fn test_collect() { + let a = ~[1, 2, 3, 4, 5]; + let b: ~[int] = a.iter().transform(|&x| x).collect(); + assert_eq!(a, b); + } + + #[test] fn test_all() { let v = ~&[1, 2, 3, 4, 5]; - assert!(v.iter().all(|&x| *x < 10)); + assert!(v.iter().all(|&x| x < 10)); assert!(!v.iter().all(|&x| x.is_even())); - assert!(!v.iter().all(|&x| *x > 100)); + assert!(!v.iter().all(|&x| x > 100)); assert!(v.slice(0, 0).iter().all(|_| fail!())); } #[test] fn test_any() { let v = ~&[1, 2, 3, 4, 5]; - assert!(v.iter().any(|&x| *x < 10)); - assert!(v.iter().any(|&x| x.is_even())); - assert!(!v.iter().any(|&x| *x > 100)); - assert!(!v.slice(0, 0).iter().any(|_| fail!())); + assert!(v.iter().any_(|&x| x < 10)); + assert!(v.iter().any_(|&x| x.is_even())); + assert!(!v.iter().any_(|&x| x > 100)); + assert!(!v.slice(0, 0).iter().any_(|_| fail!())); } } diff --git a/src/libstd/kinds.rs b/src/libstd/kinds.rs index d9b3e35b6b9..05c963a32cc 100644 --- a/src/libstd/kinds.rs +++ b/src/libstd/kinds.rs @@ -37,6 +37,8 @@ instead implement `Clone`. */ +#[allow(missing_doc)]; + #[lang="copy"] pub trait Copy { // Empty. @@ -51,3 +53,8 @@ pub trait Owned { pub trait Const { // Empty. } + +#[lang="sized"] +pub trait Sized { + // Empty. +} diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 7ae3f0fd2d4..26205c930f0 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -64,6 +64,7 @@ */ #[allow(non_camel_case_types)]; +#[allow(missing_doc)]; // Initial glob-exports mean that all the contents of all the modules // wind up exported, if you're interested in writing platform-specific code. @@ -158,8 +159,8 @@ pub use libc::funcs::c95::stdlib::{free, getenv, labs, malloc, rand}; pub use libc::funcs::c95::stdlib::{realloc, srand, strtod, strtol}; pub use libc::funcs::c95::stdlib::{strtoul, system}; -pub use libc::funcs::c95::string::{memchr, memcmp, memcpy, memmove}; -pub use libc::funcs::c95::string::{memset, strcat, strchr, strcmp}; +pub use libc::funcs::c95::string::{memchr, memcmp}; +pub use libc::funcs::c95::string::{strcat, strchr, strcmp}; pub use libc::funcs::c95::string::{strcoll, strcpy, strcspn, strerror}; pub use libc::funcs::c95::string::{strlen, strncat, strncmp, strncpy}; pub use libc::funcs::c95::string::{strpbrk, strrchr, strspn, strstr}; @@ -1451,26 +1452,17 @@ pub mod funcs { -> size_t; unsafe fn wcslen(buf: *wchar_t) -> size_t; + // Omitted: memcpy, memmove, memset (provided by LLVM) + // These are fine to execute on the Rust stack. They must be, // in fact, because LLVM generates calls to them! #[rust_stack] #[inline(always)] - unsafe fn memcpy(s: *c_void, ct: *c_void, n: size_t) - -> *c_void; - #[rust_stack] - #[inline(always)] - unsafe fn memmove(s: *c_void, ct: *c_void, n: size_t) - -> *c_void; - #[rust_stack] - #[inline(always)] unsafe fn memcmp(cx: *c_void, ct: *c_void, n: size_t) -> c_int; #[rust_stack] #[inline(always)] unsafe fn memchr(cx: *c_void, c: c_int, n: size_t) -> *c_void; - #[rust_stack] - #[inline(always)] - unsafe fn memset(s: *c_void, c: c_int, n: size_t) -> *c_void; } } } diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 2cbf8b9f05e..82c01c998cf 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -27,8 +27,11 @@ magic. */ use prelude::*; + use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handle}; +#[cfg(test)] use task; + /** * Indexes a task-local data slot. The function's code pointer is used for * comparison. Recommended use is to write an empty function for each desired diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index 693d7863297..c2f854179b8 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -36,6 +36,7 @@ pub fn console_off() { #[cfg(not(test))] #[lang="log_type"] +#[allow(missing_doc)] pub fn log_type<T>(level: u32, object: &T) { use cast; use container::Container; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index fda48b6ffb7..8d221fe6a1b 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -38,16 +38,19 @@ macro_rules! rtassert ( } ) ) + +// The do_abort function was originally inside the abort macro, but +// this was ICEing the compiler so it has been moved outside. Now this +// seems to work? +#[allow(missing_doc)] +pub fn do_abort() -> ! { + unsafe { ::libc::abort(); } +} + macro_rules! abort( ($( $msg:expr),+) => ( { rtdebug!($($msg),+); - - do_abort(); - - // NB: This is in a fn to avoid putting the `unsafe` block in a macro, - // which causes spurious 'unnecessary unsafe block' warnings. - fn do_abort() -> ! { - unsafe { ::libc::abort(); } - } + ::macros::do_abort(); } ) ) + diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index ecde1eb1917..7d0defea05a 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -21,6 +21,7 @@ pub mod raw { pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; pub static RC_IMMORTAL : uint = 0x77777777; + #[allow(missing_doc)] pub struct BoxHeaderRepr { ref_count: uint, type_desc: *TyDesc, @@ -28,6 +29,7 @@ pub mod raw { next: *BoxRepr, } + #[allow(missing_doc)] pub struct BoxRepr { header: BoxHeaderRepr, data: u8 @@ -38,14 +40,14 @@ pub mod raw { /// Determine if two shared boxes point to the same object #[inline(always)] pub fn ptr_eq<T>(a: @T, b: @T) -> bool { - let a_ptr: *T = to_unsafe_ptr(&*a), b_ptr: *T = to_unsafe_ptr(&*b); + let (a_ptr, b_ptr): (*T, *T) = (to_unsafe_ptr(&*a), to_unsafe_ptr(&*b)); a_ptr == b_ptr } /// Determine if two mutable shared boxes point to the same object #[inline(always)] pub fn mut_ptr_eq<T>(a: @mut T, b: @mut T) -> bool { - let a_ptr: *T = to_unsafe_ptr(&*a), b_ptr: *T = to_unsafe_ptr(&*b); + let (a_ptr, b_ptr): (*T, *T) = (to_unsafe_ptr(&*a), to_unsafe_ptr(&*b)); a_ptr == b_ptr } diff --git a/src/libstd/num/cmath.rs b/src/libstd/num/cmath.rs index 9626224916b..96d3b79e338 100644 --- a/src/libstd/num/cmath.rs +++ b/src/libstd/num/cmath.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(missing_doc)]; + // function names are almost identical to C's libmath, a few have been // renamed, grep for "rename:" diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index b578084268a..7f981187300 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -9,11 +9,14 @@ // except according to those terms. //! Operations and constants for `f32` +#[allow(missing_doc)]; use libc::c_int; use num::{Zero, One, strconv}; use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; +use num; use prelude::*; +use to_str; pub use cmath::c_float_targ_consts::*; @@ -388,7 +391,7 @@ impl Fractional for f32 { impl Algebraic for f32 { #[inline(always)] - fn pow(&self, n: f32) -> f32 { pow(*self, n) } + fn pow(&self, n: &f32) -> f32 { pow(*self, *n) } #[inline(always)] fn sqrt(&self) -> f32 { sqrt(*self) } @@ -400,7 +403,7 @@ impl Algebraic for f32 { fn cbrt(&self) -> f32 { cbrt(*self) } #[inline(always)] - fn hypot(&self, other: f32) -> f32 { hypot(*self, other) } + fn hypot(&self, other: &f32) -> f32 { hypot(*self, *other) } } impl Trigonometric for f32 { @@ -423,7 +426,7 @@ impl Trigonometric for f32 { fn atan(&self) -> f32 { atan(*self) } #[inline(always)] - fn atan2(&self, other: f32) -> f32 { atan2(*self, other) } + fn atan2(&self, other: &f32) -> f32 { atan2(*self, *other) } /// Simultaneously computes the sine and cosine of the number #[inline(always)] @@ -447,7 +450,7 @@ impl Exponential for f32 { /// Returns the logarithm of the number with respect to an arbitrary base #[inline(always)] - fn log(&self, base: f32) -> f32 { self.ln() / base.ln() } + fn log(&self, base: &f32) -> f32 { self.ln() / base.ln() } /// Returns the base 2 logarithm of the number #[inline(always)] @@ -958,9 +961,12 @@ impl num::FromStrRadix for f32 { #[cfg(test)] mod tests { use f32::*; - use num::*; use prelude::*; + use num::*; + use num; + use sys; + #[test] fn test_num() { num::test_num(10f32, 2f32); diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index bca730c5748..6303e304576 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -10,10 +10,14 @@ //! Operations and constants for `f64` +#[allow(missing_doc)]; + use libc::c_int; use num::{Zero, One, strconv}; use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; +use num; use prelude::*; +use to_str; pub use cmath::c_double_targ_consts::*; pub use cmp::{min, max}; @@ -399,7 +403,7 @@ impl Fractional for f64 { impl Algebraic for f64 { #[inline(always)] - fn pow(&self, n: f64) -> f64 { pow(*self, n) } + fn pow(&self, n: &f64) -> f64 { pow(*self, *n) } #[inline(always)] fn sqrt(&self) -> f64 { sqrt(*self) } @@ -411,7 +415,7 @@ impl Algebraic for f64 { fn cbrt(&self) -> f64 { cbrt(*self) } #[inline(always)] - fn hypot(&self, other: f64) -> f64 { hypot(*self, other) } + fn hypot(&self, other: &f64) -> f64 { hypot(*self, *other) } } impl Trigonometric for f64 { @@ -434,7 +438,7 @@ impl Trigonometric for f64 { fn atan(&self) -> f64 { atan(*self) } #[inline(always)] - fn atan2(&self, other: f64) -> f64 { atan2(*self, other) } + fn atan2(&self, other: &f64) -> f64 { atan2(*self, *other) } /// Simultaneously computes the sine and cosine of the number #[inline(always)] @@ -458,7 +462,7 @@ impl Exponential for f64 { /// Returns the logarithm of the number with respect to an arbitrary base #[inline(always)] - fn log(&self, base: f64) -> f64 { self.ln() / base.ln() } + fn log(&self, base: &f64) -> f64 { self.ln() / base.ln() } /// Returns the base 2 logarithm of the number #[inline(always)] @@ -999,9 +1003,12 @@ impl num::FromStrRadix for f64 { #[cfg(test)] mod tests { use f64::*; - use num::*; use prelude::*; + use num::*; + use num; + use sys; + #[test] fn test_num() { num::test_num(10f64, 2f64); diff --git a/src/libstd/num/float.rs b/src/libstd/num/float.rs index acc5e5a6f39..267a8890e82 100644 --- a/src/libstd/num/float.rs +++ b/src/libstd/num/float.rs @@ -20,10 +20,15 @@ // PORT this must match in width according to architecture +#[allow(missing_doc)]; + +use f64; use libc::c_int; use num::{Zero, One, strconv}; use num::FPCategory; +use num; use prelude::*; +use to_str; pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt}; pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor}; @@ -42,8 +47,8 @@ pub static neg_infinity: float = -1.0/0.0; /* Module: consts */ pub mod consts { // FIXME (requires Issue #1433 to fix): replace with mathematical - // staticants from cmath. - /// Archimedes' staticant + // constants from cmath. + /// Archimedes' constant pub static pi: float = 3.14159265358979323846264338327950288; /// pi/2.0 @@ -470,8 +475,8 @@ impl Fractional for float { impl Algebraic for float { #[inline(always)] - fn pow(&self, n: float) -> float { - (*self as f64).pow(n as f64) as float + fn pow(&self, n: &float) -> float { + (*self as f64).pow(&(*n as f64)) as float } #[inline(always)] @@ -490,8 +495,8 @@ impl Algebraic for float { } #[inline(always)] - fn hypot(&self, other: float) -> float { - (*self as f64).hypot(other as f64) as float + fn hypot(&self, other: &float) -> float { + (*self as f64).hypot(&(*other as f64)) as float } } @@ -527,8 +532,8 @@ impl Trigonometric for float { } #[inline(always)] - fn atan2(&self, other: float) -> float { - (*self as f64).atan2(other as f64) as float + fn atan2(&self, other: &float) -> float { + (*self as f64).atan2(&(*other as f64)) as float } /// Simultaneously computes the sine and cosine of the number @@ -561,8 +566,8 @@ impl Exponential for float { /// Returns the logarithm of the number with respect to an arbitrary base #[inline(always)] - fn log(&self, base: float) -> float { - (*self as f64).log(base as f64) as float + fn log(&self, base: &float) -> float { + (*self as f64).log(&(*base as f64)) as float } /// Returns the base 2 logarithm of the number @@ -945,10 +950,13 @@ impl Float for float { #[cfg(test)] mod tests { - use num::*; use super::*; use prelude::*; + use num::*; + use num; + use sys; + #[test] fn test_num() { num::test_num(10f, 2f); diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 27e872003ec..74f74d11b73 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -26,12 +26,17 @@ pub static bytes : uint = ($bits / 8); pub static min_value: $T = (-1 as $T) << (bits - 1); pub static max_value: $T = min_value - 1 as $T; +/// Calculates the sum of two numbers #[inline(always)] pub fn add(x: $T, y: $T) -> $T { x + y } +/// Subtracts the second number from the first #[inline(always)] pub fn sub(x: $T, y: $T) -> $T { x - y } +/// Multiplies two numbers together #[inline(always)] pub fn mul(x: $T, y: $T) -> $T { x * y } +/// Divides the first argument by the second argument (using integer division) +/// Divides the first argument by the second argument (using integer division) #[inline(always)] pub fn div(x: $T, y: $T) -> $T { x / y } @@ -58,16 +63,22 @@ pub fn div(x: $T, y: $T) -> $T { x / y } #[inline(always)] pub fn rem(x: $T, y: $T) -> $T { x % y } +/// Returns true iff `x < y` #[inline(always)] pub fn lt(x: $T, y: $T) -> bool { x < y } +/// Returns true iff `x <= y` #[inline(always)] pub fn le(x: $T, y: $T) -> bool { x <= y } +/// Returns true iff `x == y` #[inline(always)] pub fn eq(x: $T, y: $T) -> bool { x == y } +/// Returns true iff `x != y` #[inline(always)] pub fn ne(x: $T, y: $T) -> bool { x != y } +/// Returns true iff `x >= y` #[inline(always)] pub fn ge(x: $T, y: $T) -> bool { x >= y } +/// Returns true iff `x > y` #[inline(always)] pub fn gt(x: $T, y: $T) -> bool { x > y } @@ -389,7 +400,7 @@ impl Integer for $T { #[inline(always)] fn gcd(&self, other: &$T) -> $T { // Use Euclid's algorithm - let mut m = *self, n = *other; + let mut (m, n) = (*self, *other); while m != 0 { let temp = m; m = n % temp; @@ -557,6 +568,13 @@ mod tests { use super::*; use prelude::*; + use i16; + use i32; + use i64; + use i8; + use num; + use sys; + #[test] fn test_num() { num::test_num(10 as $T, 2 as $T); @@ -775,27 +793,27 @@ mod tests { #[test] fn test_parse_bytes() { - use str::to_bytes; - assert_eq!(parse_bytes(to_bytes("123"), 10u), Some(123 as $T)); - assert_eq!(parse_bytes(to_bytes("1001"), 2u), Some(9 as $T)); - assert_eq!(parse_bytes(to_bytes("123"), 8u), Some(83 as $T)); - assert_eq!(i32::parse_bytes(to_bytes("123"), 16u), Some(291 as i32)); - assert_eq!(i32::parse_bytes(to_bytes("ffff"), 16u), Some(65535 as i32)); - assert_eq!(i32::parse_bytes(to_bytes("FFFF"), 16u), Some(65535 as i32)); - assert_eq!(parse_bytes(to_bytes("z"), 36u), Some(35 as $T)); - assert_eq!(parse_bytes(to_bytes("Z"), 36u), Some(35 as $T)); - - assert_eq!(parse_bytes(to_bytes("-123"), 10u), Some(-123 as $T)); - assert_eq!(parse_bytes(to_bytes("-1001"), 2u), Some(-9 as $T)); - assert_eq!(parse_bytes(to_bytes("-123"), 8u), Some(-83 as $T)); - assert_eq!(i32::parse_bytes(to_bytes("-123"), 16u), Some(-291 as i32)); - assert_eq!(i32::parse_bytes(to_bytes("-ffff"), 16u), Some(-65535 as i32)); - assert_eq!(i32::parse_bytes(to_bytes("-FFFF"), 16u), Some(-65535 as i32)); - assert_eq!(parse_bytes(to_bytes("-z"), 36u), Some(-35 as $T)); - assert_eq!(parse_bytes(to_bytes("-Z"), 36u), Some(-35 as $T)); - - assert!(parse_bytes(to_bytes("Z"), 35u).is_none()); - assert!(parse_bytes(to_bytes("-9"), 2u).is_none()); + use str::StrSlice; + assert_eq!(parse_bytes("123".as_bytes(), 10u), Some(123 as $T)); + assert_eq!(parse_bytes("1001".as_bytes(), 2u), Some(9 as $T)); + assert_eq!(parse_bytes("123".as_bytes(), 8u), Some(83 as $T)); + assert_eq!(i32::parse_bytes("123".as_bytes(), 16u), Some(291 as i32)); + assert_eq!(i32::parse_bytes("ffff".as_bytes(), 16u), Some(65535 as i32)); + assert_eq!(i32::parse_bytes("FFFF".as_bytes(), 16u), Some(65535 as i32)); + assert_eq!(parse_bytes("z".as_bytes(), 36u), Some(35 as $T)); + assert_eq!(parse_bytes("Z".as_bytes(), 36u), Some(35 as $T)); + + assert_eq!(parse_bytes("-123".as_bytes(), 10u), Some(-123 as $T)); + assert_eq!(parse_bytes("-1001".as_bytes(), 2u), Some(-9 as $T)); + assert_eq!(parse_bytes("-123".as_bytes(), 8u), Some(-83 as $T)); + assert_eq!(i32::parse_bytes("-123".as_bytes(), 16u), Some(-291 as i32)); + assert_eq!(i32::parse_bytes("-ffff".as_bytes(), 16u), Some(-65535 as i32)); + assert_eq!(i32::parse_bytes("-FFFF".as_bytes(), 16u), Some(-65535 as i32)); + assert_eq!(parse_bytes("-z".as_bytes(), 36u), Some(-35 as $T)); + assert_eq!(parse_bytes("-Z".as_bytes(), 36u), Some(-35 as $T)); + + assert!(parse_bytes("Z".as_bytes(), 35u).is_none()); + assert!(parse_bytes("-9".as_bytes(), 2u).is_none()); } #[test] diff --git a/src/libstd/num/num.rs b/src/libstd/num/num.rs index 96b302d3174..a9893579721 100644 --- a/src/libstd/num/num.rs +++ b/src/libstd/num/num.rs @@ -9,6 +9,9 @@ // except according to those terms. //! An interface for numeric types + +#[allow(missing_doc)]; + use cmp::{Eq, ApproxEq, Ord}; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; @@ -103,11 +106,11 @@ pub trait Fractional: Num } pub trait Algebraic { - fn pow(&self, n: Self) -> Self; + fn pow(&self, n: &Self) -> Self; fn sqrt(&self) -> Self; fn rsqrt(&self) -> Self; fn cbrt(&self) -> Self; - fn hypot(&self, other: Self) -> Self; + fn hypot(&self, other: &Self) -> Self; } pub trait Trigonometric { @@ -117,7 +120,7 @@ pub trait Trigonometric { fn asin(&self) -> Self; fn acos(&self) -> Self; fn atan(&self) -> Self; - fn atan2(&self, other: Self) -> Self; + fn atan2(&self, other: &Self) -> Self; fn sin_cos(&self) -> (Self, Self); } @@ -125,7 +128,7 @@ pub trait Exponential { fn exp(&self) -> Self; fn exp2(&self) -> Self; fn ln(&self) -> Self; - fn log(&self, base: Self) -> Self; + fn log(&self, base: &Self) -> Self; fn log2(&self) -> Self; fn log10(&self) -> Self; } diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 1d65b84b7ce..3905d82cd0f 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(missing_doc)]; + use container::Container; use core::cmp::{Ord, Eq}; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use option::{None, Option, Some}; use char; use str; +use str::{StrSlice}; use kinds::Copy; use vec; use vec::{CopyableVector, ImmutableVector}; @@ -187,18 +190,18 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ let _1: T = One::one(); if is_NaN(num) { - return (str::to_bytes("NaN"), true); + return ("NaN".as_bytes().to_owned(), true); } else if is_inf(num){ return match sign { - SignAll => (str::to_bytes("+inf"), true), - _ => (str::to_bytes("inf"), true) + SignAll => ("+inf".as_bytes().to_owned(), true), + _ => ("inf".as_bytes().to_owned(), true) } } else if is_neg_inf(num) { return match sign { - SignNone => (str::to_bytes("inf"), true), - _ => (str::to_bytes("-inf"), true), + SignNone => ("inf".as_bytes().to_owned(), true), + _ => ("-inf".as_bytes().to_owned(), true), } } @@ -636,7 +639,7 @@ pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+ special: bool, exponent: ExponentFormat, empty_zero: bool, ignore_underscores: bool ) -> Option<T> { - from_str_bytes_common(str::to_bytes(buf), radix, negative, + from_str_bytes_common(buf.as_bytes(), radix, negative, fractional, special, exponent, empty_zero, ignore_underscores) } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index e6267bfe9e1..2bc1ca9c673 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -27,34 +27,55 @@ pub static bytes : uint = ($bits / 8); pub static min_value: $T = 0 as $T; pub static max_value: $T = 0 as $T - 1 as $T; +/// Calculates the sum of two numbers #[inline(always)] pub fn add(x: $T, y: $T) -> $T { x + y } +/// Subtracts the second number from the first #[inline(always)] pub fn sub(x: $T, y: $T) -> $T { x - y } +/// Multiplies two numbers together #[inline(always)] pub fn mul(x: $T, y: $T) -> $T { x * y } +/// Divides the first argument by the second argument (using integer division) #[inline(always)] pub fn div(x: $T, y: $T) -> $T { x / y } +/// Calculates the integer remainder when x is divided by y (equivalent to the +/// '%' operator) #[inline(always)] pub fn rem(x: $T, y: $T) -> $T { x % y } +/// Returns true iff `x < y` #[inline(always)] pub fn lt(x: $T, y: $T) -> bool { x < y } +/// Returns true iff `x <= y` #[inline(always)] pub fn le(x: $T, y: $T) -> bool { x <= y } +/// Returns true iff `x == y` #[inline(always)] pub fn eq(x: $T, y: $T) -> bool { x == y } +/// Returns true iff `x != y` #[inline(always)] pub fn ne(x: $T, y: $T) -> bool { x != y } +/// Returns true iff `x >= y` #[inline(always)] pub fn ge(x: $T, y: $T) -> bool { x >= y } +/// Returns true iff `x > y` #[inline(always)] pub fn gt(x: $T, y: $T) -> bool { x > y } #[inline(always)] -/// -/// Iterate over the range [`start`,`start`+`step`..`stop`) -/// +/** + * Iterate through a range with a given step value. + * + * # Examples + * ~~~ {.rust} + * let nums = [1,2,3,4,5,6,7]; + * + * for uint::range_step(0, nums.len() - 1, 2) |i| { + * println(fmt!("%d & %d", nums[i], nums[i+1])); + * } + * ~~~ + */ pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool { let mut i = start; if step == 0 { @@ -216,7 +237,7 @@ impl Integer for $T { #[inline(always)] fn gcd(&self, other: &$T) -> $T { // Use Euclid's algorithm - let mut m = *self, n = *other; + let mut (m, n) = (*self, *other); while m != 0 { let temp = m; m = n % temp; @@ -402,6 +423,14 @@ mod tests { use super::*; use prelude::*; + use num; + use sys; + use u16; + use u32; + use u64; + use u8; + use uint; + #[test] fn test_num() { num::test_num(10 as $T, 2 as $T); @@ -509,16 +538,16 @@ mod tests { #[test] pub fn test_parse_bytes() { - use str::to_bytes; - assert_eq!(parse_bytes(to_bytes("123"), 10u), Some(123u as $T)); - assert_eq!(parse_bytes(to_bytes("1001"), 2u), Some(9u as $T)); - assert_eq!(parse_bytes(to_bytes("123"), 8u), Some(83u as $T)); - assert_eq!(u16::parse_bytes(to_bytes("123"), 16u), Some(291u as u16)); - assert_eq!(u16::parse_bytes(to_bytes("ffff"), 16u), Some(65535u as u16)); - assert_eq!(parse_bytes(to_bytes("z"), 36u), Some(35u as $T)); - - assert!(parse_bytes(to_bytes("Z"), 10u).is_none()); - assert!(parse_bytes(to_bytes("_"), 2u).is_none()); + use str::StrSlice; + assert_eq!(parse_bytes("123".as_bytes(), 10u), Some(123u as $T)); + assert_eq!(parse_bytes("1001".as_bytes(), 2u), Some(9u as $T)); + assert_eq!(parse_bytes("123".as_bytes(), 8u), Some(83u as $T)); + assert_eq!(u16::parse_bytes("123".as_bytes(), 16u), Some(291u as u16)); + assert_eq!(u16::parse_bytes("ffff".as_bytes(), 16u), Some(65535u as u16)); + assert_eq!(parse_bytes("z".as_bytes(), 36u), Some(35u as $T)); + + assert!(parse_bytes("Z".as_bytes(), 10u).is_none()); + assert!(parse_bytes("_".as_bytes(), 2u).is_none()); } #[test] diff --git a/src/libstd/old_iter.rs b/src/libstd/old_iter.rs index 389b643572c..9fea4376816 100644 --- a/src/libstd/old_iter.rs +++ b/src/libstd/old_iter.rs @@ -14,6 +14,8 @@ */ +#[allow(missing_doc)]; + use cmp::{Eq, Ord}; use kinds::Copy; use option::{None, Option, Some}; @@ -31,10 +33,6 @@ pub trait ReverseIter<A>: BaseIter<A> { fn each_reverse(&self, blk: &fn(&A) -> bool) -> bool; } -pub trait MutableIter<A>: BaseIter<A> { - fn each_mut(&mut self, blk: &fn(&mut A) -> bool) -> bool; -} - pub trait ExtendedIter<A> { fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool; fn all(&self, blk: &fn(&A) -> bool) -> bool; @@ -45,10 +43,6 @@ pub trait ExtendedIter<A> { fn flat_map_to_vec<B,IB: BaseIter<B>>(&self, op: &fn(&A) -> IB) -> ~[B]; } -pub trait ExtendedMutableIter<A> { - fn eachi_mut(&mut self, blk: &fn(uint, &mut A) -> bool) -> bool; -} - pub trait EqIter<A:Eq> { fn contains(&self, x: &A) -> bool; fn count(&self, x: &A) -> uint; @@ -65,13 +59,6 @@ pub trait CopyableOrderedIter<A:Copy + Ord> { fn max(&self) -> A; } -pub trait CopyableNonstrictIter<A:Copy> { - // Like "each", but copies out the value. If the receiver is mutated while - // iterating over it, the semantics must not be memory-unsafe but are - // otherwise undefined. - fn each_val(&const self, f: &fn(A) -> bool) -> bool; -} - // A trait for sequences that can be built by imperatively pushing elements // onto them. pub trait Buildable<A> { diff --git a/src/libstd/ops.rs b/src/libstd/ops.rs index 47ff45be687..77cfe62e495 100644 --- a/src/libstd/ops.rs +++ b/src/libstd/ops.rs @@ -10,6 +10,8 @@ //! Traits for the built-in operators +#[allow(missing_doc)]; + #[lang="drop"] pub trait Drop { fn finalize(&self); // FIXME(#4332): Rename to "drop"? --pcwalton diff --git a/src/libstd/option.rs b/src/libstd/option.rs index be6ec8c8518..80f4fb7643c 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -46,12 +46,12 @@ use ops::Add; use kinds::Copy; use util; use num::Zero; -use old_iter::{BaseIter, MutableIter, ExtendedIter}; -use old_iter; +use iterator::Iterator; use str::StrSlice; use clone::DeepClone; #[cfg(test)] use str; +#[cfg(test)] use iterator::IteratorUtil; /// The option type #[deriving(Clone, DeepClone, Eq)] @@ -100,66 +100,39 @@ impl<T: Copy + Add<T,T>> Add<Option<T>, Option<T>> for Option<T> { } } -impl<T> BaseIter<T> for Option<T> { - /// Performs an operation on the contained value by reference - #[inline(always)] - fn each<'a>(&'a self, f: &fn(x: &'a T) -> bool) -> bool { - match *self { None => true, Some(ref t) => { f(t) } } - } - - #[inline(always)] - fn size_hint(&self) -> Option<uint> { - if self.is_some() { Some(1) } else { Some(0) } - } -} - -impl<T> MutableIter<T> for Option<T> { - #[inline(always)] - fn each_mut<'a>(&'a mut self, f: &fn(&'a mut T) -> bool) -> bool { - match *self { None => true, Some(ref mut t) => { f(t) } } +impl<T> Option<T> { + /// Return an iterator over the possibly contained value + #[inline] + pub fn iter<'r>(&'r self) -> OptionIterator<'r, T> { + match *self { + Some(ref x) => OptionIterator{opt: Some(x)}, + None => OptionIterator{opt: None} + } } -} -impl<A> ExtendedIter<A> for Option<A> { - pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { - old_iter::eachi(self, blk) - } - pub fn all(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::all(self, blk) - } - pub fn any(&self, blk: &fn(&A) -> bool) -> bool { - old_iter::any(self, blk) - } - pub fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B { - old_iter::foldl(self, b0, blk) - } - pub fn position(&self, f: &fn(&A) -> bool) -> Option<uint> { - old_iter::position(self, f) - } - fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B] { - old_iter::map_to_vec(self, op) - } - fn flat_map_to_vec<B,IB:BaseIter<B>>(&self, op: &fn(&A) -> IB) - -> ~[B] { - old_iter::flat_map_to_vec(self, op) + /// Return a mutable iterator over the possibly contained value + #[inline] + pub fn mut_iter<'r>(&'r mut self) -> OptionMutIterator<'r, T> { + match *self { + Some(ref mut x) => OptionMutIterator{opt: Some(x)}, + None => OptionMutIterator{opt: None} + } } -} -pub impl<T> Option<T> { /// Returns true if the option equals `none` - fn is_none(&const self) -> bool { + #[inline] + pub fn is_none(&const self) -> bool { match *self { None => true, Some(_) => false } } /// Returns true if the option contains some value #[inline(always)] - fn is_some(&const self) -> bool { !self.is_none() } + pub fn is_some(&const self) -> bool { !self.is_none() } /// Update an optional value by optionally running its content through a /// function that returns an option. #[inline(always)] - fn chain<U>(self, f: &fn(t: T) -> Option<U>) -> Option<U> { - + pub fn chain<U>(self, f: &fn(t: T) -> Option<U>) -> Option<U> { match self { Some(t) => f(t), None => None @@ -168,7 +141,7 @@ pub impl<T> Option<T> { /// Returns the leftmost Some() value, or None if both are None. #[inline(always)] - fn or(self, optb: Option<T>) -> Option<T> { + pub fn or(self, optb: Option<T>) -> Option<T> { match self { Some(opta) => Some(opta), _ => optb @@ -178,45 +151,49 @@ pub impl<T> Option<T> { /// Update an optional value by optionally running its content by reference /// through a function that returns an option. #[inline(always)] - fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option<U>) -> Option<U> { - match *self { Some(ref x) => f(x), None => None } + pub fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option<U>) + -> Option<U> { + match *self { + Some(ref x) => f(x), + None => None + } } /// Maps a `some` value from one type to another by reference #[inline(always)] - fn map<'a, U>(&self, f: &fn(&'a T) -> U) -> Option<U> { + pub fn map<'a, U>(&self, f: &fn(&'a T) -> U) -> Option<U> { match *self { Some(ref x) => Some(f(x)), None => None } } /// As `map`, but consumes the option and gives `f` ownership to avoid /// copying. #[inline(always)] - fn map_consume<U>(self, f: &fn(v: T) -> U) -> Option<U> { + 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(always)] - fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { + 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) } } /// As `map_default`, but consumes the option and gives `f` /// ownership to avoid copying. #[inline(always)] - fn map_consume_default<U>(self, def: U, f: &fn(v: T) -> U) -> U { + pub fn map_consume_default<U>(self, def: U, f: &fn(v: T) -> U) -> U { match self { None => def, Some(v) => f(v) } } /// Apply a function to the contained value or do nothing - fn mutate(&mut self, f: &fn(T) -> T) { + pub fn mutate(&mut self, f: &fn(T) -> T) { if self.is_some() { *self = Some(f(self.swap_unwrap())); } } /// Apply a function to the contained value or set it to a default - fn mutate_default(&mut self, def: T, f: &fn(T) -> T) { + pub fn mutate_default(&mut self, def: T, f: &fn(T) -> T) { if self.is_some() { *self = Some(f(self.swap_unwrap())); } else { @@ -239,7 +216,7 @@ pub impl<T> Option<T> { case explicitly. */ #[inline(always)] - fn get_ref<'a>(&'a self) -> &'a T { + pub fn get_ref<'a>(&'a self) -> &'a T { match *self { Some(ref x) => x, None => fail!("option::get_ref none") @@ -261,7 +238,7 @@ pub impl<T> Option<T> { case explicitly. */ #[inline(always)] - fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { + pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { match *self { Some(ref mut x) => x, None => fail!("option::get_mut_ref none") @@ -269,7 +246,7 @@ pub impl<T> Option<T> { } #[inline(always)] - fn unwrap(self) -> T { + pub fn unwrap(self) -> T { /*! Moves a value out of an option type and returns it. @@ -301,7 +278,7 @@ pub impl<T> Option<T> { * Fails if the value equals `None`. */ #[inline(always)] - fn swap_unwrap(&mut self) -> T { + pub fn swap_unwrap(&mut self) -> T { if self.is_none() { fail!("option::swap_unwrap none") } util::replace(self, None).unwrap() } @@ -315,7 +292,7 @@ pub impl<T> Option<T> { * Fails if the value equals `none` */ #[inline(always)] - fn expect(self, reason: &str) -> T { + pub fn expect(self, reason: &str) -> T { match self { Some(val) => val, None => fail!(reason.to_owned()), @@ -323,7 +300,7 @@ pub impl<T> Option<T> { } } -pub impl<T:Copy> Option<T> { +impl<T:Copy> Option<T> { /** Gets the value out of an option @@ -339,22 +316,22 @@ pub impl<T:Copy> Option<T> { case explicitly. */ #[inline(always)] - fn get(self) -> T { + pub fn get(self) -> T { match self { - Some(copy x) => return x, + Some(x) => return x, None => fail!("option::get none") } } /// Returns the contained value or a default #[inline(always)] - fn get_or_default(self, def: T) -> T { - match self { Some(copy x) => x, None => def } + pub fn get_or_default(self, def: T) -> T { + match self { Some(x) => x, None => def } } /// Applies a function zero or more times until the result is none. #[inline(always)] - fn while_some(self, blk: &fn(v: T) -> Option<T>) { + pub fn while_some(self, blk: &fn(v: T) -> Option<T>) { let mut opt = self; while opt.is_some() { opt = blk(opt.unwrap()); @@ -362,11 +339,36 @@ pub impl<T:Copy> Option<T> { } } -pub impl<T:Copy + Zero> Option<T> { +impl<T:Copy + Zero> Option<T> { /// Returns the contained value or zero (for this type) #[inline(always)] - fn get_or_zero(self) -> T { - match self { Some(copy x) => x, None => Zero::zero() } + pub fn get_or_zero(self) -> T { + match self { + Some(x) => x, + None => Zero::zero() + } + } +} + +/// Immutable iterator over an `Option<A>` +pub struct OptionIterator<'self, A> { + priv opt: Option<&'self A> +} + +impl<'self, A> Iterator<&'self A> for OptionIterator<'self, A> { + fn next(&mut self) -> Option<&'self A> { + util::replace(&mut self.opt, None) + } +} + +/// Mutable iterator over an `Option<A>` +pub struct OptionMutIterator<'self, A> { + priv opt: Option<&'self mut A> +} + +impl<'self, A> Iterator<&'self mut A> for OptionMutIterator<'self, A> { + fn next(&mut self) -> Option<&'self mut A> { + util::replace(&mut self.opt, None) } } @@ -423,7 +425,7 @@ fn test_option_dance() { let x = Some(()); let mut y = Some(5); let mut y2 = 0; - for x.each |_x| { + for x.iter().advance |_x| { y2 = y.swap_unwrap(); } assert_eq!(y2, 5); @@ -431,7 +433,7 @@ fn test_option_dance() { } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_option_too_much_dance() { - let mut y = Some(util::NonCopyable()); + let mut y = Some(util::NonCopyable::new()); let _y2 = y.swap_unwrap(); let _y3 = y.swap_unwrap(); } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 15c68efc7cc..044b305a0dd 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -26,13 +26,18 @@ * to write OS-ignorant code by default. */ +#[allow(missing_doc)]; + use cast; use io; +use iterator::IteratorUtil; use libc; use libc::{c_char, c_void, c_int, size_t}; use libc::{mode_t, FILE}; +use local_data; use option; use option::{Some, None}; +use os; use prelude::*; use ptr; use str; @@ -43,6 +48,7 @@ use vec; pub use libc::fclose; pub use os::consts::*; +/// Delegates to the libc close() function, returning the same return value. pub fn close(fd: c_int) -> c_int { unsafe { libc::close(fd) @@ -140,7 +146,7 @@ pub mod win32 { pub fn as_utf16_p<T>(s: &str, f: &fn(*u16) -> T) -> T { let mut t = str::to_utf16(s); // Null terminate before passing on. - t += ~[0u16]; + t += [0u16]; vec::as_imm_buf(t, |buf, _len| f(buf)) } } @@ -169,6 +175,8 @@ fn with_env_lock<T>(f: &fn() -> T) -> T { } } +/// Returns a vector of (variable, value) pairs for all the environment +/// variables of the current process. pub fn env() -> ~[(~str,~str)] { unsafe { #[cfg(windows)] @@ -217,12 +225,11 @@ pub fn env() -> ~[(~str,~str)] { fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] { let mut pairs = ~[]; for input.each |p| { - let mut vs = ~[]; - for str::each_splitn_char(*p, '=', 1) |s| { vs.push(s.to_owned()) } + let vs: ~[&str] = p.splitn_iter('=', 1).collect(); debug!("splitting: len: %u", vs.len()); assert_eq!(vs.len(), 2); - pairs.push((copy vs[0], copy vs[1])); + pairs.push((vs[0].to_owned(), vs[1].to_owned())); } pairs } @@ -234,6 +241,8 @@ pub fn env() -> ~[(~str,~str)] { } #[cfg(unix)] +/// Fetches the environment variable `n` from the current process, returning +/// None if the variable isn't set. pub fn getenv(n: &str) -> Option<~str> { unsafe { do with_env_lock { @@ -249,6 +258,8 @@ pub fn getenv(n: &str) -> Option<~str> { } #[cfg(windows)] +/// Fetches the environment variable `n` from the current process, returning +/// None if the variable isn't set. pub fn getenv(n: &str) -> Option<~str> { unsafe { do with_env_lock { @@ -264,6 +275,8 @@ pub fn getenv(n: &str) -> Option<~str> { #[cfg(unix)] +/// Sets the environment variable `n` to the value `v` for the currently running +/// process pub fn setenv(n: &str, v: &str) { unsafe { do with_env_lock { @@ -278,6 +291,8 @@ pub fn setenv(n: &str, v: &str) { #[cfg(windows)] +/// Sets the environment variable `n` to the value `v` for the currently running +/// process pub fn setenv(n: &str, v: &str) { unsafe { do with_env_lock { @@ -420,13 +435,13 @@ fn dup2(src: c_int, dst: c_int) -> c_int { } } - +/// Returns the proper dll filename for the given basename of a file. pub fn dll_filename(base: &str) -> ~str { - return str::to_owned(DLL_PREFIX) + str::to_owned(base) + - str::to_owned(DLL_SUFFIX) + fmt!("%s%s%s", DLL_PREFIX, base, DLL_SUFFIX) } - +/// Optionally returns the filesystem path to the current executable which is +/// running. If any failure occurs, None is returned. pub fn self_exe_path() -> Option<Path> { #[cfg(target_os = "freebsd")] @@ -510,7 +525,7 @@ pub fn self_exe_path() -> Option<Path> { */ pub fn homedir() -> Option<Path> { return match getenv("HOME") { - Some(ref p) => if !str::is_empty(*p) { + Some(ref p) => if !p.is_empty() { Some(Path(*p)) } else { secondary() @@ -526,7 +541,7 @@ pub fn homedir() -> Option<Path> { #[cfg(windows)] fn secondary() -> Option<Path> { do getenv(~"USERPROFILE").chain |p| { - if !str::is_empty(p) { + if !p.is_empty() { Some(Path(p)) } else { None @@ -551,7 +566,7 @@ pub fn tmpdir() -> Path { fn getenv_nonempty(v: &str) -> Option<Path> { match getenv(v) { Some(x) => - if str::is_empty(x) { + if x.is_empty() { None } else { Some(Path(x)) @@ -826,6 +841,8 @@ pub fn remove_dir(p: &Path) -> bool { } } +/// Changes the current working directory to the specified path, returning +/// whether the change was completed successfully or not. pub fn change_dir(p: &Path) -> bool { return chdir(p); @@ -861,20 +878,18 @@ pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { fn key(_: Exclusive<()>) { } - let result = unsafe { - global_data_clone_create(key, || { - ~exclusive(()) - }) - }; + unsafe { + let result = global_data_clone_create(key, || { ~exclusive(()) }); - do result.with_imm() |_| { - let old_dir = os::getcwd(); - if change_dir(p) { - action(); - change_dir(&old_dir) - } - else { - false + do result.with_imm() |_| { + let old_dir = os::getcwd(); + if change_dir(p) { + action(); + change_dir(&old_dir) + } + else { + false + } } } } @@ -981,6 +996,7 @@ pub fn remove_file(p: &Path) -> bool { } #[cfg(unix)] +/// Returns the platform-specific value of errno pub fn errno() -> int { #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] @@ -1012,6 +1028,7 @@ pub fn errno() -> int { } #[cfg(windows)] +/// Returns the platform-specific value of errno pub fn errno() -> uint { use libc::types::os::arch::extra::DWORD; @@ -1162,7 +1179,7 @@ pub fn real_args() -> ~[~str] { #[cfg(windows)] pub fn real_args() -> ~[~str] { let mut nArgs: c_int = 0; - let lpArgCount = ptr::to_mut_unsafe_ptr(&mut nArgs); + let lpArgCount: *mut c_int = &mut nArgs; let lpCmdLine = unsafe { GetCommandLineW() }; let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) }; @@ -1211,6 +1228,11 @@ struct OverriddenArgs { fn overridden_arg_key(_v: @OverriddenArgs) {} +/// Returns the arguments which this program was started with (normally passed +/// via the command line). +/// +/// The return value of the function can be changed by invoking the +/// `os::set_args` function. pub fn args() -> ~[~str] { unsafe { match local_data::local_data_get(overridden_arg_key) { @@ -1220,6 +1242,9 @@ pub fn args() -> ~[~str] { } } +/// For the current task, overrides the task-local cache of the arguments this +/// program had when it started. These new arguments are only available to the +/// current task via the `os::args` method. pub fn set_args(new_args: ~[~str]) { unsafe { let overridden_args = @OverriddenArgs { val: copy new_args }; @@ -1423,8 +1448,9 @@ mod tests { use rand::RngUtil; use rand; use run; - use str; + use str::StrSlice; use vec; + use vec::CopyableVector; use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; @@ -1548,7 +1574,7 @@ mod tests { setenv("HOME", ""); assert!(os::homedir().is_none()); - for oldhome.each |s| { setenv("HOME", *s) } + for oldhome.iter().advance |s| { setenv("HOME", *s) } } #[test] @@ -1581,7 +1607,7 @@ mod tests { #[test] fn tmpdir() { - assert!(!str::is_empty(os::tmpdir().to_str())); + assert!(!os::tmpdir().to_str().is_empty()); } // Issue #712 @@ -1646,7 +1672,7 @@ mod tests { unsafe { let tempdir = getcwd(); // would like to use $TMPDIR, // doesn't seem to work on Linux - assert!((str::len(tempdir.to_str()) > 0u)); + assert!((tempdir.to_str().len() > 0u)); let in = tempdir.push("in.txt"); let out = tempdir.push("out.txt"); @@ -1658,10 +1684,10 @@ mod tests { }; assert!((ostream as uint != 0u)); let s = ~"hello"; - let mut buf = str::to_bytes(s) + [0 as u8]; + let mut buf = s.as_bytes_with_null().to_owned(); do vec::as_mut_buf(buf) |b, _len| { assert!((libc::fwrite(b as *c_void, 1u as size_t, - (str::len(s) + 1u) as size_t, ostream) + (s.len() + 1u) as size_t, ostream) == buf.len() as size_t)) } assert_eq!(libc::fclose(ostream), (0u as c_int)); diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ed9ef864f80..400657d0c25 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -14,12 +14,15 @@ Cross-platform file path handling */ +#[allow(missing_doc)]; + use container::Container; use cmp::Eq; +use iterator::IteratorUtil; use libc; use option::{None, Option, Some}; use str; -use str::StrSlice; +use str::{Str, StrSlice, StrVector}; use to_str::ToStr; use ascii::{AsciiCast, AsciiStr}; use old_iter::BaseIter; @@ -99,7 +102,7 @@ pub trait GenericPath { fn push_rel(&self, (&Self)) -> Self; /// Returns a new Path consisting of the path given by the given vector /// of strings, relative to `self`. - fn push_many(&self, (&[~str])) -> Self; + fn push_many<S: Str>(&self, (&[S])) -> Self; /// Identical to `dir_path` except in the case where `self` has only one /// component. In this case, `pop` returns the empty path. fn pop(&self) -> Self; @@ -306,8 +309,8 @@ mod stat { } -pub impl Path { - fn stat(&self) -> Option<libc::stat> { +impl Path { + pub fn stat(&self) -> Option<libc::stat> { unsafe { do str::as_c_str(self.to_str()) |buf| { let mut st = stat::arch::default_stat(); @@ -320,7 +323,7 @@ pub impl Path { } #[cfg(unix)] - fn lstat(&self) -> Option<libc::stat> { + pub fn lstat(&self) -> Option<libc::stat> { unsafe { do str::as_c_str(self.to_str()) |buf| { let mut st = stat::arch::default_stat(); @@ -332,21 +335,21 @@ pub impl Path { } } - fn exists(&self) -> bool { + pub fn exists(&self) -> bool { match self.stat() { None => false, Some(_) => true, } } - fn get_size(&self) -> Option<i64> { + pub fn get_size(&self) -> Option<i64> { match self.stat() { None => None, Some(ref st) => Some(st.st_size as i64), } } - fn get_mode(&self) -> Option<uint> { + pub fn get_mode(&self) -> Option<uint> { match self.stat() { None => None, Some(ref st) => Some(st.st_mode as uint), @@ -357,8 +360,8 @@ pub impl Path { #[cfg(target_os = "freebsd")] #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] -pub impl Path { - fn get_atime(&self) -> Option<(i64, int)> { +impl Path { + pub fn get_atime(&self) -> Option<(i64, int)> { match self.stat() { None => None, Some(ref st) => { @@ -368,7 +371,7 @@ pub impl Path { } } - fn get_mtime(&self) -> Option<(i64, int)> { + pub fn get_mtime(&self) -> Option<(i64, int)> { match self.stat() { None => None, Some(ref st) => { @@ -378,7 +381,7 @@ pub impl Path { } } - fn get_ctime(&self) -> Option<(i64, int)> { + pub fn get_ctime(&self) -> Option<(i64, int)> { match self.stat() { None => None, Some(ref st) => { @@ -391,8 +394,8 @@ pub impl Path { #[cfg(target_os = "freebsd")] #[cfg(target_os = "macos")] -pub impl Path { - fn get_birthtime(&self) -> Option<(i64, int)> { +impl Path { + pub fn get_birthtime(&self) -> Option<(i64, int)> { match self.stat() { None => None, Some(ref st) => { @@ -404,8 +407,8 @@ pub impl Path { } #[cfg(target_os = "win32")] -pub impl Path { - fn get_atime(&self) -> Option<(i64, int)> { +impl Path { + pub fn get_atime(&self) -> Option<(i64, int)> { match self.stat() { None => None, Some(ref st) => { @@ -414,7 +417,7 @@ pub impl Path { } } - fn get_mtime(&self) -> Option<(i64, int)> { + pub fn get_mtime(&self) -> Option<(i64, int)> { match self.stat() { None => None, Some(ref st) => { @@ -423,7 +426,7 @@ pub impl Path { } } - fn get_ctime(&self) -> Option<(i64, int)> { + pub fn get_ctime(&self) -> Option<(i64, int)> { match self.stat() { None => None, Some(ref st) => { @@ -439,7 +442,7 @@ impl ToStr for PosixPath { if self.is_absolute { s += "/"; } - s + str::connect(self.components, "/") + s + self.components.connect("/") } } @@ -447,10 +450,9 @@ impl ToStr for PosixPath { // PosixPath and WindowsPath, most of their methods are common. impl GenericPath for PosixPath { fn from_str(s: &str) -> PosixPath { - let mut components = ~[]; - for str::each_split_nonempty(s, |c| c == '/') |s| { - components.push(s.to_owned()) - } + let components = s.split_iter('/') + .filter_map(|s| if s.is_empty() {None} else {Some(s.to_owned())}) + .collect(); let is_absolute = (s.len() != 0 && s[0] == '/' as u8); PosixPath { is_absolute: is_absolute, @@ -477,8 +479,8 @@ impl GenericPath for PosixPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) => Some(f.slice(0, p).to_owned()), + match f.rfind('.') { + Some(p) => Some(f.slice_to(p).to_owned()), None => Some(copy *f), } } @@ -489,8 +491,8 @@ impl GenericPath for PosixPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) if p < f.len() => Some(f.slice(p, f.len()).to_owned()), + match f.rfind('.') { + Some(p) if p < f.len() => Some(f.slice_from(p).to_owned()), _ => None, } } @@ -506,7 +508,7 @@ impl GenericPath for PosixPath { } fn with_filename(&self, f: &str) -> PosixPath { - assert!(! str::any(f, |c| windows::is_sep(c as u8))); + assert!(! f.iter().all(windows::is_sep)); self.dir_path().push(f) } @@ -564,14 +566,14 @@ impl GenericPath for PosixPath { false } - fn push_many(&self, cs: &[~str]) -> PosixPath { + fn push_many<S: Str>(&self, cs: &[S]) -> PosixPath { let mut v = copy self.components; for cs.each |e| { - let mut ss = ~[]; - for str::each_split_nonempty(*e, |c| windows::is_sep(c as u8)) |s| { - ss.push(s.to_owned()) + for e.as_slice().split_iter(windows::is_sep).advance |s| { + if !s.is_empty() { + v.push(s.to_owned()) + } } - v.push_all_move(ss); } PosixPath { is_absolute: self.is_absolute, @@ -581,11 +583,11 @@ impl GenericPath for PosixPath { fn push(&self, s: &str) -> PosixPath { let mut v = copy self.components; - let mut ss = ~[]; - for str::each_split_nonempty(s, |c| windows::is_sep(c as u8)) |s| { - ss.push(s.to_owned()) + for s.split_iter(windows::is_sep).advance |s| { + if !s.is_empty() { + v.push(s.to_owned()) + } } - v.push_all_move(ss); PosixPath { components: v, ..copy *self } } @@ -627,7 +629,7 @@ impl ToStr for WindowsPath { if self.is_absolute { s += "\\"; } - s + str::connect(self.components, "\\") + s + self.components.connect("\\") } } @@ -659,11 +661,11 @@ impl GenericPath for WindowsPath { } } - let mut components = ~[]; - for str::each_split_nonempty(rest, |c| windows::is_sep(c as u8)) |s| { - components.push(s.to_owned()) - } - let is_absolute = (rest.len() != 0 && windows::is_sep(rest[0])); + let components = rest.split_iter(windows::is_sep) + .filter_map(|s| if s.is_empty() {None} else {Some(s.to_owned())}) + .collect(); + + let is_absolute = (rest.len() != 0 && windows::is_sep(rest[0] as char)); WindowsPath { host: host, device: device, @@ -691,8 +693,8 @@ impl GenericPath for WindowsPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) => Some(f.slice(0, p).to_owned()), + match f.rfind('.') { + Some(p) => Some(f.slice_to(p).to_owned()), None => Some(copy *f), } } @@ -703,8 +705,8 @@ impl GenericPath for WindowsPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) if p < f.len() => Some(f.slice(p, f.len()).to_owned()), + match f.rfind('.') { + Some(p) if p < f.len() => Some(f.slice_from(p).to_owned()), _ => None, } } @@ -720,7 +722,7 @@ impl GenericPath for WindowsPath { } fn with_filename(&self, f: &str) -> WindowsPath { - assert!(! str::any(f, |c| windows::is_sep(c as u8))); + assert!(! f.iter().all(windows::is_sep)); self.dir_path().push(f) } @@ -772,9 +774,9 @@ impl GenericPath for WindowsPath { /* if rhs has a host set, then the whole thing wins */ match other.host { - Some(copy host) => { + Some(ref host) => { return WindowsPath { - host: Some(host), + host: Some(copy *host), device: copy other.device, is_absolute: true, components: copy other.components, @@ -785,10 +787,10 @@ impl GenericPath for WindowsPath { /* if rhs has a device set, then a part wins */ match other.device { - Some(copy device) => { + Some(ref device) => { return WindowsPath { host: None, - device: Some(device), + device: Some(copy *device), is_absolute: true, components: copy other.components, }; @@ -821,14 +823,14 @@ impl GenericPath for WindowsPath { } } - fn push_many(&self, cs: &[~str]) -> WindowsPath { + fn push_many<S: Str>(&self, cs: &[S]) -> WindowsPath { let mut v = copy self.components; for cs.each |e| { - let mut ss = ~[]; - for str::each_split_nonempty(*e, |c| windows::is_sep(c as u8)) |s| { - ss.push(s.to_owned()) + for e.as_slice().split_iter(windows::is_sep).advance |s| { + if !s.is_empty() { + v.push(s.to_owned()) + } } - v.push_all_move(ss); } // tedious, but as-is, we can't use ..self WindowsPath { @@ -841,11 +843,11 @@ impl GenericPath for WindowsPath { fn push(&self, s: &str) -> WindowsPath { let mut v = copy self.components; - let mut ss = ~[]; - for str::each_split_nonempty(s, |c| windows::is_sep(c as u8)) |s| { - ss.push(s.to_owned()) + for s.split_iter(windows::is_sep).advance |s| { + if !s.is_empty() { + v.push(s.to_owned()) + } } - v.push_all_move(ss); WindowsPath { components: v, ..copy *self } } @@ -903,8 +905,8 @@ pub mod windows { use option::{None, Option, Some}; #[inline(always)] - pub fn is_sep(u: u8) -> bool { - u == '/' as u8 || u == '\\' as u8 + pub fn is_sep(u: char) -> bool { + u == '/' || u == '\\' } pub fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> { @@ -913,7 +915,7 @@ pub mod windows { s[0] == s[1]) { let mut i = 2; while i < s.len() { - if is_sep(s[i]) { + if is_sep(s[i] as char) { let pre = s.slice(2, i).to_owned(); let rest = s.slice(i, s.len()).to_owned(); return Some((pre, rest)); diff --git a/src/libstd/pipes.rs b/src/libstd/pipes.rs index 4203f87f139..012ad0ed80d 100644 --- a/src/libstd/pipes.rs +++ b/src/libstd/pipes.rs @@ -82,9 +82,12 @@ bounded and unbounded protocols allows for less code duplication. */ +#[allow(missing_doc)]; + use container::Container; use cast::{forget, transmute, transmute_copy}; use either::{Either, Left, Right}; +use iterator::IteratorUtil; use kinds::Owned; use libc; use ops::Drop; @@ -92,10 +95,9 @@ use option::{None, Option, Some}; use unstable::finally::Finally; use unstable::intrinsics; use ptr; -use ptr::Ptr; +use ptr::RawPtr; use task; -use vec; -use vec::OwnedVector; +use vec::{OwnedVector, MutableVector}; use util::replace; static SPIN_COUNT: uint = 0; @@ -150,16 +152,16 @@ pub fn PacketHeader() -> PacketHeader { } } -pub impl PacketHeader { +impl PacketHeader { // Returns the old state. - unsafe fn mark_blocked(&mut self, this: *rust_task) -> State { + pub unsafe fn mark_blocked(&mut self, this: *rust_task) -> State { rustrt::rust_task_ref(this); let old_task = swap_task(&mut self.blocked_task, this); assert!(old_task.is_null()); swap_state_acq(&mut self.state, Blocked) } - unsafe fn unblock(&mut self) { + pub unsafe fn unblock(&mut self) { let old_task = swap_task(&mut self.blocked_task, ptr::null()); if !old_task.is_null() { rustrt::rust_task_deref(old_task) @@ -174,12 +176,12 @@ pub impl PacketHeader { // unsafe because this can do weird things to the space/time // continuum. It ends making multiple unique pointers to the same // thing. You'll probably want to forget them when you're done. - unsafe fn buf_header(&mut self) -> ~BufferHeader { + pub unsafe fn buf_header(&mut self) -> ~BufferHeader { assert!(self.buffer.is_not_null()); transmute_copy(&self.buffer) } - fn set_buffer<T:Owned>(&mut self, b: ~Buffer<T>) { + pub fn set_buffer<T:Owned>(&mut self, b: ~Buffer<T>) { unsafe { self.buffer = transmute_copy(&b); } @@ -235,11 +237,11 @@ pub fn packet<T>() -> *mut Packet<T> { pub fn entangle_buffer<T:Owned,Tstart:Owned>( mut buffer: ~Buffer<T>, init: &fn(*libc::c_void, x: &mut T) -> *mut Packet<Tstart>) - -> (SendPacketBuffered<Tstart, T>, RecvPacketBuffered<Tstart, T>) { + -> (RecvPacketBuffered<Tstart, T>, SendPacketBuffered<Tstart, T>) { unsafe { let p = init(transmute_copy(&buffer), &mut buffer.data); forget(buffer); - (SendPacketBuffered(p), RecvPacketBuffered(p)) + (RecvPacketBuffered(p), SendPacketBuffered(p)) } } @@ -313,6 +315,7 @@ struct BufferResource<T> { impl<T> Drop for BufferResource<T> { fn finalize(&self) { unsafe { + // FIXME(#4330) Need self by value to get mutability. let this: &mut BufferResource<T> = transmute(self); let mut b = move_it!(this.buffer); @@ -598,7 +601,7 @@ pub fn wait_many<T: Selectable>(pkts: &mut [T]) -> uint { let mut data_avail = false; let mut ready_packet = pkts.len(); - for vec::eachi_mut(pkts) |i, p| { + for pkts.mut_iter().enumerate().advance |(i, p)| { unsafe { let p = &mut *p.header(); let old = p.mark_blocked(this); @@ -620,7 +623,7 @@ pub fn wait_many<T: Selectable>(pkts: &mut [T]) -> uint { let event = wait_event(this) as *PacketHeader; let mut pos = None; - for vec::eachi_mut(pkts) |i, p| { + for pkts.mut_iter().enumerate().advance |(i, p)| { if p.header() == event { pos = Some(i); break; @@ -638,7 +641,7 @@ pub fn wait_many<T: Selectable>(pkts: &mut [T]) -> uint { debug!("%?", &mut pkts[ready_packet]); - for vec::each_mut(pkts) |p| { + for pkts.mut_iter().advance |p| { unsafe { (*p.header()).unblock() } @@ -692,12 +695,12 @@ pub fn SendPacketBuffered<T,Tbuffer>(p: *mut Packet<T>) } } -pub impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> { - fn unwrap(&mut self) -> *mut Packet<T> { +impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> { + pub fn unwrap(&mut self) -> *mut Packet<T> { replace(&mut self.p, None).unwrap() } - fn header(&mut self) -> *mut PacketHeader { + pub fn header(&mut self) -> *mut PacketHeader { match self.p { Some(packet) => unsafe { let packet = &mut *packet; @@ -708,7 +711,7 @@ pub impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> { } } - fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { + pub fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { //error!("send reuse_buffer"); replace(&mut self.buffer, None).unwrap() } @@ -740,12 +743,12 @@ impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> { } } -pub impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> { - fn unwrap(&mut self) -> *mut Packet<T> { +impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> { + pub fn unwrap(&mut self) -> *mut Packet<T> { replace(&mut self.p, None).unwrap() } - fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { + pub fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { replace(&mut self.buffer, None).unwrap() } } @@ -773,9 +776,9 @@ pub fn RecvPacketBuffered<T,Tbuffer>(p: *mut Packet<T>) } } -pub fn entangle<T>() -> (SendPacket<T>, RecvPacket<T>) { +pub fn entangle<T>() -> (RecvPacket<T>, SendPacket<T>) { let p = packet(); - (SendPacket(p), RecvPacket(p)) + (RecvPacket(p), SendPacket(p)) } /** Receives a message from one of two endpoints. @@ -851,7 +854,7 @@ pub fn select<T:Owned,Tb:Owned>(mut endpoints: ~[RecvPacketBuffered<T, Tb>]) Option<T>, ~[RecvPacketBuffered<T, Tb>]) { let mut endpoint_headers = ~[]; - for vec::each_mut(endpoints) |endpoint| { + for endpoints.mut_iter().advance |endpoint| { endpoint_headers.push(endpoint.header()); } diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 58d0c40efa0..61b8d36266e 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -8,12 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The Rust prelude. Imported into every module by default. +/*! -/* Reexported core operators */ +Many programming languages have a 'prelude': a particular subset of the +libraries that come with the language. Every program imports the prelude by +default. +For example, it would be annoying to add `use std::io::println;` to every single +program, and the vast majority of Rust programs will wish to print to standard +output. Therefore, it makes sense to import it into every program. + +Rust's prelude has three main parts: + +1. io::print and io::println. +2. Core operators, such as `Add`, `Mul`, and `Not`. +3. Various types and traits, such as `Clone`, `Eq`, and `comm::Chan`. + +*/ + + +// Reexported core operators pub use either::{Either, Left, Right}; -pub use kinds::{Const, Copy, Owned}; +pub use kinds::{Const, Copy, Owned, Sized}; pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; @@ -21,21 +37,19 @@ pub use ops::{Shl, Shr, Index}; pub use option::{Option, Some, None}; pub use result::{Result, Ok, Err}; -/* Reexported functions */ - +// Reexported functions pub use io::{print, println}; -/* Reexported types and traits */ - +// Reexported types and traits pub use clone::{Clone, DeepClone}; pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; pub use char::Char; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; -pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; -pub use old_iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter}; -pub use old_iter::{ExtendedMutableIter}; -pub use iter::Times; +pub use old_iter::{BaseIter, ReverseIter, ExtendedIter, EqIter}; +pub use old_iter::{CopyableIter, CopyableOrderedIter}; +pub use iter::{Times, FromIter}; +pub use iterator::{Iterator, IteratorUtil}; pub use num::{Num, NumCast}; pub use num::{Orderable, Signed, Unsigned, Round}; pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; @@ -46,9 +60,9 @@ pub use path::GenericPath; pub use path::Path; pub use path::PosixPath; pub use path::WindowsPath; -pub use ptr::Ptr; +pub use ptr::RawPtr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; -pub use str::{StrSlice, OwnedStr}; +pub use str::{Str, StrVector, StrSlice, OwnedStr, StrUtil, NullTerminatedStr}; pub use from_str::{FromStr}; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; @@ -59,53 +73,11 @@ pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12}; pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5}; pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9}; pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12}; -pub use vec::{CopyableVector, ImmutableVector}; +pub use vec::{VectorVector, CopyableVector, ImmutableVector}; pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector}; pub use io::{Reader, ReaderUtil, Writer, WriterUtil}; -/* Reexported runtime types */ +// Reexported runtime types pub use comm::{stream, Port, Chan, GenericChan, GenericSmartChan, GenericPort, Peekable}; pub use task::spawn; - -/* Reexported modules */ - -pub use at_vec; -pub use bool; -pub use cast; -pub use char; -pub use cmp; -pub use either; -pub use f32; -pub use f64; -pub use float; -pub use i16; -pub use i32; -pub use i64; -pub use i8; -pub use int; -pub use io; -pub use iter; -pub use old_iter; -pub use libc; -pub use local_data; -pub use num; -pub use ops; -pub use option; -pub use os; -pub use path; -pub use comm; -pub use unstable; -pub use ptr; -pub use rand; -pub use result; -pub use str; -pub use sys; -pub use task; -pub use to_str; -pub use u16; -pub use u32; -pub use u64; -pub use u8; -pub use uint; -pub use vec; diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 38d7095a366..cd5a3182f6b 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -11,30 +11,13 @@ //! Unsafe pointer utility functions use cast; -#[cfg(stage0)] use libc; -#[cfg(stage0)] use libc::{c_void, size_t}; use option::{Option, Some, None}; use sys; +use unstable::intrinsics; #[cfg(not(test))] use cmp::{Eq, Ord}; use uint; -#[cfg(stage0)] -pub mod libc_ { - use libc::c_void; - use libc; - - #[nolink] - #[abi = "cdecl"] - pub extern { - #[rust_stack] - unsafe fn memset(dest: *mut c_void, - c: libc::c_int, - len: libc::size_t) - -> *c_void; - } -} - /// Calculate the offset from a pointer #[inline(always)] pub fn offset<T>(ptr: *T, count: uint) -> *T { @@ -71,11 +54,11 @@ pub unsafe fn position<T>(buf: *T, f: &fn(&T) -> bool) -> uint { /// Create an unsafe null pointer #[inline(always)] -pub fn null<T>() -> *T { unsafe { cast::transmute(0u) } } +pub fn null<T>() -> *T { 0 as *T } /// Create an unsafe mutable null pointer #[inline(always)] -pub fn mut_null<T>() -> *mut T { unsafe { cast::transmute(0u) } } +pub fn mut_null<T>() -> *mut T { 0 as *mut T } /// Returns true if the pointer is equal to the null pointer. #[inline(always)] @@ -86,7 +69,7 @@ pub fn is_null<T>(ptr: *const T) -> bool { ptr == null() } pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) } /** - * Copies data from one location to another + * Copies data from one location to another. * * Copies `count` elements (not bytes) from `src` to `dst`. The source * and destination may overlap. @@ -100,7 +83,7 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { } /** - * Copies data from one location to another + * Copies data from one location to another. * * Copies `count` elements (not bytes) from `src` to `dst`. The source * and destination may overlap. @@ -112,6 +95,12 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { memmove32(dst, src as *T, count as u32); } +/** + * Copies data from one location to another. + * + * Copies `count` elements (not bytes) from `src` to `dst`. The source + * and destination may overlap. + */ #[inline(always)] #[cfg(target_word_size = "64", stage0)] pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { @@ -120,6 +109,12 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { memmove64(dst as *mut u8, src as *u8, n as u64); } +/** + * Copies data from one location to another. + * + * Copies `count` elements (not bytes) from `src` to `dst`. The source + * and destination may overlap. + */ #[inline(always)] #[cfg(target_word_size = "64", not(stage0))] pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { @@ -127,6 +122,12 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { memmove64(dst, src as *T, count as u64); } +/** + * Copies data from one location to another. + * + * Copies `count` elements (not bytes) from `src` to `dst`. The source + * and destination may *not* overlap. + */ #[inline(always)] #[cfg(target_word_size = "32", stage0)] pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) { @@ -135,6 +136,12 @@ pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: u memmove32(dst as *mut u8, src as *u8, n as u32); } +/** + * Copies data from one location to another. + * + * Copies `count` elements (not bytes) from `src` to `dst`. The source + * and destination may *not* overlap. + */ #[inline(always)] #[cfg(target_word_size = "32", not(stage0))] pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) { @@ -142,6 +149,12 @@ pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: u memcpy32(dst, src as *T, count as u32); } +/** + * Copies data from one location to another. + * + * Copies `count` elements (not bytes) from `src` to `dst`. The source + * and destination may *not* overlap. + */ #[inline(always)] #[cfg(target_word_size = "64", stage0)] pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) { @@ -150,6 +163,12 @@ pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: u memmove64(dst as *mut u8, src as *u8, n as u64); } +/** + * Copies data from one location to another. + * + * Copies `count` elements (not bytes) from `src` to `dst`. The source + * and destination may *not* overlap. + */ #[inline(always)] #[cfg(target_word_size = "64", not(stage0))] pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) { @@ -157,13 +176,10 @@ pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: u memcpy64(dst, src as *T, count as u64); } -#[inline(always)] -#[cfg(stage0)] -pub unsafe fn set_memory<T>(dst: *mut T, c: int, count: uint) { - let n = count * sys::size_of::<T>(); - libc_::memset(dst as *mut c_void, c as libc::c_int, n as size_t); -} - +/** + * Invokes memset on the specified pointer, setting `count * size_of::<T>()` + * bytes of memory starting at `dst` to `c`. + */ #[inline(always)] #[cfg(target_word_size = "32", not(stage0))] pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) { @@ -171,6 +187,10 @@ pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) { memset32(dst, c, count as u32); } +/** + * Invokes memset on the specified pointer, setting `count * size_of::<T>()` + * bytes of memory starting at `dst` to `c`. + */ #[inline(always)] #[cfg(target_word_size = "64", not(stage0))] pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) { @@ -179,53 +199,51 @@ pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) { } /** - Transform a region pointer - &T - to an unsafe pointer - *T. - This is safe, but is implemented with an unsafe block due to - transmute. -*/ -#[inline(always)] -pub fn to_unsafe_ptr<T>(thing: &T) -> *T { - unsafe { cast::transmute(thing) } + * Swap the values at two mutable locations of the same type, without + * deinitialising or copying either one. + */ +#[inline] +pub unsafe fn swap_ptr<T>(x: *mut T, y: *mut T) { + // Give ourselves some scratch space to work with + let mut tmp: T = intrinsics::uninit(); + let t: *mut T = &mut tmp; + + // Perform the swap + copy_memory(t, x, 1); + copy_memory(x, y, 1); + copy_memory(y, t, 1); + + // y and t now point to the same thing, but we need to completely forget `tmp` + // because it's no longer relevant. + cast::forget(tmp); } /** - Transform a const region pointer - &const T - to a const unsafe pointer - - *const T. This is safe, but is implemented with an unsafe block due to - transmute. -*/ + * Replace the value at a mutable location with a new one, returning the old + * value, without deinitialising or copying either one. + */ #[inline(always)] -pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T { - unsafe { cast::transmute(thing) } +pub unsafe fn replace_ptr<T>(dest: *mut T, mut src: T) -> T { + swap_ptr(dest, &mut src); + src } -/** - Transform a mutable region pointer - &mut T - to a mutable unsafe pointer - - *mut T. This is safe, but is implemented with an unsafe block due to - transmute. -*/ +/// Transform a region pointer - &T - to an unsafe pointer - *T. #[inline(always)] -pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T { - unsafe { cast::transmute(thing) } +pub fn to_unsafe_ptr<T>(thing: &T) -> *T { + thing as *T } -/** - Cast a region pointer - &T - to a uint. - This is safe, but is implemented with an unsafe block due to - transmute. - - (I couldn't think of a cutesy name for this one.) -*/ +/// Transform a const region pointer - &const T - to a const unsafe pointer - *const T. #[inline(always)] -pub fn to_uint<T>(thing: &T) -> uint { - unsafe { - cast::transmute(thing) - } +pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T { + thing as *const T } -/// Determine if two borrowed pointers point to the same thing. +/// Transform a mutable region pointer - &mut T - to a mutable unsafe pointer - *mut T. #[inline(always)] -pub fn ref_eq<'a,'b,T>(thing: &'a T, other: &'b T) -> bool { - to_uint(thing) == to_uint(other) +pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T { + thing as *mut T } /** @@ -268,7 +286,8 @@ pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) { array_each_with_len(arr, len, cb); } -pub trait Ptr<T> { +#[allow(missing_doc)] +pub trait RawPtr<T> { fn is_null(&const self) -> bool; fn is_not_null(&const self) -> bool; unsafe fn to_option(&const self) -> Option<&T>; @@ -276,7 +295,7 @@ pub trait Ptr<T> { } /// Extension methods for immutable pointers -impl<T> Ptr<T> for *T { +impl<T> RawPtr<T> for *T { /// Returns true if the pointer is equal to the null pointer. #[inline(always)] fn is_null(&const self) -> bool { is_null(*self) } @@ -308,7 +327,7 @@ impl<T> Ptr<T> for *T { } /// Extension methods for mutable pointers -impl<T> Ptr<T> for *mut T { +impl<T> RawPtr<T> for *mut T { /// Returns true if the pointer is equal to the null pointer. #[inline(always)] fn is_null(&const self) -> bool { is_null(*self) } @@ -344,14 +363,10 @@ impl<T> Ptr<T> for *mut T { impl<T> Eq for *const T { #[inline(always)] fn eq(&self, other: &*const T) -> bool { - unsafe { - let a: uint = cast::transmute(*self); - let b: uint = cast::transmute(*other); - return a == b; - } + (*self as uint) == (*other as uint) } #[inline(always)] - fn ne(&self, other: &*const T) -> bool { !(*self).eq(other) } + fn ne(&self, other: &*const T) -> bool { !self.eq(other) } } // Comparison for pointers @@ -359,69 +374,19 @@ impl<T> Eq for *const T { impl<T> Ord for *const T { #[inline(always)] fn lt(&self, other: &*const T) -> bool { - unsafe { - let a: uint = cast::transmute(*self); - let b: uint = cast::transmute(*other); - return a < b; - } + (*self as uint) < (*other as uint) } #[inline(always)] fn le(&self, other: &*const T) -> bool { - unsafe { - let a: uint = cast::transmute(*self); - let b: uint = cast::transmute(*other); - return a <= b; - } + (*self as uint) <= (*other as uint) } #[inline(always)] fn ge(&self, other: &*const T) -> bool { - unsafe { - let a: uint = cast::transmute(*self); - let b: uint = cast::transmute(*other); - return a >= b; - } + (*self as uint) >= (*other as uint) } #[inline(always)] fn gt(&self, other: &*const T) -> bool { - unsafe { - let a: uint = cast::transmute(*self); - let b: uint = cast::transmute(*other); - return a > b; - } - } -} - -// Equality for region pointers -#[cfg(not(test))] -impl<'self,T:Eq> Eq for &'self T { - #[inline(always)] - fn eq(&self, other: & &'self T) -> bool { - return *(*self) == *(*other); - } - #[inline(always)] - fn ne(&self, other: & &'self T) -> bool { - return *(*self) != *(*other); - } -} - -// Comparison for region pointers -#[cfg(not(test))] -impl<'self,T:Ord> Ord for &'self T { - #[inline(always)] - fn lt(&self, other: & &'self T) -> bool { - *(*self) < *(*other) - } - #[inline(always)] - fn le(&self, other: & &'self T) -> bool { - *(*self) <= *(*other) - } - #[inline(always)] - fn ge(&self, other: & &'self T) -> bool { - *(*self) >= *(*other) - } - #[inline(always)] - fn gt(&self, other: & &'self T) -> bool { - *(*self) > *(*other) + (*self as uint) > (*other as uint) } } @@ -430,6 +395,11 @@ pub mod ptr_tests { use super::*; use prelude::*; + use cast; + use libc; + use str; + use vec; + #[test] fn test() { unsafe { @@ -522,18 +492,19 @@ pub mod ptr_tests { #[test] fn test_to_option() { - let p: *int = null(); - // FIXME (#6641): Usage of unsafe methods in safe code doesn't cause an error. - assert_eq!(p.to_option(), None); + unsafe { + let p: *int = null(); + assert_eq!(p.to_option(), None); - let q: *int = &2; - assert_eq!(q.to_option().unwrap(), &2); // FIXME (#6641) + let q: *int = &2; + assert_eq!(q.to_option().unwrap(), &2); - let p: *mut int = mut_null(); - assert_eq!(p.to_option(), None); // FIXME (#6641) + let p: *mut int = mut_null(); + assert_eq!(p.to_option(), None); - let q: *mut int = &mut 2; - assert_eq!(q.to_option().unwrap(), &2); // FIXME (#6641) + let q: *mut int = &mut 2; + assert_eq!(q.to_option().unwrap(), &2); + } } #[test] @@ -621,6 +592,7 @@ pub mod ptr_tests { } #[test] + #[cfg(not(stage0))] fn test_set_memory() { let mut xs = [0u8, ..20]; let ptr = vec::raw::to_mut_ptr(xs); diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 2bcc9c8bba2..7946f7e4f13 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -25,7 +25,7 @@ distributions like normal and exponential. use core::rand::RngUtil; fn main() { - let rng = rand::rng(); + let mut rng = rand::rng(); if rng.gen() { // bool println(fmt!("int: %d, uint: %u", rng.gen(), rng.gen())) } @@ -40,10 +40,14 @@ fn main () { ~~~ */ - +use cast; +use cmp; use int; +use iterator::IteratorUtil; +use local_data; use prelude::*; use str; +use sys; use u32; use uint; use util; @@ -55,6 +59,8 @@ pub mod distributions; /// A type that can be randomly generated using an Rng pub trait Rand { + /// Generates a random instance of this type using the specified source of + /// randomness fn rand<R: Rng>(rng: &mut R) -> Self; } @@ -253,10 +259,13 @@ pub trait Rng { /// A value with a particular weight compared to other values pub struct Weighted<T> { + /// The numerical weight of this item weight: uint, + /// The actual item which is being weighted item: T, } +/// Helper functions attached to the Rng type pub trait RngUtil { /// Return a random value of a Rand type fn gen<T:Rand>(&mut self) -> T; @@ -471,7 +480,7 @@ impl<R: Rng> RngUtil for R { fn gen_char_from(&mut self, chars: &str) -> char { assert!(!chars.is_empty()); let mut cs = ~[]; - for str::each_char(chars) |c| { cs.push(c) } + for chars.iter().advance |c| { cs.push(c) } self.choose(cs) } @@ -604,9 +613,9 @@ pub struct IsaacRng { priv c: u32 } -pub impl IsaacRng { +impl IsaacRng { /// Create an ISAAC random number generator with a random seed. - fn new() -> IsaacRng { + pub fn new() -> IsaacRng { IsaacRng::new_seeded(seed()) } @@ -615,7 +624,7 @@ pub impl IsaacRng { /// will be silently ignored. A generator constructed with a given seed /// will generate the same sequence of values as all other generators /// constructed with the same seed. - fn new_seeded(seed: &[u8]) -> IsaacRng { + pub fn new_seeded(seed: &[u8]) -> IsaacRng { let mut rng = IsaacRng { cnt: 0, rsl: [0, .. RAND_SIZE], @@ -635,7 +644,7 @@ pub impl IsaacRng { /// Create an ISAAC random number generator using the default /// fixed seed. - fn new_unseeded() -> IsaacRng { + pub fn new_unseeded() -> IsaacRng { let mut rng = IsaacRng { cnt: 0, rsl: [0, .. RAND_SIZE], @@ -649,14 +658,15 @@ pub impl IsaacRng { /// Initialises `self`. If `use_rsl` is true, then use the current value /// of `rsl` as a seed, otherwise construct one algorithmically (not /// randomly). - priv fn init(&mut self, use_rsl: bool) { - macro_rules! init_mut_many ( - ($( $var:ident ),* = $val:expr ) => { - let mut $( $var = $val ),*; - } - ); - init_mut_many!(a, b, c, d, e, f, g, h = 0x9e3779b9); - + fn init(&mut self, use_rsl: bool) { + let mut a = 0x9e3779b9; + let mut b = a; + let mut c = a; + let mut d = a; + let mut e = a; + let mut f = a; + let mut g = a; + let mut h = a; macro_rules! mix( () => {{ @@ -707,12 +717,12 @@ pub impl IsaacRng { /// Refills the output buffer (`self.rsl`) #[inline] - priv fn isaac(&mut self) { + fn isaac(&mut self) { self.c += 1; // abbreviations - let mut a = self.a, b = self.b + self.c; + let mut (a, b) = (self.a, self.b + self.c); - static midpoint: uint = RAND_SIZE as uint / 2; + static midpoint: uint = RAND_SIZE as uint / 2; macro_rules! ind (($x:expr) => { self.mem[($x >> 2) & (RAND_SIZE - 1)] @@ -787,9 +797,9 @@ impl Rng for XorShiftRng { } } -pub impl XorShiftRng { +impl XorShiftRng { /// Create an xor shift random number generator with a default seed. - fn new() -> XorShiftRng { + pub fn new() -> XorShiftRng { // constants taken from http://en.wikipedia.org/wiki/Xorshift XorShiftRng::new_seeded(123456789u32, 362436069u32, @@ -799,10 +809,10 @@ pub impl XorShiftRng { /** * Create a random number generator using the specified seed. A generator - * constructed with a given seed will generate the same sequence of values as - * all other generators constructed with the same seed. + * constructed with a given seed will generate the same sequence of values + * as all other generators constructed with the same seed. */ - fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng { + pub fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng { XorShiftRng { x: x, y: y, diff --git a/src/libstd/rand/distributions.rs b/src/libstd/rand/distributions.rs index 72cff5111e7..f08d967cbe0 100644 --- a/src/libstd/rand/distributions.rs +++ b/src/libstd/rand/distributions.rs @@ -20,7 +20,7 @@ // Generating Random Variables"], but more robust. If one wanted, one // could implement VIZIGNOR the ZIGNOR paper for more speed. -use prelude::*; +use f64; use rand::{Rng,Rand}; mod ziggurat_tables; @@ -89,7 +89,7 @@ impl Rand for StandardNormal { // do-while, so the condition should be true on the first // run, they get overwritten anyway (0 < 1, so these are // good). - let mut x = 1.0, y = 0.0; + let mut (x, y) = (1.0, 0.0); // XXX infinities? while -2.0*y < x * x { diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs index 30f60dce041..1eb3d3a0daa 100644 --- a/src/libstd/reflect.rs +++ b/src/libstd/reflect.rs @@ -14,6 +14,8 @@ Runtime type reflection */ +#[allow(missing_doc)]; + use intrinsic::{TyDesc, TyVisitor}; use intrinsic::Opaque; use libc::c_void; @@ -46,28 +48,28 @@ pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> { MovePtrAdaptor { inner: v } } -pub impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> { +impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> { #[inline(always)] - fn bump(&self, sz: uint) { - do self.inner.move_ptr() |p| { + pub fn bump(&self, sz: uint) { + do self.inner.move_ptr() |p| { ((p as uint) + sz) as *c_void - }; + }; } #[inline(always)] - fn align(&self, a: uint) { - do self.inner.move_ptr() |p| { + pub fn align(&self, a: uint) { + do self.inner.move_ptr() |p| { align(p as uint, a) as *c_void - }; + }; } #[inline(always)] - fn align_to<T>(&self) { + pub fn align_to<T>(&self) { self.align(sys::min_align_of::<T>()); } #[inline(always)] - fn bump_past<T>(&self) { + pub fn bump_past<T>(&self) { self.bump(sys::size_of::<T>()); } } diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index a05009e375c..46f69d020d1 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -14,12 +14,15 @@ More runtime type reflection */ +#[allow(missing_doc)]; + use cast::transmute; use char; use intrinsic; use intrinsic::{TyDesc, TyVisitor, visit_tydesc}; use intrinsic::Opaque; use io::{Writer, WriterUtil}; +use iterator::IteratorUtil; use libc::c_void; use managed; use ptr; @@ -172,12 +175,11 @@ impl MovePtr for ReprVisitor { } } -pub impl ReprVisitor { - +impl ReprVisitor { // Various helpers for the TyVisitor impl #[inline(always)] - fn get<T>(&self, f: &fn(&T)) -> bool { + pub fn get<T>(&self, f: &fn(&T)) -> bool { unsafe { f(transmute::<*c_void,&T>(*self.ptr)); } @@ -185,12 +187,12 @@ pub impl ReprVisitor { } #[inline(always)] - fn visit_inner(&self, inner: *TyDesc) -> bool { + pub fn visit_inner(&self, inner: *TyDesc) -> bool { self.visit_ptr_inner(*self.ptr, inner) } #[inline(always)] - fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool { + pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool { unsafe { let u = ReprVisitor(ptr, self.writer); let v = reflect::MovePtrAdaptor(u); @@ -200,21 +202,21 @@ pub impl ReprVisitor { } #[inline(always)] - fn write<T:Repr>(&self) -> bool { + pub fn write<T:Repr>(&self) -> bool { do self.get |v:&T| { v.write_repr(self.writer); } } - fn write_escaped_slice(&self, slice: &str) { + pub fn write_escaped_slice(&self, slice: &str) { self.writer.write_char('"'); - for slice.each_char |ch| { + for slice.iter().advance |ch| { self.writer.write_escaped_char(ch); } self.writer.write_char('"'); } - fn write_mut_qualifier(&self, mtbl: uint) { + pub fn write_mut_qualifier(&self, mtbl: uint) { if mtbl == 0 { self.writer.write_str("mut "); } else if mtbl == 1 { @@ -225,8 +227,12 @@ pub impl ReprVisitor { } } - fn write_vec_range(&self, mtbl: uint, ptr: *u8, len: uint, - inner: *TyDesc) -> bool { + pub fn write_vec_range(&self, + mtbl: uint, + ptr: *u8, + len: uint, + inner: *TyDesc) + -> bool { let mut p = ptr; let end = ptr::offset(p, len); let (sz, al) = unsafe { ((*inner).size, (*inner).align) }; @@ -246,13 +252,14 @@ pub impl ReprVisitor { true } - fn write_unboxed_vec_repr(&self, mtbl: uint, v: &UnboxedVecRepr, - inner: *TyDesc) -> bool { + pub fn write_unboxed_vec_repr(&self, + mtbl: uint, + v: &UnboxedVecRepr, + inner: *TyDesc) + -> bool { self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data), v.fill, inner) } - - } impl TyVisitor for ReprVisitor { diff --git a/src/libstd/result.rs b/src/libstd/result.rs index cda2fe13e37..24751b66925 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -10,7 +10,7 @@ //! A type representing either success or failure -// NB: transitionary, de-mode-ing. +#[allow(missing_doc)]; use cmp::Eq; use either; @@ -20,6 +20,7 @@ use option::{None, Option, Some}; use old_iter::BaseIter; use vec; use vec::OwnedVector; +use container::Container; /// The result type #[deriving(Clone, Eq)] @@ -40,7 +41,7 @@ pub enum Result<T, U> { #[inline(always)] pub fn get<T:Copy,U>(res: &Result<T, U>) -> T { match *res { - Ok(copy t) => t, + Ok(ref t) => copy *t, Err(ref the_err) => fail!("get called on error result: %?", *the_err) } @@ -72,7 +73,7 @@ pub fn get_ref<'a, T, U>(res: &'a Result<T, U>) -> &'a T { #[inline(always)] pub fn get_err<T, U: Copy>(res: &Result<T, U>) -> U { match *res { - Err(copy u) => u, + Err(ref u) => copy *u, Ok(_) => fail!("get_err called on ok result") } } @@ -102,8 +103,8 @@ pub fn is_err<T, U>(res: &Result<T, U>) -> bool { pub fn to_either<T:Copy,U:Copy>(res: &Result<U, T>) -> Either<T, U> { match *res { - Ok(copy res) => either::Right(res), - Err(copy fail_) => either::Left(fail_) + Ok(ref res) => either::Right(copy *res), + Err(ref fail_) => either::Left(copy *fail_) } } @@ -206,7 +207,7 @@ pub fn map<T, E: Copy, U: Copy>(res: &Result<T, E>, op: &fn(&T) -> U) -> Result<U, E> { match *res { Ok(ref t) => Ok(op(t)), - Err(copy e) => Err(e) + Err(ref e) => Err(copy *e) } } @@ -222,60 +223,60 @@ pub fn map<T, E: Copy, U: Copy>(res: &Result<T, E>, op: &fn(&T) -> U) pub fn map_err<T:Copy,E,F:Copy>(res: &Result<T, E>, op: &fn(&E) -> F) -> Result<T, F> { match *res { - Ok(copy t) => Ok(t), + Ok(ref t) => Ok(copy *t), Err(ref e) => Err(op(e)) } } -pub impl<T, E> Result<T, E> { +impl<T, E> Result<T, E> { #[inline(always)] - fn get_ref<'a>(&'a self) -> &'a T { get_ref(self) } + pub fn get_ref<'a>(&'a self) -> &'a T { get_ref(self) } #[inline(always)] - fn is_ok(&self) -> bool { is_ok(self) } + pub fn is_ok(&self) -> bool { is_ok(self) } #[inline(always)] - fn is_err(&self) -> bool { is_err(self) } + pub fn is_err(&self) -> bool { is_err(self) } #[inline(always)] - fn iter(&self, f: &fn(&T)) { iter(self, f) } + pub fn iter(&self, f: &fn(&T)) { iter(self, f) } #[inline(always)] - fn iter_err(&self, f: &fn(&E)) { iter_err(self, f) } + pub fn iter_err(&self, f: &fn(&E)) { iter_err(self, f) } #[inline(always)] - fn unwrap(self) -> T { unwrap(self) } + pub fn unwrap(self) -> T { unwrap(self) } #[inline(always)] - fn unwrap_err(self) -> E { unwrap_err(self) } + pub fn unwrap_err(self) -> E { unwrap_err(self) } #[inline(always)] - fn chain<U>(self, op: &fn(T) -> Result<U,E>) -> Result<U,E> { + pub fn chain<U>(self, op: &fn(T) -> Result<U,E>) -> Result<U,E> { chain(self, op) } #[inline(always)] - fn chain_err<F>(self, op: &fn(E) -> Result<T,F>) -> Result<T,F> { + pub fn chain_err<F>(self, op: &fn(E) -> Result<T,F>) -> Result<T,F> { chain_err(self, op) } } -pub impl<T:Copy,E> Result<T, E> { +impl<T:Copy,E> Result<T, E> { #[inline(always)] - fn get(&self) -> T { get(self) } + pub fn get(&self) -> T { get(self) } #[inline(always)] - fn map_err<F:Copy>(&self, op: &fn(&E) -> F) -> Result<T,F> { + pub fn map_err<F:Copy>(&self, op: &fn(&E) -> F) -> Result<T,F> { map_err(self, op) } } -pub impl<T, E: Copy> Result<T, E> { +impl<T, E: Copy> Result<T, E> { #[inline(always)] - fn get_err(&self) -> E { get_err(self) } + pub fn get_err(&self) -> E { get_err(self) } #[inline(always)] - fn map<U:Copy>(&self, op: &fn(&T) -> U) -> Result<U,E> { + pub fn map<U:Copy>(&self, op: &fn(&T) -> U) -> Result<U,E> { map(self, op) } } @@ -301,25 +302,26 @@ pub impl<T, E: Copy> Result<T, E> { pub fn map_vec<T,U:Copy,V:Copy>( ts: &[T], op: &fn(&T) -> Result<V,U>) -> Result<~[V],U> { - let mut vs: ~[V] = vec::with_capacity(vec::len(ts)); + let mut vs: ~[V] = vec::with_capacity(ts.len()); for ts.each |t| { match op(t) { - Ok(copy v) => vs.push(v), - Err(copy u) => return Err(u) + Ok(v) => vs.push(v), + Err(u) => return Err(u) } } return Ok(vs); } #[inline(always)] +#[allow(missing_doc)] pub fn map_opt<T,U:Copy,V:Copy>( 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(copy v) => Ok(Some(v)), - Err(copy e) => Err(e) + Ok(v) => Ok(Some(v)), + Err(e) => Err(e) } } } @@ -338,13 +340,13 @@ pub fn map_vec2<S,T,U:Copy,V:Copy>(ss: &[S], ts: &[T], op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> { assert!(vec::same_length(ss, ts)); - let n = vec::len(ts); + let n = ts.len(); let mut vs = vec::with_capacity(n); let mut i = 0u; while i < n { match op(&ss[i],&ts[i]) { - Ok(copy v) => vs.push(v), - Err(copy u) => return Err(u) + Ok(v) => vs.push(v), + Err(u) => return Err(u) } i += 1u; } @@ -361,12 +363,12 @@ pub fn iter_vec2<S,T,U:Copy>(ss: &[S], ts: &[T], op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> { assert!(vec::same_length(ss, ts)); - let n = vec::len(ts); + let n = ts.len(); let mut i = 0u; while i < n { match op(&ss[i],&ts[i]) { Ok(()) => (), - Err(copy u) => return Err(u) + Err(u) => return Err(u) } i += 1u; } diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs index b00df78f433..82e6d44fe62 100644 --- a/src/libstd/rt/comm.rs +++ b/src/libstd/rt/comm.rs @@ -120,13 +120,13 @@ impl<T> ChanOne<T> { match oldstate { STATE_BOTH => { // Port is not waiting yet. Nothing to do - do Local::borrow::<Scheduler> |sched| { + do Local::borrow::<Scheduler, ()> |sched| { rtdebug!("non-rendezvous send"); sched.metrics.non_rendezvous_sends += 1; } } STATE_ONE => { - do Local::borrow::<Scheduler> |sched| { + do Local::borrow::<Scheduler, ()> |sched| { rtdebug!("rendezvous send"); sched.metrics.rendezvous_sends += 1; } @@ -331,8 +331,8 @@ pub struct Port<T> { pub fn stream<T: Owned>() -> (Port<T>, Chan<T>) { let (pone, cone) = oneshot(); - let port = Port { next: Cell(pone) }; - let chan = Chan { next: Cell(cone) }; + let port = Port { next: Cell::new(pone) }; + let chan = Chan { next: Cell::new(cone) }; return (port, chan); } @@ -647,7 +647,7 @@ mod test { fn oneshot_multi_task_recv_then_send() { do run_in_newsched_task { let (port, chan) = oneshot::<~int>(); - let port_cell = Cell(port); + let port_cell = Cell::new(port); do spawntask_immediately { assert!(port_cell.take().recv() == ~10); } @@ -660,8 +660,8 @@ mod test { fn oneshot_multi_task_recv_then_close() { do run_in_newsched_task { let (port, chan) = oneshot::<~int>(); - let port_cell = Cell(port); - let chan_cell = Cell(chan); + let port_cell = Cell::new(port); + let chan_cell = Cell::new(chan); do spawntask_later { let _cell = chan_cell.take(); } @@ -677,7 +677,7 @@ mod test { for stress_factor().times { do run_in_newsched_task { let (port, chan) = oneshot::<int>(); - let port_cell = Cell(port); + let port_cell = Cell::new(port); let _thread = do spawntask_thread { let _p = port_cell.take(); }; @@ -691,8 +691,8 @@ mod test { for stress_factor().times { do run_in_newsched_task { let (port, chan) = oneshot::<int>(); - let chan_cell = Cell(chan); - let port_cell = Cell(port); + let chan_cell = Cell::new(chan); + let port_cell = Cell::new(port); let _thread1 = do spawntask_thread { let _p = port_cell.take(); }; @@ -709,17 +709,17 @@ mod test { for stress_factor().times { do run_in_newsched_task { let (port, chan) = oneshot::<int>(); - let chan_cell = Cell(chan); - let port_cell = Cell(port); + let chan_cell = Cell::new(chan); + let port_cell = Cell::new(port); let _thread1 = do spawntask_thread { - let port_cell = Cell(port_cell.take()); + let port_cell = Cell::new(port_cell.take()); let res = do spawntask_try { port_cell.take().recv(); }; assert!(res.is_err()); }; let _thread2 = do spawntask_thread { - let chan_cell = Cell(chan_cell.take()); + let chan_cell = Cell::new(chan_cell.take()); do spawntask { chan_cell.take(); } @@ -733,8 +733,8 @@ mod test { for stress_factor().times { do run_in_newsched_task { let (port, chan) = oneshot::<~int>(); - let chan_cell = Cell(chan); - let port_cell = Cell(port); + let chan_cell = Cell::new(chan); + let port_cell = Cell::new(port); let _thread1 = do spawntask_thread { chan_cell.take().send(~10); }; @@ -757,7 +757,7 @@ mod test { fn send(chan: Chan<~int>, i: int) { if i == 10 { return } - let chan_cell = Cell(chan); + let chan_cell = Cell::new(chan); do spawntask_random { let chan = chan_cell.take(); chan.send(~i); @@ -768,7 +768,7 @@ mod test { fn recv(port: Port<~int>, i: int) { if i == 10 { return } - let port_cell = Cell(port); + let port_cell = Cell::new(port); do spawntask_random { let port = port_cell.take(); assert!(port.recv() == ~i); @@ -918,4 +918,3 @@ mod test { } } } - diff --git a/src/libstd/rt/context.rs b/src/libstd/rt/context.rs index 0d011ce42ba..d5ca8473cee 100644 --- a/src/libstd/rt/context.rs +++ b/src/libstd/rt/context.rs @@ -27,8 +27,8 @@ pub struct Context { regs: ~Registers } -pub impl Context { - fn empty() -> Context { +impl Context { + pub fn empty() -> Context { Context { start: None, regs: new_regs() @@ -36,7 +36,7 @@ pub impl Context { } /// Create a new context that will resume execution by running ~fn() - fn new(start: ~fn(), stack: &mut StackSegment) -> Context { + pub fn new(start: ~fn(), stack: &mut StackSegment) -> Context { // XXX: Putting main into a ~ so it's a thin pointer and can // be passed to the spawn function. Another unfortunate // allocation @@ -71,7 +71,7 @@ pub impl Context { saving the registers values of the executing thread to a Context then loading the registers from a previously saved Context. */ - fn swap(out_context: &mut Context, in_context: &Context) { + pub fn swap(out_context: &mut Context, in_context: &Context) { let out_regs: &mut Registers = match out_context { &Context { regs: ~ref mut r, _ } => r }; diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs index ad9658e48ba..c7c3eadbe21 100644 --- a/src/libstd/rt/io/extensions.rs +++ b/src/libstd/rt/io/extensions.rs @@ -342,7 +342,7 @@ impl<T: Reader> ReaderByteConversions for T { fn read_le_uint_n(&mut self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut val = 0u64, pos = 0, i = nbytes; + let mut (val, pos, i) = (0u64, 0, nbytes); while i > 0 { val += (self.read_u8() as u64) << pos; pos += 8; @@ -358,7 +358,7 @@ impl<T: Reader> ReaderByteConversions for T { fn read_be_uint_n(&mut self, nbytes: uint) -> u64 { assert!(nbytes > 0 && nbytes <= 8); - let mut val = 0u64, i = nbytes; + let mut (val, i) = (0u64, nbytes); while i > 0 { i -= 1; val += (self.read_u8() as u64) << i * 8; @@ -604,7 +604,7 @@ mod test { #[test] fn read_byte_0_bytes() { let mut reader = MockReader::new(); - let count = Cell(0); + let count = Cell::new(0); reader.read = |buf| { do count.with_mut_ref |count| { if *count == 0 { @@ -652,7 +652,7 @@ mod test { #[test] fn read_bytes_partial() { let mut reader = MockReader::new(); - let count = Cell(0); + let count = Cell::new(0); reader.read = |buf| { do count.with_mut_ref |count| { if *count == 0 { @@ -691,7 +691,7 @@ mod test { #[test] fn push_bytes_partial() { let mut reader = MockReader::new(); - let count = Cell(0); + let count = Cell::new(0); reader.read = |buf| { do count.with_mut_ref |count| { if *count == 0 { @@ -725,7 +725,7 @@ mod test { #[test] fn push_bytes_error() { let mut reader = MockReader::new(); - let count = Cell(0); + let count = Cell::new(0); reader.read = |buf| { do count.with_mut_ref |count| { if *count == 0 { @@ -752,7 +752,7 @@ mod test { // push_bytes unsafely sets the vector length. This is testing that // upon failure the length is reset correctly. let mut reader = MockReader::new(); - let count = Cell(0); + let count = Cell::new(0); reader.read = |buf| { do count.with_mut_ref |count| { if *count == 0 { @@ -778,7 +778,7 @@ mod test { #[test] fn read_to_end() { let mut reader = MockReader::new(); - let count = Cell(0); + let count = Cell::new(0); reader.read = |buf| { do count.with_mut_ref |count| { if *count == 0 { @@ -805,7 +805,7 @@ mod test { #[ignore(cfg(windows))] fn read_to_end_error() { let mut reader = MockReader::new(); - let count = Cell(0); + let count = Cell::new(0); reader.read = |buf| { do count.with_mut_ref |count| { if *count == 0 { diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 1f61cf25fbd..a99f5da032c 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -75,5 +75,5 @@ fn super_simple_smoke_test_lets_go_read_some_files_and_have_a_good_time() { let message = "it's alright. have a good time"; let filename = &Path("test.txt"); let mut outstream = FileStream::open(filename, Create, Read).unwrap(); - outstream.write(message.to_bytes()); + outstream.write(message.as_bytes()); } diff --git a/src/libstd/rt/io/flate.rs b/src/libstd/rt/io/flate.rs index db2683dc85d..e57b80658ee 100644 --- a/src/libstd/rt/io/flate.rs +++ b/src/libstd/rt/io/flate.rs @@ -100,13 +100,15 @@ mod test { use super::super::mem::*; use super::super::Decorator; + use str; + #[test] #[ignore] fn smoke_test() { let mem_writer = MemWriter::new(); let mut deflate_writer = DeflateWriter::new(mem_writer); let in_msg = "test"; - let in_bytes = in_msg.to_bytes(); + let in_bytes = in_msg.as_bytes(); deflate_writer.write(in_bytes); deflate_writer.flush(); let buf = deflate_writer.inner().inner(); diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs index b2701c1fdc3..bd9cff76e57 100644 --- a/src/libstd/rt/io/mem.rs +++ b/src/libstd/rt/io/mem.rs @@ -15,9 +15,10 @@ //! * Should probably have something like this for strings. //! * Should they implement Closable? Would take extra state. +use cmp::min; use prelude::*; use super::*; -use cmp::min; +use vec; /// Writes to an owned, growable byte vector pub struct MemWriter { diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index f7c03c13a58..3607f781da3 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -287,7 +287,7 @@ mod test { do spawntask_immediately { let mut listener = TcpListener::bind(addr); for int::range(0, MAX) |i| { - let stream = Cell(listener.accept()); + let stream = Cell::new(listener.accept()); rtdebug!("accepted"); // Start another task to handle the connection do spawntask_immediately { @@ -326,7 +326,7 @@ mod test { do spawntask_immediately { let mut listener = TcpListener::bind(addr); for int::range(0, MAX) |_| { - let stream = Cell(listener.accept()); + let stream = Cell::new(listener.accept()); rtdebug!("accepted"); // Start another task to handle the connection do spawntask_later { diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index 247fe954408..57bec79563f 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -50,4 +50,3 @@ impl Writer for StdWriter { fn flush(&mut self) { fail!() } } - diff --git a/src/libstd/rt/join_latch.rs b/src/libstd/rt/join_latch.rs new file mode 100644 index 00000000000..ad5cf2eb378 --- /dev/null +++ b/src/libstd/rt/join_latch.rs @@ -0,0 +1,645 @@ +// 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. + +//! The JoinLatch is a concurrent type that establishes the task +//! tree and propagates failure. +//! +//! Each task gets a JoinLatch that is derived from the JoinLatch +//! of its parent task. Every latch must be released by either calling +//! the non-blocking `release` method or the task-blocking `wait` method. +//! Releasing a latch does not complete until all of its child latches +//! complete. +//! +//! Latches carry a `success` flag that is set to `false` during task +//! failure and is propagated both from children to parents and parents +//! to children. The status af this flag may be queried for the purposes +//! of linked failure. +//! +//! In addition to failure propagation the task tree serves to keep the +//! default task schedulers alive. The runtime only sends the shutdown +//! message to schedulers once the root task exits. +//! +//! Under this scheme tasks that terminate before their children become +//! 'zombies' since they may not exit until their children do. Zombie +//! tasks are 'tombstoned' as `Tombstone(~JoinLatch)` and the tasks +//! themselves allowed to terminate. +//! +//! XXX: Propagate flag from parents to children. +//! XXX: Tombstoning actually doesn't work. +//! XXX: This could probably be done in a way that doesn't leak tombstones +//! longer than the life of the child tasks. + +use comm::{GenericPort, Peekable, GenericSmartChan}; +use clone::Clone; +use container::Container; +use option::{Option, Some, None}; +use ops::Drop; +use rt::comm::{SharedChan, Port, stream}; +use rt::local::Local; +use rt::sched::Scheduler; +use unstable::atomics::{AtomicUint, SeqCst}; +use util; +use vec::OwnedVector; + +// FIXME #7026: Would prefer this to be an enum +pub struct JoinLatch { + priv parent: Option<ParentLink>, + priv child: Option<ChildLink>, + closed: bool, +} + +// Shared between parents and all their children. +struct SharedState { + /// Reference count, held by a parent and all children. + count: AtomicUint, + success: bool +} + +struct ParentLink { + shared: *mut SharedState, + // For communicating with the parent. + chan: SharedChan<Message> +} + +struct ChildLink { + shared: ~SharedState, + // For receiving from children. + port: Port<Message>, + chan: SharedChan<Message>, + // Prevents dropping the child SharedState reference counts multiple times. + dropped_child: bool +} + +// Messages from child latches to parent. +enum Message { + Tombstone(~JoinLatch), + ChildrenTerminated +} + +impl JoinLatch { + pub fn new_root() -> ~JoinLatch { + let this = ~JoinLatch { + parent: None, + child: None, + closed: false + }; + rtdebug!("new root latch %x", this.id()); + return this; + } + + fn id(&self) -> uint { + unsafe { ::cast::transmute(&*self) } + } + + pub fn new_child(&mut self) -> ~JoinLatch { + rtassert!(!self.closed); + + if self.child.is_none() { + // This is the first time spawning a child + let shared = ~SharedState { + count: AtomicUint::new(1), + success: true + }; + let (port, chan) = stream(); + let chan = SharedChan::new(chan); + let child = ChildLink { + shared: shared, + port: port, + chan: chan, + dropped_child: false + }; + self.child = Some(child); + } + + let child_link: &mut ChildLink = self.child.get_mut_ref(); + let shared_state: *mut SharedState = &mut *child_link.shared; + + child_link.shared.count.fetch_add(1, SeqCst); + + let child = ~JoinLatch { + parent: Some(ParentLink { + shared: shared_state, + chan: child_link.chan.clone() + }), + child: None, + closed: false + }; + rtdebug!("NEW child latch %x", child.id()); + return child; + } + + pub fn release(~self, local_success: bool) { + // XXX: This should not block, but there's a bug in the below + // code that I can't figure out. + self.wait(local_success); + } + + // XXX: Should not require ~self + fn release_broken(~self, local_success: bool) { + rtassert!(!self.closed); + + rtdebug!("releasing %x", self.id()); + + let id = self.id(); + let _ = id; // XXX: `id` is only used in debug statements so appears unused + let mut this = self; + let mut child_success = true; + let mut children_done = false; + + if this.child.is_some() { + rtdebug!("releasing children"); + let child_link: &mut ChildLink = this.child.get_mut_ref(); + let shared: &mut SharedState = &mut *child_link.shared; + + if !child_link.dropped_child { + let last_count = shared.count.fetch_sub(1, SeqCst); + rtdebug!("child count before sub %u %x", last_count, id); + if last_count == 1 { + assert!(child_link.chan.try_send(ChildrenTerminated)); + } + child_link.dropped_child = true; + } + + // Wait for messages from children + let mut tombstones = ~[]; + loop { + if child_link.port.peek() { + match child_link.port.recv() { + Tombstone(t) => { + tombstones.push(t); + }, + ChildrenTerminated => { + children_done = true; + break; + } + } + } else { + break + } + } + + rtdebug!("releasing %u tombstones %x", tombstones.len(), id); + + // Try to release the tombstones. Those that still have + // outstanding will be re-enqueued. When this task's + // parents release their latch we'll end up back here + // trying them again. + while !tombstones.is_empty() { + tombstones.pop().release(true); + } + + if children_done { + let count = shared.count.load(SeqCst); + assert!(count == 0); + // self_count is the acquire-read barrier + child_success = shared.success; + } + } else { + children_done = true; + } + + let total_success = local_success && child_success; + + rtassert!(this.parent.is_some()); + + unsafe { + { + let parent_link: &mut ParentLink = this.parent.get_mut_ref(); + let shared: *mut SharedState = parent_link.shared; + + if !total_success { + // parent_count is the write-wait barrier + (*shared).success = false; + } + } + + if children_done { + rtdebug!("children done"); + do Local::borrow::<Scheduler, ()> |sched| { + sched.metrics.release_tombstone += 1; + } + { + rtdebug!("RELEASING parent %x", id); + let parent_link: &mut ParentLink = this.parent.get_mut_ref(); + let shared: *mut SharedState = parent_link.shared; + let last_count = (*shared).count.fetch_sub(1, SeqCst); + rtdebug!("count before parent sub %u %x", last_count, id); + if last_count == 1 { + assert!(parent_link.chan.try_send(ChildrenTerminated)); + } + } + this.closed = true; + util::ignore(this); + } else { + rtdebug!("children not done"); + rtdebug!("TOMBSTONING %x", id); + do Local::borrow::<Scheduler, ()> |sched| { + sched.metrics.release_no_tombstone += 1; + } + let chan = { + let parent_link: &mut ParentLink = this.parent.get_mut_ref(); + parent_link.chan.clone() + }; + assert!(chan.try_send(Tombstone(this))); + } + } + } + + // XXX: Should not require ~self + pub fn wait(~self, local_success: bool) -> bool { + rtassert!(!self.closed); + + rtdebug!("WAITING %x", self.id()); + + let mut this = self; + let mut child_success = true; + + if this.child.is_some() { + rtdebug!("waiting for children"); + let child_link: &mut ChildLink = this.child.get_mut_ref(); + let shared: &mut SharedState = &mut *child_link.shared; + + if !child_link.dropped_child { + let last_count = shared.count.fetch_sub(1, SeqCst); + rtdebug!("child count before sub %u", last_count); + if last_count == 1 { + assert!(child_link.chan.try_send(ChildrenTerminated)); + } + child_link.dropped_child = true; + } + + // Wait for messages from children + loop { + match child_link.port.recv() { + Tombstone(t) => { + t.wait(true); + } + ChildrenTerminated => break + } + } + + let count = shared.count.load(SeqCst); + if count != 0 { ::io::println(fmt!("%u", count)); } + assert!(count == 0); + // self_count is the acquire-read barrier + child_success = shared.success; + } + + let total_success = local_success && child_success; + + if this.parent.is_some() { + rtdebug!("releasing parent"); + unsafe { + let parent_link: &mut ParentLink = this.parent.get_mut_ref(); + let shared: *mut SharedState = parent_link.shared; + + if !total_success { + // parent_count is the write-wait barrier + (*shared).success = false; + } + + let last_count = (*shared).count.fetch_sub(1, SeqCst); + rtdebug!("count before parent sub %u", last_count); + if last_count == 1 { + assert!(parent_link.chan.try_send(ChildrenTerminated)); + } + } + } + + this.closed = true; + util::ignore(this); + + return total_success; + } +} + +impl Drop for JoinLatch { + fn finalize(&self) { + rtdebug!("DESTROYING %x", self.id()); + rtassert!(self.closed); + } +} + +#[cfg(test)] +mod test { + use super::*; + use cell::Cell; + use container::Container; + use iter::Times; + use old_iter::BaseIter; + use rt::test::*; + use rand; + use rand::RngUtil; + use vec::{CopyableVector, ImmutableVector}; + + #[test] + fn success_immediately() { + do run_in_newsched_task { + let mut latch = JoinLatch::new_root(); + + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_immediately { + let child_latch = child_latch.take(); + assert!(child_latch.wait(true)); + } + + assert!(latch.wait(true)); + } + } + + #[test] + fn success_later() { + do run_in_newsched_task { + let mut latch = JoinLatch::new_root(); + + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_later { + let child_latch = child_latch.take(); + assert!(child_latch.wait(true)); + } + + assert!(latch.wait(true)); + } + } + + #[test] + fn mt_success() { + do run_in_mt_newsched_task { + let mut latch = JoinLatch::new_root(); + + for 10.times { + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_random { + let child_latch = child_latch.take(); + assert!(child_latch.wait(true)); + } + } + + assert!(latch.wait(true)); + } + } + + #[test] + fn mt_failure() { + do run_in_mt_newsched_task { + let mut latch = JoinLatch::new_root(); + + let spawn = |status| { + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_random { + let child_latch = child_latch.take(); + child_latch.wait(status); + } + }; + + for 10.times { spawn(true) } + spawn(false); + for 10.times { spawn(true) } + + assert!(!latch.wait(true)); + } + } + + #[test] + fn mt_multi_level_success() { + do run_in_mt_newsched_task { + let mut latch = JoinLatch::new_root(); + + fn child(latch: &mut JoinLatch, i: int) { + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_random { + let mut child_latch = child_latch.take(); + if i != 0 { + child(&mut *child_latch, i - 1); + child_latch.wait(true); + } else { + child_latch.wait(true); + } + } + } + + child(&mut *latch, 10); + + assert!(latch.wait(true)); + } + } + + #[test] + fn mt_multi_level_failure() { + do run_in_mt_newsched_task { + let mut latch = JoinLatch::new_root(); + + fn child(latch: &mut JoinLatch, i: int) { + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_random { + let mut child_latch = child_latch.take(); + if i != 0 { + child(&mut *child_latch, i - 1); + child_latch.wait(false); + } else { + child_latch.wait(true); + } + } + } + + child(&mut *latch, 10); + + assert!(!latch.wait(true)); + } + } + + #[test] + fn release_child() { + do run_in_newsched_task { + let mut latch = JoinLatch::new_root(); + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + + do spawntask_immediately { + let latch = child_latch.take(); + latch.release(false); + } + + assert!(!latch.wait(true)); + } + } + + #[test] + fn release_child_tombstone() { + do run_in_newsched_task { + let mut latch = JoinLatch::new_root(); + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + + do spawntask_immediately { + let mut latch = child_latch.take(); + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_later { + let latch = child_latch.take(); + latch.release(false); + } + latch.release(true); + } + + assert!(!latch.wait(true)); + } + } + + #[test] + fn release_child_no_tombstone() { + do run_in_newsched_task { + let mut latch = JoinLatch::new_root(); + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + + do spawntask_later { + let mut latch = child_latch.take(); + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + do spawntask_immediately { + let latch = child_latch.take(); + latch.release(false); + } + latch.release(true); + } + + assert!(!latch.wait(true)); + } + } + + #[test] + fn release_child_tombstone_stress() { + fn rand_orders() -> ~[bool] { + let mut v = ~[false,.. 5]; + v[0] = true; + let mut rng = rand::rng(); + return rng.shuffle(v); + } + + fn split_orders(orders: &[bool]) -> (~[bool], ~[bool]) { + if orders.is_empty() { + return (~[], ~[]); + } else if orders.len() <= 2 { + return (orders.to_owned(), ~[]); + } + let mut rng = rand::rng(); + let n = rng.gen_uint_range(1, orders.len()); + let first = orders.slice(0, n).to_owned(); + let last = orders.slice(n, orders.len()).to_owned(); + assert!(first.len() + last.len() == orders.len()); + return (first, last); + } + + for stress_factor().times { + do run_in_newsched_task { + fn doit(latch: &mut JoinLatch, orders: ~[bool], depth: uint) { + let (my_orders, remaining_orders) = split_orders(orders); + rtdebug!("(my_orders, remaining): %?", (&my_orders, &remaining_orders)); + rtdebug!("depth: %u", depth); + let mut remaining_orders = remaining_orders; + let mut num = 0; + for my_orders.each |&order| { + let child_latch = latch.new_child(); + let child_latch = Cell::new(child_latch); + let (child_orders, remaining) = split_orders(remaining_orders); + rtdebug!("(child_orders, remaining): %?", (&child_orders, &remaining)); + remaining_orders = remaining; + let child_orders = Cell::new(child_orders); + let child_num = num; + let _ = child_num; // XXX unused except in rtdebug! + do spawntask_random { + rtdebug!("depth %u num %u", depth, child_num); + let mut child_latch = child_latch.take(); + let child_orders = child_orders.take(); + doit(&mut *child_latch, child_orders, depth + 1); + child_latch.release(order); + } + + num += 1; + } + } + + let mut latch = JoinLatch::new_root(); + let orders = rand_orders(); + rtdebug!("orders: %?", orders); + + doit(&mut *latch, orders, 0); + + assert!(!latch.wait(true)); + } + } + } + + #[test] + fn whateverman() { + struct Order { + immediate: bool, + succeed: bool, + orders: ~[Order] + } + fn next(latch: &mut JoinLatch, orders: ~[Order]) { + for orders.each |order| { + let suborders = copy order.orders; + let child_latch = Cell::new(latch.new_child()); + let succeed = order.succeed; + if order.immediate { + do spawntask_immediately { + let mut child_latch = child_latch.take(); + next(&mut *child_latch, copy suborders); + rtdebug!("immediate releasing"); + child_latch.release(succeed); + } + } else { + do spawntask_later { + let mut child_latch = child_latch.take(); + next(&mut *child_latch, copy suborders); + rtdebug!("later releasing"); + child_latch.release(succeed); + } + } + } + } + + do run_in_newsched_task { + let mut latch = JoinLatch::new_root(); + let orders = ~[ Order { // 0 0 + immediate: true, + succeed: true, + orders: ~[ Order { // 1 0 + immediate: true, + succeed: false, + orders: ~[ Order { // 2 0 + immediate: false, + succeed: false, + orders: ~[ Order { // 3 0 + immediate: true, + succeed: false, + orders: ~[] + }, Order { // 3 1 + immediate: false, + succeed: false, + orders: ~[] + }] + }] + }] + }]; + + next(&mut *latch, orders); + assert!(!latch.wait(true)); + } + } +} diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index e6988c53888..6e0fbda5ec9 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -18,7 +18,7 @@ pub trait Local { fn put(value: ~Self); fn take() -> ~Self; fn exists() -> bool; - fn borrow(f: &fn(&mut Self)); + fn borrow<T>(f: &fn(&mut Self) -> T) -> T; unsafe fn unsafe_borrow() -> *mut Self; unsafe fn try_unsafe_borrow() -> Option<*mut Self>; } @@ -27,7 +27,20 @@ impl Local for Scheduler { fn put(value: ~Scheduler) { unsafe { local_ptr::put(value) }} fn take() -> ~Scheduler { unsafe { local_ptr::take() } } fn exists() -> bool { local_ptr::exists() } - fn borrow(f: &fn(&mut Scheduler)) { unsafe { local_ptr::borrow(f) } } + fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T { + let mut res: Option<T> = None; + let res_ptr: *mut Option<T> = &mut res; + unsafe { + do local_ptr::borrow |sched| { + let result = f(sched); + *res_ptr = Some(result); + } + } + match res { + Some(r) => { r } + None => abort!("function failed!") + } + } unsafe fn unsafe_borrow() -> *mut Scheduler { local_ptr::unsafe_borrow() } unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> { abort!("unimpl") } } @@ -36,8 +49,8 @@ impl Local for Task { fn put(_value: ~Task) { abort!("unimpl") } fn take() -> ~Task { abort!("unimpl") } fn exists() -> bool { abort!("unimpl") } - fn borrow(f: &fn(&mut Task)) { - do Local::borrow::<Scheduler> |sched| { + fn borrow<T>(f: &fn(&mut Task) -> T) -> T { + do Local::borrow::<Scheduler, T> |sched| { match sched.current_task { Some(~ref mut task) => { f(&mut *task.task) @@ -74,7 +87,7 @@ impl Local for IoFactoryObject { fn put(_value: ~IoFactoryObject) { abort!("unimpl") } fn take() -> ~IoFactoryObject { abort!("unimpl") } fn exists() -> bool { abort!("unimpl") } - fn borrow(_f: &fn(&mut IoFactoryObject)) { abort!("unimpl") } + fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { abort!("unimpl") } unsafe fn unsafe_borrow() -> *mut IoFactoryObject { let sched = Local::unsafe_borrow::<Scheduler>(); let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap(); @@ -115,4 +128,16 @@ mod test { } let _scheduler: ~Scheduler = Local::take(); } + + #[test] + fn borrow_with_return() { + let scheduler = ~new_test_uv_sched(); + Local::put(scheduler); + let res = do Local::borrow::<Scheduler,bool> |_sched| { + true + }; + assert!(res) + let _scheduler: ~Scheduler = Local::take(); + } + } diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs index 80d797e8c65..0db903f81ee 100644 --- a/src/libstd/rt/local_ptr.rs +++ b/src/libstd/rt/local_ptr.rs @@ -79,7 +79,7 @@ pub unsafe fn borrow<T>(f: &fn(&mut T)) { // XXX: Need a different abstraction from 'finally' here to avoid unsafety let unsafe_ptr = cast::transmute_mut_region(&mut *value); - let value_cell = Cell(value); + let value_cell = Cell::new(value); do (|| { f(unsafe_ptr); diff --git a/src/libstd/rt/message_queue.rs b/src/libstd/rt/message_queue.rs index 21711bbe84c..734be808797 100644 --- a/src/libstd/rt/message_queue.rs +++ b/src/libstd/rt/message_queue.rs @@ -32,16 +32,20 @@ impl<T: Owned> MessageQueue<T> { } pub fn push(&mut self, value: T) { - let value = Cell(value); - self.queue.with(|q| q.push(value.take()) ); + unsafe { + let value = Cell::new(value); + self.queue.with(|q| q.push(value.take()) ); + } } pub fn pop(&mut self) -> Option<T> { - do self.queue.with |q| { - if !q.is_empty() { - Some(q.shift()) - } else { - None + unsafe { + do self.queue.with |q| { + if !q.is_empty() { + Some(q.shift()) + } else { + None + } } } } diff --git a/src/libstd/rt/metrics.rs b/src/libstd/rt/metrics.rs index 70e347fdfb6..b0c0fa5d708 100644 --- a/src/libstd/rt/metrics.rs +++ b/src/libstd/rt/metrics.rs @@ -34,7 +34,11 @@ pub struct SchedMetrics { // Message receives that do not block the receiver rendezvous_recvs: uint, // Message receives that block the receiver - non_rendezvous_recvs: uint + non_rendezvous_recvs: uint, + // JoinLatch releases that create tombstones + release_tombstone: uint, + // JoinLatch releases that do not create tombstones + release_no_tombstone: uint, } impl SchedMetrics { @@ -51,7 +55,9 @@ impl SchedMetrics { rendezvous_sends: 0, non_rendezvous_sends: 0, rendezvous_recvs: 0, - non_rendezvous_recvs: 0 + non_rendezvous_recvs: 0, + release_tombstone: 0, + release_no_tombstone: 0 } } } @@ -70,6 +76,8 @@ impl ToStr for SchedMetrics { non_rendezvous_sends: %u\n\ rendezvous_recvs: %u\n\ non_rendezvous_recvs: %u\n\ + release_tombstone: %u\n\ + release_no_tombstone: %u\n\ ", self.turns, self.messages_received, @@ -82,7 +90,9 @@ impl ToStr for SchedMetrics { self.rendezvous_sends, self.non_rendezvous_sends, self.rendezvous_recvs, - self.non_rendezvous_recvs + self.non_rendezvous_recvs, + self.release_tombstone, + self.release_no_tombstone ) } } \ No newline at end of file diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index caf3e15e535..1724361cabc 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -59,7 +59,8 @@ Several modules in `core` are clients of `rt`: #[deny(unused_mut)]; #[deny(unused_variable)]; -use ptr::Ptr; +use cell::Cell; +use ptr::RawPtr; /// The global (exchange) heap. pub mod global_heap; @@ -133,6 +134,9 @@ pub mod local_ptr; /// Bindings to pthread/windows thread-local storage. pub mod thread_local_storage; +/// A concurrent data structure with which parent tasks wait on child tasks. +pub mod join_latch; + pub mod metrics; @@ -164,7 +168,7 @@ pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int { let sleepers = SleeperList::new(); let mut sched = ~Scheduler::new(loop_, work_queue, sleepers); sched.no_sleep = true; - let main_task = ~Coroutine::new(&mut sched.stack_pool, main); + let main_task = ~Coroutine::new_root(&mut sched.stack_pool, main); sched.enqueue_task(main_task); sched.run(); @@ -207,8 +211,8 @@ pub fn context() -> RuntimeContext { return OldTaskContext; } else { if Local::exists::<Scheduler>() { - let context = ::cell::empty_cell(); - do Local::borrow::<Scheduler> |sched| { + let context = Cell::new_empty(); + do Local::borrow::<Scheduler, ()> |sched| { if sched.in_task_context() { context.put_back(TaskContext); } else { @@ -238,7 +242,7 @@ fn test_context() { do run_in_bare_thread { assert_eq!(context(), GlobalContext); let mut sched = ~new_test_uv_sched(); - let task = ~do Coroutine::new(&mut sched.stack_pool) { + let task = ~do Coroutine::new_root(&mut sched.stack_pool) { assert_eq!(context(), TaskContext); let sched = Local::take::<Scheduler>(); do sched.deschedule_running_task_and_then() |sched, task| { diff --git a/src/libstd/rt/rc.rs b/src/libstd/rt/rc.rs index 1c0c8c14fdf..2977d081508 100644 --- a/src/libstd/rt/rc.rs +++ b/src/libstd/rt/rc.rs @@ -78,7 +78,7 @@ impl<T> Drop for RC<T> { assert!(self.refcount() > 0); unsafe { - // XXX: Mutable finalizer + // FIXME(#4330) Need self by value to get mutability. let this: &mut RC<T> = cast::transmute_mut(self); match *this.get_mut_state() { diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index df231f6d88a..be57247d514 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -26,6 +26,11 @@ use rt::local::Local; use rt::rtio::RemoteCallback; use rt::metrics::SchedMetrics; +//use to_str::ToStr; + +/// To allow for using pointers as scheduler ids +use borrow::{to_uint}; + /// The Scheduler is responsible for coordinating execution of Coroutines /// on a single thread. When the scheduler is running it is owned by /// thread local storage and the running task is owned by the @@ -65,12 +70,15 @@ pub struct Scheduler { /// An action performed after a context switch on behalf of the /// code running before the context switch priv cleanup_job: Option<CleanupJob>, - metrics: SchedMetrics + metrics: SchedMetrics, + /// Should this scheduler run any task, or only pinned tasks? + run_anything: bool } pub struct SchedHandle { priv remote: ~RemoteCallbackObject, - priv queue: MessageQueue<SchedMessage> + priv queue: MessageQueue<SchedMessage>, + sched_id: uint } pub struct Coroutine { @@ -81,12 +89,20 @@ pub struct Coroutine { /// the task is dead priv saved_context: Context, /// The heap, GC, unwinding, local storage, logging - task: ~Task + task: ~Task, +} + +// A scheduler home is either a handle to the home scheduler, or an +// explicit "AnySched". +pub enum SchedHome { + AnySched, + Sched(SchedHandle) } pub enum SchedMessage { Wake, - Shutdown + Shutdown, + PinnedTask(~Coroutine) } enum CleanupJob { @@ -94,13 +110,24 @@ enum CleanupJob { GiveTask(~Coroutine, UnsafeTaskReceiver) } -pub impl Scheduler { +impl Scheduler { + pub fn in_task_context(&self) -> bool { self.current_task.is_some() } + + pub fn sched_id(&self) -> uint { to_uint(self) } + + pub fn new(event_loop: ~EventLoopObject, + work_queue: WorkQueue<~Coroutine>, + sleeper_list: SleeperList) + -> Scheduler { + + Scheduler::new_special(event_loop, work_queue, sleeper_list, true) - fn in_task_context(&self) -> bool { self.current_task.is_some() } + } - fn new(event_loop: ~EventLoopObject, - work_queue: WorkQueue<~Coroutine>, - sleeper_list: SleeperList) + pub fn new_special(event_loop: ~EventLoopObject, + work_queue: WorkQueue<~Coroutine>, + sleeper_list: SleeperList, + run_anything: bool) -> Scheduler { // Lazily initialize the runtime TLS key @@ -117,7 +144,8 @@ pub impl Scheduler { saved_context: Context::empty(), current_task: None, cleanup_job: None, - metrics: SchedMetrics::new() + metrics: SchedMetrics::new(), + run_anything: run_anything } } @@ -125,7 +153,7 @@ pub impl Scheduler { // the scheduler itself doesn't have to call event_loop.run. // That will be important for embedding the runtime into external // event loops. - fn run(~self) -> ~Scheduler { + pub fn run(~self) -> ~Scheduler { assert!(!self.in_task_context()); let mut self_sched = self; @@ -147,11 +175,15 @@ pub impl Scheduler { (*event_loop).run(); } + rtdebug!("run taking sched"); let sched = Local::take::<Scheduler>(); // XXX: Reenable this once we're using a per-task queue. With a shared // queue this is not true //assert!(sched.work_queue.is_empty()); - rtdebug!("scheduler metrics: %s\n", sched.metrics.to_str()); + rtdebug!("scheduler metrics: %s\n", { + use to_str::ToStr; + sched.metrics.to_str() + }); return sched; } @@ -167,6 +199,7 @@ pub impl Scheduler { if sched.interpret_message_queue() { // We performed a scheduling action. There may be other work // to do yet, so let's try again later. + rtdebug!("run_sched_once, interpret_message_queue taking sched"); let mut sched = Local::take::<Scheduler>(); sched.metrics.messages_received += 1; sched.event_loop.callback(Scheduler::run_sched_once); @@ -175,6 +208,7 @@ pub impl Scheduler { } // Now, look in the work queue for tasks to run + rtdebug!("run_sched_once taking"); let sched = Local::take::<Scheduler>(); if sched.resume_task_from_queue() { // We performed a scheduling action. There may be other work @@ -204,38 +238,60 @@ pub impl Scheduler { Local::put(sched); } - fn make_handle(&mut self) -> SchedHandle { + pub fn make_handle(&mut self) -> SchedHandle { let remote = self.event_loop.remote_callback(Scheduler::run_sched_once); return SchedHandle { remote: remote, - queue: self.message_queue.clone() + queue: self.message_queue.clone(), + sched_id: self.sched_id() }; } /// Schedule a task to be executed later. /// - /// Pushes the task onto the work stealing queue and tells the event loop - /// to run it later. Always use this instead of pushing to the work queue - /// directly. - fn enqueue_task(&mut self, task: ~Coroutine) { - self.work_queue.push(task); - self.event_loop.callback(Scheduler::run_sched_once); - - // We've made work available. Notify a sleeping scheduler. - // XXX: perf. Check for a sleeper without synchronizing memory. - // It's not critical that we always find it. - // XXX: perf. If there's a sleeper then we might as well just send - // it the task directly instead of pushing it to the - // queue. That is essentially the intent here and it is less - // work. - match self.sleeper_list.pop() { + /// Pushes the task onto the work stealing queue and tells the + /// event loop to run it later. Always use this instead of pushing + /// to the work queue directly. + pub fn enqueue_task(&mut self, task: ~Coroutine) { + + // We don't want to queue tasks that belong on other threads, + // so we send them home at enqueue time. + + // The borrow checker doesn't like our disassembly of the + // Coroutine struct and partial use and mutation of the + // fields. So completely disassemble here and stop using? + + // XXX perf: I think we might be able to shuffle this code to + // only destruct when we need to. + + rtdebug!("a task was queued on: %u", self.sched_id()); + + let this = self; + + // We push the task onto our local queue clone. + this.work_queue.push(task); + this.event_loop.callback(Scheduler::run_sched_once); + + // We've made work available. Notify a + // sleeping scheduler. + + // XXX: perf. Check for a sleeper without + // synchronizing memory. It's not critical + // that we always find it. + + // XXX: perf. If there's a sleeper then we + // might as well just send it the task + // directly instead of pushing it to the + // queue. That is essentially the intent here + // and it is less work. + match this.sleeper_list.pop() { Some(handle) => { let mut handle = handle; handle.send(Wake) } - None => (/* pass */) - } + None => { (/* pass */) } + }; } // * Scheduler-context operations @@ -247,6 +303,15 @@ pub impl Scheduler { let mut this = self; match this.message_queue.pop() { + Some(PinnedTask(task)) => { + rtdebug!("recv BiasedTask message in sched: %u", + this.sched_id()); + let mut task = task; + task.task.home = Some(Sched(this.make_handle())); + this.resume_task_immediately(task); + return true; + } + Some(Wake) => { rtdebug!("recv Wake message"); this.sleepy = false; @@ -256,8 +321,9 @@ pub impl Scheduler { Some(Shutdown) => { rtdebug!("recv Shutdown message"); if this.sleepy { - // There may be an outstanding handle on the sleeper list. - // Pop them all to make sure that's not the case. + // There may be an outstanding handle on the + // sleeper list. Pop them all to make sure that's + // not the case. loop { match this.sleeper_list.pop() { Some(handle) => { @@ -268,8 +334,8 @@ pub impl Scheduler { } } } - // No more sleeping. After there are no outstanding event loop - // references we will shut down. + // No more sleeping. After there are no outstanding + // event loop references we will shut down. this.no_sleep = true; this.sleepy = false; Local::put(this); @@ -282,23 +348,93 @@ pub impl Scheduler { } } + /// Given an input Coroutine sends it back to its home scheduler. + fn send_task_home(task: ~Coroutine) { + let mut task = task; + let mut home = task.task.home.swap_unwrap(); + match home { + Sched(ref mut home_handle) => { + home_handle.send(PinnedTask(task)); + } + AnySched => { + abort!("error: cannot send anysched task home"); + } + } + } + + // Resume a task from the queue - but also take into account that + // it might not belong here. fn resume_task_from_queue(~self) -> bool { assert!(!self.in_task_context()); rtdebug!("looking in work queue for task to schedule"); - let mut this = self; + + // The borrow checker imposes the possibly absurd requirement + // that we split this into two match expressions. This is due + // to the inspection of the internal bits of task, as that + // can't be in scope when we act on task. match this.work_queue.pop() { Some(task) => { - rtdebug!("resuming task from work queue"); - this.resume_task_immediately(task); - return true; + let action_id = { + let home = &task.task.home; + match home { + &Some(Sched(ref home_handle)) + if home_handle.sched_id != this.sched_id() => { + 0 + } + &Some(AnySched) if this.run_anything => { + 1 + } + &Some(AnySched) => { + 2 + } + &Some(Sched(_)) => { + 3 + } + &None => { + 4 + } + } + }; + + match action_id { + 0 => { + rtdebug!("sending task home"); + Scheduler::send_task_home(task); + Local::put(this); + return false; + } + 1 => { + rtdebug!("resuming now"); + this.resume_task_immediately(task); + return true; + } + 2 => { + rtdebug!("re-queueing") + this.enqueue_task(task); + Local::put(this); + return false; + } + 3 => { + rtdebug!("resuming now"); + this.resume_task_immediately(task); + return true; + } + 4 => { + abort!("task home was None!"); + } + _ => { + abort!("literally, you should not be here"); + } + } } + None => { - rtdebug!("no tasks in queue"); - Local::put(this); - return false; - } + rtdebug!("no tasks in queue"); + Local::put(this); + return false; + } } } @@ -306,40 +442,51 @@ pub impl Scheduler { /// Called by a running task to end execution, after which it will /// be recycled by the scheduler for reuse in a new task. - fn terminate_current_task(~self) { + pub fn terminate_current_task(~self) { assert!(self.in_task_context()); rtdebug!("ending running task"); do self.deschedule_running_task_and_then |sched, dead_task| { - let dead_task = Cell(dead_task); + let dead_task = Cell::new(dead_task); dead_task.take().recycle(&mut sched.stack_pool); } abort!("control reached end of task"); } - fn schedule_new_task(~self, task: ~Coroutine) { + pub fn schedule_task(~self, task: ~Coroutine) { assert!(self.in_task_context()); - do self.switch_running_tasks_and_then(task) |sched, last_task| { - let last_task = Cell(last_task); - sched.enqueue_task(last_task.take()); - } - } + // is the task home? + let is_home = task.is_home_no_tls(&self); - fn schedule_task(~self, task: ~Coroutine) { - assert!(self.in_task_context()); + // does the task have a home? + let homed = task.homed(); + + let mut this = self; - do self.switch_running_tasks_and_then(task) |sched, last_task| { - let last_task = Cell(last_task); - sched.enqueue_task(last_task.take()); + if is_home || (!homed && this.run_anything) { + // here we know we are home, execute now OR we know we + // aren't homed, and that this sched doesn't care + do this.switch_running_tasks_and_then(task) |sched, last_task| { + let last_task = Cell::new(last_task); + sched.enqueue_task(last_task.take()); + } + } else if !homed && !this.run_anything { + // the task isn't homed, but it can't be run here + this.enqueue_task(task); + Local::put(this); + } else { + // task isn't home, so don't run it here, send it home + Scheduler::send_task_home(task); + Local::put(this); } } // Core scheduling ops - fn resume_task_immediately(~self, task: ~Coroutine) { + pub fn resume_task_immediately(~self, task: ~Coroutine) { let mut this = self; assert!(!this.in_task_context()); @@ -382,7 +529,7 @@ pub impl Scheduler { /// This passes a Scheduler pointer to the fn after the context switch /// in order to prevent that fn from performing further scheduling operations. /// Doing further scheduling could easily result in infinite recursion. - fn deschedule_running_task_and_then(~self, f: &fn(&mut Scheduler, ~Coroutine)) { + pub fn deschedule_running_task_and_then(~self, f: &fn(&mut Scheduler, ~Coroutine)) { let mut this = self; assert!(this.in_task_context()); @@ -414,8 +561,8 @@ pub impl Scheduler { /// Switch directly to another task, without going through the scheduler. /// You would want to think hard about doing this, e.g. if there are /// pending I/O events it would be a bad idea. - fn switch_running_tasks_and_then(~self, next_task: ~Coroutine, - f: &fn(&mut Scheduler, ~Coroutine)) { + pub fn switch_running_tasks_and_then(~self, next_task: ~Coroutine, + f: &fn(&mut Scheduler, ~Coroutine)) { let mut this = self; assert!(this.in_task_context()); @@ -450,12 +597,12 @@ pub impl Scheduler { // * Other stuff - fn enqueue_cleanup_job(&mut self, job: CleanupJob) { + pub fn enqueue_cleanup_job(&mut self, job: CleanupJob) { assert!(self.cleanup_job.is_none()); self.cleanup_job = Some(job); } - fn run_cleanup_job(&mut self) { + pub fn run_cleanup_job(&mut self) { rtdebug!("running cleanup job"); assert!(self.cleanup_job.is_some()); @@ -476,9 +623,9 @@ pub impl Scheduler { /// callers should first arrange for that task to be located in the /// Scheduler's current_task slot and set up the /// post-context-switch cleanup job. - fn get_contexts<'a>(&'a mut self) -> (&'a mut Context, - Option<&'a mut Context>, - Option<&'a mut Context>) { + pub fn get_contexts<'a>(&'a mut self) -> (&'a mut Context, + Option<&'a mut Context>, + Option<&'a mut Context>) { let last_task = match self.cleanup_job { Some(GiveTask(~ref task, _)) => { Some(task) @@ -514,31 +661,112 @@ impl SchedHandle { } } -pub impl Coroutine { - fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { - Coroutine::with_task(stack_pool, ~Task::new(), start) +impl Coroutine { + + /// This function checks that a coroutine is running "home". + pub fn is_home(&self) -> bool { + rtdebug!("checking if coroutine is home"); + do Local::borrow::<Scheduler,bool> |sched| { + match self.task.home { + Some(AnySched) => { false } + Some(Sched(SchedHandle { sched_id: ref id, _ })) => { + *id == sched.sched_id() + } + None => { abort!("error: homeless task!"); } + } + } } - fn with_task(stack_pool: &mut StackPool, - task: ~Task, - start: ~fn()) -> Coroutine { + /// Without access to self, but with access to the "expected home + /// id", see if we are home. + fn is_home_using_id(id: uint) -> bool { + rtdebug!("checking if coroutine is home using id"); + do Local::borrow::<Scheduler,bool> |sched| { + if sched.sched_id() == id { + true + } else { + false + } + } + } - static MIN_STACK_SIZE: uint = 10000000; // XXX: Too much stack + /// Check if this coroutine has a home + fn homed(&self) -> bool { + rtdebug!("checking if this coroutine has a home"); + match self.task.home { + Some(AnySched) => { false } + Some(Sched(_)) => { true } + None => { abort!("error: homeless task!"); + } + } + } + + /// A version of is_home that does not need to use TLS, it instead + /// takes local scheduler as a parameter. + fn is_home_no_tls(&self, sched: &~Scheduler) -> bool { + rtdebug!("checking if coroutine is home without tls"); + match self.task.home { + Some(AnySched) => { true } + Some(Sched(SchedHandle { sched_id: ref id, _})) => { + *id == sched.sched_id() + } + None => { abort!("error: homeless task!"); } + } + } + + /// Check TLS for the scheduler to see if we are on a special + /// scheduler. + pub fn on_special() -> bool { + rtdebug!("checking if coroutine is executing on special sched"); + do Local::borrow::<Scheduler,bool>() |sched| { + !sched.run_anything + } + } + + // Created new variants of "new" that takes a home scheduler + // parameter. The original with_task now calls with_task_homed + // using the AnySched paramter. + + pub fn new_homed(stack_pool: &mut StackPool, home: SchedHome, start: ~fn()) -> Coroutine { + Coroutine::with_task_homed(stack_pool, ~Task::new_root(), start, home) + } + + pub fn new_root(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { + Coroutine::with_task(stack_pool, ~Task::new_root(), start) + } + + pub fn with_task_homed(stack_pool: &mut StackPool, + task: ~Task, + start: ~fn(), + home: SchedHome) -> Coroutine { + + static MIN_STACK_SIZE: uint = 1000000; // XXX: Too much stack let start = Coroutine::build_start_wrapper(start); let mut stack = stack_pool.take_segment(MIN_STACK_SIZE); // NB: Context holds a pointer to that ~fn let initial_context = Context::new(start, &mut stack); - return Coroutine { + let mut crt = Coroutine { current_stack_segment: stack, saved_context: initial_context, - task: task + task: task, }; + crt.task.home = Some(home); + return crt; } - priv fn build_start_wrapper(start: ~fn()) -> ~fn() { + pub fn with_task(stack_pool: &mut StackPool, + task: ~Task, + start: ~fn()) -> Coroutine { + Coroutine::with_task_homed(stack_pool, + task, + start, + AnySched) + } + + fn build_start_wrapper(start: ~fn()) -> ~fn() { // XXX: The old code didn't have this extra allocation - let start_cell = Cell(start); + let start_cell = Cell::new(start); let wrapper: ~fn() = || { // This is the first code to execute after the initial // context switch to the task. The previous context may @@ -549,17 +777,20 @@ pub impl Coroutine { let sched = Local::unsafe_borrow::<Scheduler>(); let task = (*sched).current_task.get_mut_ref(); - // FIXME #6141: shouldn't neet to put `start()` in another closure - let start_cell = Cell(start_cell.take()); + // FIXME #6141: shouldn't neet to put `start()` in + // another closure + let start_cell = Cell::new(start_cell.take()); do task.task.run { - // N.B. Removing `start` from the start wrapper closure - // by emptying a cell is critical for correctness. The ~Task - // pointer, and in turn the closure used to initialize the first - // call frame, is destroyed in scheduler context, not task context. - // So any captured closures must not contain user-definable dtors - // that expect to be in task context. By moving `start` out of - // the closure, all the user code goes out of scope while - // the task is still running. + // N.B. Removing `start` from the start wrapper + // closure by emptying a cell is critical for + // correctness. The ~Task pointer, and in turn the + // closure used to initialize the first call + // frame, is destroyed in scheduler context, not + // task context. So any captured closures must + // not contain user-definable dtors that expect to + // be in task context. By moving `start` out of + // the closure, all the user code goes out of + // scope while the task is still running. let start = start_cell.take(); start(); }; @@ -572,7 +803,7 @@ pub impl Coroutine { } /// Destroy the task and try to reuse its components - fn recycle(~self, stack_pool: &mut StackPool) { + pub fn recycle(~self, stack_pool: &mut StackPool) { match self { ~Coroutine {current_stack_segment, _} => { stack_pool.give_segment(current_stack_segment); @@ -597,12 +828,312 @@ impl ClosureConverter for UnsafeTaskReceiver { mod test { use int; use cell::Cell; + use iterator::IteratorUtil; use unstable::run_in_bare_thread; use task::spawn; use rt::local::Local; use rt::test::*; use super::*; use rt::thread::Thread; + use ptr::to_uint; + use vec::MutableVector; + + // Confirm that a sched_id actually is the uint form of the + // pointer to the scheduler struct. + + #[test] + fn simple_sched_id_test() { + do run_in_bare_thread { + let sched = ~new_test_uv_sched(); + assert!(to_uint(sched) == sched.sched_id()); + } + } + + // Compare two scheduler ids that are different, this should never + // fail but may catch a mistake someday. + + #[test] + fn compare_sched_id_test() { + do run_in_bare_thread { + let sched_one = ~new_test_uv_sched(); + let sched_two = ~new_test_uv_sched(); + assert!(sched_one.sched_id() != sched_two.sched_id()); + } + } + + // A simple test to check if a homed task run on a single + // scheduler ends up executing while home. + + #[test] + fn test_home_sched() { + do run_in_bare_thread { + let mut task_ran = false; + let task_ran_ptr: *mut bool = &mut task_ran; + let mut sched = ~new_test_uv_sched(); + + let sched_handle = sched.make_handle(); + let sched_id = sched.sched_id(); + + let task = ~do Coroutine::new_homed(&mut sched.stack_pool, + Sched(sched_handle)) { + unsafe { *task_ran_ptr = true }; + let sched = Local::take::<Scheduler>(); + assert!(sched.sched_id() == sched_id); + Local::put::<Scheduler>(sched); + }; + sched.enqueue_task(task); + sched.run(); + assert!(task_ran); + } + } + + // A test for each state of schedule_task + + #[test] + fn test_schedule_home_states() { + + use rt::uv::uvio::UvEventLoop; + use rt::sched::Shutdown; + use rt::sleeper_list::SleeperList; + use rt::work_queue::WorkQueue; + + do run_in_bare_thread { +// let nthreads = 2; + + let sleepers = SleeperList::new(); + let work_queue = WorkQueue::new(); + + // our normal scheduler + let mut normal_sched = ~Scheduler::new( + ~UvEventLoop::new(), + work_queue.clone(), + sleepers.clone()); + + let normal_handle = Cell::new(normal_sched.make_handle()); + + // our special scheduler + let mut special_sched = ~Scheduler::new_special( + ~UvEventLoop::new(), + work_queue.clone(), + sleepers.clone(), + true); + + let special_handle = Cell::new(special_sched.make_handle()); + let special_handle2 = Cell::new(special_sched.make_handle()); + let special_id = special_sched.sched_id(); + let t1_handle = special_sched.make_handle(); + let t4_handle = special_sched.make_handle(); + + let t1f = ~do Coroutine::new_homed(&mut special_sched.stack_pool, + Sched(t1_handle)) { + let is_home = Coroutine::is_home_using_id(special_id); + rtdebug!("t1 should be home: %b", is_home); + assert!(is_home); + }; + let t1f = Cell::new(t1f); + + let t2f = ~do Coroutine::new_root(&mut normal_sched.stack_pool) { + let on_special = Coroutine::on_special(); + rtdebug!("t2 should not be on special: %b", on_special); + assert!(!on_special); + }; + let t2f = Cell::new(t2f); + + let t3f = ~do Coroutine::new_root(&mut normal_sched.stack_pool) { + // not on special + let on_special = Coroutine::on_special(); + rtdebug!("t3 should not be on special: %b", on_special); + assert!(!on_special); + }; + let t3f = Cell::new(t3f); + + let t4f = ~do Coroutine::new_homed(&mut special_sched.stack_pool, + Sched(t4_handle)) { + // is home + let home = Coroutine::is_home_using_id(special_id); + rtdebug!("t4 should be home: %b", home); + assert!(home); + }; + let t4f = Cell::new(t4f); + + // we have four tests, make them as closures + let t1: ~fn() = || { + // task is home on special + let task = t1f.take(); + let sched = Local::take::<Scheduler>(); + sched.schedule_task(task); + }; + let t2: ~fn() = || { + // not homed, task doesn't care + let task = t2f.take(); + let sched = Local::take::<Scheduler>(); + sched.schedule_task(task); + }; + let t3: ~fn() = || { + // task not homed, must leave + let task = t3f.take(); + let sched = Local::take::<Scheduler>(); + sched.schedule_task(task); + }; + let t4: ~fn() = || { + // task not home, send home + let task = t4f.take(); + let sched = Local::take::<Scheduler>(); + sched.schedule_task(task); + }; + + let t1 = Cell::new(t1); + let t2 = Cell::new(t2); + let t3 = Cell::new(t3); + let t4 = Cell::new(t4); + + // build a main task that runs our four tests + let main_task = ~do Coroutine::new_root(&mut normal_sched.stack_pool) { + // the two tasks that require a normal start location + t2.take()(); + t4.take()(); + normal_handle.take().send(Shutdown); + special_handle.take().send(Shutdown); + }; + + // task to run the two "special start" tests + let special_task = ~do Coroutine::new_homed( + &mut special_sched.stack_pool, + Sched(special_handle2.take())) { + t1.take()(); + t3.take()(); + }; + + // enqueue the main tasks + normal_sched.enqueue_task(special_task); + normal_sched.enqueue_task(main_task); + + let nsched_cell = Cell::new(normal_sched); + let normal_thread = do Thread::start { + let sched = nsched_cell.take(); + sched.run(); + }; + + let ssched_cell = Cell::new(special_sched); + let special_thread = do Thread::start { + let sched = ssched_cell.take(); + sched.run(); + }; + + // wait for the end + let _thread1 = normal_thread; + let _thread2 = special_thread; + + } + } + + // The following test is a bit of a mess, but it trys to do + // something tricky so I'm not sure how to get around this in the + // short term. + + // A number of schedulers are created, and then a task is created + // and assigned a home scheduler. It is then "started" on a + // different scheduler. The scheduler it is started on should + // observe that the task is not home, and send it home. + + // This test is light in that it does very little. + + #[test] + fn test_transfer_task_home() { + + use rt::uv::uvio::UvEventLoop; + use rt::sched::Shutdown; + use rt::sleeper_list::SleeperList; + use rt::work_queue::WorkQueue; + use uint; + use container::Container; + use vec::OwnedVector; + + do run_in_bare_thread { + + static N: uint = 8; + + let sleepers = SleeperList::new(); + let work_queue = WorkQueue::new(); + + let mut handles = ~[]; + let mut scheds = ~[]; + + for uint::range(0, N) |_| { + let loop_ = ~UvEventLoop::new(); + let mut sched = ~Scheduler::new(loop_, + work_queue.clone(), + sleepers.clone()); + let handle = sched.make_handle(); + rtdebug!("sched id: %u", handle.sched_id); + handles.push(handle); + scheds.push(sched); + }; + + let handles = Cell::new(handles); + + let home_handle = scheds[6].make_handle(); + let home_id = home_handle.sched_id; + let home = Sched(home_handle); + + let main_task = ~do Coroutine::new_homed(&mut scheds[1].stack_pool, home) { + + // Here we check if the task is running on its home. + let sched = Local::take::<Scheduler>(); + rtdebug!("run location scheduler id: %u, home: %u", + sched.sched_id(), + home_id); + assert!(sched.sched_id() == home_id); + Local::put::<Scheduler>(sched); + + let mut handles = handles.take(); + for handles.mut_iter().advance |handle| { + handle.send(Shutdown); + } + }; + + scheds[0].enqueue_task(main_task); + + let mut threads = ~[]; + + while !scheds.is_empty() { + let sched = scheds.pop(); + let sched_cell = Cell::new(sched); + let thread = do Thread::start { + let sched = sched_cell.take(); + sched.run(); + }; + threads.push(thread); + } + + let _threads = threads; + } + } + + // Do it a lot + + #[test] + fn test_stress_schedule_task_states() { + let n = stress_factor() * 120; + for int::range(0,n as int) |_| { + test_schedule_home_states(); + } + } + + // The goal is that this is the high-stress test for making sure + // homing is working. It allocates RUST_RT_STRESS tasks that + // do nothing but assert that they are home at execution + // time. These tasks are queued to random schedulers, so sometimes + // they are home and sometimes not. It also runs RUST_RT_STRESS + // times. + + #[test] + fn test_stress_homed_tasks() { + let n = stress_factor(); + for int::range(0,n as int) |_| { + run_in_mt_newsched_task_random_homed(); + } + } #[test] fn test_simple_scheduling() { @@ -611,7 +1142,7 @@ mod test { let task_ran_ptr: *mut bool = &mut task_ran; let mut sched = ~new_test_uv_sched(); - let task = ~do Coroutine::new(&mut sched.stack_pool) { + let task = ~do Coroutine::new_root(&mut sched.stack_pool) { unsafe { *task_ran_ptr = true; } }; sched.enqueue_task(task); @@ -629,7 +1160,7 @@ mod test { let mut sched = ~new_test_uv_sched(); for int::range(0, total) |_| { - let task = ~do Coroutine::new(&mut sched.stack_pool) { + let task = ~do Coroutine::new_root(&mut sched.stack_pool) { unsafe { *task_count_ptr = *task_count_ptr + 1; } }; sched.enqueue_task(task); @@ -646,15 +1177,15 @@ mod test { let count_ptr: *mut int = &mut count; let mut sched = ~new_test_uv_sched(); - let task1 = ~do Coroutine::new(&mut sched.stack_pool) { + let task1 = ~do Coroutine::new_root(&mut sched.stack_pool) { unsafe { *count_ptr = *count_ptr + 1; } let mut sched = Local::take::<Scheduler>(); - let task2 = ~do Coroutine::new(&mut sched.stack_pool) { + let task2 = ~do Coroutine::new_root(&mut sched.stack_pool) { unsafe { *count_ptr = *count_ptr + 1; } }; // Context switch directly to the new task do sched.switch_running_tasks_and_then(task2) |sched, task1| { - let task1 = Cell(task1); + let task1 = Cell::new(task1); sched.enqueue_task(task1.take()); } unsafe { *count_ptr = *count_ptr + 1; } @@ -674,7 +1205,7 @@ mod test { let mut sched = ~new_test_uv_sched(); - let start_task = ~do Coroutine::new(&mut sched.stack_pool) { + let start_task = ~do Coroutine::new_root(&mut sched.stack_pool) { run_task(count_ptr); }; sched.enqueue_task(start_task); @@ -683,8 +1214,8 @@ mod test { assert_eq!(count, MAX); fn run_task(count_ptr: *mut int) { - do Local::borrow::<Scheduler> |sched| { - let task = ~do Coroutine::new(&mut sched.stack_pool) { + do Local::borrow::<Scheduler, ()> |sched| { + let task = ~do Coroutine::new_root(&mut sched.stack_pool) { unsafe { *count_ptr = *count_ptr + 1; if *count_ptr != MAX { @@ -702,11 +1233,11 @@ mod test { fn test_block_task() { do run_in_bare_thread { let mut sched = ~new_test_uv_sched(); - let task = ~do Coroutine::new(&mut sched.stack_pool) { + let task = ~do Coroutine::new_root(&mut sched.stack_pool) { let sched = Local::take::<Scheduler>(); assert!(sched.in_task_context()); do sched.deschedule_running_task_and_then() |sched, task| { - let task = Cell(task); + let task = Cell::new(task); assert!(!sched.in_task_context()); sched.enqueue_task(task.take()); } @@ -726,7 +1257,7 @@ mod test { do spawn { let sched = Local::take::<Scheduler>(); do sched.deschedule_running_task_and_then |sched, task| { - let task = Cell(task); + let task = Cell::new(task); do sched.event_loop.callback_ms(10) { rtdebug!("in callback"); let mut sched = Local::take::<Scheduler>(); @@ -744,31 +1275,31 @@ mod test { do run_in_bare_thread { let (port, chan) = oneshot::<()>(); - let port_cell = Cell(port); - let chan_cell = Cell(chan); + let port_cell = Cell::new(port); + let chan_cell = Cell::new(chan); let mut sched1 = ~new_test_uv_sched(); let handle1 = sched1.make_handle(); - let handle1_cell = Cell(handle1); - let task1 = ~do Coroutine::new(&mut sched1.stack_pool) { + let handle1_cell = Cell::new(handle1); + let task1 = ~do Coroutine::new_root(&mut sched1.stack_pool) { chan_cell.take().send(()); }; sched1.enqueue_task(task1); let mut sched2 = ~new_test_uv_sched(); - let task2 = ~do Coroutine::new(&mut sched2.stack_pool) { + let task2 = ~do Coroutine::new_root(&mut sched2.stack_pool) { port_cell.take().recv(); // Release the other scheduler's handle so it can exit handle1_cell.take(); }; sched2.enqueue_task(task2); - let sched1_cell = Cell(sched1); + let sched1_cell = Cell::new(sched1); let _thread1 = do Thread::start { let sched1 = sched1_cell.take(); sched1.run(); }; - let sched2_cell = Cell(sched2); + let sched2_cell = Cell::new(sched2); let _thread2 = do Thread::start { let sched2 = sched2_cell.take(); sched2.run(); @@ -787,7 +1318,7 @@ mod test { let mut ports = ~[]; for 10.times { let (port, chan) = oneshot(); - let chan_cell = Cell(chan); + let chan_cell = Cell::new(chan); do spawntask_later { chan_cell.take().send(()); } @@ -859,8 +1390,8 @@ mod test { fn start_closure_dtor() { use ops::Drop; - // Regression test that the `start` task entrypoint can contain dtors - // that use task resources + // Regression test that the `start` task entrypoint can + // contain dtors that use task resources do run_in_newsched_task { struct S { field: () } @@ -875,6 +1406,7 @@ mod test { do spawntask { let _ss = &s; } - } + } } + } diff --git a/src/libstd/rt/sleeper_list.rs b/src/libstd/rt/sleeper_list.rs index e2873e78d80..3d6e9ef5635 100644 --- a/src/libstd/rt/sleeper_list.rs +++ b/src/libstd/rt/sleeper_list.rs @@ -31,16 +31,20 @@ impl SleeperList { } pub fn push(&mut self, handle: SchedHandle) { - let handle = Cell(handle); - self.stack.with(|s| s.push(handle.take())); + let handle = Cell::new(handle); + unsafe { + self.stack.with(|s| s.push(handle.take())); + } } pub fn pop(&mut self) -> Option<SchedHandle> { - do self.stack.with |s| { - if !s.is_empty() { - Some(s.pop()) - } else { - None + unsafe { + do self.stack.with |s| { + if !s.is_empty() { + Some(s.pop()) + } else { + None + } } } } diff --git a/src/libstd/rt/stack.rs b/src/libstd/rt/stack.rs index ec56e65931c..b0e87a62c8b 100644 --- a/src/libstd/rt/stack.rs +++ b/src/libstd/rt/stack.rs @@ -9,7 +9,7 @@ // except according to those terms. use container::Container; -use ptr::Ptr; +use ptr::RawPtr; use vec; use ops::Drop; use libc::{c_uint, uintptr_t}; @@ -19,8 +19,8 @@ pub struct StackSegment { valgrind_id: c_uint } -pub impl StackSegment { - fn new(size: uint) -> StackSegment { +impl StackSegment { + pub fn new(size: uint) -> StackSegment { unsafe { // Crate a block of uninitialized values let mut stack = vec::with_capacity(size); @@ -38,12 +38,12 @@ pub impl StackSegment { } /// Point to the low end of the allocated stack - fn start(&self) -> *uint { - vec::raw::to_ptr(self.buf) as *uint + pub fn start(&self) -> *uint { + vec::raw::to_ptr(self.buf) as *uint } /// Point one word beyond the high end of the allocated stack - fn end(&self) -> *uint { + pub fn end(&self) -> *uint { vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint } } diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index cf4967b12b3..e7f87906fe5 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -13,19 +13,27 @@ //! local storage, and logging. Even a 'freestanding' Rust would likely want //! to implement this. -use prelude::*; -use libc::{c_void, uintptr_t}; +use borrow; use cast::transmute; +use libc::{c_void, uintptr_t}; +use ptr; +use prelude::*; +use option::{Option, Some, None}; use rt::local::Local; -use super::local_heap::LocalHeap; use rt::logging::StdErrLogger; +use super::local_heap::LocalHeap; +use rt::sched::{SchedHome, AnySched}; +use rt::join_latch::JoinLatch; pub struct Task { heap: LocalHeap, gc: GarbageCollector, storage: LocalStorage, logger: StdErrLogger, - unwinder: Option<Unwinder>, + unwinder: Unwinder, + home: Option<SchedHome>, + join_latch: Option<~JoinLatch>, + on_exit: Option<~fn(bool)>, destroyed: bool } @@ -37,49 +45,63 @@ pub struct Unwinder { } impl Task { - pub fn new() -> Task { + pub fn new_root() -> Task { Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(ptr::null(), None), logger: StdErrLogger, - unwinder: Some(Unwinder { unwinding: false }), + unwinder: Unwinder { unwinding: false }, + home: Some(AnySched), + join_latch: Some(JoinLatch::new_root()), + on_exit: None, destroyed: false } } - pub fn without_unwinding() -> Task { + pub fn new_child(&mut self) -> Task { Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(ptr::null(), None), logger: StdErrLogger, - unwinder: None, + home: Some(AnySched), + unwinder: Unwinder { unwinding: false }, + join_latch: Some(self.join_latch.get_mut_ref().new_child()), + on_exit: None, destroyed: false } } + pub fn give_home(&mut self, new_home: SchedHome) { + self.home = Some(new_home); + } + pub fn run(&mut self, f: &fn()) { // This is just an assertion that `run` was called unsafely // and this instance of Task is still accessible. - do Local::borrow::<Task> |task| { - assert!(ptr::ref_eq(task, self)); + do Local::borrow::<Task, ()> |task| { + assert!(borrow::ref_eq(task, self)); } - match self.unwinder { - Some(ref mut unwinder) => { - // If there's an unwinder then set up the catch block - unwinder.try(f); + self.unwinder.try(f); + self.destroy(); + + // Wait for children. Possibly report the exit status. + let local_success = !self.unwinder.unwinding; + let join_latch = self.join_latch.swap_unwrap(); + match self.on_exit { + Some(ref on_exit) => { + let success = join_latch.wait(local_success); + (*on_exit)(success); } None => { - // Otherwise, just run the body - f() + join_latch.release(local_success); } } - self.destroy(); } - /// Must be called manually before finalization to clean up + /// must be called manually before finalization to clean up /// thread-local resources. Some of the routines here expect /// Task to be available recursively so this must be /// called unsafely, without removing Task from @@ -87,8 +109,8 @@ impl Task { fn destroy(&mut self) { // This is just an assertion that `destroy` was called unsafely // and this instance of Task is still accessible. - do Local::borrow::<Task> |task| { - assert!(ptr::ref_eq(task, self)); + do Local::borrow::<Task, ()> |task| { + assert!(borrow::ref_eq(task, self)); } match self.storage { LocalStorage(ptr, Some(ref dtor)) => { @@ -225,5 +247,14 @@ mod test { assert!(port.recv() == 10); } } -} + #[test] + fn linked_failure() { + do run_in_newsched_task() { + let res = do spawntask_try { + spawntask_random(|| fail!()); + }; + assert!(res.is_err()); + } + } +} diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index c8df3a61203..6e4fb9b1d94 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -13,11 +13,12 @@ use option::{Some, None}; use cell::Cell; use clone::Clone; use container::Container; -use old_iter::MutableIter; -use vec::OwnedVector; +use iterator::IteratorUtil; +use vec::{OwnedVector, MutableVector}; use result::{Result, Ok, Err}; use unstable::run_in_bare_thread; use super::io::net::ip::{IpAddr, Ipv4}; +use rt::comm::oneshot; use rt::task::Task; use rt::thread::Thread; use rt::local::Local; @@ -43,12 +44,15 @@ pub fn run_in_newsched_task(f: ~fn()) { use super::sched::*; use unstable::run_in_bare_thread; - let f = Cell(f); + let f = Cell::new(f); do run_in_bare_thread { let mut sched = ~new_test_uv_sched(); + let mut new_task = ~Task::new_root(); + let on_exit: ~fn(bool) = |exit_status| rtassert!(exit_status); + new_task.on_exit = Some(on_exit); let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), + new_task, f.take()); sched.enqueue_task(task); sched.run(); @@ -65,7 +69,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { use rt::uv::uvio::UvEventLoop; use rt::sched::Shutdown; - let f_cell = Cell(f); + let f_cell = Cell::new(f); do run_in_bare_thread { let nthreads = match os::getenv("RUST_TEST_THREADS") { @@ -88,37 +92,152 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { let loop_ = ~UvEventLoop::new(); let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone()); let handle = sched.make_handle(); + handles.push(handle); scheds.push(sched); } - let f_cell = Cell(f_cell.take()); - let handles = Cell(handles); - let main_task = ~do Coroutine::new(&mut scheds[0].stack_pool) { - f_cell.take()(); + let f_cell = Cell::new(f_cell.take()); + let handles = Cell::new(handles); + let mut new_task = ~Task::new_root(); + let on_exit: ~fn(bool) = |exit_status| { let mut handles = handles.take(); // Tell schedulers to exit - for handles.each_mut |handle| { + for handles.mut_iter().advance |handle| { handle.send(Shutdown); } + + rtassert!(exit_status); + }; + new_task.on_exit = Some(on_exit); + let main_task = ~Coroutine::with_task(&mut scheds[0].stack_pool, + new_task, f_cell.take()); + scheds[0].enqueue_task(main_task); + + let mut threads = ~[]; + + while !scheds.is_empty() { + let sched = scheds.pop(); + let sched_cell = Cell::new(sched); + let thread = do Thread::start { + let sched = sched_cell.take(); + sched.run(); + }; + + threads.push(thread); + } + + // Wait for schedulers + let _threads = threads; + } + + extern { + fn rust_get_num_cpus() -> libc::uintptr_t; + } +} + +// THIS IS AWFUL. Copy-pasted the above initialization function but +// with a number of hacks to make it spawn tasks on a variety of +// schedulers with a variety of homes using the new spawn. + +pub fn run_in_mt_newsched_task_random_homed() { + use libc; + use os; + use from_str::FromStr; + use rt::uv::uvio::UvEventLoop; + use rt::sched::Shutdown; + + do run_in_bare_thread { + let nthreads = match os::getenv("RUST_TEST_THREADS") { + Some(nstr) => FromStr::from_str(nstr).get(), + None => unsafe { + // Using more threads than cores in test code to force + // the OS to preempt them frequently. Assuming that + // this help stress test concurrent types. + rust_get_num_cpus() * 2 + } }; + let sleepers = SleeperList::new(); + let work_queue = WorkQueue::new(); + + let mut handles = ~[]; + let mut scheds = ~[]; + + // create a few special schedulers, those with even indicies + // will be pinned-only + for uint::range(0, nthreads) |i| { + let special = (i % 2) == 0; + let loop_ = ~UvEventLoop::new(); + let mut sched = ~Scheduler::new_special( + loop_, work_queue.clone(), sleepers.clone(), special); + let handle = sched.make_handle(); + handles.push(handle); + scheds.push(sched); + } + + // Schedule a pile o tasks + let n = 5*stress_factor(); + for uint::range(0,n) |_i| { + rtdebug!("creating task: %u", _i); + let hf: ~fn() = || { assert!(true) }; + spawntask_homed(&mut scheds, hf); + } + + // Now we want another pile o tasks that do not ever run on a + // special scheduler, because they are normal tasks. Because + // we can we put these in the "main" task. + + let n = 5*stress_factor(); + + let f: ~fn() = || { + for uint::range(0,n) |_| { + let f: ~fn() = || { + // Borrow the scheduler we run on and check if it is + // privileged. + do Local::borrow::<Scheduler,()> |sched| { + assert!(sched.run_anything); + }; + }; + spawntask_random(f); + }; + }; + + let f_cell = Cell::new(f); + let handles = Cell::new(handles); + + rtdebug!("creating main task"); + + let main_task = ~do Coroutine::new_root(&mut scheds[0].stack_pool) { + f_cell.take()(); + let mut handles = handles.take(); + // Tell schedulers to exit + for handles.mut_iter().advance |handle| { + handle.send(Shutdown); + } + }; + + rtdebug!("queuing main task") + scheds[0].enqueue_task(main_task); let mut threads = ~[]; while !scheds.is_empty() { let sched = scheds.pop(); - let sched_cell = Cell(sched); + let sched_cell = Cell::new(sched); let thread = do Thread::start { let sched = sched_cell.take(); + rtdebug!("running sched: %u", sched.sched_id()); sched.run(); }; threads.push(thread); } + rtdebug!("waiting on scheduler threads"); + // Wait for schedulers let _threads = threads; } @@ -128,25 +247,34 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { } } + /// Test tasks will abort on failure instead of unwinding pub fn spawntask(f: ~fn()) { use super::sched::*; + rtdebug!("spawntask taking the scheduler from TLS") + let task = do Local::borrow::<Task, ~Task>() |running_task| { + ~running_task.new_child() + }; + let mut sched = Local::take::<Scheduler>(); let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - sched.schedule_new_task(task); + task, f); + rtdebug!("spawntask scheduling the new task"); + sched.schedule_task(task); } /// Create a new task and run it right now. Aborts on failure pub fn spawntask_immediately(f: ~fn()) { use super::sched::*; + let task = do Local::borrow::<Task, ~Task>() |running_task| { + ~running_task.new_child() + }; + let mut sched = Local::take::<Scheduler>(); let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); + task, f); do sched.switch_running_tasks_and_then(task) |sched, task| { sched.enqueue_task(task); } @@ -156,10 +284,13 @@ pub fn spawntask_immediately(f: ~fn()) { pub fn spawntask_later(f: ~fn()) { use super::sched::*; + let task = do Local::borrow::<Task, ~Task>() |running_task| { + ~running_task.new_child() + }; + let mut sched = Local::take::<Scheduler>(); let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); + task, f); sched.enqueue_task(task); Local::put(sched); @@ -170,13 +301,16 @@ pub fn spawntask_random(f: ~fn()) { use super::sched::*; use rand::{Rand, rng}; - let mut rng = rng(); - let run_now: bool = Rand::rand(&mut rng); + let task = do Local::borrow::<Task, ~Task>() |running_task| { + ~running_task.new_child() + }; let mut sched = Local::take::<Scheduler>(); let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); + task, f); + + let mut rng = rng(); + let run_now: bool = Rand::rand(&mut rng); if run_now { do sched.switch_running_tasks_and_then(task) |sched, task| { @@ -188,52 +322,75 @@ pub fn spawntask_random(f: ~fn()) { } } +/// Spawn a task, with the current scheduler as home, and queue it to +/// run later. +pub fn spawntask_homed(scheds: &mut ~[~Scheduler], f: ~fn()) { + use super::sched::*; + use rand::{rng, RngUtil}; + let mut rng = rng(); + + let task = { + let sched = &mut scheds[rng.gen_int_range(0,scheds.len() as int)]; + let handle = sched.make_handle(); + let home_id = handle.sched_id; + + // now that we know where this is going, build a new function + // that can assert it is in the right place + let af: ~fn() = || { + do Local::borrow::<Scheduler,()>() |sched| { + rtdebug!("home_id: %u, runtime loc: %u", + home_id, + sched.sched_id()); + assert!(home_id == sched.sched_id()); + }; + f() + }; + + ~Coroutine::with_task_homed(&mut sched.stack_pool, + ~Task::new_root(), + af, + Sched(handle)) + }; + let dest_sched = &mut scheds[rng.gen_int_range(0,scheds.len() as int)]; + // enqueue it for future execution + dest_sched.enqueue_task(task); +} /// Spawn a task and wait for it to finish, returning whether it completed successfully or failed pub fn spawntask_try(f: ~fn()) -> Result<(), ()> { use cell::Cell; use super::sched::*; - use task; - use unstable::finally::Finally; - - // Our status variables will be filled in from the scheduler context - let mut failed = false; - let failed_ptr: *mut bool = &mut failed; - - // Switch to the scheduler - let f = Cell(Cell(f)); - let sched = Local::take::<Scheduler>(); - do sched.deschedule_running_task_and_then() |sched, old_task| { - let old_task = Cell(old_task); - let f = f.take(); - let new_task = ~do Coroutine::new(&mut sched.stack_pool) { - do (|| { - (f.take())() - }).finally { - // Check for failure then resume the parent task - unsafe { *failed_ptr = task::failing(); } - let sched = Local::take::<Scheduler>(); - do sched.switch_running_tasks_and_then(old_task.take()) |sched, new_task| { - sched.enqueue_task(new_task); - } - } - }; - sched.enqueue_task(new_task); + let (port, chan) = oneshot(); + let chan = Cell::new(chan); + let mut new_task = ~Task::new_root(); + let on_exit: ~fn(bool) = |exit_status| chan.take().send(exit_status); + new_task.on_exit = Some(on_exit); + let mut sched = Local::take::<Scheduler>(); + let new_task = ~Coroutine::with_task(&mut sched.stack_pool, + new_task, f); + do sched.switch_running_tasks_and_then(new_task) |sched, old_task| { + sched.enqueue_task(old_task); } - if !failed { Ok(()) } else { Err(()) } + let exit_status = port.recv(); + if exit_status { Ok(()) } else { Err(()) } } // Spawn a new task in a new scheduler and return a thread handle. pub fn spawntask_thread(f: ~fn()) -> Thread { use rt::sched::*; - let f = Cell(f); + let task = do Local::borrow::<Task, ~Task>() |running_task| { + ~running_task.new_child() + }; + + let task = Cell::new(task); + let f = Cell::new(f); let thread = do Thread::start { let mut sched = ~new_test_uv_sched(); let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), + task.take(), f.take()); sched.enqueue_task(task); sched.run(); @@ -265,4 +422,3 @@ pub fn stress_factor() -> uint { None => 1 } } - diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index 0f1ae09bd94..bc290191310 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -19,8 +19,8 @@ pub struct Thread { raw_thread: *raw_thread } -pub impl Thread { - fn start(main: ~fn()) -> Thread { +impl Thread { + pub fn start(main: ~fn()) -> Thread { fn substart(main: &~fn()) -> *raw_thread { unsafe { rust_raw_thread_start(main) } } diff --git a/src/libstd/rt/tube.rs b/src/libstd/rt/tube.rs index 4482a92d916..89f3d10b5e4 100644 --- a/src/libstd/rt/tube.rs +++ b/src/libstd/rt/tube.rs @@ -105,7 +105,7 @@ mod test { do run_in_newsched_task { let mut tube: Tube<int> = Tube::new(); let tube_clone = tube.clone(); - let tube_clone_cell = Cell(tube_clone); + let tube_clone_cell = Cell::new(tube_clone); let sched = Local::take::<Scheduler>(); do sched.deschedule_running_task_and_then |sched, task| { let mut tube_clone = tube_clone_cell.take(); @@ -122,10 +122,10 @@ mod test { do run_in_newsched_task { let mut tube: Tube<int> = Tube::new(); let tube_clone = tube.clone(); - let tube_clone = Cell(tube_clone); + let tube_clone = Cell::new(tube_clone); let sched = Local::take::<Scheduler>(); do sched.deschedule_running_task_and_then |sched, task| { - let tube_clone = Cell(tube_clone.take()); + let tube_clone = Cell::new(tube_clone.take()); do sched.event_loop.callback { let mut tube_clone = tube_clone.take(); // The task should be blocked on this now and @@ -146,7 +146,7 @@ mod test { do run_in_newsched_task { let mut tube: Tube<int> = Tube::new(); let tube_clone = tube.clone(); - let tube_clone = Cell(tube_clone); + let tube_clone = Cell::new(tube_clone); let sched = Local::take::<Scheduler>(); do sched.deschedule_running_task_and_then |sched, task| { callback_send(tube_clone.take(), 0); @@ -154,8 +154,8 @@ mod test { fn callback_send(tube: Tube<int>, i: int) { if i == 100 { return; } - let tube = Cell(Cell(tube)); - do Local::borrow::<Scheduler> |sched| { + let tube = Cell::new(Cell::new(tube)); + do Local::borrow::<Scheduler, ()> |sched| { let tube = tube.take(); do sched.event_loop.callback { let mut tube = tube.take(); diff --git a/src/libstd/rt/uv/async.rs b/src/libstd/rt/uv/async.rs index 6ed06cc10b7..f3d1024024f 100644 --- a/src/libstd/rt/uv/async.rs +++ b/src/libstd/rt/uv/async.rs @@ -93,7 +93,7 @@ mod test { do run_in_bare_thread { let mut loop_ = Loop::new(); let watcher = AsyncWatcher::new(&mut loop_, |w, _| w.close(||()) ); - let watcher_cell = Cell(watcher); + let watcher_cell = Cell::new(watcher); let _thread = do Thread::start { let mut watcher = watcher_cell.take(); watcher.send(); diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs index a81ab48696a..a3630c9b9bf 100644 --- a/src/libstd/rt/uv/idle.rs +++ b/src/libstd/rt/uv/idle.rs @@ -17,8 +17,8 @@ use rt::uv::status_to_maybe_uv_error; pub struct IdleWatcher(*uvll::uv_idle_t); impl Watcher for IdleWatcher { } -pub impl IdleWatcher { - fn new(loop_: &mut Loop) -> IdleWatcher { +impl IdleWatcher { + pub fn new(loop_: &mut Loop) -> IdleWatcher { unsafe { let handle = uvll::idle_new(); assert!(handle.is_not_null()); @@ -29,7 +29,7 @@ pub impl IdleWatcher { } } - fn start(&mut self, cb: IdleCallback) { + pub fn start(&mut self, cb: IdleCallback) { { let data = self.get_watcher_data(); data.idle_cb = Some(cb); @@ -48,16 +48,17 @@ pub impl IdleWatcher { } } - fn stop(&mut self) { - // NB: Not resetting the Rust idle_cb to None here because `stop` is likely - // called from *within* the idle callback, causing a use after free + pub fn stop(&mut self) { + // NB: Not resetting the Rust idle_cb to None here because `stop` is + // likely called from *within* the idle callback, causing a use after + // free unsafe { assert!(0 == uvll::idle_stop(self.native_handle())); } } - fn close(self, cb: NullCallback) { + pub fn close(self, cb: NullCallback) { { let mut this = self; let data = this.get_watcher_data(); diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index f7cc5c6cc8b..a6a8edafe60 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -38,11 +38,9 @@ use container::Container; use option::*; use str::raw::from_c_str; use to_str::ToStr; -use ptr::Ptr; -use libc; +use ptr::RawPtr; use vec; use ptr; -use cast; use str; use libc::{c_void, c_int, size_t, malloc, free}; use cast::transmute; @@ -94,18 +92,18 @@ pub trait NativeHandle<T> { pub fn native_handle(&self) -> T; } -pub impl Loop { - fn new() -> Loop { +impl Loop { + pub fn new() -> Loop { let handle = unsafe { uvll::loop_new() }; assert!(handle.is_not_null()); NativeHandle::from_native_handle(handle) } - fn run(&mut self) { + pub fn run(&mut self) { unsafe { uvll::run(self.native_handle()) }; } - fn close(&mut self) { + pub fn close(&mut self) { unsafe { uvll::loop_delete(self.native_handle()) }; } } @@ -204,9 +202,8 @@ impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W { pub struct UvError(uvll::uv_err_t); -pub impl UvError { - - fn name(&self) -> ~str { +impl UvError { + pub fn name(&self) -> ~str { unsafe { let inner = match self { &UvError(ref a) => a }; let name_str = uvll::err_name(inner); @@ -215,7 +212,7 @@ pub impl UvError { } } - fn desc(&self) -> ~str { + pub fn desc(&self) -> ~str { unsafe { let inner = match self { &UvError(ref a) => a }; let desc_str = uvll::strerror(inner); @@ -224,7 +221,7 @@ pub impl UvError { } } - fn is_eof(&self) -> bool { + pub fn is_eof(&self) -> bool { self.code == uvll::EOF } } @@ -250,20 +247,6 @@ pub fn last_uv_error<H, W: Watcher + NativeHandle<*H>>(watcher: &W) -> UvError { } pub fn uv_error_to_io_error(uverr: UvError) -> IoError { - - // XXX: Could go in str::raw - unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str { - let s = s as *u8; - let mut curr = s, len = 0u; - while *curr != 0u8 { - len += 1u; - curr = ptr::offset(s, len); - } - - str::raw::buf_as_slice(s, len, |d| cast::transmute(d)) - } - - unsafe { // Importing error constants use rt::uv::uvll::*; @@ -271,7 +254,7 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError { // uv error descriptions are static let c_desc = uvll::strerror(&*uverr); - let desc = c_str_to_static_slice(c_desc); + let desc = str::raw::c_str_to_static_slice(c_desc); let kind = match uverr.code { UNKNOWN => OtherIoError, diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 0b77bd83958..5491b82b725 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -51,9 +51,8 @@ pub fn uv_ip4_to_ip4(addr: *sockaddr_in) -> IpAddr { pub struct StreamWatcher(*uvll::uv_stream_t); impl Watcher for StreamWatcher { } -pub impl StreamWatcher { - - fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) { +impl StreamWatcher { + pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) { { let data = self.get_watcher_data(); data.alloc_cb = Some(alloc); @@ -81,7 +80,7 @@ pub impl StreamWatcher { } } - fn read_stop(&mut self) { + pub fn read_stop(&mut self) { // It would be nice to drop the alloc and read callbacks here, // but read_stop may be called from inside one of them and we // would end up freeing the in-use environment @@ -89,7 +88,7 @@ pub impl StreamWatcher { unsafe { uvll::read_stop(handle); } } - fn write(&mut self, buf: Buf, cb: ConnectionCallback) { + pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) { { let data = self.get_watcher_data(); assert!(data.write_cb.is_none()); @@ -118,7 +117,7 @@ pub impl StreamWatcher { } } - fn accept(&mut self, stream: StreamWatcher) { + pub fn accept(&mut self, stream: StreamWatcher) { let self_handle = self.native_handle() as *c_void; let stream_handle = stream.native_handle() as *c_void; unsafe { @@ -126,7 +125,7 @@ pub impl StreamWatcher { } } - fn close(self, cb: NullCallback) { + pub fn close(self, cb: NullCallback) { { let mut this = self; let data = this.get_watcher_data(); @@ -161,8 +160,8 @@ impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher { pub struct TcpWatcher(*uvll::uv_tcp_t); impl Watcher for TcpWatcher { } -pub impl TcpWatcher { - fn new(loop_: &mut Loop) -> TcpWatcher { +impl TcpWatcher { + pub fn new(loop_: &mut Loop) -> TcpWatcher { unsafe { let handle = malloc_handle(UV_TCP); assert!(handle.is_not_null()); @@ -173,7 +172,7 @@ pub impl TcpWatcher { } } - fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { + pub fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { match address { Ipv4(*) => { do ip4_as_uv_ip4(address) |addr| { @@ -191,7 +190,7 @@ pub impl TcpWatcher { } } - fn connect(&mut self, address: IpAddr, cb: ConnectionCallback) { + pub fn connect(&mut self, address: IpAddr, cb: ConnectionCallback) { unsafe { assert!(self.get_watcher_data().connect_cb.is_none()); self.get_watcher_data().connect_cb = Some(cb); @@ -224,7 +223,7 @@ pub impl TcpWatcher { } } - fn listen(&mut self, cb: ConnectionCallback) { + pub fn listen(&mut self, cb: ConnectionCallback) { { let data = self.get_watcher_data(); assert!(data.connect_cb.is_none()); @@ -248,7 +247,7 @@ pub impl TcpWatcher { } } - fn as_stream(&self) -> StreamWatcher { + pub fn as_stream(&self) -> StreamWatcher { NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t) } } @@ -439,9 +438,8 @@ pub struct WriteRequest(*uvll::uv_write_t); impl Request for WriteRequest { } -pub impl WriteRequest { - - fn new() -> WriteRequest { +impl WriteRequest { + pub fn new() -> WriteRequest { let write_handle = unsafe { malloc_req(UV_WRITE) }; @@ -450,14 +448,14 @@ pub impl WriteRequest { WriteRequest(write_handle) } - fn stream(&self) -> StreamWatcher { + pub fn stream(&self) -> StreamWatcher { unsafe { let stream_handle = uvll::get_stream_handle_from_write_req(self.native_handle()); NativeHandle::from_native_handle(stream_handle) } } - fn delete(self) { + pub fn delete(self) { unsafe { free_req(self.native_handle() as *c_void) } } } @@ -554,7 +552,7 @@ mod test { let client_tcp_watcher = TcpWatcher::new(&mut loop_); let mut client_tcp_watcher = client_tcp_watcher.as_stream(); server_stream_watcher.accept(client_tcp_watcher); - let count_cell = Cell(0); + let count_cell = Cell::new(0); let server_stream_watcher = server_stream_watcher; rtdebug!("starting read"); let alloc: AllocCallback = |size| { @@ -594,11 +592,11 @@ mod test { let mut stream_watcher = stream_watcher; let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9]; let buf = slice_to_uv_buf(msg); - let msg_cell = Cell(msg); + let msg_cell = Cell::new(msg); do stream_watcher.write(buf) |stream_watcher, status| { rtdebug!("writing"); assert!(status.is_none()); - let msg_cell = Cell(msg_cell.take()); + let msg_cell = Cell::new(msg_cell.take()); stream_watcher.close(||ignore(msg_cell.take())); } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 1274dbc3220..eba84e537f9 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -11,7 +11,7 @@ use option::*; use result::*; use ops::Drop; -use cell::{Cell, empty_cell}; +use cell::Cell; use cast; use cast::transmute; use clone::Clone; @@ -35,8 +35,8 @@ pub struct UvEventLoop { uvio: UvIoFactory } -pub impl UvEventLoop { - fn new() -> UvEventLoop { +impl UvEventLoop { + pub fn new() -> UvEventLoop { UvEventLoop { uvio: UvIoFactory(Loop::new()) } @@ -54,7 +54,6 @@ impl Drop for UvEventLoop { } impl EventLoop for UvEventLoop { - fn run(&mut self) { self.uvio.uv_loop().run(); } @@ -117,9 +116,11 @@ impl UvRemoteCallback { let async = do AsyncWatcher::new(loop_) |watcher, status| { assert!(status.is_none()); f(); - do exit_flag_clone.with_imm |&should_exit| { - if should_exit { - watcher.close(||()); + unsafe { + do exit_flag_clone.with_imm |&should_exit| { + if should_exit { + watcher.close(||()); + } } } }; @@ -152,7 +153,6 @@ impl Drop for UvRemoteCallback { #[cfg(test)] mod test_remote { - use cell; use cell::Cell; use rt::test::*; use rt::thread::Thread; @@ -166,10 +166,10 @@ mod test_remote { do run_in_newsched_task { let mut tube = Tube::new(); let tube_clone = tube.clone(); - let remote_cell = cell::empty_cell(); - do Local::borrow::<Scheduler>() |sched| { + let remote_cell = Cell::new_empty(); + do Local::borrow::<Scheduler, ()>() |sched| { let tube_clone = tube_clone.clone(); - let tube_clone_cell = Cell(tube_clone); + let tube_clone_cell = Cell::new(tube_clone); let remote = do sched.event_loop.remote_callback { tube_clone_cell.take().send(1); }; @@ -186,8 +186,8 @@ mod test_remote { pub struct UvIoFactory(Loop); -pub impl UvIoFactory { - fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { +impl UvIoFactory { + pub fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { match self { &UvIoFactory(ref mut ptr) => ptr } } } @@ -199,7 +199,7 @@ impl IoFactory for UvIoFactory { fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError> { // Create a cell in the task to hold the result. We will fill // the cell before resuming the task. - let result_cell = empty_cell(); + let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell<Result<~RtioTcpStreamObject, IoError>> = &result_cell; let scheduler = Local::take::<Scheduler>(); @@ -211,7 +211,7 @@ impl IoFactory for UvIoFactory { rtdebug!("connect: entered scheduler context"); assert!(!sched.in_task_context()); let mut tcp_watcher = TcpWatcher::new(self.uv_loop()); - let task_cell = Cell(task); + let task_cell = Cell::new(task); // Wait for a connection do tcp_watcher.connect(addr) |stream_watcher, status| { @@ -228,7 +228,7 @@ impl IoFactory for UvIoFactory { scheduler.resume_task_immediately(task_cell.take()); } else { rtdebug!("status is some"); - let task_cell = Cell(task_cell.take()); + let task_cell = Cell::new(task_cell.take()); do stream_watcher.close { let res = Err(uv_error_to_io_error(status.get())); unsafe { (*result_cell_ptr).put_back(res); } @@ -250,7 +250,7 @@ impl IoFactory for UvIoFactory { Err(uverr) => { let scheduler = Local::take::<Scheduler>(); do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell(task); + let task_cell = Cell::new(task); do watcher.as_stream().close { let scheduler = Local::take::<Scheduler>(); scheduler.resume_task_immediately(task_cell.take()); @@ -286,7 +286,7 @@ impl Drop for UvTcpListener { let watcher = self.watcher(); let scheduler = Local::take::<Scheduler>(); do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell(task); + let task_cell = Cell::new(task); do watcher.as_stream().close { let scheduler = Local::take::<Scheduler>(); scheduler.resume_task_immediately(task_cell.take()); @@ -307,9 +307,9 @@ impl RtioTcpListener for UvTcpListener { self.listening = true; let server_tcp_watcher = self.watcher(); - let incoming_streams_cell = Cell(self.incoming_streams.clone()); + let incoming_streams_cell = Cell::new(self.incoming_streams.clone()); - let incoming_streams_cell = Cell(incoming_streams_cell.take()); + let incoming_streams_cell = Cell::new(incoming_streams_cell.take()); let mut server_tcp_watcher = server_tcp_watcher; do server_tcp_watcher.listen |server_stream_watcher, status| { let maybe_stream = if status.is_none() { @@ -348,7 +348,7 @@ impl Drop for UvTcpStream { let watcher = self.watcher(); let scheduler = Local::take::<Scheduler>(); do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell(task); + let task_cell = Cell::new(task); do watcher.close { let scheduler = Local::take::<Scheduler>(); scheduler.resume_task_immediately(task_cell.take()); @@ -359,7 +359,7 @@ impl Drop for UvTcpStream { impl RtioTcpStream for UvTcpStream { fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> { - let result_cell = empty_cell(); + let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell; let scheduler = Local::take::<Scheduler>(); @@ -370,7 +370,7 @@ impl RtioTcpStream for UvTcpStream { rtdebug!("read: entered scheduler context"); assert!(!sched.in_task_context()); let mut watcher = watcher; - let task_cell = Cell(task); + let task_cell = Cell::new(task); // XXX: We shouldn't reallocate these callbacks every // call to read let alloc: AllocCallback = |_| unsafe { @@ -404,7 +404,7 @@ impl RtioTcpStream for UvTcpStream { } fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { - let result_cell = empty_cell(); + let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell; let scheduler = Local::take::<Scheduler>(); assert!(scheduler.in_task_context()); @@ -412,7 +412,7 @@ impl RtioTcpStream for UvTcpStream { let buf_ptr: *&[u8] = &buf; do scheduler.deschedule_running_task_and_then |_, task| { let mut watcher = watcher; - let task_cell = Cell(task); + let task_cell = Cell::new(task); let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; do watcher.write(buf) |_watcher, status| { let result = if status.is_none() { @@ -585,7 +585,7 @@ fn test_read_and_block() { // will trigger a read callback while we are // not ready for it do scheduler.deschedule_running_task_and_then |sched, task| { - let task = Cell(task); + let task = Cell::new(task); sched.enqueue_task(task.take()); } } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 06315c4cb38..b73db77f3bb 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -31,7 +31,11 @@ use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t}; use libc::{malloc, free}; +use libc; use prelude::*; +use ptr; +use str; +use vec; pub static UNKNOWN: c_int = -1; pub static OK: c_int = 0; diff --git a/src/libstd/rt/work_queue.rs b/src/libstd/rt/work_queue.rs index e9eb663392b..cfffc55a58c 100644 --- a/src/libstd/rt/work_queue.rs +++ b/src/libstd/rt/work_queue.rs @@ -21,40 +21,48 @@ pub struct WorkQueue<T> { priv queue: ~Exclusive<~[T]> } -pub impl<T: Owned> WorkQueue<T> { - fn new() -> WorkQueue<T> { +impl<T: Owned> WorkQueue<T> { + pub fn new() -> WorkQueue<T> { WorkQueue { queue: ~exclusive(~[]) } } - fn push(&mut self, value: T) { - let value = Cell(value); - self.queue.with(|q| q.unshift(value.take()) ); + pub fn push(&mut self, value: T) { + unsafe { + let value = Cell::new(value); + self.queue.with(|q| q.unshift(value.take()) ); + } } - fn pop(&mut self) -> Option<T> { - do self.queue.with |q| { - if !q.is_empty() { - Some(q.shift()) - } else { - None + pub fn pop(&mut self) -> Option<T> { + unsafe { + do self.queue.with |q| { + if !q.is_empty() { + Some(q.shift()) + } else { + None + } } } } - fn steal(&mut self) -> Option<T> { - do self.queue.with |q| { - if !q.is_empty() { - Some(q.pop()) - } else { - None + pub fn steal(&mut self) -> Option<T> { + unsafe { + do self.queue.with |q| { + if !q.is_empty() { + Some(q.pop()) + } else { + None + } } } } - fn is_empty(&self) -> bool { - self.queue.with_imm(|q| q.is_empty() ) + pub fn is_empty(&self) -> bool { + unsafe { + self.queue.with_imm(|q| q.is_empty() ) + } } } diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 3cdc5dcca07..b204cf6cfb0 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -10,11 +10,15 @@ //! Process spawning. +#[allow(missing_doc)]; + +use iterator::IteratorUtil; use cast; +use comm::{stream, SharedChan, GenericChan, GenericPort}; +use int; use io; -use libc; use libc::{pid_t, c_void, c_int}; -use comm::{stream, SharedChan, GenericChan, GenericPort}; +use libc; use option::{Some, None}; use os; use prelude::*; @@ -133,8 +137,7 @@ pub struct ProcessOutput { error: ~[u8], } -pub impl Process { - +impl Process { /** * Spawns a new Process. * @@ -145,8 +148,8 @@ pub impl Process { * * options - Options to configure the environment of the process, * the working directory and the standard IO streams. */ - pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Process { - + pub fn new(prog: &str, args: &[~str], options: ProcessOptions) + -> Process { let (in_pipe, in_fd) = match options.in_fd { None => { let pipe = os::pipe(); @@ -173,9 +176,9 @@ pub impl Process { in_fd, out_fd, err_fd); unsafe { - for in_pipe.each |pipe| { libc::close(pipe.in); } - for out_pipe.each |pipe| { libc::close(pipe.out); } - for err_pipe.each |pipe| { libc::close(pipe.out); } + for in_pipe.iter().advance |pipe| { libc::close(pipe.in); } + for out_pipe.iter().advance |pipe| { libc::close(pipe.out); } + for err_pipe.iter().advance |pipe| { libc::close(pipe.out); } } Process { @@ -189,9 +192,9 @@ pub impl Process { } /// Returns the unique id of the process - fn get_id(&self) -> pid_t { self.pid } + pub fn get_id(&self) -> pid_t { self.pid } - priv fn input_fd(&mut self) -> c_int { + fn input_fd(&mut self) -> c_int { match self.input { Some(fd) => fd, None => fail!("This Process's stdin was redirected to an \ @@ -199,7 +202,7 @@ pub impl Process { } } - priv fn output_file(&mut self) -> *libc::FILE { + fn output_file(&mut self) -> *libc::FILE { match self.output { Some(file) => file, None => fail!("This Process's stdout was redirected to an \ @@ -207,7 +210,7 @@ pub impl Process { } } - priv fn error_file(&mut self) -> *libc::FILE { + fn error_file(&mut self) -> *libc::FILE { match self.error { Some(file) => file, None => fail!("This Process's stderr was redirected to an \ @@ -222,7 +225,7 @@ pub impl Process { * * If this method returns true then self.input() will fail. */ - fn input_redirected(&self) -> bool { + pub fn input_redirected(&self) -> bool { self.input.is_none() } @@ -233,7 +236,7 @@ pub impl Process { * * If this method returns true then self.output() will fail. */ - fn output_redirected(&self) -> bool { + pub fn output_redirected(&self) -> bool { self.output.is_none() } @@ -244,7 +247,7 @@ pub impl Process { * * If this method returns true then self.error() will fail. */ - fn error_redirected(&self) -> bool { + pub fn error_redirected(&self) -> bool { self.error.is_none() } @@ -253,7 +256,7 @@ pub impl Process { * * Fails if this Process's stdin was redirected to an existing file descriptor. */ - fn input(&mut self) -> @io::Writer { + pub fn input(&mut self) -> @io::Writer { // FIXME: the Writer can still be used after self is destroyed: #2625 io::fd_writer(self.input_fd(), false) } @@ -263,7 +266,7 @@ pub impl Process { * * Fails if this Process's stdout was redirected to an existing file descriptor. */ - fn output(&mut self) -> @io::Reader { + pub fn output(&mut self) -> @io::Reader { // FIXME: the Reader can still be used after self is destroyed: #2625 io::FILE_reader(self.output_file(), false) } @@ -273,7 +276,7 @@ pub impl Process { * * Fails if this Process's stderr was redirected to an existing file descriptor. */ - fn error(&mut self) -> @io::Reader { + pub fn error(&mut self) -> @io::Reader { // FIXME: the Reader can still be used after self is destroyed: #2625 io::FILE_reader(self.error_file(), false) } @@ -284,7 +287,7 @@ pub impl Process { * If this process is reading its stdin from an existing file descriptor, then this * method does nothing. */ - fn close_input(&mut self) { + pub fn close_input(&mut self) { match self.input { Some(-1) | None => (), Some(fd) => { @@ -296,7 +299,7 @@ pub impl Process { } } - priv fn close_outputs(&mut self) { + fn close_outputs(&mut self) { fclose_and_null(&mut self.output); fclose_and_null(&mut self.error); @@ -319,8 +322,8 @@ pub impl Process { * * If the child has already been finished then the exit code is returned. */ - fn finish(&mut self) -> int { - for self.exit_code.each |&code| { + pub fn finish(&mut self) -> int { + for self.exit_code.iter().advance |&code| { return code; } self.close_input(); @@ -339,8 +342,7 @@ pub impl Process { * This method will fail if the child process's stdout or stderr streams were * redirected to existing file descriptors. */ - fn finish_with_output(&mut self) -> ProcessOutput { - + pub fn finish_with_output(&mut self) -> ProcessOutput { let output_file = self.output_file(); let error_file = self.error_file(); @@ -375,8 +377,7 @@ pub impl Process { error: errs}; } - priv fn destroy_internal(&mut self, force: bool) { - + fn destroy_internal(&mut self, force: bool) { // if the process has finished, and therefore had waitpid called, // and we kill it, then on unix we might ending up killing a // newer process that happens to have the same (re-used) id @@ -414,7 +415,7 @@ pub impl Process { * On Posix OSs SIGTERM will be sent to the process. On Win32 * TerminateProcess(..) will be called. */ - fn destroy(&mut self) { self.destroy_internal(false); } + pub fn destroy(&mut self) { self.destroy_internal(false); } /** * Terminates the process as soon as possible without giving it a @@ -423,12 +424,12 @@ pub impl Process { * On Posix OSs SIGKILL will be sent to the process. On Win32 * TerminateProcess(..) will be called. */ - fn force_destroy(&mut self) { self.destroy_internal(true); } + pub fn force_destroy(&mut self) { self.destroy_internal(true); } } impl Drop for Process { fn finalize(&self) { - // FIXME #4943: transmute is bad. + // FIXME(#4330) Need self by value to get mutability. let mut_self: &mut Process = unsafe { cast::transmute(self) }; mut_self.finish(); @@ -463,6 +464,9 @@ fn spawn_process_os(prog: &str, args: &[~str], }; use libc::funcs::extra::msvcrt::get_osfhandle; + use sys; + use uint; + unsafe { let mut si = zeroed_startupinfo(); @@ -519,7 +523,7 @@ fn spawn_process_os(prog: &str, args: &[~str], CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); - for create_err.each |msg| { + for create_err.iter().advance |msg| { fail!("failure in CreateProcess: %s", *msg); } @@ -574,6 +578,8 @@ fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMA #[cfg(windows)] pub fn make_command_line(prog: &str, args: &[~str]) -> ~str { + use uint; + let mut cmd = ~""; append_arg(&mut cmd, prog); for args.each |arg| { @@ -583,7 +589,7 @@ pub fn make_command_line(prog: &str, args: &[~str]) -> ~str { return cmd; fn append_arg(cmd: &mut ~str, arg: &str) { - let quote = arg.any(|c| c == ' ' || c == '\t'); + let quote = arg.iter().any_(|c| c == ' ' || c == '\t'); if quote { cmd.push_char('"'); } @@ -735,8 +741,7 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T { let mut blk = ~[]; for es.each |&(k, v)| { let kv = fmt!("%s=%s", k, v); - blk.push_all(str::as_bytes_slice(kv)); - blk.push(0); + blk.push_all(kv.as_bytes_with_null_consume()); } blk.push(0); vec::as_imm_buf(blk, |p, _len| @@ -1095,28 +1100,34 @@ mod tests { #[test] fn test_keep_current_working_dir() { - let mut prog = run_pwd(None); let output = str::from_bytes(prog.finish_with_output().output); let parent_dir = os::getcwd().normalize(); let child_dir = Path(output.trim()).normalize(); - assert_eq!(child_dir.to_str(), parent_dir.to_str()); + let parent_stat = parent_dir.stat().unwrap(); + let child_stat = child_dir.stat().unwrap(); + + assert_eq!(parent_stat.st_dev, child_stat.st_dev); + assert_eq!(parent_stat.st_ino, child_stat.st_ino); } #[test] fn test_change_working_directory() { - // test changing to the parent of os::getcwd() because we know // the path exists (and os::getcwd() is not expected to be root) - let parent_path = os::getcwd().dir_path().normalize(); - let mut prog = run_pwd(Some(&parent_path)); + let parent_dir = os::getcwd().dir_path().normalize(); + let mut prog = run_pwd(Some(&parent_dir)); let output = str::from_bytes(prog.finish_with_output().output); let child_dir = Path(output.trim()).normalize(); - assert_eq!(child_dir.to_str(), parent_path.to_str()); + let parent_stat = parent_dir.stat().unwrap(); + let child_stat = child_dir.stat().unwrap(); + + assert_eq!(parent_stat.st_dev, child_stat.st_dev); + assert_eq!(parent_stat.st_ino, child_stat.st_ino); } #[cfg(unix)] diff --git a/src/libstd/stackwalk.rs b/src/libstd/stackwalk.rs index a22599e9fc6..c3e3ca57a8e 100644 --- a/src/libstd/stackwalk.rs +++ b/src/libstd/stackwalk.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(missing_doc)]; + use cast::transmute; use unstable::intrinsics; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 349a848e2c7..1086fcaa75c 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -21,25 +21,32 @@ use at_vec; use cast::transmute; use cast; use char; +use char::Char; use clone::Clone; use cmp::{TotalOrd, Ordering, Less, Equal, Greater}; use container::Container; use iter::Times; -use iterator::Iterator; +use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator}; use libc; use option::{None, Option, Some}; use old_iter::{BaseIter, EqIter}; use ptr; -use ptr::Ptr; -use str; +use ptr::RawPtr; use to_str::ToStr; use uint; use vec; -use vec::{OwnedVector, OwnedCopyableVector}; +use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector}; #[cfg(not(test))] use cmp::{Eq, Ord, Equiv, TotalEq}; /* +Section: Conditions +*/ +condition! { + not_utf8: (~str) -> ~str; +} + +/* Section: Creating a string */ @@ -48,11 +55,20 @@ Section: Creating a string * * # Failure * - * Fails if invalid UTF-8 + * Raises the `not_utf8` condition if invalid UTF-8 */ -pub fn from_bytes(vv: &const [u8]) -> ~str { - assert!(is_utf8(vv)); - return unsafe { raw::from_bytes(vv) }; + +pub fn from_bytes(vv: &[u8]) -> ~str { + use str::not_utf8::cond; + + if !is_utf8(vv) { + let first_bad_byte = vec::find(vv, |b| !is_utf8([*b])).get(); + cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u", + first_bad_byte as uint)) + } + else { + return unsafe { raw::from_bytes(vv) } + } } /** @@ -72,6 +88,16 @@ pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str { return unsafe { raw::from_bytes_with_null(vv) }; } +/** + * Converts a vector to a string slice without performing any allocations. + * + * Once the slice has been validated as utf-8, it is transmuted in-place and + * returned as a '&str' instead of a '&[u8]' + * + * # Failure + * + * Fails if invalid UTF-8 + */ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { unsafe { assert!(is_utf8(vector)); @@ -84,7 +110,7 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { /// Copy a slice into a new unique str #[inline(always)] pub fn to_owned(s: &str) -> ~str { - unsafe { raw::slice_bytes_owned(s, 0, len(s)) } + unsafe { raw::slice_bytes_owned(s, 0, s.len()) } } impl ToStr for ~str { @@ -112,644 +138,266 @@ pub fn from_byte(b: u8) -> ~str { unsafe { ::cast::transmute(~[b, 0u8]) } } -/// Appends a character at the end of a string -pub fn push_char(s: &mut ~str, ch: char) { - unsafe { - let code = ch as uint; - let nb = if code < max_one_b { 1u } - else if code < max_two_b { 2u } - else if code < max_three_b { 3u } - else if code < max_four_b { 4u } - else if code < max_five_b { 5u } - else { 6u }; - let len = len(*s); - let new_len = len + nb; - reserve_at_least(&mut *s, new_len); - let off = len; - do as_buf(*s) |buf, _len| { - let buf: *mut u8 = ::cast::transmute(buf); - match nb { - 1u => { - *ptr::mut_offset(buf, off) = code as u8; - } - 2u => { - *ptr::mut_offset(buf, off) = (code >> 6u & 31u | tag_two_b) as u8; - *ptr::mut_offset(buf, off + 1u) = (code & 63u | tag_cont) as u8; - } - 3u => { - *ptr::mut_offset(buf, off) = (code >> 12u & 15u | tag_three_b) as u8; - *ptr::mut_offset(buf, off + 1u) = (code >> 6u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 2u) = (code & 63u | tag_cont) as u8; - } - 4u => { - *ptr::mut_offset(buf, off) = (code >> 18u & 7u | tag_four_b) as u8; - *ptr::mut_offset(buf, off + 1u) = (code >> 12u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 2u) = (code >> 6u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 3u) = (code & 63u | tag_cont) as u8; - } - 5u => { - *ptr::mut_offset(buf, off) = (code >> 24u & 3u | tag_five_b) as u8; - *ptr::mut_offset(buf, off + 1u) = (code >> 18u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 2u) = (code >> 12u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 3u) = (code >> 6u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 4u) = (code & 63u | tag_cont) as u8; - } - 6u => { - *ptr::mut_offset(buf, off) = (code >> 30u & 1u | tag_six_b) as u8; - *ptr::mut_offset(buf, off + 1u) = (code >> 24u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 2u) = (code >> 18u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 3u) = (code >> 12u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 4u) = (code >> 6u & 63u | tag_cont) as u8; - *ptr::mut_offset(buf, off + 5u) = (code & 63u | tag_cont) as u8; - } - _ => {} - } - } - raw::set_len(s, new_len); - } -} - /// Convert a char to a string pub fn from_char(ch: char) -> ~str { let mut buf = ~""; - push_char(&mut buf, ch); + buf.push_char(ch); buf } /// Convert a vector of chars to a string pub fn from_chars(chs: &[char]) -> ~str { let mut buf = ~""; - reserve(&mut buf, chs.len()); + buf.reserve(chs.len()); for chs.each |ch| { - push_char(&mut buf, *ch); + buf.push_char(*ch) } buf } -/// Appends a string slice to the back of a string, without overallocating -#[inline(always)] -pub fn push_str_no_overallocate(lhs: &mut ~str, rhs: &str) { - unsafe { - let llen = lhs.len(); - let rlen = rhs.len(); - reserve(&mut *lhs, llen + rlen); - do as_buf(*lhs) |lbuf, _llen| { - do as_buf(rhs) |rbuf, _rlen| { - let dst = ptr::offset(lbuf, llen); - let dst = ::cast::transmute_mut_unsafe(dst); - ptr::copy_memory(dst, rbuf, rlen); - } - } - raw::set_len(lhs, llen + rlen); - } -} - -/// Appends a string slice to the back of a string -#[inline(always)] +#[doc(hidden)] pub fn push_str(lhs: &mut ~str, rhs: &str) { - unsafe { - let llen = lhs.len(); - let rlen = rhs.len(); - reserve_at_least(&mut *lhs, llen + rlen); - do as_buf(*lhs) |lbuf, _llen| { - do as_buf(rhs) |rbuf, _rlen| { - let dst = ptr::offset(lbuf, llen); - let dst = ::cast::transmute_mut_unsafe(dst); - ptr::copy_memory(dst, rbuf, rlen); - } - } - raw::set_len(lhs, llen + rlen); - } + lhs.push_str(rhs) } -/// Concatenate two strings together -#[inline(always)] -pub fn append(lhs: ~str, rhs: &str) -> ~str { - let mut v = lhs; - push_str_no_overallocate(&mut v, rhs); - v +#[allow(missing_doc)] +pub trait StrVector { + pub fn concat(&self) -> ~str; + pub fn connect(&self, sep: &str) -> ~str; } -/// Concatenate a vector of strings -pub fn concat(v: &[~str]) -> ~str { - if v.is_empty() { return ~""; } +impl<'self, S: Str> StrVector for &'self [S] { + /// Concatenate a vector of strings. + pub fn concat(&self) -> ~str { + if self.is_empty() { return ~""; } - let mut len = 0; - for v.each |ss| { - len += ss.len(); - } - let mut s = ~""; + let len = self.iter().transform(|s| s.as_slice().len()).sum(); - reserve(&mut s, len); + let mut s = ~""; - unsafe { - do as_buf(s) |buf, _len| { - let mut buf = ::cast::transmute_mut_unsafe(buf); - for v.each |ss| { - do as_buf(*ss) |ssbuf, sslen| { - let sslen = sslen - 1; - ptr::copy_memory(buf, ssbuf, sslen); - buf = buf.offset(sslen); - } - } - } - raw::set_len(&mut s, len); - } - s -} - -/// Concatenate a vector of strings, placing a given separator between each -pub fn connect(v: &[~str], sep: &str) -> ~str { - if v.is_empty() { return ~""; } - - // concat is faster - if sep.is_empty() { return concat(v); } - - // this is wrong without the guarantee that v is non-empty - let mut len = sep.len() * (v.len() - 1); - for v.each |ss| { - len += ss.len(); - } - let mut s = ~"", first = true; + s.reserve(len); - reserve(&mut s, len); - - unsafe { - do as_buf(s) |buf, _len| { - do as_buf(sep) |sepbuf, seplen| { - let seplen = seplen - 1; + unsafe { + do as_buf(s) |buf, _| { let mut buf = ::cast::transmute_mut_unsafe(buf); - for v.each |ss| { - do as_buf(*ss) |ssbuf, sslen| { + for self.iter().advance |ss| { + do as_buf(ss.as_slice()) |ssbuf, sslen| { let sslen = sslen - 1; - if first { - first = false; - } else { - ptr::copy_memory(buf, sepbuf, seplen); - buf = buf.offset(seplen); - } ptr::copy_memory(buf, ssbuf, sslen); buf = buf.offset(sslen); } } } + raw::set_len(&mut s, len); } - raw::set_len(&mut s, len); + s } - s -} -/// Concatenate a vector of strings, placing a given separator between each -pub fn connect_slices(v: &[&str], sep: &str) -> ~str { - if v.is_empty() { return ~""; } + /// Concatenate a vector of strings, placing a given separator between each. + pub fn connect(&self, sep: &str) -> ~str { + if self.is_empty() { return ~""; } - // this is wrong without the guarantee that v is non-empty - let mut len = sep.len() * (v.len() - 1); - for v.each |ss| { - len += ss.len(); - } - let mut s = ~"", first = true; + // concat is faster + if sep.is_empty() { return self.concat(); } - reserve(&mut s, len); + // this is wrong without the guarantee that `self` is non-empty + let len = sep.len() * (self.len() - 1) + + self.iter().transform(|s| s.as_slice().len()).sum(); + let mut s = ~""; + let mut first = true; - unsafe { - do as_buf(s) |buf, _len| { - do as_buf(sep) |sepbuf, seplen| { - let seplen = seplen - 1; - let mut buf = ::cast::transmute_mut_unsafe(buf); - for v.each |ss| { - do as_buf(*ss) |ssbuf, sslen| { - let sslen = sslen - 1; - if first { - first = false; - } else if seplen > 0 { - ptr::copy_memory(buf, sepbuf, seplen); - buf = buf.offset(seplen); + s.reserve(len); + + unsafe { + do as_buf(s) |buf, _| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for self.iter().advance |ss| { + do as_buf(ss.as_slice()) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); } - ptr::copy_memory(buf, ssbuf, sslen); - buf = buf.offset(sslen); } } } + raw::set_len(&mut s, len); } - raw::set_len(&mut s, len); + s } - s } -/// Given a string, make a new string with repeated copies of it -pub fn repeat(ss: &str, nn: uint) -> ~str { - do as_buf(ss) |buf, len| { - let mut ret = ~""; - // ignore the NULL terminator - let len = len - 1; - reserve(&mut ret, nn * len); - - unsafe { - do as_buf(ret) |rbuf, _len| { - let mut rbuf = ::cast::transmute_mut_unsafe(rbuf); - - for nn.times { - ptr::copy_memory(rbuf, buf, len); - rbuf = rbuf.offset(len); - } - } - raw::set_len(&mut ret, nn * len); - } - ret - } -} - -/* -Section: Adding to and removing from a string -*/ - -/** - * Remove the final character from a string and return it - * - * # Failure - * - * If the string does not contain any characters - */ -pub fn pop_char(s: &mut ~str) -> char { - let end = len(*s); - assert!(end > 0u); - let CharRange {ch, next} = char_range_at_reverse(*s, end); - unsafe { raw::set_len(s, next); } - return ch; -} - -/** - * Remove the first character from a string and return it - * - * # Failure - * - * If the string does not contain any characters - */ -pub fn shift_char(s: &mut ~str) -> char { - let CharRange {ch, next} = char_range_at(*s, 0u); - *s = unsafe { raw::slice_bytes_owned(*s, next, len(*s)) }; - return ch; -} - -/** - * Removes the first character from a string slice and returns it. This does - * not allocate a new string; instead, it mutates a slice to point one - * character beyond the character that was shifted. - * - * # Failure - * - * If the string does not contain any characters - */ -#[inline] -pub fn slice_shift_char<'a>(s: &'a str) -> (char, &'a str) { - let CharRange {ch, next} = char_range_at(s, 0u); - let next_s = unsafe { raw::slice_bytes(s, next, len(s)) }; - return (ch, next_s); -} - -/// Prepend a char to a string -pub fn unshift_char(s: &mut ~str, ch: char) { - // This could be more efficient. - let mut new_str = ~""; - new_str.push_char(ch); - new_str.push_str(*s); - *s = new_str; -} - -/** - * Returns a string with leading `chars_to_trim` removed. - * - * # Arguments - * - * * s - A string - * * chars_to_trim - A vector of chars - * - */ -pub fn trim_left_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str { - if chars_to_trim.is_empty() { return s; } - - match find(s, |c| !chars_to_trim.contains(&c)) { - None => "", - Some(first) => unsafe { raw::slice_bytes(s, first, s.len()) } - } -} - -/** - * Returns a string with trailing `chars_to_trim` removed. - * - * # Arguments - * - * * s - A string - * * chars_to_trim - A vector of chars - * - */ -pub fn trim_right_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str { - if chars_to_trim.is_empty() { return s; } - - match rfind(s, |c| !chars_to_trim.contains(&c)) { - None => "", - Some(last) => { - let next = char_range_at(s, last).next; - unsafe { raw::slice_bytes(s, 0u, next) } - } - } -} - -/** - * Returns a string with leading and trailing `chars_to_trim` removed. - * - * # Arguments - * - * * s - A string - * * chars_to_trim - A vector of chars - * - */ -pub fn trim_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str { - trim_left_chars(trim_right_chars(s, chars_to_trim), chars_to_trim) +/// Something that can be used to compare against a character +pub trait CharEq { + /// Determine if the splitter should split at the given character + fn matches(&self, char) -> bool; + /// Indicate if this is only concerned about ASCII characters, + /// which can allow for a faster implementation. + fn only_ascii(&self) -> bool; } +impl CharEq for char { + #[inline(always)] + fn matches(&self, c: char) -> bool { *self == c } -/// Returns a string with leading whitespace removed -pub fn trim_left<'a>(s: &'a str) -> &'a str { - match find(s, |c| !char::is_whitespace(c)) { - None => "", - Some(first) => unsafe { raw::slice_bytes(s, first, len(s)) } - } + fn only_ascii(&self) -> bool { (*self as uint) < 128 } } +impl<'self> CharEq for &'self fn(char) -> bool { + #[inline(always)] + fn matches(&self, c: char) -> bool { (*self)(c) } -/// Returns a string with trailing whitespace removed -pub fn trim_right<'a>(s: &'a str) -> &'a str { - match rfind(s, |c| !char::is_whitespace(c)) { - None => "", - Some(last) => { - let next = char_range_at(s, last).next; - unsafe { raw::slice_bytes(s, 0u, next) } - } - } + fn only_ascii(&self) -> bool { false } } +impl CharEq for extern "Rust" fn(char) -> bool { + #[inline(always)] + fn matches(&self, c: char) -> bool { (*self)(c) } -/// Returns a string with leading and trailing whitespace removed -pub fn trim<'a>(s: &'a str) -> &'a str { trim_left(trim_right(s)) } - -/* -Section: Transforming strings -*/ - -/** - * Converts a string to a unique vector of bytes - * - * The result vector is not null-terminated. - */ -pub fn to_bytes(s: &str) -> ~[u8] { - unsafe { - let mut v: ~[u8] = ::cast::transmute(to_owned(s)); - vec::raw::set_len(&mut v, len(s)); - v - } + fn only_ascii(&self) -> bool { false } } -/// Work with the string as a byte slice, not including trailing null. -#[inline(always)] -pub fn byte_slice<T>(s: &str, f: &fn(v: &[u8]) -> T) -> T { - do as_buf(s) |p,n| { - unsafe { vec::raw::buf_as_slice(p, n-1u, f) } +impl<'self, C: CharEq> CharEq for &'self [C] { + #[inline(always)] + fn matches(&self, c: char) -> bool { + self.iter().any_(|m| m.matches(c)) } -} -/// Work with the string as a byte slice, not including trailing null, without -/// a callback. -#[inline(always)] -pub fn byte_slice_no_callback<'a>(s: &'a str) -> &'a [u8] { - unsafe { - cast::transmute(s) + fn only_ascii(&self) -> bool { + self.iter().all(|m| m.only_ascii()) } } -/// Convert a string to a unique vector of characters -pub fn to_chars(s: &str) -> ~[char] { - let mut buf = ~[]; - for each_char(s) |c| { - buf.push(c); - } - buf -} -/** - * Take a substring of another. - * - * Returns a slice pointing at `n` characters starting from byte offset - * `begin`. - */ -pub fn substr<'a>(s: &'a str, begin: uint, n: uint) -> &'a str { - slice(s, begin, begin + count_bytes(s, begin, n)) -} - -/** - * 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 - */ -pub fn slice<'a>(s: &'a str, begin: uint, end: uint) -> &'a str { - assert!(is_char_boundary(s, begin)); - assert!(is_char_boundary(s, end)); - unsafe { raw::slice_bytes(s, begin, end) } -} - -/// Splits a string into substrings at each occurrence of a given character -pub fn each_split_char<'a>(s: &'a str, sep: char, - it: &fn(&'a str) -> bool) -> bool { - each_split_char_inner(s, sep, len(s), true, true, it) -} - -/// Like `each_split_char`, but a trailing empty string is omitted -pub fn each_split_char_no_trailing<'a>(s: &'a str, - sep: char, - it: &fn(&'a str) -> bool) -> bool { - each_split_char_inner(s, sep, len(s), true, false, it) -} - -/** - * Splits a string into substrings at each occurrence of a given - * character up to 'count' times. - * - * The character must be a valid UTF-8/ASCII character - */ -pub fn each_splitn_char<'a>(s: &'a str, - sep: char, - count: uint, - it: &fn(&'a str) -> bool) -> bool { - each_split_char_inner(s, sep, count, true, true, it) -} - -/// Like `each_split_char`, but omits empty strings -pub fn each_split_char_nonempty<'a>(s: &'a str, - sep: char, - it: &fn(&'a str) -> bool) -> bool { - each_split_char_inner(s, sep, len(s), false, false, it) -} - -fn each_split_char_inner<'a>(s: &'a str, - sep: char, - count: uint, - allow_empty: bool, - allow_trailing_empty: bool, - it: &fn(&'a str) -> bool) -> bool { - if sep < 128u as char { - let b = sep as u8, l = len(s); - let mut done = 0u; - let mut i = 0u, start = 0u; - while i < l && done < count { - if s[i] == b { - if allow_empty || start < i { - if !it( unsafe{ raw::slice_bytes(s, start, i) } ) { - return false; - } +/// An iterator over the substrings of a string, separated by `sep`. +pub struct StrCharSplitIterator<'self,Sep> { + priv string: &'self str, + priv position: uint, + priv sep: Sep, + /// The number of splits remaining + priv count: uint, + /// Whether an empty string at the end is allowed + priv allow_trailing_empty: bool, + priv finished: bool, + priv only_ascii: bool +} + +/// An iterator over the words of a string, separated by an sequence of whitespace +pub type WordIterator<'self> = + FilterIterator<'self, &'self str, + StrCharSplitIterator<'self, extern "Rust" fn(char) -> bool>>; + +impl<'self, Sep: CharEq> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> { + #[inline] + fn next(&mut self) -> Option<&'self str> { + if self.finished { return None } + + let l = self.string.len(); + let start = self.position; + + if self.only_ascii { + // this gives a *huge* speed up for splitting on ASCII + // characters (e.g. '\n' or ' ') + while self.position < l && self.count > 0 { + let byte = self.string[self.position]; + + if self.sep.matches(byte as char) { + let slice = unsafe { raw::slice_bytes(self.string, start, self.position) }; + self.position += 1; + self.count -= 1; + return Some(slice); } - start = i + 1u; - done += 1u; + self.position += 1; + } + } else { + while self.position < l && self.count > 0 { + let CharRange {ch, next} = self.string.char_range_at(self.position); + + if self.sep.matches(ch) { + let slice = unsafe { raw::slice_bytes(self.string, start, self.position) }; + self.position = next; + self.count -= 1; + return Some(slice); + } + self.position = next; } - i += 1u; } - // only slice a non-empty trailing substring - if allow_trailing_empty || start < l { - if !it( unsafe{ raw::slice_bytes(s, start, l) } ) { return false; } + self.finished = true; + if self.allow_trailing_empty || start < l { + Some(unsafe { raw::slice_bytes(self.string, start, l) }) + } else { + None } - return true; } - return each_split_inner(s, |cur| cur == sep, count, - allow_empty, allow_trailing_empty, it) } -/// Splits a string into substrings using a character function -pub fn each_split<'a>(s: &'a str, - sepfn: &fn(char) -> bool, - it: &fn(&'a str) -> bool) -> bool { - each_split_inner(s, sepfn, len(s), true, true, it) +/// An iterator over the start and end indicies of the matches of a +/// substring within a larger string +pub struct StrMatchesIndexIterator<'self> { + priv haystack: &'self str, + priv needle: &'self str, + priv position: uint, } -/// Like `each_split`, but a trailing empty string is omitted -pub fn each_split_no_trailing<'a>(s: &'a str, - sepfn: &fn(char) -> bool, - it: &fn(&'a str) -> bool) -> bool { - each_split_inner(s, sepfn, len(s), true, false, it) +/// An iterator over the substrings of a string separated by a given +/// search string +pub struct StrStrSplitIterator<'self> { + priv it: StrMatchesIndexIterator<'self>, + priv last_end: uint, + priv finished: bool } -/** - * Splits a string into substrings using a character function, cutting at - * most `count` times. - */ -pub fn each_splitn<'a>(s: &'a str, - sepfn: &fn(char) -> bool, - count: uint, - it: &fn(&'a str) -> bool) -> bool { - each_split_inner(s, sepfn, count, true, true, it) -} - -/// Like `each_split`, but omits empty strings -pub fn each_split_nonempty<'a>(s: &'a str, - sepfn: &fn(char) -> bool, - it: &fn(&'a str) -> bool) -> bool { - each_split_inner(s, sepfn, len(s), false, false, it) -} - -fn each_split_inner<'a>(s: &'a str, - sepfn: &fn(cc: char) -> bool, - count: uint, - allow_empty: bool, - allow_trailing_empty: bool, - it: &fn(&'a str) -> bool) -> bool { - let l = len(s); - let mut i = 0u, start = 0u, done = 0u; - while i < l && done < count { - let CharRange {ch, next} = char_range_at(s, i); - if sepfn(ch) { - if allow_empty || start < i { - if !it( unsafe{ raw::slice_bytes(s, start, i) } ) { - return false; +impl<'self> Iterator<(uint, uint)> for StrMatchesIndexIterator<'self> { + #[inline] + fn next(&mut self) -> Option<(uint, uint)> { + // See Issue #1932 for why this is a naive search + let (h_len, n_len) = (self.haystack.len(), self.needle.len()); + let mut (match_start, match_i) = (0, 0); + + while self.position < h_len { + if self.haystack[self.position] == self.needle[match_i] { + if match_i == 0 { match_start = self.position; } + match_i += 1; + self.position += 1; + + if match_i == n_len { + // found a match! + return Some((match_start, self.position)); + } + } else { + // failed match, backtrack + if match_i > 0 { + match_i = 0; + self.position = match_start; } + self.position += 1; } - start = next; - done += 1u; } - i = next; + None } - if allow_trailing_empty || start < l { - if !it( unsafe{ raw::slice_bytes(s, start, l) } ) { return false; } - } - return true; } -// See Issue #1932 for why this is a naive search -fn iter_matches<'a,'b>(s: &'a str, sep: &'b str, - f: &fn(uint, uint) -> bool) -> bool { - let sep_len = len(sep), l = len(s); - assert!(sep_len > 0u); - let mut i = 0u, match_start = 0u, match_i = 0u; - - while i < l { - if s[i] == sep[match_i] { - if match_i == 0u { match_start = i; } - match_i += 1u; - // Found a match - if match_i == sep_len { - if !f(match_start, i + 1u) { return false; } - match_i = 0u; +impl<'self> Iterator<&'self str> for StrStrSplitIterator<'self> { + #[inline] + fn next(&mut self) -> Option<&'self str> { + if self.finished { return None; } + + match self.it.next() { + Some((from, to)) => { + let ret = Some(self.it.haystack.slice(self.last_end, from)); + self.last_end = to; + ret } - i += 1u; - } else { - // Failed match, backtrack - if match_i > 0u { - match_i = 0u; - i = match_start + 1u; - } else { - i += 1u; + None => { + self.finished = true; + Some(self.it.haystack.slice(self.last_end, self.it.haystack.len())) } } } - return true; -} - -fn iter_between_matches<'a,'b>(s: &'a str, - sep: &'b str, - f: &fn(uint, uint) -> bool) -> bool { - let mut last_end = 0u; - for iter_matches(s, sep) |from, to| { - if !f(last_end, from) { return false; } - last_end = to; - } - return f(last_end, len(s)); -} - -/** - * Splits a string into a vector of the substrings separated by a given string - * - * # Example - * - * ~~~ {.rust} - * let mut v = ~[]; - * for each_split_str(".XXX.YYY.", ".") |subs| { v.push(subs); } - * assert!(v == ["", "XXX", "YYY", ""]); - * ~~~ - */ -pub fn each_split_str<'a,'b>(s: &'a str, - sep: &'b str, - it: &fn(&'a str) -> bool) -> bool { - for iter_between_matches(s, sep) |from, to| { - if !it( unsafe { raw::slice_bytes(s, from, to) } ) { return false; } - } - return true; -} - -pub fn each_split_str_nonempty<'a,'b>(s: &'a str, - sep: &'b str, - it: &fn(&'a str) -> bool) -> bool { - for iter_between_matches(s, sep) |from, to| { - if to > from { - if !it( unsafe { raw::slice_bytes(s, from, to) } ) { return false; } - } - } - return true; } /// Levenshtein Distance between two strings @@ -763,12 +411,12 @@ pub fn levdistance(s: &str, t: &str) -> uint { let mut dcol = vec::from_fn(tlen + 1, |x| x); - for s.each_chari |i, sc| { + for s.iter().enumerate().advance |(i, sc)| { let mut current = i; dcol[0] = current + 1; - for t.each_chari |j, tc| { + for t.iter().enumerate().advance |(j, tc)| { let next = dcol[j + 1]; @@ -787,18 +435,11 @@ pub fn levdistance(s: &str, t: &str) -> uint { } /** - * Splits a string into substrings separated by LF ('\n'). - */ -pub fn each_line<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { - each_split_char_no_trailing(s, '\n', it) -} - -/** * Splits a string into substrings separated by LF ('\n') * and/or CR LF ("\r\n") */ pub fn each_line_any<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { - for each_line(s) |s| { + for s.line_iter().advance |s| { let l = s.len(); if l > 0u && s[l - 1u] == '\r' as u8 { if !it( unsafe { raw::slice_bytes(s, 0, l - 1) } ) { return false; } @@ -809,11 +450,6 @@ pub fn each_line_any<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { return true; } -/// Splits a string into substrings separated by whitespace -pub fn each_word<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { - each_split_nonempty(s, char::is_whitespace, it) -} - /** Splits a string into substrings with possibly internal whitespace, * each of them at most `lim` bytes long. The substrings have leading and trailing * whitespace removed, and are only cut at whitespace boundaries. @@ -823,7 +459,7 @@ pub fn each_word<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { * Fails during iteration if the string contains a non-whitespace * sequence longer than the limit. */ -pub fn _each_split_within<'a>(ss: &'a str, +pub 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: @@ -848,9 +484,9 @@ pub fn _each_split_within<'a>(ss: &'a str, let mut state = A; let mut cont = true; - let slice: &fn() = || { cont = it(slice(ss, slice_start, last_end)) }; + let slice: &fn() = || { cont = it(ss.slice(slice_start, last_end)) }; - let machine: &fn(uint, char) -> bool = |i, c| { + let machine: &fn((uint, char)) -> bool = |(i, c)| { let whitespace = if char::is_whitespace(c) { Ws } else { Cr }; let limit = if (i - slice_start + 1) <= lim { UnderLim } else { OverLim }; @@ -861,7 +497,7 @@ pub fn _each_split_within<'a>(ss: &'a str, (B, Cr, UnderLim) => { B } (B, Cr, OverLim) if (i - last_start + 1) > lim => fail!("word starting with %? longer than limit!", - self::slice(ss, last_start, i + 1)), + ss.slice(last_start, i + 1)), (B, Cr, OverLim) => { slice(); slice_start = last_start; B } (B, Ws, UnderLim) => { last_end = i; C } (B, Ws, OverLim) => { last_end = i; slice(); A } @@ -875,49 +511,17 @@ pub fn _each_split_within<'a>(ss: &'a str, cont }; - str::each_chari(ss, machine); + ss.iter().enumerate().advance(machine); // Let the automaton 'run out' by supplying trailing whitespace let mut fake_i = ss.len(); while cont && match state { B | C => true, A => false } { - machine(fake_i, ' '); + machine((fake_i, ' ')); fake_i += 1; } return cont; } -pub fn each_split_within<'a>(ss: &'a str, - lim: uint, - it: &fn(&'a str) -> bool) -> bool { - _each_split_within(ss, lim, it) -} - -/** - * Replace all occurrences of one string with another - * - * # Arguments - * - * * s - The string containing substrings to replace - * * from - The string to replace - * * to - The replacement string - * - * # Return value - * - * The original string with all occurances of `from` replaced with `to` - */ -pub fn replace(s: &str, from: &str, to: &str) -> ~str { - let mut result = ~"", first = true; - for iter_between_matches(s, from) |start, end| { - if first { - first = false; - } else { - push_str(&mut result, to); - } - push_str(&mut result, unsafe{raw::slice_bytes(s, start, end)}); - } - result -} - /* Section: Comparing strings */ @@ -1131,622 +735,48 @@ impl Ord for @str { } #[cfg(not(test))] -impl<'self> Equiv<~str> for &'self str { +impl<'self, S: Str> Equiv<S> for &'self str { + #[inline(always)] + fn equiv(&self, other: &S) -> bool { eq_slice(*self, other.as_slice()) } +} +#[cfg(not(test))] +impl<'self, S: Str> Equiv<S> for @str { + #[inline(always)] + fn equiv(&self, other: &S) -> bool { eq_slice(*self, other.as_slice()) } +} + +#[cfg(not(test))] +impl<'self, S: Str> Equiv<S> for ~str { #[inline(always)] - fn equiv(&self, other: &~str) -> bool { eq_slice(*self, *other) } + fn equiv(&self, other: &S) -> bool { eq_slice(*self, other.as_slice()) } } + /* Section: Iterating through strings */ -/** - * Return true if a predicate matches all characters or if the string - * contains no characters - */ -pub fn all(s: &str, it: &fn(char) -> bool) -> bool { - all_between(s, 0u, len(s), it) -} - -/** - * Return true if a predicate matches any character (and false if it - * matches none or there are no characters) - */ -pub fn any(ss: &str, pred: &fn(char) -> bool) -> bool { - !all(ss, |cc| !pred(cc)) -} - /// Apply a function to each character pub fn map(ss: &str, ff: &fn(char) -> char) -> ~str { let mut result = ~""; - reserve(&mut result, len(ss)); - for ss.each_char |cc| { - str::push_char(&mut result, ff(cc)); + result.reserve(ss.len()); + for ss.iter().advance |cc| { + result.push_char(ff(cc)); } result } -/// Iterate over the bytes in a string -#[inline(always)] -pub fn each(s: &str, it: &fn(u8) -> bool) -> bool { - eachi(s, |_i, b| it(b)) -} - -/// Iterate over the bytes in a string, with indices -#[inline(always)] -pub fn eachi(s: &str, it: &fn(uint, u8) -> bool) -> bool { - let mut pos = 0; - let len = s.len(); - - while pos < len { - if !it(pos, s[pos]) { return false; } - pos += 1; - } - return true; -} - -/// Iterate over the bytes in a string in reverse -#[inline(always)] -pub fn each_reverse(s: &str, it: &fn(u8) -> bool) -> bool { - eachi_reverse(s, |_i, b| it(b) ) -} - -/// Iterate over the bytes in a string in reverse, with indices -#[inline(always)] -pub fn eachi_reverse(s: &str, it: &fn(uint, u8) -> bool) -> bool { - let mut pos = s.len(); - while pos > 0 { - pos -= 1; - if !it(pos, s[pos]) { return false; } - } - return true; -} - -/// Iterate over each char of a string, without allocating -#[inline(always)] -pub fn each_char(s: &str, it: &fn(char) -> bool) -> bool { - let mut i = 0; - let len = len(s); - while i < len { - let CharRange {ch, next} = char_range_at(s, i); - if !it(ch) { return false; } - i = next; - } - return true; -} - -/// Iterates over the chars in a string, with indices -#[inline(always)] -pub fn each_chari(s: &str, it: &fn(uint, char) -> bool) -> bool { - let mut pos = 0; - let mut ch_pos = 0u; - let len = s.len(); - while pos < len { - let CharRange {ch, next} = char_range_at(s, pos); - pos = next; - if !it(ch_pos, ch) { return false; } - ch_pos += 1u; - } - return true; -} - -/// Iterates over the chars in a string in reverse -#[inline(always)] -pub fn each_char_reverse(s: &str, it: &fn(char) -> bool) -> bool { - each_chari_reverse(s, |_, c| it(c)) -} - -// Iterates over the chars in a string in reverse, with indices -#[inline(always)] -pub fn each_chari_reverse(s: &str, it: &fn(uint, char) -> bool) -> bool { - let mut pos = s.len(); - let mut ch_pos = s.char_len(); - while pos > 0 { - let CharRange {ch, next} = char_range_at_reverse(s, pos); - pos = next; - ch_pos -= 1; - - if !it(ch_pos, ch) { return false; } - } - return true; -} - /* Section: Searching */ -/** - * Returns the byte index of the first matching character - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - */ -pub fn find_char(s: &str, c: char) -> Option<uint> { - find_char_between(s, c, 0u, len(s)) -} - -/** - * Returns the byte index of the first matching character beginning - * from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, inclusive - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `len(s)`. `start` must be the - * index of a character boundary, as defined by `is_char_boundary`. - */ -pub fn find_char_from(s: &str, c: char, start: uint) -> Option<uint> { - find_char_between(s, c, start, len(s)) -} - -/** - * Returns the byte index of the first matching character within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, inclusive - * * `end` - The byte index to end searching at, exclusive - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `end` and `end` must be less than - * or equal to `len(s)`. `start` must be the index of a character boundary, - * as defined by `is_char_boundary`. - */ -pub fn find_char_between(s: &str, c: char, start: uint, end: uint) - -> Option<uint> { - if c < 128u as char { - assert!(start <= end); - assert!(end <= len(s)); - let mut i = start; - let b = c as u8; - while i < end { - if s[i] == b { return Some(i); } - i += 1u; - } - return None; - } else { - find_between(s, start, end, |x| x == c) - } -} - -/** - * Returns the byte index of the last matching character - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - */ -pub fn rfind_char(s: &str, c: char) -> Option<uint> { - rfind_char_between(s, c, len(s), 0u) -} - -/** - * Returns the byte index of the last matching character beginning - * from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, exclusive - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `len(s)`. `start` must be - * the index of a character boundary, as defined by `is_char_boundary`. - */ -pub fn rfind_char_from(s: &str, c: char, start: uint) -> Option<uint> { - rfind_char_between(s, c, start, 0u) -} - -/** - * Returns the byte index of the last matching character within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, exclusive - * * `end` - The byte index to end searching at, inclusive - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `end` must be less than or equal to `start` and `start` must be less than - * or equal to `len(s)`. `start` must be the index of a character boundary, - * as defined by `is_char_boundary`. - */ -pub fn rfind_char_between(s: &str, c: char, start: uint, end: uint) -> Option<uint> { - if c < 128u as char { - assert!(start >= end); - assert!(start <= len(s)); - let mut i = start; - let b = c as u8; - while i > end { - i -= 1u; - if s[i] == b { return Some(i); } - } - return None; - } else { - rfind_between(s, start, end, |x| x == c) - } -} - -/** - * Returns the byte index of the first character that satisfies - * the given predicate - * - * # Arguments - * - * * `s` - The string to search - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - */ -pub fn find(s: &str, f: &fn(char) -> bool) -> Option<uint> { - find_between(s, 0u, len(s), f) -} - -/** - * Returns the byte index of the first character that satisfies - * the given predicate, beginning from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, inclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the first matching charactor - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `len(s)`. `start` must be the - * index of a character boundary, as defined by `is_char_boundary`. - */ -pub fn find_from(s: &str, start: uint, f: &fn(char) - -> bool) -> Option<uint> { - find_between(s, start, len(s), f) -} - -/** - * Returns the byte index of the first character that satisfies - * the given predicate, within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, inclusive - * * `end` - The byte index to end searching at, exclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `end` and `end` must be less than - * or equal to `len(s)`. `start` must be the index of a character - * boundary, as defined by `is_char_boundary`. - */ -pub fn find_between(s: &str, start: uint, end: uint, f: &fn(char) -> bool) -> Option<uint> { - assert!(start <= end); - assert!(end <= len(s)); - assert!(is_char_boundary(s, start)); - let mut i = start; - while i < end { - let CharRange {ch, next} = char_range_at(s, i); - if f(ch) { return Some(i); } - i = next; - } - return None; -} - -/** - * Returns the byte index of the last character that satisfies - * the given predicate - * - * # Arguments - * - * * `s` - The string to search - * * `f` - The predicate to satisfy - * - * # Return value - * - * An option containing the byte index of the last matching character - * or `none` if there is no match - */ -pub fn rfind(s: &str, f: &fn(char) -> bool) -> Option<uint> { - rfind_between(s, len(s), 0u, f) -} - -/** - * Returns the byte index of the last character that satisfies - * the given predicate, beginning from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, exclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `len(s)', `start` must be the - * index of a character boundary, as defined by `is_char_boundary` - */ -pub fn rfind_from(s: &str, start: uint, f: &fn(char) -> bool) -> Option<uint> { - rfind_between(s, start, 0u, f) -} - -/** - * Returns the byte index of the last character that satisfies - * the given predicate, within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, exclusive - * * `end` - The byte index to end searching at, inclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `end` must be less than or equal to `start` and `start` must be less - * than or equal to `len(s)`. `start` must be the index of a character - * boundary, as defined by `is_char_boundary` - */ -pub fn rfind_between(s: &str, start: uint, end: uint, f: &fn(char) -> bool) -> Option<uint> { - assert!(start >= end); - assert!(start <= len(s)); - assert!(is_char_boundary(s, start)); - let mut i = start; - while i > end { - let CharRange {ch, next: prev} = char_range_at_reverse(s, i); - if f(ch) { return Some(prev); } - i = prev; - } - return None; -} - // Utility used by various searching functions fn match_at<'a,'b>(haystack: &'a str, needle: &'b str, at: uint) -> bool { let mut i = at; - for each(needle) |c| { if haystack[i] != c { return false; } i += 1u; } + for needle.bytes_iter().advance |c| { if haystack[i] != c { return false; } i += 1u; } return true; } -/** - * Returns the byte index of the first matching substring - * - * # Arguments - * - * * `haystack` - The string to search - * * `needle` - The string to search for - * - * # Return value - * - * An `option` containing the byte index of the first matching substring - * or `none` if there is no match - */ -pub fn find_str<'a,'b>(haystack: &'a str, needle: &'b str) -> Option<uint> { - find_str_between(haystack, needle, 0u, len(haystack)) -} - -/** - * Returns the byte index of the first matching substring beginning - * from a given byte offset - * - * # Arguments - * - * * `haystack` - The string to search - * * `needle` - The string to search for - * * `start` - The byte index to begin searching at, inclusive - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `len(s)` - */ -pub fn find_str_from<'a,'b>(haystack: &'a str, - needle: &'b str, - start: uint) - -> Option<uint> { - find_str_between(haystack, needle, start, len(haystack)) -} - -/** - * Returns the byte index of the first matching substring within a given range - * - * # Arguments - * - * * `haystack` - The string to search - * * `needle` - The string to search for - * * `start` - The byte index to begin searching at, inclusive - * * `end` - The byte index to end searching at, exclusive - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `end` and `end` must be less than - * or equal to `len(s)`. - */ -pub fn find_str_between<'a,'b>(haystack: &'a str, - needle: &'b str, - start: uint, - end:uint) - -> Option<uint> { - // See Issue #1932 for why this is a naive search - assert!(end <= len(haystack)); - let needle_len = len(needle); - if needle_len == 0u { return Some(start); } - if needle_len > end { return None; } - - let mut i = start; - let e = end - needle_len; - while i <= e { - if match_at(haystack, needle, i) { return Some(i); } - i += 1u; - } - return None; -} - -/** - * Returns true if one string contains another - * - * # Arguments - * - * * haystack - The string to look in - * * needle - The string to look for - */ -pub fn contains<'a,'b>(haystack: &'a str, needle: &'b str) -> bool { - find_str(haystack, needle).is_some() -} - -/** - * Returns true if a string contains a char. - * - * # Arguments - * - * * haystack - The string to look in - * * needle - The char to look for - */ -pub fn contains_char(haystack: &str, needle: char) -> bool { - find_char(haystack, needle).is_some() -} - -/** - * Returns true if one string starts with another - * - * # Arguments - * - * * haystack - The string to look in - * * needle - The string to look for - */ -pub fn starts_with<'a,'b>(haystack: &'a str, needle: &'b str) -> bool { - let haystack_len = len(haystack), needle_len = len(needle); - if needle_len == 0u { true } - else if needle_len > haystack_len { false } - else { match_at(haystack, needle, 0u) } -} - -/** - * Returns true if one string ends with another - * - * # Arguments - * - * * haystack - The string to look in - * * needle - The string to look for - */ -pub fn ends_with<'a,'b>(haystack: &'a str, needle: &'b str) -> bool { - let haystack_len = len(haystack), needle_len = len(needle); - if needle_len == 0u { true } - else if needle_len > haystack_len { false } - else { match_at(haystack, needle, haystack_len - needle_len) } -} - -/* -Section: String properties -*/ - -/// Returns true if the string has length 0 -#[inline(always)] -pub fn is_empty(s: &str) -> bool { len(s) == 0u } - -/** - * Returns true if the string contains only whitespace - * - * Whitespace characters are determined by `char::is_whitespace` - */ -pub fn is_whitespace(s: &str) -> bool { - return all(s, char::is_whitespace); -} - -/** - * Returns true if the string contains only alphanumerics - * - * Alphanumeric characters are determined by `char::is_alphanumeric` - */ -fn is_alphanumeric(s: &str) -> bool { - return all(s, char::is_alphanumeric); -} - -/// Returns the string length/size in bytes not counting the null terminator -#[inline(always)] -pub fn len(s: &str) -> uint { - do as_buf(s) |_p, n| { n - 1u } -} - -/// Returns the number of characters that a string holds -#[inline(always)] -pub fn char_len(s: &str) -> uint { count_chars(s, 0u, len(s)) } - /* Section: Misc */ @@ -1754,7 +784,7 @@ Section: Misc /// Determines if a vector of bytes contains valid UTF-8 pub fn is_utf8(v: &const [u8]) -> bool { let mut i = 0u; - let total = vec::len::<u8>(v); + let total = v.len(); while i < total { let mut chsize = utf8_char_width(v[i]); if chsize == 0u { return false; } @@ -1793,7 +823,7 @@ pub fn is_utf16(v: &[u16]) -> bool { /// Converts to a vector of `u16` encoded as UTF-16 pub fn to_utf16(s: &str) -> ~[u16] { let mut u = ~[]; - for s.each_char |ch| { + for s.iter().advance |ch| { // Arithmetic with u32 literals is easier on the eyes than chars. let mut ch = ch as u32; @@ -1814,6 +844,12 @@ pub fn to_utf16(s: &str) -> ~[u16] { u } +/// Iterates over the utf-16 characters in the specified slice, yielding each +/// decoded unicode character to the function provided. +/// +/// # Failures +/// +/// * Fails on invalid utf-16 data pub fn utf16_chars(v: &[u16], f: &fn(char)) { let len = v.len(); let mut i = 0u; @@ -1838,59 +874,26 @@ pub fn utf16_chars(v: &[u16], f: &fn(char)) { } } +/** + * Allocates a new string from the utf-16 slice provided + */ pub fn from_utf16(v: &[u16]) -> ~str { let mut buf = ~""; - reserve(&mut buf, v.len()); - utf16_chars(v, |ch| push_char(&mut buf, ch)); + buf.reserve(v.len()); + utf16_chars(v, |ch| buf.push_char(ch)); buf } +/** + * Allocates a new string with the specified capacity. The string returned is + * the empty string, but has capacity for much more. + */ pub fn with_capacity(capacity: uint) -> ~str { let mut buf = ~""; - reserve(&mut buf, capacity); + buf.reserve(capacity); buf } -/** - * As char_len but for a slice of a string - * - * # Arguments - * - * * s - A valid string - * * start - The position inside `s` where to start counting in bytes - * * end - The position where to stop counting - * - * # Return value - * - * The number of Unicode characters in `s` between the given indices. - */ -pub fn count_chars(s: &str, start: uint, end: uint) -> uint { - assert!(is_char_boundary(s, start)); - assert!(is_char_boundary(s, end)); - let mut i = start, len = 0u; - while i < end { - let next = char_range_at(s, i).next; - len += 1u; - i = next; - } - return len; -} - -/// Counts the number of bytes taken by the first `n` chars in `s` -/// starting from `start`. -pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { - assert!(is_char_boundary(s, start)); - let mut end = start, cnt = n; - let l = len(s); - while cnt > 0u { - assert!(end < l); - let next = char_range_at(s, end).next; - cnt -= 1u; - end = next; - } - end - start -} - /// Given a first byte, determine how many bytes are in this UTF-8 character pub fn utf8_char_width(b: u8) -> uint { let byte: uint = b as uint; @@ -1904,189 +907,12 @@ pub fn utf8_char_width(b: u8) -> uint { return 6u; } -/** - * Returns false if the index points into the middle of a multi-byte - * character sequence. - */ -pub fn is_char_boundary(s: &str, index: uint) -> bool { - if index == len(s) { return true; } - let b = s[index]; - 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 < str::len(s) { - * let CharRange {ch, next} = str::char_range_at(s, i); - * std::io::println(fmt!("%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. - */ -pub fn char_range_at(s: &str, i: uint) -> CharRange { - let b0 = s[i]; - let w = utf8_char_width(b0); - assert!((w != 0u)); - if w == 1u { return CharRange {ch: b0 as char, next: i + 1u}; } - let mut val = 0u; - let end = i + w; - let mut i = i + 1u; - while i < end { - let byte = s[i]; - assert_eq!(byte & 192u8, tag_cont_u8); - val <<= 6u; - val += (byte & 63u8) as uint; - i += 1u; - } - // Clunky way to get the right bits from the first byte. Uses two shifts, - // the first to clip off the marker bits at the left of the byte, and then - // a second (as uint) to get it to the right position. - val += ((b0 << ((w + 1u) as u8)) as uint) << ((w - 1u) * 6u - w - 1u); - return CharRange {ch: val as char, next: i}; -} - -/// Plucks the character starting at the `i`th byte of a string -pub fn char_at(s: &str, i: uint) -> char { - return char_range_at(s, i).ch; -} - +#[allow(missing_doc)] pub struct CharRange { ch: char, next: uint } -/** - * 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. - */ -pub fn char_range_at_reverse(ss: &str, start: uint) -> CharRange { - let mut prev = start; - - // while there is a previous byte == 10...... - while prev > 0u && ss[prev - 1u] & 192u8 == tag_cont_u8 { - prev -= 1u; - } - - // now refer to the initial byte of previous char - if prev > 0u { - prev -= 1u; - } else { - prev = 0u; - } - - - let ch = char_at(ss, prev); - return CharRange {ch:ch, next:prev}; -} - -/// Plucks the character ending at the `i`th byte of a string -pub fn char_at_reverse(s: &str, i: uint) -> char { - char_range_at_reverse(s, i).ch -} - -/** - * Loop through a substring, char by char - * - * # Safety note - * - * * This function does not check whether the substring is valid. - * * This function fails if `start` or `end` do not - * represent valid positions inside `s` - * - * # Arguments - * - * * s - A string to traverse. It may be empty. - * * start - The byte offset at which to start in the string. - * * end - The end of the range to traverse - * * it - A block to execute with each consecutive character of `s`. - * Return `true` to continue, `false` to stop. - * - * # Return value - * - * `true` If execution proceeded correctly, `false` if it was interrupted, - * that is if `it` returned `false` at any point. - */ -pub fn all_between(s: &str, start: uint, end: uint, - it: &fn(char) -> bool) -> bool { - assert!(is_char_boundary(s, start)); - let mut i = start; - while i < end { - let CharRange {ch, next} = char_range_at(s, i); - if !it(ch) { return false; } - i = next; - } - return true; -} - -/** - * Loop through a substring, char by char - * - * # Safety note - * - * * This function does not check whether the substring is valid. - * * This function fails if `start` or `end` do not - * represent valid positions inside `s` - * - * # Arguments - * - * * s - A string to traverse. It may be empty. - * * start - The byte offset at which to start in the string. - * * end - The end of the range to traverse - * * it - A block to execute with each consecutive character of `s`. - * Return `true` to continue, `false` to stop. - * - * # Return value - * - * `true` if `it` returns `true` for any character - */ -pub fn any_between(s: &str, start: uint, end: uint, - it: &fn(char) -> bool) -> bool { - !all_between(s, start, end, |c| !it(c)) -} - // UTF-8 tags and ranges static tag_cont_u8: u8 = 128u8; static tag_cont: uint = 128u; @@ -2102,64 +928,48 @@ static max_five_b: uint = 67108864u; static tag_six_b: uint = 252u; /** - * Work with the byte buffer of a string. - * - * Allows for unsafe manipulation of strings, which is useful for foreign - * interop. - * - * # Example - * - * ~~~ {.rust} - * let i = str::as_bytes("Hello World") { |bytes| bytes.len() }; - * ~~~ + * A dummy trait to hold all the utility methods that we implement on strings. */ -#[inline] -pub fn as_bytes<T>(s: &const ~str, f: &fn(&~[u8]) -> T) -> T { - unsafe { - let v: *~[u8] = cast::transmute(copy s); - f(&*v) - } +pub trait StrUtil { + /** + * Work with the byte buffer of a string as a null-terminated C string. + * + * Allows for unsafe manipulation of strings, which is useful for foreign + * interop. This is similar to `str::as_buf`, but guarantees null-termination. + * If the given slice is not already null-terminated, this function will + * allocate a temporary, copy the slice, null terminate it, and pass + * that instead. + * + * # Example + * + * ~~~ {.rust} + * let s = "PATH".as_c_str(|path| libc::getenv(path)); + * ~~~ + */ + fn as_c_str<T>(self, f: &fn(*libc::c_char) -> T) -> T; } -/** - * Work with the byte buffer of a string as a byte slice. - * - * The byte slice does not include the null terminator. - */ -pub fn as_bytes_slice<'a>(s: &'a str) -> &'a [u8] { - unsafe { - let (ptr, len): (*u8, uint) = ::cast::transmute(s); - let outgoing_tuple: (*u8, uint) = (ptr, len - 1); - return ::cast::transmute(outgoing_tuple); +impl<'self> StrUtil for &'self str { + #[inline] + fn as_c_str<T>(self, f: &fn(*libc::c_char) -> T) -> T { + do as_buf(self) |buf, len| { + // NB: len includes the trailing null. + assert!(len > 0); + if unsafe { *(ptr::offset(buf,len-1)) != 0 } { + to_owned(self).as_c_str(f) + } else { + f(buf as *libc::c_char) + } + } } } /** - * Work with the byte buffer of a string as a null-terminated C string. - * - * Allows for unsafe manipulation of strings, which is useful for foreign - * interop. This is similar to `str::as_buf`, but guarantees null-termination. - * If the given slice is not already null-terminated, this function will - * allocate a temporary, copy the slice, null terminate it, and pass - * that instead. - * - * # Example - * - * ~~~ {.rust} - * let s = str::as_c_str("PATH", { |path| libc::getenv(path) }); - * ~~~ + * Deprecated. Use the `as_c_str` method on strings instead. */ -#[inline] +#[inline(always)] pub fn as_c_str<T>(s: &str, f: &fn(*libc::c_char) -> T) -> T { - do as_buf(s) |buf, len| { - // NB: len includes the trailing null. - assert!(len > 0); - if unsafe { *(ptr::offset(buf,len-1)) != 0 } { - as_c_str(to_owned(s), f) - } else { - f(buf as *libc::c_char) - } - } + s.as_c_str(f) } /** @@ -2187,7 +997,7 @@ pub fn as_buf<T>(s: &str, f: &fn(*u8, uint) -> T) -> T { * ~~~ {.rust} * let string = "a\nb\nc"; * let mut lines = ~[]; - * for each_line(string) |line| { lines.push(line) } + * for string.line_iter().advance |line| { lines.push(line) } * * assert!(subslice_offset(string, lines[0]) == 0); // &"a" * assert!(subslice_offset(string, lines[1]) == 2); // &"b" @@ -2198,7 +1008,10 @@ pub fn as_buf<T>(s: &str, f: &fn(*u8, uint) -> T) -> T { pub fn subslice_offset(outer: &str, inner: &str) -> uint { do as_buf(outer) |a, a_len| { do as_buf(inner) |b, b_len| { - let a_start: uint, a_end: uint, b_start: uint, b_end: uint; + let a_start: uint; + let a_end: uint; + let b_start: uint; + let b_end: uint; unsafe { a_start = cast::transmute(a); a_end = a_len + cast::transmute(a); b_start = cast::transmute(b); b_end = b_len + cast::transmute(b); @@ -2210,99 +1023,18 @@ pub fn subslice_offset(outer: &str, inner: &str) -> uint { } } -/** - * Reserves capacity for exactly `n` bytes in the given string, not including - * the null terminator. - * - * Assuming single-byte characters, the resulting string will be large - * enough to hold a string of length `n`. To account for the null terminator, - * the underlying buffer will have the size `n` + 1. - * - * 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(always)] -pub fn reserve(s: &mut ~str, n: uint) { - unsafe { - let v: *mut ~[u8] = cast::transmute(s); - vec::reserve(&mut *v, n + 1); - } -} - -/** - * Reserves capacity for at least `n` bytes in the given string, not including - * the null terminator. - * - * Assuming single-byte characters, the resulting string will be large - * enough to hold a string of length `n`. To account for the null terminator, - * the underlying buffer will have the size `n` + 1. - * - * 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(always)] -pub fn reserve_at_least(s: &mut ~str, n: uint) { - reserve(s, uint::next_power_of_two(n + 1u) - 1u) -} - -/** - * Returns the number of single-byte characters the string can hold without - * reallocating - */ -pub fn capacity(s: &const ~str) -> uint { - do as_bytes(s) |buf| { - let vcap = vec::capacity(buf); - assert!(vcap > 0u); - vcap - 1u - } -} - -/// Escape each char in `s` with char::escape_default. -pub fn escape_default(s: &str) -> ~str { - let mut out: ~str = ~""; - reserve_at_least(&mut out, str::len(s)); - for s.each_char |c| { - push_str(&mut out, char::escape_default(c)); - } - out -} - -/// Escape each char in `s` with char::escape_unicode. -pub fn escape_unicode(s: &str) -> ~str { - let mut out: ~str = ~""; - reserve_at_least(&mut out, str::len(s)); - for s.each_char |c| { - push_str(&mut out, char::escape_unicode(c)); - } - out -} - /// Unsafe operations pub mod raw { use cast; use libc; use ptr; use str::raw; - use str::{as_buf, is_utf8, len, reserve_at_least}; + use str::{as_buf, is_utf8}; use vec; /// Create a Rust string from a null-terminated *u8 buffer pub unsafe fn from_buf(buf: *u8) -> ~str { - let mut curr = buf, i = 0u; + let mut (curr, i) = (buf, 0u); while *curr != 0u8 { i += 1u; curr = ptr::offset(buf, i); @@ -2350,12 +1082,19 @@ pub mod raw { /// Converts a byte to a string. pub unsafe fn from_byte(u: u8) -> ~str { raw::from_bytes([u]) } - /// Form a slice from a *u8 buffer of the given length without copying. - pub unsafe fn buf_as_slice<T>(buf: *u8, len: uint, - f: &fn(v: &str) -> T) -> T { - let v = (buf, len + 1); + /// Form a slice from a C string. Unsafe because the caller must ensure the + /// C string has the static lifetime, or else the return value may be + /// invalidated later. + pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str { + let s = s as *u8; + let mut (curr, len) = (s, 0u); + while *curr != 0u8 { + len += 1u; + curr = ptr::offset(s, len); + } + let v = (s, len + 1); assert!(is_utf8(::cast::transmute(v))); - f(::cast::transmute(v)) + ::cast::transmute(v) } /** @@ -2409,7 +1148,7 @@ pub mod raw { /// Appends a byte to a string. (Not UTF-8 safe). pub unsafe fn push_byte(s: &mut ~str, b: u8) { let new_len = s.len() + 1; - reserve_at_least(&mut *s, new_len); + s.reserve_at_least(new_len); do as_buf(*s) |buf, len| { let buf: *mut u8 = ::cast::transmute(buf); *ptr::mut_offset(buf, len) = b; @@ -2420,13 +1159,13 @@ pub mod raw { /// Appends a vector of bytes to a string. (Not UTF-8 safe). unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) { let new_len = s.len() + bytes.len(); - reserve_at_least(&mut *s, new_len); + s.reserve_at_least(new_len); for bytes.each |byte| { push_byte(&mut *s, *byte); } } /// Removes the last byte from a string and returns it. (Not UTF-8 safe). pub unsafe fn pop_byte(s: &mut ~str) -> u8 { - let len = len(*s); + let len = s.len(); assert!((len > 0u)); let b = s[len - 1u]; set_len(s, len - 1u); @@ -2435,7 +1174,7 @@ pub mod raw { /// Removes the first byte from a string and returns it. (Not UTF-8 safe). pub unsafe fn shift_byte(s: &mut ~str) -> u8 { - let len = len(*s); + let len = s.len(); assert!((len > 0u)); let b = s[0]; *s = raw::slice_bytes_owned(*s, 1u, len); @@ -2468,12 +1207,10 @@ pub mod raw { #[cfg(not(test))] pub mod traits { use ops::Add; - use str::append; - impl<'self> Add<&'self str,~str> for ~str { #[inline(always)] fn add(&self, rhs: & &'self str) -> ~str { - append(copy *self, (*rhs)) + self.append((*rhs)) } } } @@ -2481,141 +1218,258 @@ pub mod traits { #[cfg(test)] pub mod traits {} +/// Any string that can be represented as a slice +pub trait Str { + /// Work with `self` as a slice. + fn as_slice<'a>(&'a self) -> &'a str; +} + +impl<'self> Str for &'self str { + #[inline(always)] + fn as_slice<'a>(&'a self) -> &'a str { *self } +} +impl<'self> Str for ~str { + #[inline(always)] + fn as_slice<'a>(&'a self) -> &'a str { + let s: &'a str = *self; s + } +} +impl<'self> Str for @str { + #[inline(always)] + fn as_slice<'a>(&'a self) -> &'a str { + let s: &'a str = *self; s + } +} + +#[allow(missing_doc)] pub trait StrSlice<'self> { - fn all(&self, it: &fn(char) -> bool) -> bool; - fn any(&self, it: &fn(char) -> bool) -> bool; fn contains<'a>(&self, needle: &'a str) -> bool; fn contains_char(&self, needle: char) -> bool; - fn char_iter(&self) -> StrCharIterator<'self>; - fn each(&self, it: &fn(u8) -> bool) -> bool; - fn eachi(&self, it: &fn(uint, u8) -> bool) -> bool; - fn each_reverse(&self, it: &fn(u8) -> bool) -> bool; - fn eachi_reverse(&self, it: &fn(uint, u8) -> bool) -> bool; - fn each_char(&self, it: &fn(char) -> bool) -> bool; - fn each_chari(&self, it: &fn(uint, char) -> bool) -> bool; - fn each_char_reverse(&self, it: &fn(char) -> bool) -> bool; - fn each_chari_reverse(&self, it: &fn(uint, char) -> bool) -> bool; + fn iter(&self) -> StrCharIterator<'self>; + fn rev_iter(&self) -> StrCharRevIterator<'self>; + fn bytes_iter(&self) -> StrBytesIterator<'self>; + fn bytes_rev_iter(&self) -> StrBytesRevIterator<'self>; + fn split_iter<Sep: CharEq>(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep>; + fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> StrCharSplitIterator<'self, Sep>; + fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool) + -> StrCharSplitIterator<'self, Sep>; + fn matches_index_iter(&self, sep: &'self str) -> StrMatchesIndexIterator<'self>; + fn split_str_iter(&self, &'self str) -> StrStrSplitIterator<'self>; + fn line_iter(&self) -> StrCharSplitIterator<'self, char>; + fn word_iter(&self) -> WordIterator<'self>; fn ends_with(&self, needle: &str) -> bool; fn is_empty(&self) -> bool; fn is_whitespace(&self) -> bool; fn is_alphanumeric(&self) -> bool; fn len(&self) -> uint; fn char_len(&self) -> uint; + fn slice(&self, begin: uint, end: uint) -> &'self str; - fn each_split(&self, sepfn: &fn(char) -> bool, it: &fn(&'self str) -> bool) -> bool; - fn each_split_char(&self, sep: char, it: &fn(&'self str) -> bool) -> bool; - fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool) -> bool; - fn starts_with<'a>(&self, needle: &'a str) -> bool; - fn substr(&self, begin: uint, n: 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(&self, chars_to_trim: &[char]) -> &'self str; - fn trim_left_chars(&self, chars_to_trim: &[char]) -> &'self str; - fn trim_right_chars(&self, chars_to_trim: &[char]) -> &'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 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 to_bytes(&self) -> ~[u8]; + 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); } /// Extension methods for strings impl<'self> StrSlice<'self> for &'self str { /** - * Return true if a predicate matches all characters or if the string - * contains no characters - */ - #[inline] - fn all(&self, it: &fn(char) -> bool) -> bool { all(*self, it) } - /** - * Return true if a predicate matches any character (and false if it - * matches none or there are no characters) + * Returns true if one string contains another + * + * # Arguments + * + * * needle - The string to look for */ #[inline] - fn any(&self, it: &fn(char) -> bool) -> bool { any(*self, it) } - /// Returns true if one string contains another - #[inline] fn contains<'a>(&self, needle: &'a str) -> bool { - contains(*self, needle) + self.find_str(needle).is_some() } - /// Returns true if a string contains a char + /** + * Returns true if a string contains a char. + * + * # Arguments + * + * * needle - The char to look for + */ #[inline] fn contains_char(&self, needle: char) -> bool { - contains_char(*self, needle) - } - + self.find(needle).is_some() + } + /// An iterator over the characters of `self`. Note, this iterates + /// over unicode code-points, not unicode graphemes. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let v: ~[char] = "abc åäö".iter().collect(); + /// assert_eq!(v, ~['a', 'b', 'c', ' ', 'å', 'ä', 'ö']); + /// ~~~ #[inline] - fn char_iter(&self) -> StrCharIterator<'self> { + fn iter(&self) -> StrCharIterator<'self> { StrCharIterator { index: 0, string: *self } } + /// An iterator over the characters of `self`, in reverse order. + #[inline] + fn rev_iter(&self) -> StrCharRevIterator<'self> { + StrCharRevIterator { + index: self.len(), + string: *self + } + } - /// Iterate over the bytes in a string + /// An iterator over the bytes of `self` #[inline] - fn each(&self, it: &fn(u8) -> bool) -> bool { each(*self, it) } - /// Iterate over the bytes in a string, with indices + fn bytes_iter(&self) -> StrBytesIterator<'self> { + StrBytesIterator { it: self.as_bytes().iter() } + } + /// An iterator over the bytes of `self`, in reverse order #[inline] - fn eachi(&self, it: &fn(uint, u8) -> bool) -> bool { eachi(*self, it) } - /// Iterate over the bytes in a string + fn bytes_rev_iter(&self) -> StrBytesRevIterator<'self> { + StrBytesRevIterator { it: self.as_bytes().rev_iter() } + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by `sep`. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let v: ~[&str] = "Mary had a little lamb".split_iter(' ').collect(); + /// assert_eq!(v, ~["Mary", "had", "a", "little", "lamb"]); + /// + /// let v: ~[&str] = "abc1def2ghi".split_iter(|c: char| c.is_digit()).collect(); + /// assert_eq!(v, ~["abc", "def", "ghi"]); + /// ~~~ #[inline] - fn each_reverse(&self, it: &fn(u8) -> bool) -> bool { each_reverse(*self, it) } - /// Iterate over the bytes in a string, with indices + fn split_iter<Sep: CharEq>(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep> { + self.split_options_iter(sep, self.len(), true) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by `sep`, restricted to splitting at most `count` + /// times. #[inline] - fn eachi_reverse(&self, it: &fn(uint, u8) -> bool) -> bool { - eachi_reverse(*self, it) + fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> StrCharSplitIterator<'self, Sep> { + self.split_options_iter(sep, count, true) } - /// Iterate over the chars in a string + + /// An iterator over substrings of `self`, separated by characters + /// matched by `sep`, splitting at most `count` times, and + /// possibly not including the trailing empty substring, if it + /// exists. #[inline] - fn each_char(&self, it: &fn(char) -> bool) -> bool { each_char(*self, it) } - /// Iterate over the chars in a string, with indices + fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool) + -> StrCharSplitIterator<'self, Sep> { + let only_ascii = sep.only_ascii(); + StrCharSplitIterator { + string: *self, + position: 0, + sep: sep, + count: count, + allow_trailing_empty: allow_trailing_empty, + finished: false, + only_ascii: only_ascii + } + } + /// An iterator over the start and end indices of each match of + /// `sep` within `self`. #[inline] - fn each_chari(&self, it: &fn(uint, char) -> bool) -> bool { - each_chari(*self, it) + fn matches_index_iter(&self, sep: &'self str) -> StrMatchesIndexIterator<'self> { + assert!(!sep.is_empty()) + StrMatchesIndexIterator { + haystack: *self, + needle: sep, + position: 0 + } } - /// Iterate over the chars in a string in reverse + /** + * An iterator over the substrings of `self` separated by `sep`. + * + * # Example + * + * ~~~ {.rust} + * let v: ~[&str] = "abcXXXabcYYYabc".split_str_iter("abc").collect() + * assert_eq!(v, ["", "XXX", "YYY", ""]); + * ~~~ + */ #[inline] - fn each_char_reverse(&self, it: &fn(char) -> bool) -> bool { - each_char_reverse(*self, it) + fn split_str_iter(&self, sep: &'self str) -> StrStrSplitIterator<'self> { + StrStrSplitIterator { + it: self.matches_index_iter(sep), + last_end: 0, + finished: false + } } - /// Iterate over the chars in a string in reverse, with indices from the - /// end + + /// An iterator over the lines of a string (subsequences separated + /// by `\n`). #[inline] - fn each_chari_reverse(&self, it: &fn(uint, char) -> bool) -> bool { - each_chari_reverse(*self, it) + fn line_iter(&self) -> StrCharSplitIterator<'self, char> { + self.split_options_iter('\n', self.len(), false) } - /// Returns true if one string ends with another + /// An iterator over the words of a string (subsequences separated + /// by any sequence of whitespace). #[inline] - fn ends_with(&self, needle: &str) -> bool { - ends_with(*self, needle) + fn word_iter(&self) -> WordIterator<'self> { + self.split_iter(char::is_whitespace).filter(|s| !s.is_empty()) } + /// Returns true if the string has length 0 #[inline] - fn is_empty(&self) -> bool { is_empty(*self) } + fn is_empty(&self) -> bool { self.len() == 0 } /** * Returns true if the string contains only whitespace * * Whitespace characters are determined by `char::is_whitespace` */ #[inline] - fn is_whitespace(&self) -> bool { is_whitespace(*self) } + fn is_whitespace(&self) -> bool { self.iter().all(char::is_whitespace) } /** * Returns true if the string contains only alphanumerics * * Alphanumeric characters are determined by `char::is_alphanumeric` */ #[inline] - fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) } + fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) } /// Returns the size in bytes not counting the null terminator #[inline(always)] - fn len(&self) -> uint { len(*self) } + fn len(&self) -> uint { + do as_buf(*self) |_p, n| { n - 1u } + } /// Returns the number of characters that a string holds #[inline] - fn char_len(&self) -> uint { char_len(*self) } + fn char_len(&self) -> uint { self.iter().count() } + /** * Returns a slice of the given string from the byte range * [`begin`..`end`) @@ -2625,74 +1479,195 @@ impl<'self> StrSlice<'self> for &'self str { */ #[inline] fn slice(&self, begin: uint, end: uint) -> &'self str { - slice(*self, begin, end) - } - /// Splits a string into substrings using a character function + assert!(self.is_char_boundary(begin)); + assert!(self.is_char_boundary(end)); + unsafe { raw::slice_bytes(*self, begin, end) } + } + /// 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 each_split(&self, sepfn: &fn(char) -> bool, it: &fn(&'self str) -> bool) -> bool { - each_split(*self, sepfn, it) - } - /** - * Splits a string into substrings at each occurrence of a given character - */ + fn slice_from(&self, begin: uint) -> &'self str { + self.slice(begin, self.len()) + } + /// 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 each_split_char(&self, sep: char, it: &fn(&'self str) -> bool) -> bool { - each_split_char(*self, sep, it) + fn slice_to(&self, end: uint) -> &'self str { + self.slice(0, end) } - /** - * Splits a string into a vector of the substrings separated by a given - * string - */ - #[inline] - fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool) -> bool { - each_split_str(*self, sep, it) + + /// 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); + // not sure how to use the iterators for this nicely. + let mut (position, count) = (0, 0); + let l = self.len(); + while count < begin && position < l { + position = self.char_range_at(position).next; + count += 1; + } + if count < begin { fail!("Attempted to begin slice_chars beyond end of string") } + let start_byte = position; + while count < end && position < l { + position = self.char_range_at(position).next; + count += 1; + } + if count < end { fail!("Attempted to end slice_chars beyond end of string") } + + self.slice(start_byte, position) } - /// Returns true if one string starts with another - #[inline] + + /// Returns true if `needle` is a prefix of the string. fn starts_with<'a>(&self, needle: &'a str) -> bool { - starts_with(*self, needle) + let (self_len, needle_len) = (self.len(), needle.len()); + if needle_len == 0u { true } + else if needle_len > self_len { false } + else { match_at(*self, needle, 0u) } } - /** - * Take a substring of another. - * - * Returns a string containing `n` characters starting at byte offset - * `begin`. - */ - #[inline] - fn substr(&self, begin: uint, n: uint) -> &'self str { - substr(*self, begin, n) + /// 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 } + else if needle_len > self_len { false } + else { match_at(*self, needle, self_len - needle_len) } } + /// Escape each char in `s` with char::escape_default. - #[inline] - fn escape_default(&self) -> ~str { escape_default(*self) } + fn escape_default(&self) -> ~str { + let mut out: ~str = ~""; + out.reserve_at_least(self.len()); + for self.iter().advance |c| { + out.push_str(char::escape_default(c)); + } + out + } + /// Escape each char in `s` with char::escape_unicode. - #[inline] - fn escape_unicode(&self) -> ~str { escape_unicode(*self) } + fn escape_unicode(&self) -> ~str { + let mut out: ~str = ~""; + out.reserve_at_least(self.len()); + for self.iter().advance |c| { + out.push_str(char::escape_unicode(c)); + } + out + } /// Returns a string with leading and trailing whitespace removed #[inline] - fn trim(&self) -> &'self str { trim(*self) } + fn trim(&self) -> &'self str { + self.trim_left().trim_right() + } /// Returns a string with leading whitespace removed #[inline] - fn trim_left(&self) -> &'self str { trim_left(*self) } + 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 { trim_right(*self) } + 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 + * + * ~~~ + * 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(&self, chars_to_trim: &[char]) -> &'self str { - trim_chars(*self, chars_to_trim) + 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 + * + * ~~~ + * 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_left_chars(&self, chars_to_trim: &[char]) -> &'self str { - trim_left_chars(*self, chars_to_trim) + fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'self str { + match self.find(|c: char| !to_trim.matches(c)) { + None => "", + Some(first) => unsafe { raw::slice_bytes(*self, first, self.len()) } + } } + /** + * Returns a string with trailing `chars_to_trim` removed. + * + * # Arguments + * + * * to_trim - a character matcher + * + * # Example + * + * ~~~ + * 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(&self, chars_to_trim: &[char]) -> &'self str { - trim_right_chars(*self, chars_to_trim) + fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'self str { + match self.rfind(|c: char| !to_trim.matches(c)) { + None => "", + Some(last) => { + let next = self.char_range_at(last).next; + unsafe { raw::slice_bytes(*self, 0u, next) } + } + } } + /** + * 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` + */ + pub fn replace(&self, from: &str, to: &str) -> ~str { + let mut (result, last_end) = (~"", 0); + for self.matches_index_iter(from).advance |(start, end)| { + result.push_str(unsafe{raw::slice_bytes(*self, last_end, start)}); + result.push_str(to); + last_end = end; + } + result.push_str(unsafe{raw::slice_bytes(*self, last_end, self.len())}); + result + } + /// Copy a slice into a new unique str #[inline] fn to_owned(&self) -> ~str { to_owned(*self) } @@ -2704,30 +1679,502 @@ impl<'self> StrSlice<'self> for &'self str { unsafe { ::cast::transmute(v) } } + /** + * Returns false if the index points into the middle of a multi-byte + * character sequence. + */ + fn is_char_boundary(&self, index: uint) -> bool { + if index == self.len() { return true; } + let b = self[index]; + 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); + * std::io::println(fmt!("%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, i: uint) -> CharRange { + let b0 = self[i]; + let w = utf8_char_width(b0); + assert!((w != 0u)); + if w == 1u { return CharRange {ch: b0 as char, next: i + 1u}; } + let mut val = 0u; + let end = i + w; + let mut i = i + 1u; + while i < end { + let byte = self[i]; + assert_eq!(byte & 192u8, tag_cont_u8); + val <<= 6u; + val += (byte & 63u8) as uint; + i += 1u; + } + // Clunky way to get the right bits from the first byte. Uses two shifts, + // the first to clip off the marker bits at the left of the byte, and then + // a second (as uint) to get it to the right position. + val += ((b0 << ((w + 1u) as u8)) as uint) << ((w - 1u) * 6u - w - 1u); + return CharRange {ch: val as char, next: i}; + } + + /// Plucks the character starting at the `i`th byte of a string #[inline] - fn char_at(&self, i: uint) -> char { char_at(*self, i) } + 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. + */ + fn char_range_at_reverse(&self, start: uint) -> CharRange { + let mut prev = start; + + // while there is a previous byte == 10...... + while prev > 0u && self[prev - 1u] & 192u8 == tag_cont_u8 { + prev -= 1u; + } + + // now refer to the initial byte of previous char + if prev > 0u { + prev -= 1u; + } else { + prev = 0u; + } + + + let ch = self.char_at(prev); + return CharRange {ch:ch, next:prev}; + } + /// Plucks the character ending at the `i`th byte of a string #[inline] fn char_at_reverse(&self, i: uint) -> char { - char_at_reverse(*self, i) + self.char_range_at_reverse(i).ch + } + + /** + * Work with the byte buffer of a string as a byte slice. + * + * The byte slice does not include the null terminator. + */ + fn as_bytes(&self) -> &'self [u8] { + unsafe { + let (ptr, len): (*u8, uint) = ::cast::transmute(*self); + let outgoing_tuple: (*u8, uint) = (ptr, len - 1); + ::cast::transmute(outgoing_tuple) + } + } + + /** + * 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() { + for self.bytes_iter().enumerate().advance |(i, b)| { + if search.matches(b as char) { return Some(i) } + } + } else { + let mut index = 0; + for self.iter().advance |c| { + if search.matches(c) { return Some(index); } + index += c.len_utf8_bytes(); + } + } + + None } + /** + * 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> { + let mut index = self.len(); + if search.only_ascii() { + for self.bytes_rev_iter().advance |b| { + index -= 1; + if search.matches(b as char) { return Some(index); } + } + } else { + for self.rev_iter().advance |c| { + index -= c.len_utf8_bytes(); + if search.matches(c) { return Some(index); } + } + } + + None + } + + /** + * 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) + } else { + self.matches_index_iter(needle) + .next() + .map_consume(|(start, _end)| start) + } + } + + /// Given a string, make a new string with repeated copies of it. + fn repeat(&self, nn: uint) -> ~str { + do as_buf(*self) |buf, len| { + let mut ret = ~""; + // ignore the NULL terminator + let len = len - 1; + ret.reserve(nn * len); + + unsafe { + do as_buf(ret) |rbuf, _len| { + let mut rbuf = ::cast::transmute_mut_unsafe(rbuf); + + for nn.times { + ptr::copy_memory(rbuf, buf, len); + rbuf = rbuf.offset(len); + } + } + raw::set_len(&mut ret, nn * len); + } + 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); + let next_s = unsafe { raw::slice_bytes(*self, next, self.len()) }; + return (ch, next_s); + } + - fn to_bytes(&self) -> ~[u8] { to_bytes(*self) } } +#[allow(missing_doc)] +pub trait NullTerminatedStr { + fn as_bytes_with_null<'a>(&'a self) -> &'a [u8]; +} + +impl NullTerminatedStr for ~str { + /** + * Work with the byte buffer of a string as a byte slice. + * + * The byte slice does include the null terminator. + */ + #[inline] + fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { + let ptr: &'a ~[u8] = unsafe { ::cast::transmute(self) }; + let slice: &'a [u8] = *ptr; + slice + } +} +impl NullTerminatedStr for @str { + /** + * Work with the byte buffer of a string as a byte slice. + * + * The byte slice does include the null terminator. + */ + #[inline] + fn as_bytes_with_null<'a>(&'a self) -> &'a [u8] { + let ptr: &'a ~[u8] = unsafe { ::cast::transmute(self) }; + let slice: &'a [u8] = *ptr; + slice + } +} + +#[allow(missing_doc)] pub trait OwnedStr { - fn push_str(&mut self, v: &str); + fn push_str_no_overallocate(&mut self, rhs: &str); + fn push_str(&mut self, rhs: &str); fn push_char(&mut self, c: char); + fn pop_char(&mut self) -> char; + fn shift_char(&mut self) -> char; + fn unshift_char(&mut self, ch: char); + fn append(&self, rhs: &str) -> ~str; // FIXME #4850: this should consume self. + fn reserve(&mut self, n: uint); + fn reserve_at_least(&mut self, n: uint); + fn capacity(&self) -> uint; + + fn as_bytes_with_null_consume(self) -> ~[u8]; } impl OwnedStr for ~str { + /// Appends a string slice to the back of a string, without overallocating + #[inline(always)] + fn push_str_no_overallocate(&mut self, rhs: &str) { + unsafe { + let llen = self.len(); + let rlen = rhs.len(); + self.reserve(llen + rlen); + do as_buf(*self) |lbuf, _llen| { + do as_buf(rhs) |rbuf, _rlen| { + let dst = ptr::offset(lbuf, llen); + let dst = ::cast::transmute_mut_unsafe(dst); + ptr::copy_memory(dst, rbuf, rlen); + } + } + raw::set_len(self, llen + rlen); + } + } + + /// Appends a string slice to the back of a string #[inline] - fn push_str(&mut self, v: &str) { - push_str(self, v); + fn push_str(&mut self, rhs: &str) { + unsafe { + let llen = self.len(); + let rlen = rhs.len(); + self.reserve_at_least(llen + rlen); + do as_buf(*self) |lbuf, _llen| { + do as_buf(rhs) |rbuf, _rlen| { + let dst = ptr::offset(lbuf, llen); + let dst = ::cast::transmute_mut_unsafe(dst); + ptr::copy_memory(dst, rbuf, rlen); + } + } + raw::set_len(self, llen + rlen); + } } + /// Appends a character to the back of a string #[inline] fn push_char(&mut self, c: char) { - push_char(self, c); + unsafe { + let code = c as uint; + let nb = if code < max_one_b { 1u } + else if code < max_two_b { 2u } + else if code < max_three_b { 3u } + else if code < max_four_b { 4u } + else if code < max_five_b { 5u } + else { 6u }; + let len = self.len(); + let new_len = len + nb; + self.reserve_at_least(new_len); + let off = len; + do as_buf(*self) |buf, _len| { + let buf: *mut u8 = ::cast::transmute(buf); + match nb { + 1u => { + *ptr::mut_offset(buf, off) = code as u8; + } + 2u => { + *ptr::mut_offset(buf, off) = (code >> 6u & 31u | tag_two_b) as u8; + *ptr::mut_offset(buf, off + 1u) = (code & 63u | tag_cont) as u8; + } + 3u => { + *ptr::mut_offset(buf, off) = (code >> 12u & 15u | tag_three_b) as u8; + *ptr::mut_offset(buf, off + 1u) = (code >> 6u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 2u) = (code & 63u | tag_cont) as u8; + } + 4u => { + *ptr::mut_offset(buf, off) = (code >> 18u & 7u | tag_four_b) as u8; + *ptr::mut_offset(buf, off + 1u) = (code >> 12u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 2u) = (code >> 6u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 3u) = (code & 63u | tag_cont) as u8; + } + 5u => { + *ptr::mut_offset(buf, off) = (code >> 24u & 3u | tag_five_b) as u8; + *ptr::mut_offset(buf, off + 1u) = (code >> 18u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 2u) = (code >> 12u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 3u) = (code >> 6u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 4u) = (code & 63u | tag_cont) as u8; + } + 6u => { + *ptr::mut_offset(buf, off) = (code >> 30u & 1u | tag_six_b) as u8; + *ptr::mut_offset(buf, off + 1u) = (code >> 24u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 2u) = (code >> 18u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 3u) = (code >> 12u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 4u) = (code >> 6u & 63u | tag_cont) as u8; + *ptr::mut_offset(buf, off + 5u) = (code & 63u | tag_cont) as u8; + } + _ => {} + } + } + raw::set_len(self, new_len); + } + } + /** + * 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 { + let end = self.len(); + assert!(end > 0u); + let CharRange {ch, next} = self.char_range_at_reverse(end); + unsafe { raw::set_len(self, next); } + return ch; + } + + /** + * 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 { + let CharRange {ch, next} = self.char_range_at(0u); + *self = unsafe { raw::slice_bytes_owned(*self, next, self.len()) }; + return ch; + } + + /// Prepend a char to a string + fn unshift_char(&mut self, ch: char) { + // This could be more efficient. + let mut new_str = ~""; + new_str.push_char(ch); + new_str.push_str(*self); + *self = new_str; + } + + /// Concatenate two strings together. + #[inline] + fn append(&self, rhs: &str) -> ~str { + // FIXME #4850: this should consume self, but that causes segfaults + let mut v = self.clone(); + v.push_str_no_overallocate(rhs); + v + } + + /** + * Reserves capacity for exactly `n` bytes in the given string, not including + * the null terminator. + * + * Assuming single-byte characters, the resulting string will be large + * enough to hold a string of length `n`. To account for the null terminator, + * the underlying buffer will have the size `n` + 1. + * + * 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(always)] + pub fn reserve(&mut self, n: uint) { + unsafe { + let v: *mut ~[u8] = cast::transmute(self); + vec::reserve(&mut *v, n + 1); + } + } + + /** + * Reserves capacity for at least `n` bytes in the given string, not including + * the null terminator. + * + * Assuming single-byte characters, the resulting string will be large + * enough to hold a string of length `n`. To account for the null terminator, + * the underlying buffer will have the size `n` + 1. + * + * 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(always)] + fn reserve_at_least(&mut self, n: uint) { + self.reserve(uint::next_power_of_two(n + 1u) - 1u) + } + + /** + * Returns the number of single-byte characters the string can hold without + * reallocating + */ + fn capacity(&self) -> uint { + let buf: &const ~[u8] = unsafe { cast::transmute(self) }; + let vcap = vec::capacity(buf); + assert!(vcap > 0u); + vcap - 1u + } + + /// Convert to a vector of bytes. This does not allocate a new + /// string, and includes the null terminator. + #[inline] + fn as_bytes_with_null_consume(self) -> ~[u8] { + unsafe { ::cast::transmute(self) } } } @@ -2738,6 +2185,8 @@ impl Clone for ~str { } } +/// External iterator for a string's characters. Use with the `std::iterator` +/// module. pub struct StrCharIterator<'self> { priv index: uint, priv string: &'self str, @@ -2747,7 +2196,26 @@ impl<'self> Iterator<char> for StrCharIterator<'self> { #[inline] fn next(&mut self) -> Option<char> { if self.index < self.string.len() { - let CharRange {ch, next} = char_range_at(self.string, self.index); + let CharRange {ch, next} = self.string.char_range_at(self.index); + self.index = next; + Some(ch) + } else { + None + } + } +} +/// External iterator for a string's characters in reverse order. Use +/// with the `std::iterator` module. +pub struct StrCharRevIterator<'self> { + priv index: uint, + priv string: &'self str, +} + +impl<'self> Iterator<char> for StrCharRevIterator<'self> { + #[inline] + fn next(&mut self) -> Option<char> { + if self.index > 0 { + let CharRange {ch, next} = self.string.char_range_at_reverse(self.index); self.index = next; Some(ch) } else { @@ -2756,10 +2224,36 @@ impl<'self> Iterator<char> for StrCharIterator<'self> { } } +/// External iterator for a string's bytes. Use with the `std::iterator` +/// module. +pub struct StrBytesIterator<'self> { + priv it: vec::VecIterator<'self, u8> +} + +impl<'self> Iterator<u8> for StrBytesIterator<'self> { + #[inline] + fn next(&mut self) -> Option<u8> { + self.it.next().map_consume(|&x| x) + } +} + +/// External iterator for a string's bytes in reverse order. Use with +/// the `std::iterator` module. +pub struct StrBytesRevIterator<'self> { + priv it: vec::VecRevIterator<'self, u8> +} + +impl<'self> Iterator<u8> for StrBytesRevIterator<'self> { + #[inline] + fn next(&mut self) -> Option<u8> { + self.it.next().map_consume(|&x| x) + } +} + #[cfg(test)] mod tests { + use iterator::IteratorUtil; use container::Container; - use char; use option::Some; use libc::c_char; use libc; @@ -2767,7 +2261,7 @@ mod tests { use ptr; use str::*; use vec; - use vec::ImmutableVector; + use vec::{ImmutableVector, CopyableVector}; use cmp::{TotalOrd, Less, Equal, Greater}; #[test] @@ -2779,8 +2273,8 @@ mod tests { #[test] fn test_eq_slice() { - assert!((eq_slice(slice("foobar", 0, 3), "foo"))); - assert!((eq_slice(slice("barfoo", 3, 6), "foo"))); + assert!((eq_slice("foobar".slice(0, 3), "foo"))); + assert!((eq_slice("barfoo".slice(3, 6), "foo"))); assert!((!eq_slice("foo1", "foo2"))); } @@ -2794,37 +2288,69 @@ mod tests { #[test] fn test_len() { - assert_eq!(len(""), 0u); - assert_eq!(len("hello world"), 11u); - assert_eq!(len("\x63"), 1u); - assert_eq!(len("\xa2"), 2u); - assert_eq!(len("\u03c0"), 2u); - assert_eq!(len("\u2620"), 3u); - assert_eq!(len("\U0001d11e"), 4u); + assert_eq!("".len(), 0u); + assert_eq!("hello world".len(), 11u); + assert_eq!("\x63".len(), 1u); + assert_eq!("\xa2".len(), 2u); + assert_eq!("\u03c0".len(), 2u); + assert_eq!("\u2620".len(), 3u); + assert_eq!("\U0001d11e".len(), 4u); + + assert_eq!("".char_len(), 0u); + assert_eq!("hello world".char_len(), 11u); + assert_eq!("\x63".char_len(), 1u); + assert_eq!("\xa2".char_len(), 1u); + assert_eq!("\u03c0".char_len(), 1u); + assert_eq!("\u2620".char_len(), 1u); + assert_eq!("\U0001d11e".char_len(), 1u); + assert_eq!("ประเทศไทย中华Việt Nam".char_len(), 19u); + } - assert_eq!(char_len(""), 0u); - assert_eq!(char_len("hello world"), 11u); - assert_eq!(char_len("\x63"), 1u); - assert_eq!(char_len("\xa2"), 1u); - assert_eq!(char_len("\u03c0"), 1u); - assert_eq!(char_len("\u2620"), 1u); - assert_eq!(char_len("\U0001d11e"), 1u); - assert_eq!(char_len("ประเทศไทย中华Việt Nam"), 19u); + #[test] + fn test_find() { + assert_eq!("hello".find('l'), Some(2u)); + assert_eq!("hello".find(|c:char| c == 'o'), Some(4u)); + assert!("hello".find('x').is_none()); + assert!("hello".find(|c:char| c == 'x').is_none()); + assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30u)); + assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30u)); } #[test] - fn test_rfind_char() { - assert_eq!(rfind_char("hello", 'l'), Some(3u)); - assert_eq!(rfind_char("hello", 'o'), Some(4u)); - assert_eq!(rfind_char("hello", 'h'), Some(0u)); - assert!(rfind_char("hello", 'z').is_none()); - assert_eq!(rfind_char("ประเทศไทย中华Việt Nam", '华'), Some(30u)); + fn test_rfind() { + assert_eq!("hello".rfind('l'), Some(3u)); + assert_eq!("hello".rfind(|c:char| c == 'o'), Some(4u)); + assert!("hello".rfind('x').is_none()); + assert!("hello".rfind(|c:char| c == 'x').is_none()); + assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30u)); + assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30u)); + } + + #[test] + fn test_push_str() { + let mut s = ~""; + s.push_str(""); + assert_eq!(s.slice_from(0), ""); + s.push_str("abc"); + assert_eq!(s.slice_from(0), "abc"); + s.push_str("ประเทศไทย中华Việt Nam"); + assert_eq!(s.slice_from(0), "abcประเทศไทย中华Việt Nam"); + } + #[test] + fn test_append() { + let mut s = ~""; + s = s.append(""); + assert_eq!(s.slice_from(0), ""); + s = s.append("abc"); + assert_eq!(s.slice_from(0), "abc"); + s = s.append("ประเทศไทย中华Việt Nam"); + assert_eq!(s.slice_from(0), "abcประเทศไทย中华Việt Nam"); } #[test] fn test_pop_char() { let mut data = ~"ประเทศไทย中华"; - let cc = pop_char(&mut data); + let cc = data.pop_char(); assert_eq!(~"ประเทศไทย中", data); assert_eq!('华', cc); } @@ -2832,7 +2358,7 @@ mod tests { #[test] fn test_pop_char_2() { let mut data2 = ~"华"; - let cc2 = pop_char(&mut data2); + let cc2 = data2.pop_char(); assert_eq!(~"", data2); assert_eq!('华', cc2); } @@ -2842,225 +2368,29 @@ mod tests { #[ignore(cfg(windows))] fn test_pop_char_fail() { let mut data = ~""; - let _cc3 = pop_char(&mut data); - } - - #[test] - fn test_split_char() { - fn t(s: &str, c: char, u: &[~str]) { - debug!("split_byte: %?", s); - let mut v = ~[]; - for each_split_char(s, c) |s| { v.push(s.to_owned()) } - debug!("split_byte to: %?", v); - assert!(vec::all2(v, u, |a,b| a == b)); - } - t("abc.hello.there", '.', [~"abc", ~"hello", ~"there"]); - t(".hello.there", '.', [~"", ~"hello", ~"there"]); - t("...hello.there.", '.', [~"", ~"", ~"", ~"hello", ~"there", ~""]); - - t("", 'z', [~""]); - t("z", 'z', [~"",~""]); - t("ok", 'z', [~"ok"]); - } - - #[test] - fn test_split_char_2() { - fn t(s: &str, c: char, u: &[~str]) { - debug!("split_byte: %?", s); - let mut v = ~[]; - for each_split_char(s, c) |s| { v.push(s.to_owned()) } - debug!("split_byte to: %?", v); - assert!(vec::all2(v, u, |a,b| a == b)); - } - let data = "ประเทศไทย中华Việt Nam"; - t(data, 'V', [~"ประเทศไทย中华", ~"iệt Nam"]); - t(data, 'ท', [~"ประเ", ~"ศไ", ~"ย中华Việt Nam"]); - } - - #[test] - fn test_splitn_char() { - fn t(s: &str, c: char, n: uint, u: &[~str]) { - debug!("splitn_byte: %?", s); - let mut v = ~[]; - for each_splitn_char(s, c, n) |s| { v.push(s.to_owned()) } - debug!("split_byte to: %?", v); - debug!("comparing vs. %?", u); - assert!(vec::all2(v, u, |a,b| a == b)); - } - t("abc.hello.there", '.', 0u, [~"abc.hello.there"]); - t("abc.hello.there", '.', 1u, [~"abc", ~"hello.there"]); - t("abc.hello.there", '.', 2u, [~"abc", ~"hello", ~"there"]); - t("abc.hello.there", '.', 3u, [~"abc", ~"hello", ~"there"]); - t(".hello.there", '.', 0u, [~".hello.there"]); - t(".hello.there", '.', 1u, [~"", ~"hello.there"]); - t("...hello.there.", '.', 3u, [~"", ~"", ~"", ~"hello.there."]); - t("...hello.there.", '.', 5u, [~"", ~"", ~"", ~"hello", ~"there", ~""]); - - t("", 'z', 5u, [~""]); - t("z", 'z', 5u, [~"",~""]); - t("ok", 'z', 5u, [~"ok"]); - t("z", 'z', 0u, [~"z"]); - t("w.x.y", '.', 0u, [~"w.x.y"]); - t("w.x.y", '.', 1u, [~"w",~"x.y"]); - } - - #[test] - fn test_splitn_char_2() { - fn t(s: &str, c: char, n: uint, u: &[~str]) { - debug!("splitn_byte: %?", s); - let mut v = ~[]; - for each_splitn_char(s, c, n) |s| { v.push(s.to_owned()) } - debug!("split_byte to: %?", v); - debug!("comparing vs. %?", u); - assert!(vec::all2(v, u, |a,b| a == b)); - } - - t("ประเทศไทย中华Việt Nam", '华', 1u, [~"ประเทศไทย中", ~"Việt Nam"]); - t("zzXXXzYYYzWWWz", 'z', 3u, [~"", ~"", ~"XXX", ~"YYYzWWWz"]); - t("z", 'z', 5u, [~"",~""]); - t("", 'z', 5u, [~""]); - t("ok", 'z', 5u, [~"ok"]); - } - - #[test] - fn test_splitn_char_3() { - fn t(s: &str, c: char, n: uint, u: &[~str]) { - debug!("splitn_byte: %?", s); - let mut v = ~[]; - for each_splitn_char(s, c, n) |s| { v.push(s.to_owned()) } - debug!("split_byte to: %?", v); - debug!("comparing vs. %?", u); - assert!(vec::all2(v, u, |a,b| a == b)); - } - let data = "ประเทศไทย中华Việt Nam"; - t(data, 'V', 1u, [~"ประเทศไทย中华", ~"iệt Nam"]); - t(data, 'ท', 1u, [~"ประเ", ~"ศไทย中华Việt Nam"]); - } - - #[test] - fn test_split_char_no_trailing() { - fn t(s: &str, c: char, u: &[~str]) { - debug!("split_byte: %?", s); - let mut v = ~[]; - for each_split_char_no_trailing(s, c) |s| { v.push(s.to_owned()) } - debug!("split_byte to: %?", v); - assert!(vec::all2(v, u, |a,b| a == b)); - } - t("abc.hello.there", '.', [~"abc", ~"hello", ~"there"]); - t(".hello.there", '.', [~"", ~"hello", ~"there"]); - t("...hello.there.", '.', [~"", ~"", ~"", ~"hello", ~"there"]); - - t("...hello.there.", '.', [~"", ~"", ~"", ~"hello", ~"there"]); - t("", 'z', []); - t("z", 'z', [~""]); - t("ok", 'z', [~"ok"]); - } - - #[test] - fn test_split_char_no_trailing_2() { - fn t(s: &str, c: char, u: &[~str]) { - debug!("split_byte: %?", s); - let mut v = ~[]; - for each_split_char_no_trailing(s, c) |s| { v.push(s.to_owned()) } - debug!("split_byte to: %?", v); - assert!(vec::all2(v, u, |a,b| a == b)); - } - let data = "ประเทศไทย中华Việt Nam"; - t(data, 'V', [~"ประเทศไทย中华", ~"iệt Nam"]); - t(data, 'ท', [~"ประเ", ~"ศไ", ~"ย中华Việt Nam"]); + let _cc3 = data.pop_char(); } #[test] - fn test_split_str() { - fn t<'a>(s: &str, sep: &'a str, u: &[~str]) { - let mut v = ~[]; - for each_split_str(s, sep) |s| { v.push(s.to_owned()) } - assert!(vec::all2(v, u, |a,b| a == b)); - } - t("--1233345--", "12345", [~"--1233345--"]); - t("abc::hello::there", "::", [~"abc", ~"hello", ~"there"]); - t("::hello::there", "::", [~"", ~"hello", ~"there"]); - t("hello::there::", "::", [~"hello", ~"there", ~""]); - t("::hello::there::", "::", [~"", ~"hello", ~"there", ~""]); - t("ประเทศไทย中华Việt Nam", "中华", [~"ประเทศไทย", ~"Việt Nam"]); - t("zzXXXzzYYYzz", "zz", [~"", ~"XXX", ~"YYY", ~""]); - t("zzXXXzYYYz", "XXX", [~"zz", ~"zYYYz"]); - t(".XXX.YYY.", ".", [~"", ~"XXX", ~"YYY", ~""]); - t("", ".", [~""]); - t("zz", "zz", [~"",~""]); - t("ok", "z", [~"ok"]); - t("zzz", "zz", [~"",~"z"]); - t("zzzzz", "zz", [~"",~"",~"z"]); + fn test_push_char() { + let mut data = ~"ประเทศไทย中"; + data.push_char('华'); + assert_eq!(~"ประเทศไทย中华", data); } - #[test] - fn test_split() { - fn t(s: &str, sepf: &fn(char) -> bool, u: &[~str]) { - let mut v = ~[]; - for each_split(s, sepf) |s| { v.push(s.to_owned()) } - assert!(vec::all2(v, u, |a,b| a == b)); - } - - t("ประเทศไทย中华Việt Nam", |cc| cc == '华', [~"ประเทศไทย中", ~"Việt Nam"]); - t("zzXXXzYYYz", char::is_lowercase, [~"", ~"", ~"XXX", ~"YYY", ~""]); - t("zzXXXzYYYz", char::is_uppercase, [~"zz", ~"", ~"", ~"z", ~"", ~"", ~"z"]); - t("z", |cc| cc == 'z', [~"",~""]); - t("", |cc| cc == 'z', [~""]); - t("ok", |cc| cc == 'z', [~"ok"]); - } - - #[test] - fn test_split_no_trailing() { - fn t(s: &str, sepf: &fn(char) -> bool, u: &[~str]) { - let mut v = ~[]; - for each_split_no_trailing(s, sepf) |s| { v.push(s.to_owned()) } - assert!(vec::all2(v, u, |a,b| a == b)); - } - - t("ประเทศไทย中华Việt Nam", |cc| cc == '华', [~"ประเทศไทย中", ~"Việt Nam"]); - t("zzXXXzYYYz", char::is_lowercase, [~"", ~"", ~"XXX", ~"YYY"]); - t("zzXXXzYYYz", char::is_uppercase, [~"zz", ~"", ~"", ~"z", ~"", ~"", ~"z"]); - t("z", |cc| cc == 'z', [~""]); - t("", |cc| cc == 'z', []); - t("ok", |cc| cc == 'z', [~"ok"]); - } - - #[test] - fn test_lines() { - let lf = "\nMary had a little lamb\nLittle lamb\n"; - let crlf = "\r\nMary had a little lamb\r\nLittle lamb\r\n"; - - fn t(s: &str, f: &fn(&str, &fn(&str) -> bool) -> bool, u: &[~str]) { - let mut v = ~[]; - for f(s) |s| { v.push(s.to_owned()) } - assert!(vec::all2(v, u, |a,b| a == b)); - } - - t(lf, each_line, [~"", ~"Mary had a little lamb", ~"Little lamb"]); - t(lf, each_line_any, [~"", ~"Mary had a little lamb", ~"Little lamb"]); - t(crlf, each_line, [~"\r", ~"Mary had a little lamb\r", ~"Little lamb\r"]); - t(crlf, each_line_any, [~"", ~"Mary had a little lamb", ~"Little lamb"]); - t("", each_line, []); - t("", each_line_any, []); - t("\n", each_line, [~""]); - t("\n", each_line_any, [~""]); - t("banana", each_line, [~"banana"]); - t("banana", each_line_any, [~"banana"]); + fn test_shift_char() { + let mut data = ~"ประเทศไทย中"; + let cc = data.shift_char(); + assert_eq!(~"ระเทศไทย中", data); + assert_eq!('ป', cc); } #[test] - fn test_words() { - fn t(s: &str, f: &fn(&str, &fn(&str) -> bool) -> bool, u: &[~str]) { - let mut v = ~[]; - for f(s) |s| { v.push(s.to_owned()) } - assert!(vec::all2(v, u, |a,b| a == b)); - } - let data = "\nMary had a little lamb\nLittle lamb\n"; - - t(data, each_word, [~"Mary",~"had",~"a",~"little",~"lamb",~"Little",~"lamb"]); - t("ok", each_word, [~"ok"]); - t("", each_word, []); + fn test_unshift_char() { + let mut data = ~"ประเทศไทย中"; + data.unshift_char('华'); + assert_eq!(~"华ประเทศไทย中", data); } #[test] @@ -3068,7 +2398,7 @@ mod tests { fn t(s: &str, i: uint, u: &[~str]) { let mut v = ~[]; for each_split_within(s, i) |s| { v.push(s.to_owned()) } - assert!(vec::all2(v, u, |a,b| a == b)); + assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b)); } t("", 0, []); t("", 15, []); @@ -3080,59 +2410,47 @@ mod tests { #[test] fn test_find_str() { // byte positions - assert!(find_str("banana", "apple pie").is_none()); - assert_eq!(find_str("", ""), Some(0u)); - - let data = "ประเทศไทย中华Việt Nam"; - assert_eq!(find_str(data, ""), Some(0u)); - assert_eq!(find_str(data, "ประเ"), Some( 0u)); - assert_eq!(find_str(data, "ะเ"), Some( 6u)); - assert_eq!(find_str(data, "中华"), Some(27u)); - assert!(find_str(data, "ไท华").is_none()); - } - - #[test] - fn test_find_str_between() { - // byte positions - assert_eq!(find_str_between("", "", 0u, 0u), Some(0u)); + assert_eq!("".find_str(""), Some(0u)); + assert!("banana".find_str("apple pie").is_none()); let data = "abcabc"; - assert_eq!(find_str_between(data, "ab", 0u, 6u), Some(0u)); - assert_eq!(find_str_between(data, "ab", 2u, 6u), Some(3u)); - assert!(find_str_between(data, "ab", 2u, 4u).is_none()); + assert_eq!(data.slice(0u, 6u).find_str("ab"), Some(0u)); + assert_eq!(data.slice(2u, 6u).find_str("ab"), Some(3u - 2u)); + assert!(data.slice(2u, 4u).find_str("ab").is_none()); let mut data = ~"ประเทศไทย中华Việt Nam"; data = data + data; - assert_eq!(find_str_between(data, "", 0u, 43u), Some(0u)); - assert_eq!(find_str_between(data, "", 6u, 43u), Some(6u)); + assert!(data.find_str("ไท华").is_none()); + assert_eq!(data.slice(0u, 43u).find_str(""), Some(0u)); + assert_eq!(data.slice(6u, 43u).find_str(""), Some(6u - 6u)); - assert_eq!(find_str_between(data, "ประ", 0u, 43u), Some( 0u)); - assert_eq!(find_str_between(data, "ทศไ", 0u, 43u), Some(12u)); - assert_eq!(find_str_between(data, "ย中", 0u, 43u), Some(24u)); - assert_eq!(find_str_between(data, "iệt", 0u, 43u), Some(34u)); - assert_eq!(find_str_between(data, "Nam", 0u, 43u), Some(40u)); + assert_eq!(data.slice(0u, 43u).find_str("ประ"), Some( 0u)); + assert_eq!(data.slice(0u, 43u).find_str("ทศไ"), Some(12u)); + assert_eq!(data.slice(0u, 43u).find_str("ย中"), Some(24u)); + assert_eq!(data.slice(0u, 43u).find_str("iệt"), Some(34u)); + assert_eq!(data.slice(0u, 43u).find_str("Nam"), Some(40u)); - assert_eq!(find_str_between(data, "ประ", 43u, 86u), Some(43u)); - assert_eq!(find_str_between(data, "ทศไ", 43u, 86u), Some(55u)); - assert_eq!(find_str_between(data, "ย中", 43u, 86u), Some(67u)); - assert_eq!(find_str_between(data, "iệt", 43u, 86u), Some(77u)); - assert_eq!(find_str_between(data, "Nam", 43u, 86u), Some(83u)); + assert_eq!(data.slice(43u, 86u).find_str("ประ"), Some(43u - 43u)); + assert_eq!(data.slice(43u, 86u).find_str("ทศไ"), Some(55u - 43u)); + assert_eq!(data.slice(43u, 86u).find_str("ย中"), Some(67u - 43u)); + assert_eq!(data.slice(43u, 86u).find_str("iệt"), Some(77u - 43u)); + assert_eq!(data.slice(43u, 86u).find_str("Nam"), Some(83u - 43u)); } #[test] - fn test_substr() { - fn t(a: &str, b: &str, start: int) { - assert_eq!(substr(a, start as uint, len(b)), b); + fn test_slice_chars() { + fn t(a: &str, b: &str, start: uint) { + assert_eq!(a.slice_chars(start, start + b.char_len()), b); } t("hello", "llo", 2); t("hello", "el", 1); - assert_eq!("ะเทศไท", substr("ประเทศไทย中华Việt Nam", 6u, 6u)); + assert_eq!("ะเทศไท", "ประเทศไทย中华Việt Nam".slice_chars(2, 8)); } #[test] fn test_concat() { fn t(v: &[~str], s: &str) { - assert_eq!(concat(v), s.to_str()); + assert_eq!(v.concat(), s.to_str()); } t([~"you", ~"know", ~"I'm", ~"no", ~"good"], "youknowI'mnogood"); let v: &[~str] = []; @@ -3143,7 +2461,7 @@ mod tests { #[test] fn test_connect() { fn t(v: &[~str], sep: &str, s: &str) { - assert_eq!(connect(v, sep), s.to_str()); + assert_eq!(v.connect(sep), s.to_str()); } t([~"you", ~"know", ~"I'm", ~"no", ~"good"], " ", "you know I'm no good"); @@ -3153,9 +2471,20 @@ mod tests { } #[test] + fn test_concat_slices() { + fn t(v: &[&str], s: &str) { + assert_eq!(v.concat(), s.to_str()); + } + t(["you", "know", "I'm", "no", "good"], "youknowI'mnogood"); + let v: &[&str] = []; + t(v, ""); + t(["hi"], "hi"); + } + + #[test] fn test_connect_slices() { fn t(v: &[&str], sep: &str, s: &str) { - assert_eq!(connect_slices(v, sep), s.to_str()); + assert_eq!(v.connect(sep), s.to_str()); } t(["you", "know", "I'm", "no", "good"], " ", "you know I'm no good"); @@ -3165,11 +2494,11 @@ mod tests { #[test] fn test_repeat() { - assert_eq!(repeat("x", 4), ~"xxxx"); - assert_eq!(repeat("hi", 4), ~"hihihihi"); - assert_eq!(repeat("ไท华", 3), ~"ไท华ไท华ไท华"); - assert_eq!(repeat("", 4), ~""); - assert_eq!(repeat("hi", 0), ~""); + assert_eq!("x".repeat(4), ~"xxxx"); + assert_eq!("hi".repeat(4), ~"hihihihi"); + assert_eq!("ไท华".repeat(3), ~"ไท华ไท华ไท华"); + assert_eq!("".repeat(4), ~""); + assert_eq!("hi".repeat(0), ~""); } #[test] @@ -3180,13 +2509,13 @@ mod tests { fn a_million_letter_a() -> ~str { let mut i = 0; let mut rs = ~""; - while i < 100000 { push_str(&mut rs, "aaaaaaaaaa"); i += 1; } + while i < 100000 { rs.push_str("aaaaaaaaaa"); i += 1; } rs } fn half_a_million_letter_a() -> ~str { let mut i = 0; let mut rs = ~""; - while i < 100000 { push_str(&mut rs, "aaaaa"); i += 1; } + while i < 100000 { rs.push_str("aaaaa"); i += 1; } rs } let letters = a_million_letter_a(); @@ -3196,38 +2525,38 @@ mod tests { #[test] fn test_starts_with() { - assert!((starts_with("", ""))); - assert!((starts_with("abc", ""))); - assert!((starts_with("abc", "a"))); - assert!((!starts_with("a", "abc"))); - assert!((!starts_with("", "abc"))); + assert!(("".starts_with(""))); + assert!(("abc".starts_with(""))); + assert!(("abc".starts_with("a"))); + assert!((!"a".starts_with("abc"))); + assert!((!"".starts_with("abc"))); } #[test] fn test_ends_with() { - assert!((ends_with("", ""))); - assert!((ends_with("abc", ""))); - assert!((ends_with("abc", "c"))); - assert!((!ends_with("a", "abc"))); - assert!((!ends_with("", "abc"))); + assert!(("".ends_with(""))); + assert!(("abc".ends_with(""))); + assert!(("abc".ends_with("c"))); + assert!((!"a".ends_with("abc"))); + assert!((!"".ends_with("abc"))); } #[test] fn test_is_empty() { - assert!((is_empty(""))); - assert!((!is_empty("a"))); + assert!("".is_empty()); + assert!(!"a".is_empty()); } #[test] fn test_replace() { let a = "a"; - assert_eq!(replace("", a, "b"), ~""); - assert_eq!(replace("a", a, "b"), ~"b"); - assert_eq!(replace("ab", a, "b"), ~"bb"); + assert_eq!("".replace(a, "b"), ~""); + assert_eq!("a".replace(a, "b"), ~"b"); + assert_eq!("ab".replace(a, "b"), ~"bb"); let test = "test"; - assert!(replace(" test test ", test, "toast") == + assert!(" test test ".replace(test, "toast") == ~" toast toast "); - assert_eq!(replace(" test test ", test, ""), ~" "); + assert_eq!(" test test ".replace(test, ""), ~" "); } #[test] @@ -3237,7 +2566,7 @@ mod tests { let a = ~"ประเ"; let A = ~"دولة الكويتทศไทย中华"; - assert_eq!(replace(data, a, repl), A); + assert_eq!(data.replace(a, repl), A); } #[test] @@ -3247,7 +2576,7 @@ mod tests { let b = ~"ะเ"; let B = ~"ปรدولة الكويتทศไทย中华"; - assert_eq!(replace(data, b, repl), B); + assert_eq!(data.replace(b, repl), B); } #[test] @@ -3257,7 +2586,7 @@ mod tests { let c = ~"中华"; let C = ~"ประเทศไทยدولة الكويت"; - assert_eq!(replace(data, c, repl), C); + assert_eq!(data.replace(c, repl), C); } #[test] @@ -3266,21 +2595,21 @@ mod tests { let repl = ~"دولة الكويت"; let d = ~"ไท华"; - assert_eq!(replace(data, d, repl), data); + assert_eq!(data.replace(d, repl), data); } #[test] fn test_slice() { - assert_eq!("ab", slice("abc", 0, 2)); - assert_eq!("bc", slice("abc", 1, 3)); - assert_eq!("", slice("abc", 1, 1)); - assert_eq!("\u65e5", slice("\u65e5\u672c", 0, 3)); + assert_eq!("ab", "abc".slice(0, 2)); + assert_eq!("bc", "abc".slice(1, 3)); + assert_eq!("", "abc".slice(1, 1)); + assert_eq!("\u65e5", "\u65e5\u672c".slice(0, 3)); let data = "ประเทศไทย中华"; - assert_eq!("ป", slice(data, 0, 3)); - assert_eq!("ร", slice(data, 3, 6)); - assert_eq!("", slice(data, 3, 3)); - assert_eq!("华", slice(data, 30, 33)); + assert_eq!("ป", data.slice(0, 3)); + assert_eq!("ร", data.slice(3, 6)); + assert_eq!("", data.slice(3, 3)); + assert_eq!("华", data.slice(30, 33)); fn a_million_letter_X() -> ~str { let mut i = 0; @@ -3299,23 +2628,23 @@ mod tests { } let letters = a_million_letter_X(); assert!(half_a_million_letter_X() == - slice(letters, 0u, 3u * 500000u).to_owned()); + letters.slice(0u, 3u * 500000u).to_owned()); } #[test] fn test_slice_2() { let ss = "中华Việt Nam"; - assert_eq!("华", slice(ss, 3u, 6u)); - assert_eq!("Việt Nam", slice(ss, 6u, 16u)); + assert_eq!("华", ss.slice(3u, 6u)); + assert_eq!("Việt Nam", ss.slice(6u, 16u)); - assert_eq!("ab", slice("abc", 0u, 2u)); - assert_eq!("bc", slice("abc", 1u, 3u)); - assert_eq!("", slice("abc", 1u, 1u)); + assert_eq!("ab", "abc".slice(0u, 2u)); + assert_eq!("bc", "abc".slice(1u, 3u)); + assert_eq!("", "abc".slice(1u, 1u)); - assert_eq!("中", slice(ss, 0u, 3u)); - assert_eq!("华V", slice(ss, 3u, 7u)); - assert_eq!("", slice(ss, 3u, 3u)); + assert_eq!("中", ss.slice(0u, 3u)); + assert_eq!("华V", ss.slice(3u, 7u)); + assert_eq!("", ss.slice(3u, 3u)); /*0: 中 3: 华 6: V @@ -3332,70 +2661,98 @@ mod tests { #[should_fail] #[ignore(cfg(windows))] fn test_slice_fail() { - slice("中华Việt Nam", 0u, 2u); + "中华Việt Nam".slice(0u, 2u); + } + + #[test] + fn test_slice_from() { + assert_eq!("abcd".slice_from(0), "abcd"); + assert_eq!("abcd".slice_from(2), "cd"); + assert_eq!("abcd".slice_from(4), ""); + } + #[test] + fn test_slice_to() { + assert_eq!("abcd".slice_to(0), ""); + assert_eq!("abcd".slice_to(2), "ab"); + assert_eq!("abcd".slice_to(4), "abcd"); } #[test] fn test_trim_left_chars() { - assert!(trim_left_chars(" *** foo *** ", []) == " *** foo *** "); - assert!(trim_left_chars(" *** foo *** ", ['*', ' ']) == "foo *** "); - assert_eq!(trim_left_chars(" *** *** ", ['*', ' ']), ""); - assert!(trim_left_chars("foo *** ", ['*', ' ']) == "foo *** "); + let v: &[char] = &[]; + assert_eq!(" *** foo *** ".trim_left_chars(&v), " *** foo *** "); + assert_eq!(" *** foo *** ".trim_left_chars(& &['*', ' ']), "foo *** "); + assert_eq!(" *** *** ".trim_left_chars(& &['*', ' ']), ""); + assert_eq!("foo *** ".trim_left_chars(& &['*', ' ']), "foo *** "); + + 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"); } #[test] fn test_trim_right_chars() { - assert!(trim_right_chars(" *** foo *** ", []) == " *** foo *** "); - assert!(trim_right_chars(" *** foo *** ", ['*', ' ']) == " *** foo"); - assert_eq!(trim_right_chars(" *** *** ", ['*', ' ']), ""); - assert!(trim_right_chars(" *** foo", ['*', ' ']) == " *** foo"); + let v: &[char] = &[]; + assert_eq!(" *** foo *** ".trim_right_chars(&v), " *** foo *** "); + assert_eq!(" *** foo *** ".trim_right_chars(& &['*', ' ']), " *** foo"); + assert_eq!(" *** *** ".trim_right_chars(& &['*', ' ']), ""); + assert_eq!(" *** foo".trim_right_chars(& &['*', ' ']), " *** foo"); + + 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"); } #[test] fn test_trim_chars() { - assert_eq!(trim_chars(" *** foo *** ", []), " *** foo *** "); - assert_eq!(trim_chars(" *** foo *** ", ['*', ' ']), "foo"); - assert_eq!(trim_chars(" *** *** ", ['*', ' ']), ""); - assert_eq!(trim_chars("foo", ['*', ' ']), "foo"); + let v: &[char] = &[]; + assert_eq!(" *** foo *** ".trim_chars(&v), " *** foo *** "); + assert_eq!(" *** foo *** ".trim_chars(& &['*', ' ']), "foo"); + assert_eq!(" *** *** ".trim_chars(& &['*', ' ']), ""); + assert_eq!("foo".trim_chars(& &['*', ' ']), "foo"); + + 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"); } #[test] fn test_trim_left() { - assert_eq!(trim_left(""), ""); - assert_eq!(trim_left("a"), "a"); - assert_eq!(trim_left(" "), ""); - assert_eq!(trim_left(" blah"), "blah"); - assert_eq!(trim_left(" \u3000 wut"), "wut"); - assert_eq!(trim_left("hey "), "hey "); + assert_eq!("".trim_left(), ""); + assert_eq!("a".trim_left(), "a"); + assert_eq!(" ".trim_left(), ""); + assert_eq!(" blah".trim_left(), "blah"); + assert_eq!(" \u3000 wut".trim_left(), "wut"); + assert_eq!("hey ".trim_left(), "hey "); } #[test] fn test_trim_right() { - assert_eq!(trim_right(""), ""); - assert_eq!(trim_right("a"), "a"); - assert_eq!(trim_right(" "), ""); - assert_eq!(trim_right("blah "), "blah"); - assert_eq!(trim_right("wut \u3000 "), "wut"); - assert_eq!(trim_right(" hey"), " hey"); + assert_eq!("".trim_right(), ""); + assert_eq!("a".trim_right(), "a"); + assert_eq!(" ".trim_right(), ""); + assert_eq!("blah ".trim_right(), "blah"); + assert_eq!("wut \u3000 ".trim_right(), "wut"); + assert_eq!(" hey".trim_right(), " hey"); } #[test] fn test_trim() { - assert_eq!(trim(""), ""); - assert_eq!(trim("a"), "a"); - assert_eq!(trim(" "), ""); - assert_eq!(trim(" blah "), "blah"); - assert_eq!(trim("\nwut \u3000 "), "wut"); - assert_eq!(trim(" hey dude "), "hey dude"); + assert_eq!("".trim(), ""); + assert_eq!("a".trim(), "a"); + assert_eq!(" ".trim(), ""); + assert_eq!(" blah ".trim(), "blah"); + assert_eq!("\nwut \u3000 ".trim(), "wut"); + assert_eq!(" hey dude ".trim(), "hey dude"); } #[test] fn test_is_whitespace() { - assert!(is_whitespace("")); - assert!(is_whitespace(" ")); - assert!(is_whitespace("\u2009")); // Thin space - assert!(is_whitespace(" \n\t ")); - assert!(!is_whitespace(" _ ")); + assert!("".is_whitespace()); + assert!(" ".is_whitespace()); + assert!("\u2009".is_whitespace()); // Thin space + assert!(" \n\t ".is_whitespace()); + assert!(!" _ ".is_whitespace()); } #[test] @@ -3439,9 +2796,10 @@ mod tests { } #[test] - #[should_fail] #[ignore(cfg(windows))] fn test_from_bytes_fail() { + use str::not_utf8::cond; + let bb = ~[0xff_u8, 0xb8_u8, 0xa8_u8, 0xe0_u8, 0xb9_u8, 0x84_u8, 0xe0_u8, 0xb8_u8, 0x97_u8, @@ -3453,7 +2811,15 @@ mod tests { 0x20_u8, 0x4e_u8, 0x61_u8, 0x6d_u8]; - let _x = from_bytes(bb); + let mut error_happened = false; + let _x = do cond.trap(|err| { + assert_eq!(err, ~"from_bytes: input is not UTF-8; first bad byte is 255"); + error_happened = true; + ~"" + }).in { + from_bytes(bb) + }; + assert!(error_happened); } #[test] @@ -3527,11 +2893,65 @@ mod tests { } #[test] + fn test_as_bytes() { + // no null + let v = [ + 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, + 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, + 109 + ]; + assert_eq!("".as_bytes(), &[]); + assert_eq!("abc".as_bytes(), &['a' as u8, 'b' as u8, 'c' as u8]); + assert_eq!("ศไทย中华Việt Nam".as_bytes(), v); + } + + #[test] + fn test_as_bytes_with_null() { + // has null + let v = [ + 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, + 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, + 109, 0 + ]; + + let s1 = @""; + let s2 = @"abc"; + let s3 = @"ศไทย中华Việt Nam"; + assert_eq!(s1.as_bytes_with_null(), &[0]); + assert_eq!(s2.as_bytes_with_null(), &['a' as u8, 'b' as u8, 'c' as u8, 0]); + assert_eq!(s3.as_bytes_with_null(), v); + + let s1 = ~""; + let s2 = ~"abc"; + let s3 = ~"ศไทย中华Việt Nam"; + assert_eq!(s1.as_bytes_with_null(), &[0]); + assert_eq!(s2.as_bytes_with_null(), &['a' as u8, 'b' as u8, 'c' as u8, 0]); + assert_eq!(s3.as_bytes_with_null(), v); + } + + #[test] + fn test_as_bytes_with_null_consume() { + let s = ~"ศไทย中华Việt Nam"; + let v = ~[ + 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, + 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, + 109, 0 + ]; + assert_eq!((~"").as_bytes_with_null_consume(), ~[0]); + assert_eq!((~"abc").as_bytes_with_null_consume(), + ~['a' as u8, 'b' as u8, 'c' as u8, 0]); + assert_eq!(s.as_bytes_with_null_consume(), v); + } + + #[test] #[ignore(cfg(windows))] #[should_fail] fn test_as_bytes_fail() { - // Don't double free - as_bytes::<()>(&~"", |_bytes| fail!() ); + // Don't double free. (I'm not sure if this exercises the + // original problem code path anymore.) + let s = ~""; + let _bytes = s.as_bytes_with_null(); + fail!(); } #[test] @@ -3581,14 +3001,14 @@ mod tests { #[test] fn test_subslice_offset() { let a = "kernelsprite"; - let b = slice(a, 7, len(a)); - let c = slice(a, 0, len(a) - 6); + let b = a.slice(7, a.len()); + let c = a.slice(0, a.len() - 6); assert_eq!(subslice_offset(a, b), 7); assert_eq!(subslice_offset(a, c), 0); let string = "a\nb\nc"; let mut lines = ~[]; - for each_line(string) |line| { lines.push(line) } + for string.line_iter().advance |line| { lines.push(line) } assert_eq!(subslice_offset(string, lines[0]), 0); assert_eq!(subslice_offset(string, lines[1]), 2); assert_eq!(subslice_offset(string, lines[2]), 4); @@ -3606,11 +3026,11 @@ mod tests { fn vec_str_conversions() { let s1: ~str = ~"All mimsy were the borogoves"; - let v: ~[u8] = to_bytes(s1); + let v: ~[u8] = s1.as_bytes().to_owned(); let s2: ~str = from_bytes(v); let mut i: uint = 0u; - let n1: uint = len(s1); - let n2: uint = vec::len::<u8>(v); + let n1: uint = s1.len(); + let n2: uint = v.len(); assert_eq!(n1, n2); while i < n1 { let a: u8 = s1[i]; @@ -3624,99 +3044,27 @@ mod tests { #[test] fn test_contains() { - assert!(contains("abcde", "bcd")); - assert!(contains("abcde", "abcd")); - assert!(contains("abcde", "bcde")); - assert!(contains("abcde", "")); - assert!(contains("", "")); - assert!(!contains("abcde", "def")); - assert!(!contains("", "a")); + assert!("abcde".contains("bcd")); + assert!("abcde".contains("abcd")); + assert!("abcde".contains("bcde")); + assert!("abcde".contains("")); + assert!("".contains("")); + assert!(!"abcde".contains("def")); + assert!(!"".contains("a")); let data = ~"ประเทศไทย中华Việt Nam"; - assert!(contains(data, "ประเ")); - assert!(contains(data, "ะเ")); - assert!(contains(data, "中华")); - assert!(!contains(data, "ไท华")); + assert!(data.contains("ประเ")); + assert!(data.contains("ะเ")); + assert!(data.contains("中华")); + assert!(!data.contains("ไท华")); } #[test] fn test_contains_char() { - assert!(contains_char("abc", 'b')); - assert!(contains_char("a", 'a')); - assert!(!contains_char("abc", 'd')); - assert!(!contains_char("", 'a')); - } - - #[test] - fn test_split_char_each() { - let data = "\nMary had a little lamb\nLittle lamb\n"; - - let mut ii = 0; - - for each_split_char(data, ' ') |xx| { - match ii { - 0 => assert!("\nMary" == xx), - 1 => assert!("had" == xx), - 2 => assert!("a" == xx), - 3 => assert!("little" == xx), - _ => () - } - ii += 1; - } - } - - #[test] - fn test_splitn_char_each() { - let data = "\nMary had a little lamb\nLittle lamb\n"; - - let mut ii = 0; - - for each_splitn_char(data, ' ', 2u) |xx| { - match ii { - 0 => assert!("\nMary" == xx), - 1 => assert!("had" == xx), - 2 => assert!("a little lamb\nLittle lamb\n" == xx), - _ => () - } - ii += 1; - } - } - - #[test] - fn test_words_each() { - let data = "\nMary had a little lamb\nLittle lamb\n"; - - let mut ii = 0; - - for each_word(data) |ww| { - match ii { - 0 => assert!("Mary" == ww), - 1 => assert!("had" == ww), - 2 => assert!("a" == ww), - 3 => assert!("little" == ww), - _ => () - } - ii += 1; - } - - each_word("", |_x| fail!()); // should not fail - } - - #[test] - fn test_lines_each () { - let lf = "\nMary had a little lamb\nLittle lamb\n"; - - let mut ii = 0; - - for each_line(lf) |x| { - match ii { - 0 => assert!("" == x), - 1 => assert!("Mary had a little lamb" == x), - 2 => assert!("Little lamb" == x), - _ => () - } - ii += 1; - } + assert!("abc".contains_char('b')); + assert!("a".contains_char('a')); + assert!(!"abc".contains_char('d')); + assert!(!"".contains_char('a')); } #[test] @@ -3726,32 +3074,6 @@ mod tests { } #[test] - fn test_all() { - assert_eq!(true, all("", char::is_uppercase)); - assert_eq!(false, all("ymca", char::is_uppercase)); - assert_eq!(true, all("YMCA", char::is_uppercase)); - assert_eq!(false, all("yMCA", char::is_uppercase)); - assert_eq!(false, all("YMCy", char::is_uppercase)); - } - - #[test] - fn test_any() { - assert_eq!(false, any("", char::is_uppercase)); - assert_eq!(false, any("ymca", char::is_uppercase)); - assert_eq!(true, any("YMCA", char::is_uppercase)); - assert_eq!(true, any("yMCA", char::is_uppercase)); - assert_eq!(true, any("Ymcy", char::is_uppercase)); - } - - #[test] - fn test_chars() { - let ss = ~"ศไทย中华Việt Nam"; - assert!(~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a', - 'm'] - == to_chars(ss)); - } - - #[test] fn test_utf16() { let pairs = [(~"𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n", @@ -3815,85 +3137,107 @@ mod tests { let s = ~"ศไทย中华Việt Nam"; let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; let mut pos = s.len(); - for v.each_reverse |ch| { + for v.rev_iter().advance |ch| { assert!(s.char_at_reverse(pos) == *ch); pos -= from_char(*ch).len(); } } #[test] - fn test_each() { - let s = ~"ศไทย中华Việt Nam"; - let v = [ - 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, - 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, - 109 - ]; - let mut pos = 0; + fn test_escape_unicode() { + assert_eq!("abc".escape_unicode(), ~"\\x61\\x62\\x63"); + assert_eq!("a c".escape_unicode(), ~"\\x61\\x20\\x63"); + assert_eq!("\r\n\t".escape_unicode(), ~"\\x0d\\x0a\\x09"); + assert_eq!("'\"\\".escape_unicode(), ~"\\x27\\x22\\x5c"); + assert_eq!("\x00\x01\xfe\xff".escape_unicode(), ~"\\x00\\x01\\xfe\\xff"); + assert_eq!("\u0100\uffff".escape_unicode(), ~"\\u0100\\uffff"); + assert_eq!("\U00010000\U0010ffff".escape_unicode(), ~"\\U00010000\\U0010ffff"); + assert_eq!("ab\ufb00".escape_unicode(), ~"\\x61\\x62\\ufb00"); + assert_eq!("\U0001d4ea\r".escape_unicode(), ~"\\U0001d4ea\\x0d"); + } - for s.each |b| { - assert_eq!(b, v[pos]); - pos += 1; - } + #[test] + fn test_escape_default() { + assert_eq!("abc".escape_default(), ~"abc"); + assert_eq!("a c".escape_default(), ~"a c"); + assert_eq!("\r\n\t".escape_default(), ~"\\r\\n\\t"); + assert_eq!("'\"\\".escape_default(), ~"\\'\\\"\\\\"); + assert_eq!("\u0100\uffff".escape_default(), ~"\\u0100\\uffff"); + assert_eq!("\U00010000\U0010ffff".escape_default(), ~"\\U00010000\\U0010ffff"); + assert_eq!("ab\ufb00".escape_default(), ~"ab\\ufb00"); + assert_eq!("\U0001d4ea\r".escape_default(), ~"\\U0001d4ea\\r"); } #[test] - fn test_each_empty() { - for "".each |b| { - assert_eq!(b, 0u8); - } + fn test_to_managed() { + assert_eq!("abc".to_managed(), @"abc"); + assert_eq!("abcdef".slice(1, 5).to_managed(), @"bcde"); + } + + #[test] + fn test_total_ord() { + "1234".cmp(& &"123") == Greater; + "123".cmp(& &"1234") == Less; + "1234".cmp(& &"1234") == Equal; + "12345555".cmp(& &"123456") == Less; + "22".cmp(& &"1234") == Greater; + } + + #[test] + fn test_char_range_at_reverse_underflow() { + assert_eq!("abc".char_range_at_reverse(0).next, 0); } #[test] - fn test_eachi() { + fn test_iterator() { + use iterator::*; let s = ~"ศไทย中华Việt Nam"; - let v = [ - 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, - 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, - 109 - ]; + let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; + let mut pos = 0; + let mut it = s.iter(); - for s.eachi |i, b| { - assert_eq!(pos, i); - assert_eq!(b, v[pos]); + for it.advance |c| { + assert_eq!(c, v[pos]); pos += 1; } + assert_eq!(pos, v.len()); } #[test] - fn test_eachi_empty() { - for "".eachi |i, b| { - assert_eq!(i, 0); - assert_eq!(b, 0); + fn test_rev_iterator() { + use iterator::*; + let s = ~"ศไทย中华Việt Nam"; + let v = ~['m', 'a', 'N', ' ', 't', 'ệ','i','V','华','中','ย','ท','ไ','ศ']; + + let mut pos = 0; + let mut it = s.rev_iter(); + + for it.advance |c| { + assert_eq!(c, v[pos]); + pos += 1; } + assert_eq!(pos, v.len()); } #[test] - fn test_each_reverse() { + fn test_bytes_iterator() { let s = ~"ศไทย中华Việt Nam"; let v = [ 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, 109 ]; - let mut pos = v.len(); + let mut pos = 0; - for s.each_reverse |b| { - pos -= 1; + for s.bytes_iter().advance |b| { assert_eq!(b, v[pos]); + pos += 1; } } #[test] - fn test_each_empty_reverse() { - for "".each_reverse |b| { - assert_eq!(b, 0u8); - } - } - - #[test] - fn test_eachi_reverse() { + fn test_bytes_rev_iterator() { let s = ~"ศไทย中华Việt Nam"; let v = [ 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, @@ -3902,128 +3246,95 @@ mod tests { ]; let mut pos = v.len(); - for s.eachi_reverse |i, b| { + for s.bytes_rev_iter().advance |b| { pos -= 1; - assert_eq!(pos, i); assert_eq!(b, v[pos]); } } #[test] - fn test_eachi_reverse_empty() { - for "".eachi_reverse |i, b| { - assert_eq!(i, 0); - assert_eq!(b, 0); - } - } + fn test_split_char_iterator() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - #[test] - fn test_each_char() { - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; - let mut pos = 0; - for s.each_char |ch| { - assert_eq!(ch, v[pos]); - pos += 1; - } - } + let split: ~[&str] = data.split_iter(' ').collect(); + assert_eq!(split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - #[test] - fn test_each_chari() { - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; - let mut pos = 0; - for s.each_chari |i, ch| { - assert_eq!(pos, i); - assert_eq!(ch, v[pos]); - pos += 1; - } - } + let split: ~[&str] = data.split_iter(|c: char| c == ' ').collect(); + assert_eq!(split, ~["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - #[test] - fn test_each_char_reverse() { - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; - let mut pos = v.len(); - for s.each_char_reverse |ch| { - pos -= 1; - assert_eq!(ch, v[pos]); - } - } + // Unicode + let split: ~[&str] = data.split_iter('ä').collect(); + assert_eq!(split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); - #[test] - fn test_each_chari_reverse() { - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; - let mut pos = v.len(); - for s.each_chari_reverse |i, ch| { - pos -= 1; - assert_eq!(pos, i); - assert_eq!(ch, v[pos]); - } + let split: ~[&str] = data.split_iter(|c: char| c == 'ä').collect(); + assert_eq!(split, ~["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); } - #[test] - fn test_escape_unicode() { - assert_eq!(escape_unicode("abc"), ~"\\x61\\x62\\x63"); - assert_eq!(escape_unicode("a c"), ~"\\x61\\x20\\x63"); - assert_eq!(escape_unicode("\r\n\t"), ~"\\x0d\\x0a\\x09"); - assert_eq!(escape_unicode("'\"\\"), ~"\\x27\\x22\\x5c"); - assert!(escape_unicode("\x00\x01\xfe\xff") == - ~"\\x00\\x01\\xfe\\xff"); - assert_eq!(escape_unicode("\u0100\uffff"), ~"\\u0100\\uffff"); - assert!(escape_unicode("\U00010000\U0010ffff") == - ~"\\U00010000\\U0010ffff"); - assert_eq!(escape_unicode("ab\ufb00"), ~"\\x61\\x62\\ufb00"); - assert_eq!(escape_unicode("\U0001d4ea\r"), ~"\\U0001d4ea\\x0d"); - } + fn test_splitn_char_iterator() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - #[test] - fn test_escape_default() { - assert_eq!(escape_default("abc"), ~"abc"); - assert_eq!(escape_default("a c"), ~"a c"); - assert_eq!(escape_default("\r\n\t"), ~"\\r\\n\\t"); - assert_eq!(escape_default("'\"\\"), ~"\\'\\\"\\\\"); - assert_eq!(escape_default("\u0100\uffff"), ~"\\u0100\\uffff"); - assert!(escape_default("\U00010000\U0010ffff") == - ~"\\U00010000\\U0010ffff"); - assert_eq!(escape_default("ab\ufb00"), ~"ab\\ufb00"); - assert_eq!(escape_default("\U0001d4ea\r"), ~"\\U0001d4ea\\r"); - } + let split: ~[&str] = data.splitn_iter(' ', 3).collect(); + assert_eq!(split, ~["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); - #[test] - fn test_to_managed() { - assert_eq!("abc".to_managed(), @"abc"); - assert_eq!(slice("abcdef", 1, 5).to_managed(), @"bcde"); + let split: ~[&str] = data.splitn_iter(|c: char| c == ' ', 3).collect(); + assert_eq!(split, ~["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); + + // Unicode + let split: ~[&str] = data.splitn_iter('ä', 3).collect(); + assert_eq!(split, ~["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); + + let split: ~[&str] = data.splitn_iter(|c: char| c == 'ä', 3).collect(); + assert_eq!(split, ~["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); } #[test] - fn test_total_ord() { - "1234".cmp(& &"123") == Greater; - "123".cmp(& &"1234") == Less; - "1234".cmp(& &"1234") == Equal; - "12345555".cmp(& &"123456") == Less; - "22".cmp(& &"1234") == Greater; + fn test_split_char_iterator_no_trailing() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: ~[&str] = data.split_options_iter('\n', 1000, true).collect(); + assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb", ""]); + + let split: ~[&str] = data.split_options_iter('\n', 1000, false).collect(); + assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb"]); } #[test] - fn test_char_range_at_reverse_underflow() { - assert_eq!(char_range_at_reverse("abc", 0).next, 0); + fn test_word_iter() { + let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n"; + let words: ~[&str] = data.word_iter().collect(); + assert_eq!(words, ~["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"]) } #[test] - fn test_iterator() { - use iterator::*; - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; + fn test_line_iter() { + let data = "\nMäry häd ä little lämb\n\nLittle lämb\n"; + let lines: ~[&str] = data.line_iter().collect(); + assert_eq!(lines, ~["", "Märy häd ä little lämb", "", "Little lämb"]); - let mut pos = 0; - let mut it = s.char_iter(); + let data = "\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n + let lines: ~[&str] = data.line_iter().collect(); + assert_eq!(lines, ~["", "Märy häd ä little lämb", "", "Little lämb"]); + } - for it.advance |c| { - assert_eq!(c, v[pos]); - pos += 1; + #[test] + fn test_split_str_iterator() { + fn t<'a>(s: &str, sep: &'a str, u: ~[&str]) { + let v: ~[&str] = s.split_str_iter(sep).collect(); + assert_eq!(v, u); } - assert_eq!(pos, v.len()); + t("--1233345--", "12345", ~["--1233345--"]); + t("abc::hello::there", "::", ~["abc", "hello", "there"]); + t("::hello::there", "::", ~["", "hello", "there"]); + t("hello::there::", "::", ~["hello", "there", ""]); + t("::hello::there::", "::", ~["", "hello", "there", ""]); + t("ประเทศไทย中华Việt Nam", "中华", ~["ประเทศไทย", "Việt Nam"]); + t("zzXXXzzYYYzz", "zz", ~["", "XXX", "YYY", ""]); + t("zzXXXzYYYz", "XXX", ~["zz", "zYYYz"]); + t(".XXX.YYY.", ".", ~["", "XXX", "YYY", ""]); + t("", ".", ~[""]); + t("zz", "zz", ~["",""]); + t("ok", "z", ~["ok"]); + t("zzz", "zz", ~["","z"]); + t("zzzzz", "zz", ~["","","z"]); } } diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index e48fef01df9..618d5095777 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -15,28 +15,29 @@ use str; use str::StrSlice; use cast; use old_iter::BaseIter; +use iterator::IteratorUtil; use vec::{CopyableVector, ImmutableVector, OwnedVector}; /// Datatype to hold one ascii character. It is 8 bit long. #[deriving(Clone, Eq)] pub struct Ascii { priv chr: u8 } -pub impl Ascii { +impl Ascii { /// Converts a ascii character into a `u8`. #[inline(always)] - fn to_byte(self) -> u8 { + pub fn to_byte(self) -> u8 { self.chr } /// Converts a ascii character into a `char`. #[inline(always)] - fn to_char(self) -> char { + pub fn to_char(self) -> char { self.chr as char } /// Convert to lowercase. #[inline(always)] - fn to_lower(self) -> Ascii { + pub fn to_lower(self) -> Ascii { if self.chr >= 65 && self.chr <= 90 { Ascii{chr: self.chr | 0x20 } } else { @@ -46,7 +47,7 @@ pub impl Ascii { /// Convert to uppercase. #[inline(always)] - fn to_upper(self) -> Ascii { + pub fn to_upper(self) -> Ascii { if self.chr >= 97 && self.chr <= 122 { Ascii{chr: self.chr & !0x20 } } else { @@ -54,9 +55,9 @@ pub impl Ascii { } } - // Compares two ascii characters of equality, ignoring case. + /// Compares two ascii characters of equality, ignoring case. #[inline(always)] - fn eq_ignore_case(self, other: Ascii) -> bool { + pub fn eq_ignore_case(self, other: Ascii) -> bool { self.to_lower().chr == other.to_lower().chr } } @@ -101,10 +102,7 @@ impl<'self> AsciiCast<&'self[Ascii]> for &'self str { #[inline(always)] fn is_ascii(&self) -> bool { - for self.each |b| { - if !b.is_ascii() { return false; } - } - true + self.bytes_iter().all(|b| b.is_ascii()) } } @@ -204,7 +202,6 @@ impl ToStrConsume for ~[Ascii] { #[cfg(test)] mod tests { use super::*; - use str; macro_rules! v2ascii ( ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]); @@ -228,8 +225,8 @@ mod tests { assert_eq!('`'.to_ascii().to_upper().to_char(), '`'); assert_eq!('{'.to_ascii().to_upper().to_char(), '{'); - assert!(str::all("banana", |c| c.is_ascii())); - assert!(! str::all("ประเทศไทย中华Việt Nam", |c| c.is_ascii())); + assert!("banana".iter().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华Việt Nam".iter().all(|c| c.is_ascii())); } #[test] diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index 137070ce202..e49ad348542 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -10,9 +10,10 @@ //! Misc low level stuff +#[allow(missing_doc)]; + use option::{Some, None}; use cast; -use cmp::{Eq, Ord}; use gc; use io; use libc; @@ -50,20 +51,6 @@ pub mod rustrt { } } -/// Compares contents of two pointers using the default method. -/// Equivalent to `*x1 == *x2`. Useful for hashtables. -pub fn shape_eq<T:Eq>(x1: &T, x2: &T) -> bool { - *x1 == *x2 -} - -pub fn shape_lt<T:Ord>(x1: &T, x2: &T) -> bool { - *x1 < *x2 -} - -pub fn shape_le<T:Ord>(x1: &T, x2: &T) -> bool { - *x1 <= *x2 -} - /** * Returns a pointer to a type descriptor. * @@ -226,11 +213,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { gc::cleanup_stack_for_failure(); let task = Local::unsafe_borrow::<Task>(); - let unwinder: &mut Option<Unwinder> = &mut (*task).unwinder; - match *unwinder { - Some(ref mut unwinder) => unwinder.begin_unwind(), - None => abort!("failure without unwinder. aborting process") - } + (*task).unwinder.begin_unwind(); } } } diff --git a/src/libstd/task/local_data_priv.rs b/src/libstd/task/local_data_priv.rs index d3757ea3f4f..f6b14a51539 100644 --- a/src/libstd/task/local_data_priv.rs +++ b/src/libstd/task/local_data_priv.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(missing_doc)]; + use cast; use cmp::Eq; use libc; diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index f24d2327358..99858feab22 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -33,19 +33,26 @@ * ~~~ */ +#[allow(missing_doc)]; + +use prelude::*; + use cell::Cell; use cmp::Eq; -use result::Result; use comm::{stream, Chan, GenericChan, GenericPort, Port}; -use prelude::*; +use result::Result; use result; +use rt::{context, OldTaskContext}; use task::rt::{task_id, sched_id}; -use util; -use util::replace; use unstable::finally::Finally; -use rt::{context, OldTaskContext}; +use util::replace; +use util; +#[cfg(test)] use cast; #[cfg(test)] use comm::SharedChan; +#[cfg(test)] use comm; +#[cfg(test)] use ptr; +#[cfg(test)] use task; mod local_data_priv; pub mod rt; @@ -195,7 +202,7 @@ pub fn task() -> TaskBuilder { } } -priv impl TaskBuilder { +impl TaskBuilder { fn consume(&mut self) -> TaskBuilder { if self.consumed { fail!("Cannot copy a task_builder"); // Fake move mode on self @@ -217,24 +224,24 @@ priv impl TaskBuilder { } } -pub impl TaskBuilder { +impl TaskBuilder { /// Decouple the child task's failure from the parent's. If either fails, /// the other will not be killed. - fn unlinked(&mut self) { + pub fn unlinked(&mut self) { self.opts.linked = false; } /// Unidirectionally link the child task's failure with the parent's. The /// child's failure will not kill the parent, but the parent's will kill /// the child. - fn supervised(&mut self) { + pub fn supervised(&mut self) { self.opts.supervised = true; self.opts.linked = false; } /// Link the child task's and parent task's failures. If either fails, the /// other will be killed. - fn linked(&mut self) { + pub fn linked(&mut self) { self.opts.linked = true; self.opts.supervised = false; } @@ -256,7 +263,7 @@ pub impl TaskBuilder { * # Failure * Fails if a future_result was already set for this task. */ - fn future_result(&mut self, blk: &fn(v: Port<TaskResult>)) { + pub fn future_result(&mut self, blk: &fn(v: Port<TaskResult>)) { // FIXME (#3725): Once linked failure and notification are // handled in the library, I can imagine implementing this by just // registering an arbitrary number of task::on_exit handlers and @@ -276,7 +283,7 @@ pub impl TaskBuilder { } /// Configure a custom scheduler mode for the task. - fn sched_mode(&mut self, mode: SchedMode) { + pub fn sched_mode(&mut self, mode: SchedMode) { self.opts.sched.mode = mode; } @@ -292,7 +299,7 @@ pub impl TaskBuilder { * generator by applying the task body which results from the * existing body generator to the new body generator. */ - fn add_wrapper(&mut self, wrapper: ~fn(v: ~fn()) -> ~fn()) { + pub fn add_wrapper(&mut self, wrapper: ~fn(v: ~fn()) -> ~fn()) { let prev_gen_body = replace(&mut self.gen_body, None); let prev_gen_body = match prev_gen_body { Some(gen) => gen, @@ -301,7 +308,7 @@ pub impl TaskBuilder { f } }; - let prev_gen_body = Cell(prev_gen_body); + let prev_gen_body = Cell::new(prev_gen_body); let next_gen_body = { let f: ~fn(~fn()) -> ~fn() = |body| { let prev_gen_body = prev_gen_body.take(); @@ -324,7 +331,7 @@ pub impl TaskBuilder { * When spawning into a new scheduler, the number of threads requested * must be greater than zero. */ - fn spawn(&mut self, f: ~fn()) { + pub fn spawn(&mut self, f: ~fn()) { let gen_body = replace(&mut self.gen_body, None); let notify_chan = replace(&mut self.opts.notify_chan, None); let x = self.consume(); @@ -346,8 +353,8 @@ pub impl TaskBuilder { } /// Runs a task, while transfering ownership of one argument to the child. - fn spawn_with<A:Owned>(&mut self, arg: A, f: ~fn(v: A)) { - let arg = Cell(arg); + pub fn spawn_with<A:Owned>(&mut self, arg: A, f: ~fn(v: A)) { + let arg = Cell::new(arg); do self.spawn { f(arg.take()); } @@ -366,7 +373,7 @@ pub impl TaskBuilder { * # Failure * Fails if a future_result was already set for this task. */ - fn try<T:Owned>(&mut self, f: ~fn() -> T) -> Result<T,()> { + pub fn try<T:Owned>(&mut self, f: ~fn() -> T) -> Result<T,()> { let (po, ch) = stream::<T>(); let mut result = None; @@ -513,20 +520,9 @@ pub fn failing() -> bool { } } _ => { - let mut unwinding = false; - do Local::borrow::<Task> |local| { - unwinding = match local.unwinder { - Some(unwinder) => { - unwinder.unwinding - } - None => { - // Because there is no unwinder we can't be unwinding. - // (The process will abort on failure) - false - } - } + do Local::borrow::<Task, bool> |local| { + local.unwinder.unwinding } - return unwinding; } } } @@ -784,9 +780,9 @@ struct Wrapper { fn test_add_wrapper() { let (po, ch) = stream::<()>(); let mut b0 = task(); - let ch = Cell(ch); + let ch = Cell::new(ch); do b0.add_wrapper |body| { - let ch = Cell(ch.take()); + let ch = Cell::new(ch.take()); let result: ~fn() = || { let ch = ch.take(); body(); @@ -883,10 +879,10 @@ fn test_spawn_sched_childs_on_default_sched() { // Assuming tests run on the default scheduler let default_id = unsafe { rt::rust_get_sched_id() }; - let ch = Cell(ch); + let ch = Cell::new(ch); do spawn_sched(SingleThreaded) { let parent_sched_id = unsafe { rt::rust_get_sched_id() }; - let ch = Cell(ch.take()); + let ch = Cell::new(ch.take()); do spawn { let ch = ch.take(); let child_sched_id = unsafe { rt::rust_get_sched_id() }; diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 5941221821a..9df93d19d21 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -72,12 +72,13 @@ #[doc(hidden)]; +use prelude::*; + use cast::transmute; use cast; use cell::Cell; use container::Map; use comm::{Chan, GenericChan}; -use prelude::*; use ptr; use hashmap::HashSet; use task::local_data_priv::{local_get, local_set, OldHandle}; @@ -91,8 +92,12 @@ use uint; use util; use unstable::sync::{Exclusive, exclusive}; use rt::local::Local; +use iterator::{IteratorUtil}; +use rt::task::Task; #[cfg(test)] use task::default_task_opts; +#[cfg(test)] use comm; +#[cfg(test)] use task; macro_rules! move_it ( { $x:expr } => ( unsafe { let y = *ptr::to_unsafe_ptr(&($x)); y } ) @@ -159,13 +164,17 @@ struct AncestorList(Option<Exclusive<AncestorNode>>); // Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety. #[inline(always)] fn access_group<U>(x: &TaskGroupArc, blk: &fn(TaskGroupInner) -> U) -> U { - x.with(blk) + unsafe { + x.with(blk) + } } #[inline(always)] fn access_ancestors<U>(x: &Exclusive<AncestorNode>, blk: &fn(x: &mut AncestorNode) -> U) -> U { - x.with(blk) + unsafe { + x.with(blk) + } } // Iterates over an ancestor list. @@ -269,7 +278,7 @@ fn each_ancestor(list: &mut AncestorList, * Step 3: Maybe unwind; compute return info for our caller. *##########################################################*/ if need_unwind && !nobe_is_dead { - for bail_opt.each |bail_blk| { + for bail_opt.iter().advance |bail_blk| { do with_parent_tg(&mut nobe.parent_group) |tg_opt| { (*bail_blk)(tg_opt) } @@ -316,11 +325,12 @@ impl Drop for TCB { // Runs on task exit. fn finalize(&self) { unsafe { + // FIXME(#4330) Need self by value to get mutability. let this: &mut TCB = transmute(self); // If we are failing, the whole taskgroup needs to die. if rt::rust_task_is_unwinding(self.me) { - for this.notifier.each_mut |x| { + for this.notifier.mut_iter().advance |x| { x.failed = true; } // Take everybody down with us. @@ -349,7 +359,7 @@ fn TCB(me: *rust_task, ancestors: AncestorList, is_main: bool, mut notifier: Option<AutoNotify>) -> TCB { - for notifier.each_mut |x| { + for notifier.mut_iter().advance |x| { x.failed = false; } @@ -576,9 +586,14 @@ pub fn spawn_raw(opts: TaskOpts, f: ~fn()) { fn spawn_raw_newsched(_opts: TaskOpts, f: ~fn()) { use rt::sched::*; + let task = do Local::borrow::<Task, ~Task>() |running_task| { + ~running_task.new_child() + }; + let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::new(&mut sched.stack_pool, f); - sched.schedule_new_task(task); + let task = ~Coroutine::with_task(&mut sched.stack_pool, + task, f); + sched.schedule_task(task); } fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { @@ -587,7 +602,7 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { gen_child_taskgroup(opts.linked, opts.supervised); unsafe { - let child_data = Cell((child_tg, ancestors, f)); + let child_data = Cell::new((child_tg, ancestors, f)); // Being killed with the unsafe task/closure pointers would leak them. do unkillable { // Agh. Get move-mode items into the closure. FIXME (#2829) @@ -629,7 +644,7 @@ fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { notify_chan: Option<Chan<TaskResult>>, f: ~fn()) -> ~fn() { - let child_data = Cell((child_arc, ancestors)); + let child_data = Cell::new((child_arc, ancestors)); let result: ~fn() = || { // Agh. Get move-mode items into the closure. FIXME (#2829) let mut (child_arc, ancestors) = child_data.take(); diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 20b45dfb2cc..c0c8b729f9e 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -18,7 +18,7 @@ use io; use io::Writer; use option::{None, Option, Some}; use old_iter::BaseIter; -use str; +use str::StrSlice; pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool; @@ -239,27 +239,25 @@ impl<A:IterBytes> IterBytes for @[A] { impl<'self> IterBytes for &'self str { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { - do str::byte_slice(*self) |bytes| { - f(bytes) - } + f(self.as_bytes()) } } impl IterBytes for ~str { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { - do str::byte_slice(*self) |bytes| { - f(bytes) - } + // this should possibly include the null terminator, but that + // breaks .find_equiv on hashmaps. + f(self.as_bytes()) } } impl IterBytes for @str { #[inline(always)] fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { - do str::byte_slice(*self) |bytes| { - f(bytes) - } + // this should possibly include the null terminator, but that + // breaks .find_equiv on hashmaps. + f(self.as_bytes()) } } @@ -303,7 +301,11 @@ impl<A> IterBytes for *const A { } } +/// A trait for converting a value to a list of bytes. pub trait ToBytes { + /// Converts the current value to a list of bytes. This is equivalent to + /// invoking iter_bytes on a type and collecting all yielded values in an + /// array fn to_bytes(&self, lsb0: bool) -> ~[u8]; } diff --git a/src/libstd/to_str.rs b/src/libstd/to_str.rs index 9ca54066289..bfda92d46a2 100644 --- a/src/libstd/to_str.rs +++ b/src/libstd/to_str.rs @@ -22,20 +22,18 @@ use hash::Hash; use cmp::Eq; use old_iter::BaseIter; +/// A generic trait for converting a value to a string pub trait ToStr { + /// Converts the value of `self` to an owned string fn to_str(&self) -> ~str; } /// Trait for converting a type to a string, consuming it in the process. pub trait ToStrConsume { - // Cosume and convert to a string. + /// Cosume and convert to a string. fn to_str_consume(self) -> ~str; } -impl ToStr for bool { - #[inline(always)] - fn to_str(&self) -> ~str { ::bool::to_str(*self) } -} impl ToStr for () { #[inline(always)] fn to_str(&self) -> ~str { ~"()" } @@ -46,7 +44,7 @@ impl<A:ToStr> ToStr for (A,) { fn to_str(&self) -> ~str { match *self { (ref a,) => { - ~"(" + a.to_str() + ",)" + fmt!("(%s,)", (*a).to_str()) } } } @@ -55,7 +53,7 @@ impl<A:ToStr> ToStr for (A,) { impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> { #[inline(always)] fn to_str(&self) -> ~str { - let mut acc = ~"{", first = true; + let mut (acc, first) = (~"{", true); for self.each |key, value| { if first { first = false; @@ -75,29 +73,29 @@ impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> { impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> { #[inline(always)] fn to_str(&self) -> ~str { - let mut acc = ~"{", first = true; - for self.each |element| { - if first { - first = false; - } - else { - acc.push_str(", "); + let mut (acc, first) = (~"{", true); + for self.each |element| { + if first { + first = false; + } + else { + acc.push_str(", "); + } + acc.push_str(element.to_str()); } - acc.push_str(element.to_str()); - } - acc.push_char('}'); - acc + acc.push_char('}'); + acc } } impl<A:ToStr,B:ToStr> ToStr for (A, B) { #[inline(always)] fn to_str(&self) -> ~str { - // FIXME(#4760): this causes an llvm assertion + // FIXME(#4653): this causes an llvm assertion //let &(ref a, ref b) = self; match *self { (ref a, ref b) => { - ~"(" + a.to_str() + ", " + b.to_str() + ")" + fmt!("(%s, %s)", (*a).to_str(), (*b).to_str()) } } } @@ -106,7 +104,7 @@ impl<A:ToStr,B:ToStr> ToStr for (A, B) { impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) { #[inline(always)] fn to_str(&self) -> ~str { - // FIXME(#4760): this causes an llvm assertion + // FIXME(#4653): this causes an llvm assertion //let &(ref a, ref b, ref c) = self; match *self { (ref a, ref b, ref c) => { @@ -123,7 +121,7 @@ impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) { impl<'self,A:ToStr> ToStr for &'self [A] { #[inline(always)] fn to_str(&self) -> ~str { - let mut acc = ~"[", first = true; + let mut (acc, first) = (~"[", true); for self.each |elt| { if first { first = false; @@ -141,7 +139,7 @@ impl<'self,A:ToStr> ToStr for &'self [A] { impl<A:ToStr> ToStr for ~[A] { #[inline(always)] fn to_str(&self) -> ~str { - let mut acc = ~"[", first = true; + let mut (acc, first) = (~"[", true); for self.each |elt| { if first { first = false; @@ -159,7 +157,7 @@ impl<A:ToStr> ToStr for ~[A] { impl<A:ToStr> ToStr for @[A] { #[inline(always)] fn to_str(&self) -> ~str { - let mut acc = ~"[", first = true; + let mut (acc, first) = (~"[", true); for self.each |elt| { if first { first = false; diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 13b892e700e..4bd3946f885 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -11,6 +11,8 @@ //! An ordered map and set for integer keys implemented as a radix trie use prelude::*; +use iterator::IteratorUtil; +use uint; use util::{swap, replace}; // FIXME: #5244: need to manually update the TrieNode constructor @@ -24,6 +26,7 @@ enum Child<T> { Nothing } +#[allow(missing_doc)] pub struct TrieMap<T> { priv root: TrieNode<T>, priv length: uint @@ -142,32 +145,33 @@ impl<T> Map<uint, T> for TrieMap<T> { } } -pub impl<T> TrieMap<T> { +impl<T> TrieMap<T> { /// Create an empty TrieMap #[inline(always)] - fn new() -> TrieMap<T> { + pub fn new() -> TrieMap<T> { TrieMap{root: TrieNode::new(), length: 0} } /// Visit all key-value pairs in reverse order #[inline(always)] - fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { + pub fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { self.root.each_reverse(f) } /// Visit all keys in reverse order #[inline(always)] - fn each_key_reverse(&self, f: &fn(&uint) -> bool) -> bool { + pub fn each_key_reverse(&self, f: &fn(&uint) -> bool) -> bool { self.each_reverse(|k, _| f(k)) } /// Visit all values in reverse order #[inline(always)] - fn each_value_reverse(&self, f: &fn(&T) -> bool) -> bool { + pub fn each_value_reverse(&self, f: &fn(&T) -> bool) -> bool { self.each_reverse(|_, v| f(v)) } } +#[allow(missing_doc)] pub struct TrieSet { priv map: TrieMap<()> } @@ -204,28 +208,32 @@ impl Mutable for TrieSet { fn clear(&mut self) { self.map.clear() } } -pub impl TrieSet { +impl TrieSet { /// Create an empty TrieSet #[inline(always)] - fn new() -> TrieSet { + pub fn new() -> TrieSet { TrieSet{map: TrieMap::new()} } /// Return true if the set contains a value #[inline(always)] - fn contains(&self, value: &uint) -> bool { + pub fn contains(&self, value: &uint) -> bool { self.map.contains_key(value) } /// Add a value to the set. Return true if the value was not already /// present in the set. #[inline(always)] - fn insert(&mut self, value: uint) -> bool { self.map.insert(value, ()) } + pub fn insert(&mut self, value: uint) -> bool { + self.map.insert(value, ()) + } /// Remove a value from the set. Return true if the value was /// present in the set. #[inline(always)] - fn remove(&mut self, value: &uint) -> bool { self.map.remove(value) } + pub fn remove(&mut self, value: &uint) -> bool { + self.map.remove(value) + } } struct TrieNode<T> { @@ -269,7 +277,7 @@ impl<T> TrieNode<T> { } fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { - for vec::each_mut(self.children) |child| { + for self.children.mut_iter().advance |child| { match *child { Internal(ref mut x) => if !x.mutate_values(f) { return false diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 639df89a377..589c18de0ab 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -10,14 +10,20 @@ //! Operations on tuples +#[allow(missing_doc)]; + use kinds::Copy; use vec; pub use self::inner::*; +/// Method extensions to pairs where both types satisfy the `Copy` bound pub trait CopyableTuple<T, U> { + /// Return the first element of self fn first(&self) -> T; + /// Return the second element of self fn second(&self) -> U; + /// Return the results of swapping the two elements of self fn swap(&self) -> (U, T); } @@ -47,8 +53,12 @@ impl<T:Copy,U:Copy> CopyableTuple<T, U> for (T, U) { } } +/// Method extensions for pairs where the types don't necessarily satisfy the +/// `Copy` bound pub trait ImmutableTuple<T, U> { + /// Return a reference to the first element of self fn first_ref<'a>(&'a self) -> &'a T; + /// Return a reference to the second element of self fn second_ref<'a>(&'a self) -> &'a U; } @@ -402,7 +412,7 @@ mod tests { #[test] fn test_tuple_cmp() { - let small = (1u, 2u, 3u), big = (3u, 2u, 1u); + let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u)); // Eq assert_eq!(small, small); diff --git a/src/libstd/unicode.rs b/src/libstd/unicode.rs index ce584c0f1ba..f8f56c75a29 100644 --- a/src/libstd/unicode.rs +++ b/src/libstd/unicode.rs @@ -10,6 +10,8 @@ // The following code was generated by "src/etc/unicode.py" +#[allow(missing_doc)]; + pub mod general_category { fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { diff --git a/src/libstd/unstable/atomics.rs b/src/libstd/unstable/atomics.rs index 58d0c01f990..aa70897ad48 100644 --- a/src/libstd/unstable/atomics.rs +++ b/src/libstd/unstable/atomics.rs @@ -155,11 +155,13 @@ impl AtomicInt { unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) } } + /// Returns the old value (like __sync_fetch_and_add). #[inline(always)] pub fn fetch_add(&mut self, val: int, order: Ordering) -> int { unsafe { atomic_add(&mut self.v, val, order) } } + /// Returns the old value (like __sync_fetch_and_sub). #[inline(always)] pub fn fetch_sub(&mut self, val: int, order: Ordering) -> int { unsafe { atomic_sub(&mut self.v, val, order) } @@ -191,11 +193,13 @@ impl AtomicUint { unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) } } + /// Returns the old value (like __sync_fetch_and_add). #[inline(always)] pub fn fetch_add(&mut self, val: uint, order: Ordering) -> uint { unsafe { atomic_add(&mut self.v, val, order) } } + /// Returns the old value (like __sync_fetch_and_sub).. #[inline(always)] pub fn fetch_sub(&mut self, val: uint, order: Ordering) -> uint { unsafe { atomic_sub(&mut self.v, val, order) } @@ -275,6 +279,7 @@ impl<T> Drop for AtomicOption<T> { // This will ensure that the contained data is // destroyed, unless it's null. unsafe { + // FIXME(#4330) Need self by value to get mutability. let this : &mut AtomicOption<T> = cast::transmute(self); let _ = this.take(SeqCst); } @@ -314,6 +319,7 @@ pub unsafe fn atomic_swap<T>(dst: &mut T, val: T, order: Ordering) -> T { }) } +/// Returns the old value (like __sync_fetch_and_add). #[inline(always)] pub unsafe fn atomic_add<T>(dst: &mut T, val: T, order: Ordering) -> T { let dst = cast::transmute(dst); @@ -326,6 +332,7 @@ pub unsafe fn atomic_add<T>(dst: &mut T, val: T, order: Ordering) -> T { }) } +/// Returns the old value (like __sync_fetch_and_sub). #[inline(always)] pub unsafe fn atomic_sub<T>(dst: &mut T, val: T, order: Ordering) -> T { let dst = cast::transmute(dst); diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs new file mode 100644 index 00000000000..96aba1d2971 --- /dev/null +++ b/src/libstd/unstable/dynamic_lib.rs @@ -0,0 +1,199 @@ +// 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. + +/*! + +Dynamic library facilities. + +A simple wrapper over the platforms dynamic library facilities + +*/ +use ptr; +use cast; +use path; +use libc; +use ops::*; +use option::*; +use result::*; + +pub struct DynamicLibrary { priv handle: *libc::c_void } + +impl Drop for DynamicLibrary { + fn finalize(&self) { + match do dl::check_for_errors_in { + unsafe { + dl::close(self.handle) + } + } { + Ok(()) => { }, + Err(str) => fail!(str) + } + } +} + +impl DynamicLibrary { + /// Lazily open a dynamic library. When passed None it gives a + /// handle to the calling process + pub fn open(filename: Option<&path::Path>) -> Result<DynamicLibrary, ~str> { + let open_wrapper = |raw_ptr| { + do dl::check_for_errors_in { + unsafe { + DynamicLibrary { handle: dl::open(raw_ptr) } + } + } + }; + + match filename { + Some(name) => do name.to_str().as_c_str |raw_name| { + open_wrapper(raw_name) + }, + None => open_wrapper(ptr::null()) + } + } + + /// Access the value at the symbol of the dynamic library + pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<T, ~str> { + // This function should have a lifetime constraint of 'self on + // T but that feature is still unimplemented + + do dl::check_for_errors_in { + let symbol_value = do symbol.as_c_str |raw_string| { + dl::symbol(self.handle, raw_string) + }; + + cast::transmute(symbol_value) + } + } +} + +#[test] +priv fn test_loading_cosine () { + // The math library does not need to be loaded since it is already + // statically linked in + let libm = match DynamicLibrary::open(None) { + Err (error) => fail!("Could not load self as module: %s", error), + Ok (libm) => libm + }; + + // Unfortunately due to issue #6194 it is not possible to call + // this as a C function + let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe { + match libm.symbol("cos") { + Err (error) => fail!("Could not load function cos: %s", error), + Ok (cosine) => cosine + } + }; + + let argument = 0.0; + let expected_result = 1.0; + let result = cosine(argument); + if result != expected_result { + fail!("cos(%?) != %? but equaled %? instead", argument, + expected_result, result) + } +} + +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[cfg(target_os = "macos")] +#[cfg(target_os = "freebsd")] +mod dl { + use libc; + use ptr; + use str; + use task; + use result::*; + + pub unsafe fn open(filename: *libc::c_char) -> *libc::c_void { + dlopen(filename, Lazy as libc::c_int) + } + + pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> { + unsafe { + do task::atomically { + let _old_error = dlerror(); + + let result = f(); + + let last_error = dlerror(); + if ptr::null() == last_error { + Ok(result) + } else { + Err(str::raw::from_c_str(last_error)) + } + } + } + } + + pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void { + dlsym(handle, symbol) + } + pub unsafe fn close(handle: *libc::c_void) { + dlclose(handle); () + } + + pub enum RTLD { + Lazy = 1, + Now = 2, + Global = 256, + Local = 0, + } + + #[link_name = "dl"] + extern { + fn dlopen(filename: *libc::c_char, flag: libc::c_int) -> *libc::c_void; + fn dlerror() -> *libc::c_char; + fn dlsym(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void; + fn dlclose(handle: *libc::c_void) -> libc::c_int; + } +} + +#[cfg(target_os = "win32")] +mod dl { + use os; + use libc; + use task; + use result::*; + + pub unsafe fn open(filename: *libc::c_char) -> *libc::c_void { + LoadLibrary(filename) + } + + pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> { + unsafe { + do task::atomically { + SetLastError(0); + + let result = f(); + + let error = os::errno(); + if 0 == error { + Ok(result) + } else { + Err(fmt!("Error code %?", error)) + } + } + } + } + pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void { + GetProcAddress(handle, symbol) + } + pub unsafe fn close(handle: *libc::c_void) { + FreeLibrary(handle); () + } + + #[link_name = "kernel32"] + extern "stdcall" { + fn SetLastError(error: u32); + fn LoadLibrary(name: *libc::c_char) -> *libc::c_void; + fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void; + fn FreeLibrary(handle: *libc::c_void); + } +} diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs index 8da378fdc97..7d9ce585d7c 100644 --- a/src/libstd/unstable/extfmt.rs +++ b/src/libstd/unstable/extfmt.rs @@ -76,8 +76,8 @@ debug!("hello, %s!", "world"); */ -use cmp::Eq; use prelude::*; +use iterator::IteratorUtil; /* * We have a 'ct' (compile-time) module that parses format strings into a @@ -139,8 +139,8 @@ pub mod ct { next: uint } - pub impl<T> Parsed<T> { - fn new(val: T, next: uint) -> Parsed<T> { + impl<T> Parsed<T> { + pub fn new(val: T, next: uint) -> Parsed<T> { Parsed {val: val, next: next} } } @@ -325,7 +325,7 @@ pub mod ct { 'o' => TyOctal, 'f' => TyFloat, '?' => TyPoly, - _ => err(~"unknown type in conversion: " + s.substr(i, 1)) + _ => err(fmt!("unknown type in conversion: %c", s.char_at(i))) }; Parsed::new(t, i + 1) @@ -546,8 +546,8 @@ pub mod rt { // displayed let unpadded = match cv.precision { CountImplied => s, - CountIs(max) => if (max as uint) < str::char_len(s) { - str::slice(s, 0, max as uint) + CountIs(max) => if (max as uint) < s.char_len() { + s.slice(0, max as uint) } else { s } @@ -584,7 +584,7 @@ pub mod rt { ~"" } else { let s = uint::to_str_radix(num, radix); - let len = str::char_len(s); + let len = s.char_len(); if len < prec { let diff = prec - len; let pad = str::from_chars(vec::from_elem(diff, '0')); @@ -607,16 +607,16 @@ pub mod rt { let headsize = match head { Some(_) => 1, _ => 0 }; let uwidth : uint = match cv.width { CountImplied => { - for head.each |&c| { + for head.iter().advance |&c| { buf.push_char(c); } return buf.push_str(s); } CountIs(width) => { width as uint } }; - let strlen = str::char_len(s) + headsize; + let strlen = s.char_len() + headsize; if uwidth <= strlen { - for head.each |&c| { + for head.iter().advance |&c| { buf.push_char(c); } return buf.push_str(s); @@ -624,7 +624,7 @@ pub mod rt { let mut padchar = ' '; let diff = uwidth - strlen; if have_flag(cv.flags, flag_left_justify) { - for head.each |&c| { + for head.iter().advance |&c| { buf.push_char(c); } buf.push_str(s); @@ -658,7 +658,7 @@ pub mod rt { // instead. if signed && zero_padding { - for head.each |&head| { + for head.iter().advance |&head| { if head == '+' || head == '-' || head == ' ' { buf.push_char(head); buf.push_str(padstr); @@ -668,7 +668,7 @@ pub mod rt { } } buf.push_str(padstr); - for head.each |&c| { + for head.iter().advance |&c| { buf.push_char(c); } buf.push_str(s); diff --git a/src/libstd/unstable/finally.rs b/src/libstd/unstable/finally.rs index 5001fb421cd..b15bceddb1c 100644 --- a/src/libstd/unstable/finally.rs +++ b/src/libstd/unstable/finally.rs @@ -31,17 +31,20 @@ pub trait Finally<T> { fn finally(&self, dtor: &fn()) -> T; } -impl<'self,T> Finally<T> for &'self fn() -> T { - fn finally(&self, dtor: &fn()) -> T { - let _d = Finallyalizer { - dtor: dtor - }; - - (*self)() +macro_rules! finally_fn { + ($fnty:ty) => { + impl<T> Finally<T> for $fnty { + fn finally(&self, dtor: &fn()) -> T { + let _d = Finallyalizer { + dtor: dtor + }; + (*self)() + } + } } } -impl<T> Finally<T> for ~fn() -> T { +impl<'self,T> Finally<T> for &'self fn() -> T { fn finally(&self, dtor: &fn()) -> T { let _d = Finallyalizer { dtor: dtor @@ -51,15 +54,9 @@ impl<T> Finally<T> for ~fn() -> T { } } -impl<T> Finally<T> for @fn() -> T { - fn finally(&self, dtor: &fn()) -> T { - let _d = Finallyalizer { - dtor: dtor - }; - - (*self)() - } -} +finally_fn!(~fn() -> T) +finally_fn!(@fn() -> T) +finally_fn!(extern "Rust" fn() -> T) struct Finallyalizer<'self> { dtor: &'self fn() @@ -108,10 +105,7 @@ fn test_retval() { #[test] fn test_compact() { - // FIXME #4727: Should be able to use a fn item instead - // of a closure for do_some_fallible_work, - // but it's a type error. - let do_some_fallible_work: &fn() = || { }; + fn do_some_fallible_work() {} fn but_always_run_this_function() { } do_some_fallible_work.finally( but_always_run_this_function); @@ -136,4 +130,4 @@ fn test_managed() { }; assert_eq!(do managed.finally {}, 10); assert_eq!(*i, 20); -} \ No newline at end of file +} diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 350b18d4541..3d61c1fe144 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -10,6 +10,7 @@ //! Runtime calls emitted by the compiler. +use iterator::IteratorUtil; use uint; use cast::transmute; use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO}; @@ -133,12 +134,12 @@ unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { Some(borrow_list) => { // recording borrows let mut msg = ~"borrowed"; let mut sep = " at "; - for borrow_list.each_reverse |entry| { + for borrow_list.rev_iter().advance |entry| { if entry.box == box { - str::push_str(&mut msg, sep); + msg.push_str(sep); let filename = str::raw::from_c_str(entry.file); - str::push_str(&mut msg, filename); - str::push_str(&mut msg, fmt!(":%u", entry.line as uint)); + msg.push_str(filename); + msg.push_str(fmt!(":%u", entry.line as uint)); sep = " and at "; } } @@ -244,7 +245,7 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { } _ => { let mut alloc = ::ptr::null(); - do Local::borrow::<Task> |task| { + do Local::borrow::<Task,()> |task| { alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char; } return alloc; @@ -262,7 +263,7 @@ pub unsafe fn local_free(ptr: *c_char) { rustrt::rust_upcall_free_noswitch(ptr); } _ => { - do Local::borrow::<Task> |task| { + do Local::borrow::<Task,()> |task| { task.heap.free(ptr as *c_void); } } diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index afdc22a1c63..ae878050142 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,12 +10,21 @@ #[doc(hidden)]; -use libc; use comm::{GenericChan, GenericPort}; +use comm; +use libc; use prelude::*; use task; pub mod at_exit; + +// Currently only works for *NIXes +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[cfg(target_os = "macos")] +#[cfg(target_os = "freebsd")] +pub mod dynamic_lib; + pub mod global; pub mod finally; pub mod weak_task; diff --git a/src/libstd/unstable/sync.rs b/src/libstd/unstable/sync.rs index 6085ca1a482..3cf46bec41a 100644 --- a/src/libstd/unstable/sync.rs +++ b/src/libstd/unstable/sync.rs @@ -117,9 +117,9 @@ fn LittleLock() -> LittleLock { } } -pub impl LittleLock { +impl LittleLock { #[inline(always)] - unsafe fn lock<T>(&self, f: &fn() -> T) -> T { + pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T { do atomically { rust_lock_little_lock(self.l); do (|| { @@ -162,7 +162,7 @@ impl<T:Owned> Clone for Exclusive<T> { } } -pub impl<T:Owned> Exclusive<T> { +impl<T:Owned> Exclusive<T> { // Exactly like std::arc::mutex_arc,access(), but with the little_lock // instead of a proper mutex. Same reason for being unsafe. // @@ -170,7 +170,7 @@ pub impl<T:Owned> Exclusive<T> { // accessing the provided condition variable) are prohibited while inside // the exclusive. Supporting that is a work in progress. #[inline(always)] - unsafe fn with<U>(&self, f: &fn(x: &mut T) -> U) -> U { + pub unsafe fn with<U>(&self, f: &fn(x: &mut T) -> U) -> U { let rec = self.x.get(); do (*rec).lock.lock { if (*rec).failed { @@ -184,7 +184,7 @@ pub impl<T:Owned> Exclusive<T> { } #[inline(always)] - unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U { + pub unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U { do self.with |x| { f(cast::transmute_immut(x)) } @@ -259,48 +259,52 @@ mod tests { #[test] fn exclusive_arc() { - let mut futures = ~[]; + unsafe { + let mut futures = ~[]; - let num_tasks = 10; - let count = 10; + let num_tasks = 10; + let count = 10; - let total = exclusive(~0); + let total = exclusive(~0); - for uint::range(0, num_tasks) |_i| { - let total = total.clone(); - let (port, chan) = comm::stream(); - futures.push(port); + for uint::range(0, num_tasks) |_i| { + let total = total.clone(); + let (port, chan) = comm::stream(); + futures.push(port); - do task::spawn || { - for uint::range(0, count) |_i| { - do total.with |count| { - **count += 1; + do task::spawn || { + for uint::range(0, count) |_i| { + do total.with |count| { + **count += 1; + } } + chan.send(()); } - chan.send(()); - } - }; + }; - for futures.each |f| { f.recv() } + for futures.each |f| { f.recv() } - do total.with |total| { - assert!(**total == num_tasks * count) - }; + do total.with |total| { + assert!(**total == num_tasks * count) + }; + } } #[test] #[should_fail] #[ignore(cfg(windows))] fn exclusive_poison() { - // Tests that if one task fails inside of an exclusive, subsequent - // accesses will also fail. - let x = exclusive(1); - let x2 = x.clone(); - do task::try || { - do x2.with |one| { - assert_eq!(*one, 2); + unsafe { + // Tests that if one task fails inside of an exclusive, subsequent + // accesses will also fail. + let x = exclusive(1); + let x2 = x.clone(); + do task::try || { + do x2.with |one| { + assert_eq!(*one, 2); + } + }; + do x.with |one| { + assert_eq!(*one, 1); } - }; - do x.with |one| { - assert_eq!(*one, 1); } } diff --git a/src/libstd/unstable/weak_task.rs b/src/libstd/unstable/weak_task.rs index d5c5230cef8..7819fe00597 100644 --- a/src/libstd/unstable/weak_task.rs +++ b/src/libstd/unstable/weak_task.rs @@ -39,7 +39,7 @@ pub unsafe fn weaken_task(f: &fn(Port<ShutdownMsg>)) { let service = global_data_clone_create(global_data_key, create_global_service); let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>(); - let shutdown_port = Cell(shutdown_port); + let shutdown_port = Cell::new(shutdown_port); let task = get_task_id(); // Expect the weak task service to be alive assert!(service.try_send(RegisterWeakTask(task, shutdown_chan))); @@ -68,7 +68,7 @@ fn create_global_service() -> ~WeakTaskService { debug!("creating global weak task service"); let (port, chan) = stream::<ServiceMsg>(); - let port = Cell(port); + let port = Cell::new(port); let chan = SharedChan::new(chan); let chan_clone = chan.clone(); @@ -76,7 +76,7 @@ fn create_global_service() -> ~WeakTaskService { task.unlinked(); do task.spawn { debug!("running global weak task service"); - let port = Cell(port.take()); + let port = Cell::new(port.take()); do (|| { let port = port.take(); // The weak task service is itself a weak task @@ -192,7 +192,7 @@ fn test_select_stream_and_oneshot() { use either::{Left, Right}; let (port, chan) = stream(); - let port = Cell(port); + let port = Cell::new(port); let (waitport, waitchan) = stream(); do spawn { unsafe { diff --git a/src/libstd/util.rs b/src/libstd/util.rs index 9e7f18f446d..61c284f580c 100644 --- a/src/libstd/util.rs +++ b/src/libstd/util.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - -Miscellaneous helpers for common patterns. - -*/ +//! Miscellaneous helpers for common patterns. +use cast; +use ptr; use prelude::*; use unstable::intrinsics; @@ -67,26 +65,6 @@ pub fn swap<T>(x: &mut T, y: &mut T) { } /** - * Swap the values at two mutable locations of the same type, without - * deinitialising or copying either one. - */ -#[inline] -pub unsafe fn swap_ptr<T>(x: *mut T, y: *mut T) { - // Give ourselves some scratch space to work with - let mut tmp: T = intrinsics::uninit(); - let t: *mut T = &mut tmp; - - // Perform the swap - ptr::copy_memory(t, x, 1); - ptr::copy_memory(x, y, 1); - ptr::copy_memory(y, t, 1); - - // y and t now point to the same thing, but we need to completely forget `tmp` - // because it's no longer relevant. - cast::forget(tmp); -} - -/** * Replace the value at a mutable location with a new one, returning the old * value, without deinitialising or copying either one. */ @@ -96,34 +74,25 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T { src } -/** - * Replace the value at a mutable location with a new one, returning the old - * value, without deinitialising or copying either one. - */ -#[inline(always)] -pub unsafe fn replace_ptr<T>(dest: *mut T, mut src: T) -> T { - swap_ptr(dest, ptr::to_mut_unsafe_ptr(&mut src)); - src -} - /// A non-copyable dummy type. -pub struct NonCopyable { - i: (), +pub struct NonCopyable; + +impl NonCopyable { + /// Creates a dummy non-copyable structure and returns it for use. + pub fn new() -> NonCopyable { NonCopyable } } impl Drop for NonCopyable { fn finalize(&self) { } } -pub fn NonCopyable() -> NonCopyable { NonCopyable { i: () } } - /// A type with no inhabitants pub enum Void { } -pub impl Void { +impl Void { /// A utility function for ignoring this uninhabited type - fn uninhabited(self) -> ! { + pub fn uninhabited(self) -> ! { match self { // Nothing to match on } @@ -183,7 +152,7 @@ mod tests { } #[test] pub fn test_replace() { - let mut x = Some(NonCopyable()); + let mut x = Some(NonCopyable::new()); let y = replace(&mut x, None); assert!(x.is_none()); assert!(y.is_some()); diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 33e7b0a97c4..211ee12c291 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -19,14 +19,15 @@ use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use clone::Clone; use old_iter::BaseIter; use old_iter; -use iterator::Iterator; +use iterator::{Iterator, IteratorUtil}; +use iter::FromIter; use kinds::Copy; use libc; use old_iter::CopyableIter; use option::{None, Option, Some}; use ptr::to_unsafe_ptr; use ptr; -use ptr::Ptr; +use ptr::RawPtr; use sys; use uint; use unstable::intrinsics; @@ -55,11 +56,6 @@ pub mod rustrt { } } -/// Returns true if a vector contains no elements -pub fn is_empty<T>(v: &const [T]) -> bool { - as_const_buf(v, |_p, len| len == 0u) -} - /// Returns true if two vectors have the same length pub fn same_length<T, U>(xs: &const [T], ys: &const [U]) -> bool { xs.len() == ys.len() @@ -122,13 +118,8 @@ pub fn capacity<T>(v: &const ~[T]) -> uint { } } -/// Returns the length of a vector -#[inline(always)] -pub fn len<T>(v: &const [T]) -> uint { - as_const_buf(v, |_p, len| len) -} - // A botch to tide us over until core and std are fully demuted. +#[allow(missing_doc)] pub fn uniq_len<T>(v: &const ~[T]) -> uint { unsafe { let v: &~[T] = transmute(v); @@ -148,8 +139,7 @@ pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> ~[T] { do as_mut_buf(v) |p, _len| { let mut i: uint = 0u; while i < n_elts { - intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i)), - op(i)); + intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i)), op(i)); i += 1u; } } @@ -165,7 +155,20 @@ pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> ~[T] { * to the value `t`. */ pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> ~[T] { - from_fn(n_elts, |_i| copy t) + // hack: manually inline from_fn for 2x plus speedup (sadly very important, from_elem is a + // bottleneck in borrowck!) + unsafe { + let mut v = with_capacity(n_elts); + do as_mut_buf(v) |p, _len| { + let mut i = 0u; + while i < n_elts { + intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i)), copy t); + i += 1u; + } + } + raw::set_len(&mut v, n_elts); + v + } } /// Creates a new unique vector with the same contents as the slice @@ -277,7 +280,7 @@ pub fn last_opt<'r,T>(v: &'r [T]) -> Option<&'r T> { #[inline(always)] pub fn slice<'r,T>(v: &'r [T], start: uint, end: uint) -> &'r [T] { assert!(start <= end); - assert!(end <= len(v)); + assert!(end <= v.len()); do as_imm_buf(v) |p, _len| { unsafe { transmute((ptr::offset(p, start), @@ -305,7 +308,7 @@ pub fn mut_slice<'r,T>(v: &'r mut [T], start: uint, end: uint) pub fn const_slice<'r,T>(v: &'r const [T], start: uint, end: uint) -> &'r const [T] { assert!(start <= end); - assert!(end <= len(v)); + assert!(end <= v.len()); do as_const_buf(v) |p, _len| { unsafe { transmute((ptr::const_offset(p, start), @@ -318,7 +321,7 @@ pub fn const_slice<'r,T>(v: &'r const [T], start: uint, end: uint) /// Split the vector `v` by applying each element against the predicate `f`. pub fn split<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { - let ln = len(v); + let ln = v.len(); if (ln == 0u) { return ~[] } let mut start = 0u; @@ -341,7 +344,7 @@ pub fn split<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { * to `n` times. */ pub fn splitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { - let ln = len(v); + let ln = v.len(); if (ln == 0u) { return ~[] } let mut start = 0u; @@ -367,7 +370,7 @@ pub fn splitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { * `f`. */ pub fn rsplit<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { - let ln = len(v); + let ln = v.len(); if (ln == 0) { return ~[] } let mut end = ln; @@ -391,7 +394,7 @@ pub fn rsplit<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { * `f` up to `n times. */ pub fn rsplitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { - let ln = len(v); + let ln = v.len(); if (ln == 0u) { return ~[] } let mut end = ln; @@ -505,7 +508,7 @@ pub fn shift<T>(v: &mut ~[T]) -> T { let vp = raw::to_mut_ptr(*v); let vp = ptr::mut_offset(vp, next_ln - 1); - util::replace_ptr(vp, work_elt) + ptr::replace_ptr(vp, work_elt) } } @@ -543,6 +546,22 @@ pub fn remove<T>(v: &mut ~[T], i: uint) -> T { v.pop() } +/// Consumes all elements, in a vector, moving them out into the / closure +/// provided. The vector is traversed from the start to the end. +/// +/// This method does not impose any requirements on the type of the vector being +/// consumed, but it prevents any usage of the vector after this function is +/// called. +/// +/// # Examples +/// +/// ~~~ {.rust} +/// let v = ~[~"a", ~"b"]; +/// do vec::consume(v) |i, s| { +/// // s has type ~str, not &~str +/// io::println(s + fmt!(" %d", i)); +/// } +/// ~~~ pub fn consume<T>(mut v: ~[T], f: &fn(uint, v: T)) { unsafe { do as_mut_buf(v) |p, ln| { @@ -553,7 +572,7 @@ pub fn consume<T>(mut v: ~[T], f: &fn(uint, v: T)) { // elements during unwinding let x = intrinsics::init(); let p = ptr::mut_offset(p, i); - f(i, util::replace_ptr(p, x)); + f(i, ptr::replace_ptr(p, x)); } } @@ -561,6 +580,12 @@ pub fn consume<T>(mut v: ~[T], f: &fn(uint, v: T)) { } } +/// Consumes all elements, in a vector, moving them out into the / closure +/// provided. The vectors is traversed in reverse order (from end to start). +/// +/// This method does not impose any requirements on the type of the vector being +/// consumed, but it prevents any usage of the vector after this function is +/// called. pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) { unsafe { do as_mut_buf(v) |p, ln| { @@ -574,7 +599,7 @@ pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) { // elements during unwinding let x = intrinsics::init(); let p = ptr::mut_offset(p, i); - f(i, util::replace_ptr(p, x)); + f(i, ptr::replace_ptr(p, x)); } } @@ -590,7 +615,7 @@ pub fn pop<T>(v: &mut ~[T]) -> T { } let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]); unsafe { - let val = util::replace_ptr(valptr, intrinsics::init()); + let val = ptr::replace_ptr(valptr, intrinsics::init()); raw::set_len(v, ln - 1u); val } @@ -646,6 +671,16 @@ fn push_slow<T>(v: &mut ~[T], initval: T) { unsafe { push_fast(v, initval) } } +/// Iterates over the slice `rhs`, copies each element, and then appends it to +/// the vector provided `v`. The `rhs` vector is traversed in-order. +/// +/// # Example +/// +/// ~~~ {.rust} +/// let mut a = ~[1]; +/// vec::push_all(&mut a, [2, 3, 4]); +/// assert!(a == ~[1, 2, 3, 4]); +/// ~~~ #[inline(always)] pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) { let new_len = v.len() + rhs.len(); @@ -656,6 +691,17 @@ pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) { } } +/// Takes ownership of the vector `rhs`, moving all elements into the specified +/// vector `v`. This does not copy any elements, and it is illegal to use the +/// `rhs` vector after calling this method (because it is moved here). +/// +/// # Example +/// +/// ~~~ {.rust} +/// let mut a = ~[~1]; +/// vec::push_all_move(&mut a, ~[~2, ~3, ~4]); +/// assert!(a == ~[~1, ~2, ~3, ~4]); +/// ~~~ #[inline(always)] pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) { let new_len = v.len() + rhs.len(); @@ -663,8 +709,8 @@ pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) { unsafe { do as_mut_buf(rhs) |p, len| { for uint::range(0, len) |i| { - let x = util::replace_ptr(ptr::mut_offset(p, i), - intrinsics::uninit()); + let x = ptr::replace_ptr(ptr::mut_offset(p, i), + intrinsics::uninit()); push(&mut *v, x); } } @@ -679,7 +725,7 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) { unsafe { // This loop is optimized out for non-drop types. for uint::range(newlen, oldlen) |i| { - util::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); + ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); } } } @@ -693,7 +739,7 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) { pub fn dedup<T:Eq>(v: &mut ~[T]) { unsafe { if v.len() < 1 { return; } - let mut last_written = 0, next_to_read = 1; + let mut (last_written, next_to_read) = (0, 1); do as_const_buf(*v) |p, ln| { // We have a mutable reference to v, so we can make arbitrary // changes. (cf. push and pop) @@ -703,14 +749,14 @@ pub fn dedup<T:Eq>(v: &mut ~[T]) { // last_written < next_to_read < ln if *ptr::mut_offset(p, next_to_read) == *ptr::mut_offset(p, last_written) { - util::replace_ptr(ptr::mut_offset(p, next_to_read), - intrinsics::uninit()); + ptr::replace_ptr(ptr::mut_offset(p, next_to_read), + intrinsics::uninit()); } else { last_written += 1; // last_written <= next_to_read < ln if next_to_read != last_written { - util::swap_ptr(ptr::mut_offset(p, last_written), - ptr::mut_offset(p, next_to_read)); + ptr::swap_ptr(ptr::mut_offset(p, last_written), + ptr::mut_offset(p, next_to_read)); } } // last_written <= next_to_read < ln @@ -724,6 +770,9 @@ pub fn dedup<T:Eq>(v: &mut ~[T]) { } // Appending + +/// Iterates over the `rhs` vector, copying each element and appending it to the +/// `lhs`. Afterwards, the `lhs` is then returned for use again. #[inline(always)] pub fn append<T:Copy>(lhs: ~[T], rhs: &const [T]) -> ~[T] { let mut v = lhs; @@ -731,6 +780,8 @@ pub fn append<T:Copy>(lhs: ~[T], rhs: &const [T]) -> ~[T] { v } +/// Appends one element to the vector provided. The vector itself is then +/// returned for use again. #[inline(always)] pub fn append_one<T>(lhs: ~[T], x: T) -> ~[T] { let mut v = lhs; @@ -799,13 +850,20 @@ pub fn grow_set<T:Copy>(v: &mut ~[T], index: uint, initval: &T, val: T) { /// Apply a function to each element of a vector and return the results pub fn map<T, U>(v: &[T], f: &fn(t: &T) -> U) -> ~[U] { - let mut result = with_capacity(len(v)); + let mut result = with_capacity(v.len()); for each(v) |elem| { result.push(f(elem)); } result } +/// Consumes a vector, mapping it into a different vector. This function takes +/// ownership of the supplied vector `v`, moving each element into the closure +/// provided to generate a new element. The vector of new elements is then +/// returned. +/// +/// The original vector `v` cannot be used after this function call (it is moved +/// inside), but there are no restrictions on the type of the vector. pub fn map_consume<T, U>(v: ~[T], f: &fn(v: T) -> U) -> ~[U] { let mut result = ~[]; do consume(v) |_i, x| { @@ -839,8 +897,8 @@ pub fn flat_map<T, U>(v: &[T], f: &fn(t: &T) -> ~[U]) -> ~[U] { */ pub fn map_zip<T:Copy,U:Copy,V>(v0: &[T], v1: &[U], f: &fn(t: &T, v: &U) -> V) -> ~[V] { - let v0_len = len(v0); - if v0_len != len(v1) { fail!(); } + let v0_len = v0.len(); + if v0_len != v1.len() { fail!(); } let mut u: ~[V] = ~[]; let mut i = 0u; while i < v0_len { @@ -943,145 +1001,60 @@ pub fn retain<T>(v: &mut ~[T], f: &fn(t: &T) -> bool) { } } -/** - * Concatenate a vector of vectors. - * - * Flattens a vector of vectors of T into a single vector of T. - */ -pub fn concat<T:Copy>(v: &[~[T]]) -> ~[T] { - let mut r = ~[]; - for each(v) |inner| { r.push_all(*inner); } - r -} +/// Flattens a vector of vectors of T into a single vector of T. +pub fn concat<T:Copy>(v: &[~[T]]) -> ~[T] { v.concat_vec() } /// Concatenate a vector of vectors, placing a given separator between each -pub fn connect<T:Copy>(v: &[~[T]], sep: &T) -> ~[T] { - let mut r: ~[T] = ~[]; - let mut first = true; - for each(v) |inner| { - if first { first = false; } else { r.push(*sep); } - r.push_all(*inner); - } - r -} +pub fn connect<T:Copy>(v: &[~[T]], sep: &T) -> ~[T] { v.connect_vec(sep) } -/** - * Reduces a vector from left to right. - * - * # Arguments - * * `z` - initial accumulator value - * * `v` - vector to iterate over - * * `p` - a closure to operate on vector elements - * - * # Examples - * - * Sum all values in the vector [1, 2, 3]: - * - * ~~~ {.rust} - * vec::foldl(0, [1, 2, 3], |a, b| a + *b); - * ~~~ - * - */ -pub fn foldl<'a, T, U>(z: T, v: &'a [U], p: &fn(t: T, u: &'a U) -> T) -> T { - let mut accum = z; - let mut i = 0; - let l = v.len(); - while i < l { - // Use a while loop so that liveness analysis can handle moving - // the accumulator. - accum = p(accum, &v[i]); - i += 1; - } - accum -} +/// Flattens a vector of vectors of T into a single vector of T. +pub fn concat_slices<T:Copy>(v: &[&[T]]) -> ~[T] { v.concat_vec() } -/** - * Reduces a vector from right to left. Note that the argument order is - * reversed compared to `foldl` to reflect the order they are provided to - * the closure. - * - * # Arguments - * * `v` - vector to iterate over - * * `z` - initial accumulator value - * * `p` - a closure to do operate on vector elements - * - * # Examples - * - * Sum all values in the vector [1, 2, 3]: - * - * ~~~ {.rust} - * vec::foldr([1, 2, 3], 0, |a, b| a + *b); - * ~~~ - * - */ -pub fn foldr<'a, T, U>(v: &'a [T], mut z: U, p: &fn(t: &'a T, u: U) -> U) -> U { - let mut i = v.len(); - while i > 0 { - i -= 1; - z = p(&v[i], z); - } - return z; -} +/// Concatenate a vector of vectors, placing a given separator between each +pub fn connect_slices<T:Copy>(v: &[&[T]], sep: &T) -> ~[T] { v.connect_vec(sep) } -/** - * Return true if a predicate matches any elements - * - * If the vector contains no elements then false is returned. - */ -pub fn any<T>(v: &[T], f: &fn(t: &T) -> bool) -> bool { - for each(v) |elem| { if f(elem) { return true; } } - false +#[allow(missing_doc)] +pub trait VectorVector<T> { + // FIXME #5898: calling these .concat and .connect conflicts with + // StrVector::con{cat,nect}, since they have generic contents. + pub fn concat_vec(&self) -> ~[T]; + pub fn connect_vec(&self, sep: &T) -> ~[T]; } -/** - * Return true if a predicate matches any elements in both vectors. - * - * If the vectors contains no elements then false is returned. - */ -pub fn any2<T, U>(v0: &[T], v1: &[U], - f: &fn(a: &T, b: &U) -> bool) -> bool { - let v0_len = len(v0); - let v1_len = len(v1); - let mut i = 0u; - while i < v0_len && i < v1_len { - if f(&v0[i], &v1[i]) { return true; }; - i += 1u; +impl<'self, T:Copy> VectorVector<T> for &'self [~[T]] { + /// Flattens a vector of slices of T into a single vector of T. + pub fn concat_vec(&self) -> ~[T] { + self.flat_map(|&inner| inner) } - false -} -/** - * Return true if a predicate matches all elements - * - * If the vector contains no elements then true is returned. - */ -pub fn all<T>(v: &[T], f: &fn(t: &T) -> bool) -> bool { - for each(v) |elem| { if !f(elem) { return false; } } - true + /// Concatenate a vector of vectors, placing a given separator between each. + pub fn connect_vec(&self, sep: &T) -> ~[T] { + let mut r = ~[]; + let mut first = true; + for self.each |&inner| { + if first { first = false; } else { r.push(*sep); } + r.push_all(inner); + } + r + } } -/** - * Return true if a predicate matches all elements - * - * If the vector contains no elements then true is returned. - */ -pub fn alli<T>(v: &[T], f: &fn(uint, t: &T) -> bool) -> bool { - for eachi(v) |i, elem| { if !f(i, elem) { return false; } } - true -} +impl<'self, T:Copy> VectorVector<T> for &'self [&'self [T]] { + /// Flattens a vector of slices of T into a single vector of T. + pub fn concat_vec(&self) -> ~[T] { + self.flat_map(|&inner| inner.to_owned()) + } -/** - * Return true if a predicate matches all elements in both vectors. - * - * If the vectors are not the same size then false is returned. - */ -pub fn all2<T, U>(v0: &[T], v1: &[U], - f: &fn(t: &T, u: &U) -> bool) -> bool { - let v0_len = len(v0); - if v0_len != len(v1) { return false; } - let mut i = 0u; - while i < v0_len { if !f(&v0[i], &v1[i]) { return false; }; i += 1u; } - true + /// Concatenate a vector of slices, placing a given separator between each. + pub fn connect_vec(&self, sep: &T) -> ~[T] { + let mut r = ~[]; + let mut first = true; + for self.each |&inner| { + if first { first = false; } else { r.push(*sep); } + r.push_all(inner); + } + r + } } /// Return true if a vector contains an element with the given value @@ -1090,13 +1063,6 @@ pub fn contains<T:Eq>(v: &[T], x: &T) -> bool { false } -/// Returns the number of elements that are equal to a given value -pub fn count<T:Eq>(v: &[T], x: &T) -> uint { - let mut cnt = 0u; - for each(v) |elt| { if *x == *elt { cnt += 1u; } } - cnt -} - /** * Search for the first element that matches a given predicate * @@ -1105,7 +1071,7 @@ pub fn count<T:Eq>(v: &[T], x: &T) -> uint { * is returned. If `f` matches no elements then none is returned. */ pub fn find<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> Option<T> { - find_between(v, 0u, len(v), f) + find_between(v, 0u, v.len(), f) } /** @@ -1128,7 +1094,7 @@ pub fn find_between<T:Copy>(v: &[T], start: uint, end: uint, * matches no elements then none is returned. */ pub fn rfind<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> Option<T> { - rfind_between(v, 0u, len(v), f) + rfind_between(v, 0u, v.len(), f) } /** @@ -1159,7 +1125,7 @@ pub fn position_elem<T:Eq>(v: &[T], x: &T) -> Option<uint> { * then none is returned. */ pub fn position<T>(v: &[T], f: &fn(t: &T) -> bool) -> Option<uint> { - position_between(v, 0u, len(v), f) + position_between(v, 0u, v.len(), f) } /** @@ -1175,7 +1141,7 @@ pub fn position_between<T>(v: &[T], f: &fn(t: &T) -> bool) -> Option<uint> { assert!(start <= end); - assert!(end <= len(v)); + assert!(end <= v.len()); let mut i = start; while i < end { if f(&v[i]) { return Some::<uint>(i); } i += 1u; } None @@ -1194,7 +1160,7 @@ pub fn rposition_elem<T:Eq>(v: &[T], x: &T) -> Option<uint> { * matches no elements then none is returned. */ pub fn rposition<T>(v: &[T], f: &fn(t: &T) -> bool) -> Option<uint> { - rposition_between(v, 0u, len(v), f) + rposition_between(v, 0u, v.len(), f) } /** @@ -1208,7 +1174,7 @@ pub fn rposition<T>(v: &[T], f: &fn(t: &T) -> bool) -> Option<uint> { pub fn rposition_between<T>(v: &[T], start: uint, end: uint, f: &fn(t: &T) -> bool) -> Option<uint> { assert!(start <= end); - assert!(end <= len(v)); + assert!(end <= v.len()); let mut i = end; while i > start { if f(&v[i - 1u]) { return Some::<uint>(i - 1u); } @@ -1265,7 +1231,7 @@ pub fn bsearch_elem<T:TotalOrd>(v: &[T], x: &T) -> Option<uint> { * Convert a vector of pairs into a pair of vectors, by reference. As unzip(). */ pub fn unzip_slice<T:Copy,U:Copy>(v: &[(T, U)]) -> (~[T], ~[U]) { - let mut ts = ~[], us = ~[]; + let mut (ts, us) = (~[], ~[]); for each(v) |p| { let (t, u) = *p; ts.push(t); @@ -1283,7 +1249,7 @@ pub fn unzip_slice<T:Copy,U:Copy>(v: &[(T, U)]) -> (~[T], ~[U]) { * of the i-th tuple of the input vector. */ pub fn unzip<T,U>(v: ~[(T, U)]) -> (~[T], ~[U]) { - let mut ts = ~[], us = ~[]; + let mut (ts, us) = (~[], ~[]); do consume(v) |_i, p| { let (t, u) = p; ts.push(t); @@ -1298,9 +1264,9 @@ pub fn unzip<T,U>(v: ~[(T, U)]) -> (~[T], ~[U]) { pub fn zip_slice<T:Copy,U:Copy>(v: &const [T], u: &const [U]) -> ~[(T, U)] { let mut zipped = ~[]; - let sz = len(v); + let sz = v.len(); let mut i = 0u; - assert_eq!(sz, len(u)); + assert_eq!(sz, u.len()); while i < sz { zipped.push((v[i], u[i])); i += 1u; @@ -1311,12 +1277,12 @@ pub fn zip_slice<T:Copy,U:Copy>(v: &const [T], u: &const [U]) /** * Convert two vectors to a vector of pairs. * - * Returns a vector of tuples, where the i-th tuple contains contains the + * Returns a vector of tuples, where the i-th tuple contains the * i-th elements from each of the input vectors. */ pub fn zip<T, U>(mut v: ~[T], mut u: ~[U]) -> ~[(T, U)] { - let mut i = len(v); - assert_eq!(i, len(u)); + let mut i = v.len(); + assert_eq!(i, u.len()); let mut w = with_capacity(i); while i > 0 { w.push((v.pop(),u.pop())); @@ -1340,16 +1306,16 @@ pub fn swap<T>(v: &mut [T], a: uint, b: uint) { unsafe { // Can't take two mutable loans from one vector, so instead just cast // them to their raw pointers to do the swap - let pa: *mut T = ptr::to_mut_unsafe_ptr(&mut v[a]); - let pb: *mut T = ptr::to_mut_unsafe_ptr(&mut v[b]); - util::swap_ptr(pa, pb); + let pa: *mut T = &mut v[a]; + let pb: *mut T = &mut v[b]; + ptr::swap_ptr(pa, pb); } } /// Reverse the order of elements in a vector, in place pub fn reverse<T>(v: &mut [T]) { let mut i: uint = 0; - let ln = len::<T>(v); + let ln = v.len(); while i < ln / 2 { swap(v, i, ln - i - 1); i += 1; @@ -1397,7 +1363,7 @@ pub fn reverse_part<T>(v: &mut [T], start: uint, end : uint) { /// Returns a vector with the order of elements reversed pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] { let mut rs: ~[T] = ~[]; - let mut i = len::<T>(v); + let mut i = v.len(); if i == 0 { return (rs); } else { i -= 1; } while i != 0 { rs.push(v[i]); i -= 1; } rs.push(v[0]); @@ -1444,8 +1410,8 @@ pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] { * ~~~ */ #[inline(always)] -pub fn _each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) -> bool { - // ^^^^ +pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) -> bool { + // ^^^^ // NB---this CANNOT be &const [T]! The reason // is that you are passing it to `f()` using // an immutable. @@ -1464,41 +1430,13 @@ pub fn _each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) -> bool { } broke = n > 0; } - return true; -} - -pub fn each<'r,T>(v: &'r [T], f: &fn(&'r T) -> bool) -> bool { _each(v, f) } - -/// Like `each()`, but for the case where you have -/// a vector with mutable contents and you would like -/// to mutate the contents as you iterate. -#[inline(always)] -pub fn _each_mut<'r,T>(v: &'r mut [T], f: &fn(elem: &'r mut T) -> bool) -> bool { - let mut broke = false; - do as_mut_buf(v) |p, n| { - let mut n = n; - let mut p = p; - while n > 0 { - unsafe { - let q: &'r mut T = cast::transmute_mut_region(&mut *p); - if !f(q) { break; } - p = p.offset(1); - } - n -= 1; - } - broke = n > 0; - } - return broke; -} - -pub fn each_mut<'r,T>(v: &'r mut [T], f: &fn(elem: &'r mut T) -> bool) -> bool { - _each_mut(v, f) + return !broke; } /// Like `each()`, but for the case where you have a vector that *may or may /// not* have mutable contents. #[inline(always)] -pub fn _each_const<T>(v: &const [T], f: &fn(elem: &const T) -> bool) -> bool { +pub fn each_const<T>(v: &const [T], f: &fn(elem: &const T) -> bool) -> bool { let mut i = 0; let n = v.len(); while i < n { @@ -1510,17 +1448,13 @@ pub fn _each_const<T>(v: &const [T], f: &fn(elem: &const T) -> bool) -> bool { return true; } -pub fn each_const<t>(v: &const [t], f: &fn(elem: &const t) -> bool) -> bool { - _each_const(v, f) -} - /** * Iterates over a vector's elements and indices * * Return true to continue, false to break. */ #[inline(always)] -pub fn _eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { +pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { let mut i = 0; for each(v) |p| { if !f(i, p) { return false; } @@ -1529,115 +1463,6 @@ pub fn _eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { return true; } -pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { - _eachi(v, f) -} - -/** - * Iterates over a mutable vector's elements and indices - * - * Return true to continue, false to break. - */ -#[inline(always)] -pub fn _eachi_mut<'r,T>(v: &'r mut [T], - f: &fn(uint, v: &'r mut T) -> bool) -> bool { - let mut i = 0; - for each_mut(v) |p| { - if !f(i, p) { - return false; - } - i += 1; - } - return true; -} - -pub fn eachi_mut<'r,T>(v: &'r mut [T], - f: &fn(uint, v: &'r mut T) -> bool) -> bool { - _eachi_mut(v, f) -} - -/** - * Iterates over a vector's elements in reverse - * - * Return true to continue, false to break. - */ -#[inline(always)] -pub fn _each_reverse<'r,T>(v: &'r [T], blk: &fn(v: &'r T) -> bool) -> bool { - _eachi_reverse(v, |_i, v| blk(v)) -} - -pub fn each_reverse<'r,T>(v: &'r [T], blk: &fn(v: &'r T) -> bool) -> bool { - _each_reverse(v, blk) -} - -/** - * Iterates over a vector's elements and indices in reverse - * - * Return true to continue, false to break. - */ -#[inline(always)] -pub fn _eachi_reverse<'r,T>(v: &'r [T], - blk: &fn(i: uint, v: &'r T) -> bool) -> bool { - let mut i = v.len(); - while i > 0 { - i -= 1; - if !blk(i, &v[i]) { - return false; - } - } - return true; -} - -pub fn eachi_reverse<'r,T>(v: &'r [T], - blk: &fn(i: uint, v: &'r T) -> bool) -> bool { - _eachi_reverse(v, blk) -} - -/** - * Iterates over two vectors simultaneously - * - * # Failure - * - * Both vectors must have the same length - */ -#[inline] -pub fn _each2<U, T>(v1: &[U], v2: &[T], f: &fn(u: &U, t: &T) -> bool) -> bool { - assert_eq!(v1.len(), v2.len()); - for uint::range(0u, v1.len()) |i| { - if !f(&v1[i], &v2[i]) { - return false; - } - } - return true; -} - -pub fn each2<U, T>(v1: &[U], v2: &[T], f: &fn(u: &U, t: &T) -> bool) -> bool { - _each2(v1, v2, f) -} - -/** - * - * Iterates over two vector with mutable. - * - * # Failure - * - * Both vectors must have the same length - */ -#[inline] -pub fn _each2_mut<U, T>(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T) -> bool) -> bool { - assert_eq!(v1.len(), v2.len()); - for uint::range(0u, v1.len()) |i| { - if !f(&mut v1[i], &mut v2[i]) { - return false; - } - } - return true; -} - -pub fn each2_mut<U, T>(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T) -> bool) -> bool { - _each2_mut(v1, v2, f) -} - /** * Iterate over all permutations of vector `v`. * @@ -1645,7 +1470,7 @@ pub fn each2_mut<U, T>(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T) * of elements in `v` (so if `v` is sorted then the permutations are * lexicographically sorted). * - * The total number of permutations produced is `len(v)!`. If `v` contains + * The total number of permutations produced is `v.len()!`. If `v` contains * repeated elements, then some permutations are repeated. * * See [Algorithms to generate @@ -1761,6 +1586,9 @@ pub fn as_mut_buf<T,U>(s: &mut [T], f: &fn(*mut T, uint) -> U) -> U { // Equality +/// Tests whether two slices are equal to one another. This is only true if both +/// slices are of the same length, and each of the corresponding elements return +/// true when queried via the `eq` function. fn eq<T: Eq>(a: &[T], b: &[T]) -> bool { let (a_len, b_len) = (a.len(), b.len()); if a_len != b_len { return false; } @@ -1773,6 +1601,9 @@ fn eq<T: Eq>(a: &[T], b: &[T]) -> bool { true } +/// Similar to the `vec::eq` function, but this is defined for types which +/// implement `TotalEq` as opposed to types which implement `Eq`. Equality +/// comparisons are done via the `equals` function instead of `eq`. fn equals<T: TotalEq>(a: &[T], b: &[T]) -> bool { let (a_len, b_len) = (a.len(), b.len()); if a_len != b_len { return false; } @@ -1939,13 +1770,19 @@ pub mod traits { impl<'self,T> Container for &'self const [T] { /// Returns true if a vector contains no elements #[inline] - fn is_empty(&const self) -> bool { is_empty(*self) } + fn is_empty(&const self) -> bool { + as_const_buf(*self, |_p, len| len == 0u) + } /// Returns the length of a vector #[inline] - fn len(&const self) -> uint { len(*self) } + fn len(&const self) -> uint { + as_const_buf(*self, |_p, len| len) + } + } +#[allow(missing_doc)] pub trait CopyableVector<T> { fn to_owned(&self) -> ~[T]; } @@ -1965,9 +1802,11 @@ impl<'self,T:Copy> CopyableVector<T> for &'self [T] { } } +#[allow(missing_doc)] pub trait ImmutableVector<'self, T> { fn slice(&self, start: uint, end: uint) -> &'self [T]; fn iter(self) -> VecIterator<'self, T>; + fn rev_iter(self) -> VecRevIterator<'self, T>; fn head(&self) -> &'self T; fn head_opt(&self) -> Option<&'self T>; fn tail(&self) -> &'self [T]; @@ -1978,13 +1817,9 @@ pub trait ImmutableVector<'self, T> { fn last_opt(&self) -> Option<&'self T>; fn position(&self, f: &fn(t: &T) -> bool) -> Option<uint>; fn rposition(&self, f: &fn(t: &T) -> bool) -> Option<uint>; - fn each_reverse(&self, blk: &fn(&T) -> bool) -> bool; - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) -> bool; - fn foldr<'a, U>(&'a self, z: U, p: &fn(t: &'a T, u: U) -> U) -> U; fn map<U>(&self, f: &fn(t: &T) -> U) -> ~[U]; fn mapi<U>(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; fn map_r<U>(&self, f: &fn(x: &T) -> U) -> ~[U]; - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool; fn flat_map<U>(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U]; unsafe fn unsafe_ref(&self, index: uint) -> *T; @@ -2006,6 +1841,15 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { lifetime: cast::transmute(p)} } } + #[inline] + fn rev_iter(self) -> VecRevIterator<'self, T> { + unsafe { + let p = vec::raw::to_ptr(self); + VecRevIterator{ptr: p.offset(self.len() - 1), + end: p.offset(-1), + lifetime: cast::transmute(p)} + } + } /// Returns the first element of a vector, failing if the vector is empty. #[inline] @@ -2063,24 +1907,6 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { rposition(*self, f) } - /// Iterates over a vector's elements in reverse. - #[inline] - fn each_reverse(&self, blk: &fn(&T) -> bool) -> bool { - each_reverse(*self, blk) - } - - /// Iterates over a vector's elements and indices in reverse. - #[inline] - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) -> bool { - eachi_reverse(*self, blk) - } - - /// Reduce a vector from right to left - #[inline] - fn foldr<'a, U>(&'a self, z: U, p: &fn(t: &'a T, u: U) -> U) -> U { - foldr(*self, z, p) - } - /// Apply a function to each element of a vector and return the results #[inline] fn map<U>(&self, f: &fn(t: &T) -> U) -> ~[U] { map(*self, f) } @@ -2105,14 +1931,6 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { } /** - * Returns true if the function returns true for all elements. - * - * If the vector is empty, true is returned. - */ - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool { - alli(*self, f) - } - /** * Apply a function to each element of a vector and return a concatenation * of each result vector */ @@ -2140,6 +1958,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { } } +#[allow(missing_doc)] pub trait ImmutableEqVector<T:Eq> { fn position_elem(&self, t: &T) -> Option<uint>; fn rposition_elem(&self, t: &T) -> Option<uint>; @@ -2159,6 +1978,7 @@ impl<'self,T:Eq> ImmutableEqVector<T> for &'self [T] { } } +#[allow(missing_doc)] pub trait ImmutableCopyableVector<T> { fn filtered(&self, f: &fn(&T) -> bool) -> ~[T]; fn rfind(&self, f: &fn(t: &T) -> bool) -> Option<T>; @@ -2208,6 +2028,7 @@ impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] { } } +#[allow(missing_doc)] pub trait OwnedVector<T> { fn push(&mut self, t: T); fn push_all_move(&mut self, rhs: ~[T]); @@ -2312,6 +2133,7 @@ impl<T> Mutable for ~[T] { fn clear(&mut self) { self.truncate(0) } } +#[allow(missing_doc)] pub trait OwnedCopyableVector<T:Copy> { fn push_all(&mut self, rhs: &const [T]); fn grow(&mut self, n: uint, initval: &T); @@ -2335,6 +2157,7 @@ impl<T:Copy> OwnedCopyableVector<T> for ~[T] { } } +#[allow(missing_doc)] trait OwnedEqVector<T:Eq> { fn dedup(&mut self); } @@ -2346,8 +2169,11 @@ impl<T:Eq> OwnedEqVector<T> for ~[T] { } } +#[allow(missing_doc)] pub trait MutableVector<'self, T> { fn mut_slice(self, start: uint, end: uint) -> &'self mut [T]; + fn mut_iter(self) -> VecMutIterator<'self, T>; + fn mut_rev_iter(self) -> VecMutRevIterator<'self, T>; unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T; unsafe fn unsafe_set(&self, index: uint, val: T); @@ -2359,6 +2185,24 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { mut_slice(self, start, end) } + #[inline] + fn mut_iter(self) -> VecMutIterator<'self, T> { + unsafe { + let p = vec::raw::to_mut_ptr(self); + VecMutIterator{ptr: p, end: p.offset(self.len()), + lifetime: cast::transmute(p)} + } + } + + fn mut_rev_iter(self) -> VecMutRevIterator<'self, T> { + unsafe { + let p = vec::raw::to_mut_ptr(self); + VecMutRevIterator{ptr: p.offset(self.len() - 1), + end: p.offset(-1), + lifetime: cast::transmute(p)} + } + } + #[inline(always)] unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T { let pair_ptr: &(*mut T, uint) = transmute(self); @@ -2386,6 +2230,7 @@ pub unsafe fn from_buf<T>(ptr: *T, elts: uint) -> ~[T] { } /// The internal 'unboxed' representation of a vector +#[allow(missing_doc)] pub struct UnboxedVecRepr { fill: uint, alloc: uint, @@ -2401,17 +2246,21 @@ pub mod raw { use ptr; use sys; use unstable::intrinsics; - use vec::{UnboxedVecRepr, as_const_buf, as_mut_buf, len, with_capacity}; + use vec::{UnboxedVecRepr, as_const_buf, as_mut_buf, with_capacity}; use util; /// The internal representation of a (boxed) vector + #[allow(missing_doc)] pub struct VecRepr { box_header: managed::raw::BoxHeaderRepr, unboxed: UnboxedVecRepr } + /// The internal representation of a slice pub struct SliceRepr { + /// Pointer to the base of this slice data: *u8, + /// The length of the slice len: uint } @@ -2640,29 +2489,6 @@ impl<A> old_iter::BaseIter<A> for @[A] { fn size_hint(&self) -> Option<uint> { Some(self.len()) } } -impl<'self,A> old_iter::MutableIter<A> for &'self mut [A] { - #[inline(always)] - fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) -> bool { - each_mut(*self, blk) - } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::MutableIter<A> for ~[A] { - #[inline(always)] - fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) -> bool { - each_mut(*self, blk) - } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::MutableIter<A> for @mut [A] { - #[inline(always)] - fn each_mut(&mut self, blk: &fn(v: &mut A) -> bool) -> bool { - each_mut(*self, blk) - } -} - impl<'self,A> old_iter::ExtendedIter<A> for &'self [A] { pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { old_iter::eachi(self, blk) @@ -2688,13 +2514,6 @@ impl<'self,A> old_iter::ExtendedIter<A> for &'self [A] { } } -impl<'self,A> old_iter::ExtendedMutableIter<A> for &'self mut [A] { - #[inline(always)] - pub fn eachi_mut(&mut self, blk: &fn(uint, v: &mut A) -> bool) -> bool { - eachi_mut(*self, blk) - } -} - // FIXME(#4148): This should be redundant impl<A> old_iter::ExtendedIter<A> for ~[A] { pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) -> bool { @@ -2813,67 +2632,83 @@ impl<A:Copy + Ord> old_iter::CopyableOrderedIter<A> for @[A] { fn max(&self) -> A { old_iter::max(self) } } -impl<'self,A:Copy> old_iter::CopyableNonstrictIter<A> for &'self [A] { - fn each_val(&const self, f: &fn(A) -> bool) -> bool { - let mut i = 0; - while i < self.len() { - if !f(copy self[i]) { return false; } - i += 1; - } - return true; +impl<A:Clone> Clone for ~[A] { + #[inline] + fn clone(&self) -> ~[A] { + self.map(|item| item.clone()) } } -// FIXME(#4148): This should be redundant -impl<A:Copy> old_iter::CopyableNonstrictIter<A> for ~[A] { - fn each_val(&const self, f: &fn(A) -> bool) -> bool { - let mut i = 0; - while i < uniq_len(self) { - if !f(copy self[i]) { return false; } - i += 1; +macro_rules! iterator { + /* FIXME: #4375 Cannot attach documentation/attributes to a macro generated struct. + (struct $name:ident -> $ptr:ty, $elem:ty) => { + pub struct $name<'self, T> { + priv ptr: $ptr, + priv end: $ptr, + priv lifetime: $elem // FIXME: #5922 } - return true; - } -} - -// FIXME(#4148): This should be redundant -impl<A:Copy> old_iter::CopyableNonstrictIter<A> for @[A] { - fn each_val(&const self, f: &fn(A) -> bool) -> bool { - let mut i = 0; - while i < self.len() { - if !f(copy self[i]) { return false; } - i += 1; + };*/ + (impl $name:ident -> $elem:ty, $step:expr) => { + // could be implemented with &[T] with .slice(), but this avoids bounds checks + impl<'self, T> Iterator<$elem> for $name<'self, T> { + #[inline] + fn next(&mut self) -> Option<$elem> { + unsafe { + if self.ptr == self.end { + None + } else { + let old = self.ptr; + self.ptr = self.ptr.offset($step); + Some(cast::transmute(old)) + } + } + } } - return true; } } -impl<A:Clone> Clone for ~[A] { - #[inline] - fn clone(&self) -> ~[A] { - self.map(|item| item.clone()) - } +//iterator!{struct VecIterator -> *T, &'self T} +/// An iterator for iterating over a vector +pub struct VecIterator<'self, T> { + priv ptr: *T, + priv end: *T, + priv lifetime: &'self T // FIXME: #5922 } +iterator!{impl VecIterator -> &'self T, 1} -// could be implemented with &[T] with .slice(), but this avoids bounds checks -pub struct VecIterator<'self, T> { +//iterator!{struct VecRevIterator -> *T, &'self T} +/// An iterator for iterating over a vector in reverse +pub struct VecRevIterator<'self, T> { priv ptr: *T, priv end: *T, priv lifetime: &'self T // FIXME: #5922 } +iterator!{impl VecRevIterator -> &'self T, -1} -impl<'self, T> Iterator<&'self T> for VecIterator<'self, T> { - #[inline] - fn next(&mut self) -> Option<&'self T> { - unsafe { - if self.ptr == self.end { - None - } else { - let old = self.ptr; - self.ptr = self.ptr.offset(1); - Some(cast::transmute(old)) - } - } +//iterator!{struct VecMutIterator -> *mut T, &'self mut T} +/// An iterator for mutating the elements of a vector +pub struct VecMutIterator<'self, T> { + priv ptr: *mut T, + priv end: *mut T, + priv lifetime: &'self mut T // FIXME: #5922 +} +iterator!{impl VecMutIterator -> &'self mut T, 1} + +//iterator!{struct VecMutRevIterator -> *mut T, &'self mut T} +/// An iterator for mutating the elements of a vector in reverse +pub struct VecMutRevIterator<'self, T> { + priv ptr: *mut T, + priv end: *mut T, + priv lifetime: &'self mut T // FIXME: #5922 +} +iterator!{impl VecMutRevIterator -> &'self mut T, -1} + +impl<T> FromIter<T> for ~[T]{ + #[inline(always)] + pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] { + let mut v = ~[]; + for iter |x| { v.push(x) } + v } } @@ -2968,8 +2803,9 @@ mod tests { #[test] fn test_is_empty() { - assert!(is_empty::<int>([])); - assert!(!is_empty([0])); + let xs: [int, ..0] = []; + assert!(xs.is_empty()); + assert!(![0].is_empty()); } #[test] @@ -3417,39 +3253,6 @@ mod tests { } #[test] - fn test_foldl() { - // Test on-stack fold. - let mut v = ~[1u, 2u, 3u]; - let mut sum = foldl(0u, v, add); - assert_eq!(sum, 6u); - - // Test on-heap fold. - v = ~[1u, 2u, 3u, 4u, 5u]; - sum = foldl(0u, v, add); - assert_eq!(sum, 15u); - } - - #[test] - fn test_foldl2() { - fn sub(a: int, b: &int) -> int { - a - *b - } - let v = ~[1, 2, 3, 4]; - let sum = foldl(0, v, sub); - assert_eq!(sum, -10); - } - - #[test] - fn test_foldr() { - fn sub(a: &int, b: int) -> int { - *a - b - } - let v = ~[1, 2, 3, 4]; - let sum = foldr(v, 0, sub); - assert_eq!(sum, -2); - } - - #[test] fn test_each_empty() { for each::<int>([]) |_v| { fail!(); // should never be executed @@ -3477,41 +3280,18 @@ mod tests { } #[test] - fn test_each_reverse_empty() { - let v: ~[int] = ~[]; - for v.each_reverse |_v| { - fail!(); // should never execute - } + fn test_each_ret_len0() { + let a0 : [int, .. 0] = []; + assert_eq!(each(a0, |_p| fail!()), true); } #[test] - fn test_each_reverse_nonempty() { - let mut i = 0; - for each_reverse([1, 2, 3]) |v| { - if i == 0 { assert!(*v == 3); } - i += *v - } - assert_eq!(i, 6); + fn test_each_ret_len1() { + let a1 = [17]; + assert_eq!(each(a1, |_p| true), true); + assert_eq!(each(a1, |_p| false), false); } - #[test] - fn test_eachi_reverse() { - let mut i = 0; - for eachi_reverse([0, 1, 2]) |j, v| { - if i == 0 { assert!(*v == 2); } - assert_eq!(j, *v as uint); - i += *v; - } - assert_eq!(i, 3); - } - - #[test] - fn test_eachi_reverse_empty() { - let v: ~[int] = ~[]; - for v.eachi_reverse |_i, _v| { - fail!(); // should never execute - } - } #[test] fn test_each_permutation() { @@ -3536,33 +3316,6 @@ mod tests { } #[test] - fn test_any_and_all() { - assert!(any([1u, 2u, 3u], is_three)); - assert!(!any([0u, 1u, 2u], is_three)); - assert!(any([1u, 2u, 3u, 4u, 5u], is_three)); - assert!(!any([1u, 2u, 4u, 5u, 6u], is_three)); - - assert!(all([3u, 3u, 3u], is_three)); - assert!(!all([3u, 3u, 2u], is_three)); - assert!(all([3u, 3u, 3u, 3u, 3u], is_three)); - assert!(!all([3u, 3u, 0u, 1u, 2u], is_three)); - } - - #[test] - fn test_any2_and_all2() { - - assert!(any2([2u, 4u, 6u], [2u, 4u, 6u], is_equal)); - assert!(any2([1u, 2u, 3u], [4u, 5u, 3u], is_equal)); - assert!(!any2([1u, 2u, 3u], [4u, 5u, 6u], is_equal)); - assert!(any2([2u, 4u, 6u], [2u, 4u], is_equal)); - - assert!(all2([2u, 4u, 6u], [2u, 4u, 6u], is_equal)); - assert!(!all2([1u, 2u, 3u], [4u, 5u, 3u], is_equal)); - assert!(!all2([1u, 2u, 3u], [4u, 5u, 6u], is_equal)); - assert!(!all2([2u, 4u, 6u], [2u, 4u], is_equal)); - } - - #[test] fn test_zip_unzip() { let v1 = ~[1, 2, 3]; let v2 = ~[4, 5, 6]; @@ -3888,6 +3641,10 @@ mod tests { #[test] fn test_concat() { assert_eq!(concat([~[1], ~[2,3]]), ~[1, 2, 3]); + assert_eq!([~[1], ~[2,3]].concat_vec(), ~[1, 2, 3]); + + assert_eq!(concat_slices([&[1], &[2,3]]), ~[1, 2, 3]); + assert_eq!([&[1], &[2,3]].concat_vec(), ~[1, 2, 3]); } #[test] @@ -3895,6 +3652,14 @@ mod tests { assert_eq!(connect([], &0), ~[]); assert_eq!(connect([~[1], ~[2, 3]], &0), ~[1, 0, 2, 3]); assert_eq!(connect([~[1], ~[2], ~[3]], &0), ~[1, 0, 2, 0, 3]); + assert_eq!([~[1], ~[2, 3]].connect_vec(&0), ~[1, 0, 2, 3]); + assert_eq!([~[1], ~[2], ~[3]].connect_vec(&0), ~[1, 0, 2, 0, 3]); + + assert_eq!(connect_slices([], &0), ~[]); + assert_eq!(connect_slices([&[1], &[2, 3]], &0), ~[1, 0, 2, 3]); + assert_eq!(connect_slices([&[1], &[2], &[3]], &0), ~[1, 0, 2, 0, 3]); + assert_eq!([&[1], &[2, 3]].connect_vec(&0), ~[1, 0, 2, 3]); + assert_eq!([&[1], &[2], &[3]].connect_vec(&0), ~[1, 0, 2, 0, 3]); } #[test] @@ -4298,113 +4063,6 @@ mod tests { #[ignore(windows)] #[should_fail] #[allow(non_implicitly_copyable_typarams)] - fn test_foldl_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do foldl((~0, @0), v) |_a, _b| { - if i == 2 { - fail!() - } - i += 0; - (~0, @0) - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_foldr_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do foldr(v, (~0, @0)) |_a, _b| { - if i == 2 { - fail!() - } - i += 0; - (~0, @0) - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_any_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do any(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_any2_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do any(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_all_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do all(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - true - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_alli_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do alli(v) |_i, _elt| { - if i == 2 { - fail!() - } - i += 0; - true - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_all2_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do all2(v, v) |_elt1, _elt2| { - if i == 2 { - fail!() - } - i += 0; - true - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] fn test_find_fail() { let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; let mut i = 0; @@ -4556,6 +4214,40 @@ mod tests { } #[test] + fn test_mut_iterator() { + use iterator::*; + let mut xs = [1, 2, 3, 4, 5]; + for xs.mut_iter().advance |x| { + *x += 1; + } + assert_eq!(xs, [2, 3, 4, 5, 6]) + } + + #[test] + fn test_rev_iterator() { + use iterator::*; + + let xs = [1, 2, 5, 10, 11]; + let ys = [11, 10, 5, 2, 1]; + let mut i = 0; + for xs.rev_iter().advance |&x| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, 5); + } + + #[test] + fn test_mut_rev_iterator() { + use iterator::*; + let mut xs = [1u, 2, 3, 4, 5]; + for xs.mut_rev_iter().enumerate().advance |(i,x)| { + *x += i; + } + assert_eq!(xs, [5, 5, 5, 5, 5]) + } + + #[test] fn test_reverse_part() { let mut values = [1,2,3,4,5]; reverse_part(values,1,4); @@ -4601,14 +4293,4 @@ mod tests { } assert_eq!(v, ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]]); } - - #[test] - fn test_each_val() { - use old_iter::CopyableNonstrictIter; - let mut i = 0; - for [1, 2, 3].each_val |v| { - i += v; - } - assert_eq!(i, 6); - } } |
