diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2013-05-17 10:45:09 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2013-05-22 21:57:05 -0700 |
| commit | 0c820d4123c754522b0655e9e74f692c55685bfa (patch) | |
| tree | 7dbb86c30b451217b4e8f75173043744fe3255ff /src/libcore | |
| parent | 565942b145efbf6c1d1f66db46423d721b55d32c (diff) | |
| download | rust-0c820d4123c754522b0655e9e74f692c55685bfa.tar.gz rust-0c820d4123c754522b0655e9e74f692c55685bfa.zip | |
libstd: Rename libcore to libstd and libstd to libextra; update makefiles.
This only changes the directory names; it does not change the "real" metadata names.
Diffstat (limited to 'src/libcore')
118 files changed, 0 insertions, 52811 deletions
diff --git a/src/libcore/at_vec.rs b/src/libcore/at_vec.rs deleted file mode 100644 index 44c55563ac5..00000000000 --- a/src/libcore/at_vec.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Managed vectors - -use cast::transmute; -use container::Container; -use kinds::Copy; -use old_iter; -use old_iter::BaseIter; -use option::Option; -use sys; -use uint; -use vec; - -/// Code for dealing with @-vectors. This is pretty incomplete, and -/// contains a bunch of duplication from the code for ~-vectors. - -pub mod rustrt { - use libc; - use sys; - use vec; - - #[abi = "cdecl"] - #[link_name = "rustrt"] - pub extern { - pub unsafe fn vec_reserve_shared_actual(t: *sys::TypeDesc, - v: **vec::raw::VecRepr, - n: libc::size_t); - } -} - -/// Returns the number of elements the vector can hold without reallocating -#[inline(always)] -pub fn capacity<T>(v: @[T]) -> uint { - unsafe { - let repr: **raw::VecRepr = transmute(&v); - (**repr).unboxed.alloc / sys::size_of::<T>() - } -} - -/** - * Builds a vector by calling a provided function with an argument - * function that pushes an element to the back of a vector. - * This version takes an initial size for the vector. - * - * # Arguments - * - * * size - An initial size of the vector to reserve - * * builder - A function that will construct the vector. It receives - * as an argument a function that will push an element - * onto the vector being constructed. - */ -#[inline(always)] -pub fn build_sized<A>(size: uint, builder: &fn(push: &fn(v: A))) -> @[A] { - let mut vec: @[A] = @[]; - unsafe { raw::reserve(&mut vec, size); } - builder(|x| unsafe { raw::push(&mut vec, x) }); - return unsafe { transmute(vec) }; -} - -/** - * Builds a vector by calling a provided function with an argument - * function that pushes an element to the back of a vector. - * - * # Arguments - * - * * builder - A function that will construct the vector. It receives - * as an argument a function that will push an element - * onto the vector being constructed. - */ -#[inline(always)] -pub fn build<A>(builder: &fn(push: &fn(v: A))) -> @[A] { - build_sized(4, builder) -} - -/** - * Builds a vector by calling a provided function with an argument - * function that pushes an element to the back of a vector. - * This version takes an initial size for the vector. - * - * # Arguments - * - * * size - An option, maybe containing initial size of the vector to reserve - * * builder - A function that will construct the vector. It receives - * as an argument a function that will push an element - * onto the vector being constructed. - */ -#[inline(always)] -pub fn build_sized_opt<A>(size: Option<uint>, - builder: &fn(push: &fn(v: A))) - -> @[A] { - build_sized(size.get_or_default(4), builder) -} - -// Appending -#[inline(always)] -pub fn append<T:Copy>(lhs: @[T], rhs: &const [T]) -> @[T] { - do build_sized(lhs.len() + rhs.len()) |push| { - for lhs.each |x| { push(*x); } - for uint::range(0, rhs.len()) |i| { push(rhs[i]); } - } -} - - -/// Apply a function to each element of a vector and return the results -pub fn map<T, U>(v: &[T], f: &fn(x: &T) -> U) -> @[U] { - do build_sized(v.len()) |push| { - for v.each |elem| { - push(f(elem)); - } - } -} - -/** - * Creates and initializes an immutable vector. - * - * Creates an immutable vector of size `n_elts` and initializes the elements - * to the value returned by the function `op`. - */ -pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> @[T] { - do build_sized(n_elts) |push| { - let mut i: uint = 0u; - while i < n_elts { push(op(i)); i += 1u; } - } -} - -/** - * Creates and initializes an immutable vector. - * - * Creates an immutable vector of size `n_elts` and initializes the elements - * to the value `t`. - */ -pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> @[T] { - do build_sized(n_elts) |push| { - let mut i: uint = 0u; - while i < n_elts { push(copy t); i += 1u; } - } -} - -/** - * Creates and initializes an immutable managed vector by moving all the - * elements from an owned vector. - */ -pub fn to_managed_consume<T>(v: ~[T]) -> @[T] { - let mut av = @[]; - unsafe { - raw::reserve(&mut av, v.len()); - do vec::consume(v) |_i, x| { - raw::push(&mut av, x); - } - transmute(av) - } -} - -/** - * Creates and initializes an immutable managed vector by copying all the - * elements of a slice. - */ -pub fn to_managed<T:Copy>(v: &[T]) -> @[T] { - from_fn(v.len(), |i| v[i]) -} - -#[cfg(not(test))] -pub mod traits { - use at_vec::append; - use kinds::Copy; - use ops::Add; - - impl<'self,T:Copy> Add<&'self const [T],@[T]> for @[T] { - #[inline(always)] - fn add(&self, rhs: & &'self const [T]) -> @[T] { - append(*self, (*rhs)) - } - } -} - -#[cfg(test)] -pub mod traits {} - -pub mod raw { - use at_vec::{capacity, rustrt}; - use cast::{transmute, transmute_copy}; - use libc; - use ptr; - use sys; - use uint; - use unstable::intrinsics::{move_val_init}; - use vec; - - pub type VecRepr = vec::raw::VecRepr; - pub type SliceRepr = vec::raw::SliceRepr; - - /** - * Sets the length of a vector - * - * This will explicitly set the size of the vector, without actually - * modifing its buffers, so it is up to the caller to ensure that - * the vector is actually the specified size. - */ - #[inline(always)] - pub unsafe fn set_len<T>(v: @[T], new_len: uint) { - let repr: **mut VecRepr = transmute(&v); - (**repr).unboxed.fill = new_len * sys::size_of::<T>(); - } - - #[inline(always)] - pub unsafe fn push<T>(v: &mut @[T], initval: T) { - let repr: **VecRepr = transmute_copy(&v); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc > fill { - push_fast(v, initval); - } else { - push_slow(v, initval); - } - } - - #[inline(always)] // really pretty please - pub 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>(); - let p = &((**repr).unboxed.data); - let p = ptr::offset(p, fill) as *mut T; - move_val_init(&mut(*p), initval); - } - - pub unsafe fn push_slow<T>(v: &mut @[T], initval: T) { - reserve_at_least(&mut *v, v.len() + 1u); - push_fast(v, initval); - } - - /** - * Reserves capacity for exactly `n` elements in the given vector. - * - * If the capacity for `v` is already equal to or greater than the - * requested capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ - pub unsafe fn reserve<T>(v: &mut @[T], n: uint) { - // Only make the (slow) call into the runtime if we have to - if capacity(*v) < n { - let ptr: **VecRepr = transmute(v); - rustrt::vec_reserve_shared_actual(sys::get_type_desc::<T>(), - ptr, n as libc::size_t); - } - } - - /** - * Reserves capacity for at least `n` elements in the given vector. - * - * 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 `v` is already equal to or greater than the - * requested capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ - pub unsafe fn reserve_at_least<T>(v: &mut @[T], n: uint) { - reserve(v, uint::next_power_of_two(n)); - } -} - -#[cfg(test)] -mod test { - use super::*; - use prelude::*; - - #[test] - fn test() { - // Some code that could use that, then: - fn seq_range(lo: uint, hi: uint) -> @[uint] { - do build |push| { - for uint::range(lo, hi) |i| { - push(i); - } - } - } - - assert_eq!(seq_range(10, 15), @[10, 11, 12, 13, 14]); - assert_eq!(from_fn(5, |x| x+1), @[1, 2, 3, 4, 5]); - assert_eq!(from_elem(5, 3.14), @[3.14, 3.14, 3.14, 3.14, 3.14]); - } - - #[test] - fn append_test() { - assert_eq!(@[1,2,3] + @[4,5,6], @[1,2,3,4,5,6]); - } - - #[test] - fn test_to_managed_consume() { - assert_eq!(to_managed_consume::<int>(~[]), @[]); - assert_eq!(to_managed_consume(~[true]), @[true]); - assert_eq!(to_managed_consume(~[1, 2, 3, 4, 5]), @[1, 2, 3, 4, 5]); - assert_eq!(to_managed_consume(~[~"abc", ~"123"]), @[~"abc", ~"123"]); - assert_eq!(to_managed_consume(~[~[42]]), @[~[42]]); - } - - #[test] - fn test_to_managed() { - assert_eq!(to_managed::<int>([]), @[]); - assert_eq!(to_managed([true]), @[true]); - assert_eq!(to_managed([1, 2, 3, 4, 5]), @[1, 2, 3, 4, 5]); - assert_eq!(to_managed([@"abc", @"123"]), @[@"abc", @"123"]); - assert_eq!(to_managed([@[42]]), @[@[42]]); - } -} diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs deleted file mode 100644 index 5ab7f838a57..00000000000 --- a/src/libcore/bool.rs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Boolean logic - -#[cfg(not(test))] -use cmp::{Eq, Ord, TotalOrd, Ordering}; -use option::{None, Option, Some}; -use from_str::FromStr; - -/// Negation / inverse -pub fn not(v: bool) -> bool { !v } - -/// Conjunction -pub fn and(a: bool, b: bool) -> bool { a && b } - -/// Disjunction -pub fn or(a: bool, b: bool) -> bool { a || b } - -/** - * Exclusive or - * - * Identical to `or(and(a, not(b)), and(not(a), b))` - */ -pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) } - -/// Implication in the logic, i.e. from `a` follows `b` -pub fn implies(a: bool, b: bool) -> bool { !a || b } - -/// true if truth values `a` and `b` are indistinguishable in the logic -pub fn eq(a: bool, b: bool) -> bool { a == b } - -/// true if truth values `a` and `b` are distinguishable in the logic -pub fn ne(a: bool, b: bool) -> bool { a != b } - -/// true if `v` represents truth in the logic -pub fn is_true(v: bool) -> bool { v } - -/// true if `v` represents falsehood in the logic -pub fn is_false(v: bool) -> bool { !v } - -/// Parse logic value from `s` -impl FromStr for bool { - fn from_str(s: &str) -> Option<bool> { - match s { - "true" => Some(true), - "false" => Some(false), - _ => None, - } - } -} - -/// Convert `v` into a string -pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } } - -/** - * Iterates over all truth values by passing them to `blk` in an unspecified - * order - */ -pub fn all_values(blk: &fn(v: bool)) { - blk(true); - blk(false); -} - -/// converts truth value to an 8 bit byte -#[inline(always)] -pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } } - -#[cfg(not(test))] -impl Ord for bool { - #[inline(always)] - fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) } - #[inline(always)] - fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) } - #[inline(always)] - fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) } - #[inline(always)] - fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) } -} - -#[cfg(not(test))] -impl TotalOrd for bool { - #[inline(always)] - fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) } -} - -#[cfg(not(test))] -impl Eq for bool { - #[inline(always)] - fn eq(&self, other: &bool) -> bool { (*self) == (*other) } - #[inline(always)] - fn ne(&self, other: &bool) -> bool { (*self) != (*other) } -} - -#[cfg(test)] -mod tests { - use super::*; - use prelude::*; - - #[test] - fn test_bool_from_str() { - do all_values |v| { - assert!(Some(v) == FromStr::from_str(to_str(v))) - } - } - - #[test] - fn test_bool_to_str() { - assert_eq!(to_str(false), ~"false"); - assert_eq!(to_str(true), ~"true"); - } - - #[test] - fn test_bool_to_bit() { - do all_values |v| { - assert_eq!(to_bit(v), if is_true(v) { 1u8 } else { 0u8 }); - } - } - - #[test] - fn test_bool_ord() { - assert!(true > false); - assert!(!(false > true)); - - assert!(false < true); - assert!(!(true < false)); - - assert!(false <= false); - assert!(false >= false); - assert!(true <= true); - assert!(true >= true); - - assert!(false <= true); - assert!(!(false >= true)); - assert!(true >= false); - assert!(!(true <= false)); - } - - #[test] - fn test_bool_totalord() { - assert_eq!(true.cmp(&true), Equal); - assert_eq!(false.cmp(&false), Equal); - assert_eq!(true.cmp(&false), Greater); - assert_eq!(false.cmp(&true), Less); - } -} diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs deleted file mode 100644 index e3336e24a6e..00000000000 --- a/src/libcore/cast.rs +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unsafe casting functions - -use sys; -use unstable; -use unstable::intrinsics; - -/// Casts the value at `src` to U. The two types must have the same length. -pub unsafe fn transmute_copy<T, U>(src: &T) -> U { - let mut dest: U = intrinsics::init(); - { - let dest_ptr: *mut u8 = transmute(&mut dest); - let src_ptr: *u8 = transmute(src); - intrinsics::memmove64(dest_ptr, - src_ptr, - sys::size_of::<U>() as u64); - } - dest -} - -/** - * Move a thing into the void - * - * The forget function will take ownership of the provided value but neglect - * to run any required cleanup or memory-management operations on it. This - * can be used for various acts of magick, particularly when using - * reinterpret_cast on pointer types. - */ -#[inline(always)] -pub unsafe fn forget<T>(thing: T) { intrinsics::forget(thing); } - -/** - * Force-increment the reference count on a shared box. If used - * carelessly, this can leak the box. Use this in conjunction with transmute - * and/or reinterpret_cast when such calls would otherwise scramble a box's - * reference count - */ -pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); } - -/** - * Transform a value of one type into a value of another type. - * Both types must have the same size and alignment. - * - * # Example - * - * assert!(transmute("L") == ~[76u8, 0u8]); - */ -#[inline(always)] -pub unsafe fn transmute<L, G>(thing: L) -> G { - intrinsics::transmute(thing) -} - -/// Coerce an immutable reference to be mutable. -#[inline(always)] -pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) } - -/// Coerce a mutable reference to be immutable. -#[inline(always)] -pub unsafe fn transmute_immut<'a,T>(ptr: &'a mut T) -> &'a T { - transmute(ptr) -} - -/// Coerce a borrowed pointer to have an arbitrary associated region. -#[inline(always)] -pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T { - transmute(ptr) -} - -/// Coerce an immutable reference to be mutable. -#[inline(always)] -pub unsafe fn transmute_mut_unsafe<T>(ptr: *const T) -> *mut T { - transmute(ptr) -} - -/// Coerce an immutable reference to be mutable. -#[inline(always)] -pub unsafe fn transmute_immut_unsafe<T>(ptr: *const T) -> *T { - transmute(ptr) -} - -/// Coerce a borrowed mutable pointer to have an arbitrary associated region. -#[inline(always)] -pub unsafe fn transmute_mut_region<'a,'b,T>(ptr: &'a mut T) -> &'b mut T { - transmute(ptr) -} - -/// Transforms lifetime of the second pointer to match the first. -#[inline(always)] -pub unsafe fn copy_lifetime<'a,S,T>(_ptr: &'a S, ptr: &T) -> &'a T { - transmute_region(ptr) -} - -/// Transforms lifetime of the second pointer to match the first. -#[inline(always)] -pub unsafe fn copy_mut_lifetime<'a,S,T>(_ptr: &'a mut S, ptr: &mut T) -> &'a mut T { - transmute_mut_region(ptr) -} - -/// Transforms lifetime of the second pointer to match the first. -#[inline(always)] -pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T { - transmute_region(ptr) -} - - -/**************************************************************************** - * Tests - ****************************************************************************/ - -#[cfg(test)] -mod tests { - use cast::{bump_box_refcount, transmute}; - - #[test] - fn test_transmute_copy() { - assert_eq!(1u, unsafe { ::cast::transmute_copy(&1) }); - } - - #[test] - fn test_bump_box_refcount() { - unsafe { - let box = @~"box box box"; // refcount 1 - bump_box_refcount(box); // refcount 2 - let ptr: *int = transmute(box); // refcount 2 - let _box1: @~str = ::cast::transmute_copy(&ptr); - let _box2: @~str = ::cast::transmute_copy(&ptr); - assert!(*_box1 == ~"box box box"); - assert!(*_box2 == ~"box box box"); - // Will destroy _box1 and _box2. Without the bump, this would - // use-after-free. With too many bumps, it would leak. - } - } - - #[test] - fn test_transmute() { - use managed::raw::BoxRepr; - unsafe { - let x = @100u8; - let x: *BoxRepr = transmute(x); - assert!((*x).data == 100); - let _x: @int = transmute(x); - } - } - - #[test] - fn test_transmute2() { - unsafe { - assert_eq!(~[76u8, 0u8], transmute(~"L")); - } - } -} diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs deleted file mode 100644 index b707e3bbb9e..00000000000 --- a/src/libcore/cell.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A mutable, nullable memory location - -use cast::transmute_mut; -use prelude::*; -use util::replace; - -/* -A dynamic, mutable location. - -Similar to a mutable option type, but friendlier. -*/ - -#[mutable] -#[deriving(Clone)] -pub struct Cell<T> { - priv value: Option<T> -} - -impl<T: DeepClone> DeepClone for Cell<T> { - fn deep_clone(&self) -> Cell<T> { - Cell{value: self.value.deep_clone()} - } -} - -impl<T:cmp::Eq> cmp::Eq for Cell<T> { - fn eq(&self, other: &Cell<T>) -> bool { - (self.value) == (other.value) - } - fn ne(&self, other: &Cell<T>) -> bool { !self.eq(other) } -} - -/// Creates a new full cell with the given value. -pub fn Cell<T>(value: T) -> Cell<T> { - Cell { value: Some(value) } -} - -pub fn empty_cell<T>() -> Cell<T> { - Cell { value: None } -} - -pub impl<T> Cell<T> { - /// Yields the value, failing if the cell is empty. - fn take(&self) -> T { - let this = unsafe { transmute_mut(self) }; - if this.is_empty() { - fail!("attempt to take an empty cell"); - } - - replace(&mut this.value, None).unwrap() - } - - /// Returns the value, failing if the cell is full. - 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"); - } - this.value = Some(value); - } - - /// Returns true if the cell is empty and false if the cell is full. - 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 { - 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 { - let mut v = self.take(); - let r = op(&mut v); - self.put_back(v); - r - } -} - -#[test] -fn test_basic() { - let value_cell = Cell(~10); - assert!(!value_cell.is_empty()); - let value = value_cell.take(); - assert!(value == ~10); - assert!(value_cell.is_empty()); - value_cell.put_back(value); - assert!(!value_cell.is_empty()); -} - -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_take_empty() { - let value_cell = empty_cell::<~int>(); - value_cell.take(); -} - -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_put_back_non_empty() { - let value_cell = Cell(~10); - value_cell.put_back(~20); -} - -#[test] -fn test_with_ref() { - let good = 6; - let c = Cell(~[1, 2, 3, 4, 5, 6]); - let l = do c.with_ref() |v| { v.len() }; - assert_eq!(l, good); -} - -#[test] -fn test_with_mut_ref() { - let good = ~[1, 2, 3]; - let v = ~[1, 2]; - let c = Cell(v); - do c.with_mut_ref() |v| { v.push(3); } - let v = c.take(); - assert_eq!(v, good); -} diff --git a/src/libcore/char.rs b/src/libcore/char.rs deleted file mode 100644 index bd70f59212d..00000000000 --- a/src/libcore/char.rs +++ /dev/null @@ -1,406 +0,0 @@ -// 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. - -//! Utilities for manipulating the char type - -use option::{None, Option, Some}; -use str; -use str::{StrSlice, OwnedStr}; -use u32; -use uint; -use unicode::{derived_property, general_category}; - -#[cfg(not(test))] -use cmp::{Eq, Ord}; - -/* - Lu Uppercase_Letter an uppercase letter - Ll Lowercase_Letter a lowercase letter - Lt Titlecase_Letter a digraphic character, with first part uppercase - Lm Modifier_Letter a modifier letter - Lo Other_Letter other letters, including syllables and ideographs - Mn Nonspacing_Mark a nonspacing combining mark (zero advance width) - Mc Spacing_Mark a spacing combining mark (positive advance width) - Me Enclosing_Mark an enclosing combining mark - Nd Decimal_Number a decimal digit - Nl Letter_Number a letterlike numeric character - No Other_Number a numeric character of other type - Pc Connector_Punctuation a connecting punctuation mark, like a tie - Pd Dash_Punctuation a dash or hyphen punctuation mark - Ps Open_Punctuation an opening punctuation mark (of a pair) - Pe Close_Punctuation a closing punctuation mark (of a pair) - Pi Initial_Punctuation an initial quotation mark - Pf Final_Punctuation a final quotation mark - Po Other_Punctuation a punctuation mark of other type - Sm Math_Symbol a symbol of primarily mathematical use - Sc Currency_Symbol a currency sign - Sk Modifier_Symbol a non-letterlike modifier symbol - So Other_Symbol a symbol of other type - Zs Space_Separator a space character (of various non-zero widths) - Zl Line_Separator U+2028 LINE SEPARATOR only - Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only - Cc Control a C0 or C1 control code - Cf Format a format control character - Cs Surrogate a surrogate code point - Co Private_Use a private-use character - Cn Unassigned a reserved unassigned code point or a noncharacter -*/ - -pub fn is_alphabetic(c: char) -> bool { derived_property::Alphabetic(c) } -pub fn is_XID_start(c: char) -> bool { derived_property::XID_Start(c) } -pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) } - -/// -/// Indicates whether a character is in lower case, defined -/// in terms of the Unicode General Category 'Ll' -/// -#[inline(always)] -pub fn is_lowercase(c: char) -> bool { general_category::Ll(c) } - -/// -/// Indicates whether a character is in upper case, defined -/// in terms of the Unicode General Category 'Lu'. -/// -#[inline(always)] -pub fn is_uppercase(c: char) -> bool { general_category::Lu(c) } - -/// -/// Indicates whether a character is whitespace. Whitespace is defined in -/// terms of the Unicode General Categories 'Zs', 'Zl', 'Zp' -/// additional 'Cc'-category control codes in the range [0x09, 0x0d] -/// -#[inline(always)] -pub fn is_whitespace(c: char) -> bool { - ('\x09' <= c && c <= '\x0d') - || general_category::Zs(c) - || general_category::Zl(c) - || general_category::Zp(c) -} - -/// -/// Indicates whether a character is alphanumeric. Alphanumericness is -/// defined in terms of the Unicode General Categories 'Nd', 'Nl', 'No' -/// and the Derived Core Property 'Alphabetic'. -/// -#[inline(always)] -pub fn is_alphanumeric(c: char) -> bool { - derived_property::Alphabetic(c) - || general_category::Nd(c) - || general_category::Nl(c) - || general_category::No(c) -} - -/// Indicates whether the character is numeric (Nd, Nl, or No) -#[inline(always)] -pub fn is_digit(c: char) -> bool { - general_category::Nd(c) - || general_category::Nl(c) - || general_category::No(c) -} - -/// -/// Checks if a character parses as a numeric digit in the given radix. -/// Compared to `is_digit()`, this function only recognizes the -/// characters `0-9`, `a-z` and `A-Z`. -/// -/// # Return value -/// -/// Returns `true` if `c` is a valid digit under `radix`, and `false` -/// otherwise. -/// -/// # Failure -/// -/// Fails if given a `radix` > 36. -/// -/// # Note -/// -/// This just wraps `to_digit()`. -/// -#[inline(always)] -pub fn is_digit_radix(c: char, radix: uint) -> bool { - match to_digit(c, radix) { - Some(_) => true, - None => false, - } -} - -/// -/// Convert a char to the corresponding digit. -/// -/// # Return value -/// -/// If `c` is between '0' and '9', the corresponding value -/// between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is -/// 'b' or 'B', 11, etc. Returns none if the char does not -/// refer to a digit in the given radix. -/// -/// # Failure -/// -/// Fails if given a `radix` outside the range `[0..36]`. -/// -#[inline] -pub fn to_digit(c: char, radix: uint) -> Option<uint> { - if radix > 36 { - fail!("to_digit: radix %? is to high (maximum 36)", radix); - } - let val = match c { - '0' .. '9' => c as uint - ('0' as uint), - 'a' .. 'z' => c as uint + 10u - ('a' as uint), - 'A' .. 'Z' => c as uint + 10u - ('A' as uint), - _ => return None, - }; - if val < radix { Some(val) } - else { None } -} - -/// -/// Converts a number to the character representing it. -/// -/// # Return value -/// -/// Returns `Some(char)` if `num` represents one digit under `radix`, -/// using one character of `0-9` or `a-z`, or `None` if it doesn't. -/// -/// # Failure -/// -/// Fails if given an `radix` > 36. -/// -#[inline] -pub fn from_digit(num: uint, radix: uint) -> Option<char> { - if radix > 36 { - fail!("from_digit: radix %? is to high (maximum 36)", num); - } - if num < radix { - if num < 10 { - Some(('0' as uint + num) as char) - } else { - Some(('a' as uint + num - 10u) as char) - } - } else { - None - } -} - -/// -/// Return the hexadecimal unicode escape of a char. -/// -/// The rules are as follows: -/// -/// - chars in [0,0xff] get 2-digit escapes: `\\xNN` -/// - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN` -/// - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN` -/// -pub fn escape_unicode(c: char) -> ~str { - let s = u32::to_str_radix(c as u32, 16u); - let (c, pad) = cond!( - (c <= '\xff') { ('x', 2u) } - (c <= '\uffff') { ('u', 4u) } - _ { ('U', 8u) } - ); - assert!(s.len() <= pad); - let mut out = ~"\\"; - out.push_str(str::from_char(c)); - for uint::range(s.len(), pad) |_| { - out.push_str("0"); - } - out.push_str(s); - out -} - -/// -/// Return a 'default' ASCII and C++11-like char-literal escape of a char. -/// -/// The default is chosen with a bias toward producing literals that are -/// legal in a variety of languages, including C++11 and similar C-family -/// languages. The exact rules are: -/// -/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. -/// - Single-quote, double-quote and backslash chars are backslash-escaped. -/// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex unicode escapes; see `escape_unicode`. -/// -pub fn escape_default(c: char) -> ~str { - match c { - '\t' => ~"\\t", - '\r' => ~"\\r", - '\n' => ~"\\n", - '\\' => ~"\\\\", - '\'' => ~"\\'", - '"' => ~"\\\"", - '\x20' .. '\x7e' => str::from_char(c), - _ => c.escape_unicode(), - } -} - -/// Returns the amount of bytes this character would need if encoded in utf8 -pub fn len_utf8_bytes(c: char) -> uint { - static MAX_ONE_B: uint = 128u; - static MAX_TWO_B: uint = 2048u; - static MAX_THREE_B: uint = 65536u; - static MAX_FOUR_B: uint = 2097152u; - - let code = c as uint; - cond!( - (code < MAX_ONE_B) { 1u } - (code < MAX_TWO_B) { 2u } - (code < MAX_THREE_B) { 3u } - (code < MAX_FOUR_B) { 4u } - _ { fail!("invalid character!") } - ) -} - -pub trait Char { - fn is_alphabetic(&self) -> bool; - fn is_XID_start(&self) -> bool; - fn is_XID_continue(&self) -> bool; - fn is_lowercase(&self) -> bool; - fn is_uppercase(&self) -> bool; - fn is_whitespace(&self) -> bool; - fn is_alphanumeric(&self) -> bool; - fn is_digit(&self) -> bool; - fn is_digit_radix(&self, radix: uint) -> bool; - fn to_digit(&self, radix: uint) -> Option<uint>; - fn from_digit(num: uint, radix: uint) -> Option<char>; - fn escape_unicode(&self) -> ~str; - fn escape_default(&self) -> ~str; - fn len_utf8_bytes(&self) -> uint; -} - -impl Char for char { - fn is_alphabetic(&self) -> bool { is_alphabetic(*self) } - - fn is_XID_start(&self) -> bool { is_XID_start(*self) } - - fn is_XID_continue(&self) -> bool { is_XID_continue(*self) } - - fn is_lowercase(&self) -> bool { is_lowercase(*self) } - - fn is_uppercase(&self) -> bool { is_uppercase(*self) } - - fn is_whitespace(&self) -> bool { is_whitespace(*self) } - - fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) } - - fn is_digit(&self) -> bool { is_digit(*self) } - - fn is_digit_radix(&self, radix: uint) -> bool { is_digit_radix(*self, radix) } - - fn to_digit(&self, radix: uint) -> Option<uint> { to_digit(*self, radix) } - - fn from_digit(num: uint, radix: uint) -> Option<char> { from_digit(num, radix) } - - fn escape_unicode(&self) -> ~str { escape_unicode(*self) } - - fn escape_default(&self) -> ~str { escape_default(*self) } - - fn len_utf8_bytes(&self) -> uint { len_utf8_bytes(*self) } -} - -#[cfg(not(test))] -impl Eq for char { - #[inline(always)] - fn eq(&self, other: &char) -> bool { (*self) == (*other) } - #[inline(always)] - fn ne(&self, other: &char) -> bool { (*self) != (*other) } -} - -#[cfg(not(test))] -impl Ord for char { - #[inline(always)] - fn lt(&self, other: &char) -> bool { *self < *other } - #[inline(always)] - fn le(&self, other: &char) -> bool { *self <= *other } - #[inline(always)] - fn gt(&self, other: &char) -> bool { *self > *other } - #[inline(always)] - fn ge(&self, other: &char) -> bool { *self >= *other } -} - -#[test] -fn test_is_lowercase() { - assert!('a'.is_lowercase()); - assert!('ö'.is_lowercase()); - assert!('ß'.is_lowercase()); - assert!(!'Ü'.is_lowercase()); - assert!(!'P'.is_lowercase()); -} - -#[test] -fn test_is_uppercase() { - assert!(!'h'.is_uppercase()); - assert!(!'ä'.is_uppercase()); - assert!(!'ß'.is_uppercase()); - assert!('Ö'.is_uppercase()); - assert!('T'.is_uppercase()); -} - -#[test] -fn test_is_whitespace() { - assert!(' '.is_whitespace()); - assert!('\u2007'.is_whitespace()); - assert!('\t'.is_whitespace()); - assert!('\n'.is_whitespace()); - assert!(!'a'.is_whitespace()); - assert!(!'_'.is_whitespace()); - assert!(!'\u0000'.is_whitespace()); -} - -#[test] -fn test_to_digit() { - assert_eq!('0'.to_digit(10u), Some(0u)); - assert_eq!('1'.to_digit(2u), Some(1u)); - assert_eq!('2'.to_digit(3u), Some(2u)); - assert_eq!('9'.to_digit(10u), Some(9u)); - assert_eq!('a'.to_digit(16u), Some(10u)); - assert_eq!('A'.to_digit(16u), Some(10u)); - assert_eq!('b'.to_digit(16u), Some(11u)); - assert_eq!('B'.to_digit(16u), Some(11u)); - assert_eq!('z'.to_digit(36u), Some(35u)); - assert_eq!('Z'.to_digit(36u), Some(35u)); - assert_eq!(' '.to_digit(10u), None); - assert_eq!('$'.to_digit(36u), None); -} - -#[test] -fn test_is_digit() { - assert!('2'.is_digit()); - assert!('7'.is_digit()); - assert!(!'c'.is_digit()); - assert!(!'i'.is_digit()); - assert!(!'z'.is_digit()); - assert!(!'Q'.is_digit()); -} - -#[test] -fn test_escape_default() { - assert_eq!('\n'.escape_default(), ~"\\n"); - assert_eq!('\r'.escape_default(), ~"\\r"); - assert_eq!('\''.escape_default(), ~"\\'"); - assert_eq!('"'.escape_default(), ~"\\\""); - assert_eq!(' '.escape_default(), ~" "); - assert_eq!('a'.escape_default(), ~"a"); - assert_eq!('~'.escape_default(), ~"~"); - assert_eq!('\x00'.escape_default(), ~"\\x00"); - assert_eq!('\x1f'.escape_default(), ~"\\x1f"); - assert_eq!('\x7f'.escape_default(), ~"\\x7f"); - assert_eq!('\xff'.escape_default(), ~"\\xff"); - assert_eq!('\u011b'.escape_default(), ~"\\u011b"); - assert_eq!('\U0001d4b6'.escape_default(), ~"\\U0001d4b6"); -} - -#[test] -fn test_escape_unicode() { - assert_eq!('\x00'.escape_unicode(), ~"\\x00"); - assert_eq!('\n'.escape_unicode(), ~"\\x0a"); - assert_eq!(' '.escape_unicode(), ~"\\x20"); - assert_eq!('a'.escape_unicode(), ~"\\x61"); - assert_eq!('\u011b'.escape_unicode(), ~"\\u011b"); - assert_eq!('\U0001d4b6'.escape_unicode(), ~"\\U0001d4b6"); -} diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs deleted file mode 100644 index 5796be7b1e4..00000000000 --- a/src/libcore/cleanup.rs +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; - -use libc::{c_char, c_void, intptr_t, uintptr_t}; -use ptr::mut_null; -use repr::BoxRepr; -use sys::TypeDesc; -use cast::transmute; -#[cfg(not(test))] use unstable::lang::clear_task_borrow_list; - -#[cfg(not(test))] use ptr::to_unsafe_ptr; - -/** - * Runtime structures - * - * NB: These must match the representation in the C++ runtime. - */ - -type DropGlue<'self> = &'self fn(**TypeDesc, *c_void); -type FreeGlue<'self> = &'self fn(**TypeDesc, *c_void); - -type TaskID = uintptr_t; - -struct StackSegment { priv opaque: () } -struct Scheduler { priv opaque: () } -struct SchedulerLoop { priv opaque: () } -struct Kernel { priv opaque: () } -struct Env { priv opaque: () } -struct AllocHeader { priv opaque: () } -struct MemoryRegion { priv opaque: () } - -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -struct Registers { - data: [u32, ..16] -} - -#[cfg(target_arch="mips")] -struct Registers { - data: [u32, ..32] -} - -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -#[cfg(target_arch="mips")] -struct Context { - regs: Registers, - next: *Context, - pad: [u32, ..3] -} - -#[cfg(target_arch="x86_64")] -struct Registers { - data: [u64, ..22] -} - -#[cfg(target_arch="x86_64")] -struct Context { - regs: Registers, - next: *Context, - pad: uintptr_t -} - -struct BoxedRegion { - env: *Env, - backing_region: *MemoryRegion, - live_allocs: *BoxRepr -} - -#[cfg(target_arch="x86")] -#[cfg(target_arch="arm")] -#[cfg(target_arch="mips")] -struct Task { - // Public fields - refcount: intptr_t, // 0 - id: TaskID, // 4 - pad: [u32, ..2], // 8 - ctx: Context, // 16 - stack_segment: *StackSegment, // 96 - runtime_sp: uintptr_t, // 100 - scheduler: *Scheduler, // 104 - scheduler_loop: *SchedulerLoop, // 108 - - // Fields known only to the runtime - kernel: *Kernel, // 112 - name: *c_char, // 116 - list_index: i32, // 120 - boxed_region: BoxedRegion // 128 -} - -#[cfg(target_arch="x86_64")] -struct Task { - // Public fields - refcount: intptr_t, - id: TaskID, - ctx: Context, - stack_segment: *StackSegment, - runtime_sp: uintptr_t, - scheduler: *Scheduler, - scheduler_loop: *SchedulerLoop, - - // Fields known only to the runtime - kernel: *Kernel, - name: *c_char, - list_index: i32, - boxed_region: BoxedRegion -} - -/* - * Box annihilation - * - * This runs at task death to free all boxes. - */ - -struct AnnihilateStats { - n_total_boxes: uint, - n_unique_boxes: uint, - n_bytes_freed: uint -} - -unsafe fn each_live_alloc(read_next_before: bool, - f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) -> bool { - //! Walks the internal list of allocations - - use managed; - - let task: *Task = transmute(rustrt::rust_get_task()); - let box = (*task).boxed_region.live_allocs; - let mut box: *mut BoxRepr = transmute(copy box); - while box != mut_null() { - let next_before = transmute(copy (*box).header.next); - let uniq = - (*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE; - - if !f(box, uniq) { - return false; - } - - if read_next_before { - box = next_before; - } else { - box = transmute(copy (*box).header.next); - } - } - return true; -} - -#[cfg(unix)] -fn debug_mem() -> bool { - ::rt::env::get().debug_mem -} - -#[cfg(windows)] -fn debug_mem() -> bool { - false -} - -/// Destroys all managed memory (i.e. @ boxes) held by the current task. -#[cfg(not(test))] -#[lang="annihilate"] -pub unsafe fn annihilate() { - use unstable::lang::local_free; - use io::WriterUtil; - use io; - use libc; - use sys; - use managed; - - let mut stats = AnnihilateStats { - n_total_boxes: 0, - n_unique_boxes: 0, - n_bytes_freed: 0 - }; - - // Quick hack: we need to free this list upon task exit, and this - // is a convenient place to do it. - clear_task_borrow_list(); - - // Pass 1: Make all boxes immortal. - // - // In this pass, nothing gets freed, so it does not matter whether - // we read the next field before or after the callback. - for each_live_alloc(true) |box, uniq| { - stats.n_total_boxes += 1; - if uniq { - stats.n_unique_boxes += 1; - } else { - (*box).header.ref_count = managed::raw::RC_IMMORTAL; - } - } - - // Pass 2: Drop all boxes. - // - // In this pass, unique-managed boxes may get freed, but not - // managed boxes, so we must read the `next` field *after* the - // callback, as the original value may have been freed. - for each_live_alloc(false) |box, uniq| { - if !uniq { - let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc); - let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0)); - drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data)); - } - } - - // Pass 3: Free all boxes. - // - // In this pass, managed boxes may get freed (but not - // unique-managed boxes, though I think that none of those are - // left), so we must read the `next` field before, since it will - // not be valid after. - for each_live_alloc(true) |box, uniq| { - if !uniq { - stats.n_bytes_freed += - (*((*box).header.type_desc)).size - + sys::size_of::<BoxRepr>(); - local_free(transmute(box)); - } - } - - if debug_mem() { - // We do logging here w/o allocation. - let dbg = libc::STDERR_FILENO as io::fd_t; - dbg.write_str("annihilator stats:"); - dbg.write_str("\n total_boxes: "); - dbg.write_uint(stats.n_total_boxes); - dbg.write_str("\n unique_boxes: "); - dbg.write_uint(stats.n_unique_boxes); - dbg.write_str("\n bytes_freed: "); - dbg.write_uint(stats.n_bytes_freed); - dbg.write_str("\n"); - } -} - -/// Bindings to the runtime -pub mod rustrt { - use libc::c_void; - - #[link_name = "rustrt"] - pub extern { - #[rust_stack] - // FIXME (#4386): Unable to make following method private. - pub unsafe fn rust_get_task() -> *c_void; - } -} diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs deleted file mode 100644 index 2965b31a8c3..00000000000 --- a/src/libcore/clone.rs +++ /dev/null @@ -1,184 +0,0 @@ -// 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. - -/*! The Clone trait for types that cannot be "implicitly copied" - -In Rust, some simple types are "implicitly copyable" and when you -assign them or pass them as arguments, the receiver will get a copy, -leaving the original value in place. These types do not require -allocation to copy and do not have finalizers (i.e. they do not -contain owned boxes or implement `Drop`), so the compiler considers -them cheap and safe to copy and automatically implements the `Copy` -trait for them. For other types copies must be made explicitly, -by convention implementing the `Clone` trait and calling the -`clone` method. - -*/ - -use core::kinds::Const; - -pub trait Clone { - /// Returns a copy of the value. The contents of owned pointers - /// are copied to maintain uniqueness, while the contents of - /// managed pointers are not copied. - fn clone(&self) -> Self; -} - -impl<T: Clone> Clone for ~T { - /// Return a deep copy of the owned box. - #[inline(always)] - fn clone(&self) -> ~T { ~(**self).clone() } -} - -impl<T> Clone for @T { - /// Return a shallow copy of the managed box. - #[inline(always)] - fn clone(&self) -> @T { *self } -} - -impl<T> Clone for @mut T { - /// Return a shallow copy of the managed box. - #[inline(always)] - fn clone(&self) -> @mut T { *self } -} - -impl<'self, T> Clone for &'self T { - /// Return a shallow copy of the borrowed pointer. - #[inline(always)] - fn clone(&self) -> &'self T { *self } -} - -macro_rules! clone_impl( - ($t:ty) => { - impl Clone for $t { - /// Return a deep copy of the value. - #[inline(always)] - fn clone(&self) -> $t { *self } - } - } -) - -clone_impl!(int) -clone_impl!(i8) -clone_impl!(i16) -clone_impl!(i32) -clone_impl!(i64) - -clone_impl!(uint) -clone_impl!(u8) -clone_impl!(u16) -clone_impl!(u32) -clone_impl!(u64) - -clone_impl!(float) -clone_impl!(f32) -clone_impl!(f64) - -clone_impl!(()) -clone_impl!(bool) -clone_impl!(char) - -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. - fn deep_clone(&self) -> Self; -} - -impl<T: DeepClone> DeepClone for ~T { - /// Return a deep copy of the owned box. - #[inline(always)] - fn deep_clone(&self) -> ~T { ~(**self).deep_clone() } -} - -// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` -impl<T: Const + DeepClone> DeepClone for @T { - /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing - /// a deep clone of a potentially cyclical type. - #[inline(always)] - fn deep_clone(&self) -> @T { @(**self).deep_clone() } -} - -// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` -impl<T: Const + DeepClone> DeepClone for @mut T { - /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing - /// a deep clone of a potentially cyclical type. - #[inline(always)] - fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() } -} - -macro_rules! deep_clone_impl( - ($t:ty) => { - impl DeepClone for $t { - /// Return a deep copy of the value. - #[inline(always)] - fn deep_clone(&self) -> $t { *self } - } - } -) - -deep_clone_impl!(int) -deep_clone_impl!(i8) -deep_clone_impl!(i16) -deep_clone_impl!(i32) -deep_clone_impl!(i64) - -deep_clone_impl!(uint) -deep_clone_impl!(u8) -deep_clone_impl!(u16) -deep_clone_impl!(u32) -deep_clone_impl!(u64) - -deep_clone_impl!(float) -deep_clone_impl!(f32) -deep_clone_impl!(f64) - -deep_clone_impl!(()) -deep_clone_impl!(bool) -deep_clone_impl!(char) - -#[test] -fn test_owned_clone() { - let a = ~5i; - let b: ~int = a.clone(); - assert_eq!(a, b); -} - -#[test] -fn test_managed_clone() { - let a = @5i; - let b: @int = a.clone(); - assert_eq!(a, b); -} - -#[test] -fn test_managed_mut_deep_clone() { - let x = @mut 5i; - let y: @mut int = x.deep_clone(); - *x = 20; - assert_eq!(*y, 5); -} - -#[test] -fn test_managed_mut_clone() { - let a = @mut 5i; - let b: @mut int = a.clone(); - assert_eq!(a, b); - *b = 10; - assert_eq!(a, b); -} - -#[test] -fn test_borrowed_clone() { - let x = 5i; - let y: &int = &x; - let z: &int = (&y).clone(); - assert_eq!(*z, 5); -} diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs deleted file mode 100644 index ca9c49b2c06..00000000000 --- a/src/libcore/cmp.rs +++ /dev/null @@ -1,265 +0,0 @@ -// 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. - -/*! - -The `Ord` and `Eq` comparison traits - -This module contains the definition of both `Ord` and `Eq` which define -the common interfaces for doing comparison. Both are language items -that the compiler uses to implement the comparison operators. Rust code -may implement `Ord` to overload the `<`, `<=`, `>`, and `>=` operators, -and `Eq` to overload the `==` and `!=` operators. - -*/ - -/** -* Trait for values that can be compared for equality and inequality. -* -* This trait allows partial equality, where types can be unordered instead of strictly equal or -* unequal. For example, with the built-in floating-point types `a == b` and `a != b` will both -* evaluate to false if either `a` or `b` is NaN (cf. IEEE 754-2008 section 5.11). -* -* Eventually, this will be implemented by default for types that implement `TotalEq`. -*/ -#[lang="eq"] -pub trait Eq { - fn eq(&self, other: &Self) -> bool; - fn ne(&self, other: &Self) -> bool; -} - -/// Trait for equality comparisons where `a == b` and `a != b` are strict inverses. -pub trait TotalEq { - fn equals(&self, other: &Self) -> bool; -} - -macro_rules! totaleq_impl( - ($t:ty) => { - impl TotalEq for $t { - #[inline(always)] - fn equals(&self, other: &$t) -> bool { *self == *other } - } - } -) - -totaleq_impl!(bool) - -totaleq_impl!(u8) -totaleq_impl!(u16) -totaleq_impl!(u32) -totaleq_impl!(u64) - -totaleq_impl!(i8) -totaleq_impl!(i16) -totaleq_impl!(i32) -totaleq_impl!(i64) - -totaleq_impl!(int) -totaleq_impl!(uint) - -totaleq_impl!(char) - -/// Trait for testing approximate equality -pub trait ApproxEq<Eps> { - fn approx_epsilon() -> Eps; - fn approx_eq(&self, other: &Self) -> bool; - fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool; -} - -#[deriving(Clone, Eq)] -pub enum Ordering { Less = -1, Equal = 0, Greater = 1 } - -/// Trait for types that form a total order -pub trait TotalOrd: TotalEq { - fn cmp(&self, other: &Self) -> Ordering; -} - -impl TotalOrd for Ordering { - #[inline(always)] - fn cmp(&self, other: &Ordering) -> Ordering { - (*self as int).cmp(&(*other as int)) - } -} - -impl Ord for Ordering { - #[inline(always)] - fn lt(&self, other: &Ordering) -> bool { (*self as int) < (*other as int) } - #[inline(always)] - fn le(&self, other: &Ordering) -> bool { (*self as int) <= (*other as int) } - #[inline(always)] - fn gt(&self, other: &Ordering) -> bool { (*self as int) > (*other as int) } - #[inline(always)] - fn ge(&self, other: &Ordering) -> bool { (*self as int) >= (*other as int) } -} - -macro_rules! totalord_impl( - ($t:ty) => { - impl TotalOrd for $t { - #[inline(always)] - fn cmp(&self, other: &$t) -> Ordering { - if *self < *other { Less } - else if *self > *other { Greater } - else { Equal } - } - } - } -) - -totalord_impl!(u8) -totalord_impl!(u16) -totalord_impl!(u32) -totalord_impl!(u64) - -totalord_impl!(i8) -totalord_impl!(i16) -totalord_impl!(i32) -totalord_impl!(i64) - -totalord_impl!(int) -totalord_impl!(uint) - -totalord_impl!(char) - -/// Compares (a1, b1) against (a2, b2), where the a values are more significant. -pub fn cmp2<A:TotalOrd,B:TotalOrd>( - a1: &A, b1: &B, - a2: &A, b2: &B) -> Ordering -{ - match a1.cmp(a2) { - Less => Less, - Greater => Greater, - Equal => b1.cmp(b2) - } -} - -/** -Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the -lexical ordering on a type `(int, int)`. -*/ -// used in deriving code in libsyntax -#[inline(always)] -pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering { - match o1 { - Equal => o2, - _ => o1 - } -} - -/** -* Trait for values that can be compared for a sort-order. -* -* Eventually this may be simplified to only require -* an `le` method, with the others generated from -* default implementations. However it should remain -* possible to implement the others separately, for -* compatibility with floating-point NaN semantics -* (cf. IEEE 754-2008 section 5.11). -*/ -#[lang="ord"] -pub trait Ord { - fn lt(&self, other: &Self) -> bool; - fn le(&self, other: &Self) -> bool; - fn ge(&self, other: &Self) -> bool; - 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` -/// values to look up entries in a container with `~str` keys. -pub trait Equiv<T> { - fn equiv(&self, other: &T) -> bool; -} - -#[inline(always)] -pub fn min<T:Ord>(v1: T, v2: T) -> T { - if v1 < v2 { v1 } else { v2 } -} - -#[inline(always)] -pub fn max<T:Ord>(v1: T, v2: T) -> T { - if v1 > v2 { v1 } else { v2 } -} - -#[cfg(test)] -mod test { - use super::lexical_ordering; - - #[test] - fn test_int_totalord() { - assert_eq!(5.cmp(&10), Less); - assert_eq!(10.cmp(&5), Greater); - assert_eq!(5.cmp(&5), Equal); - assert_eq!((-5).cmp(&12), Less); - assert_eq!(12.cmp(-5), Greater); - } - - #[test] - fn test_cmp2() { - assert_eq!(cmp2(1, 2, 3, 4), Less); - assert_eq!(cmp2(3, 2, 3, 4), Less); - assert_eq!(cmp2(5, 2, 3, 4), Greater); - assert_eq!(cmp2(5, 5, 5, 4), Greater); - } - - #[test] - fn test_int_totaleq() { - assert!(5.equals(&5)); - assert!(!2.equals(&17)); - } - - #[test] - fn test_ordering_order() { - assert!(Less < Equal); - assert_eq!(Greater.cmp(&Less), Greater); - } - - #[test] - fn test_lexical_ordering() { - fn t(o1: Ordering, o2: Ordering, e: Ordering) { - assert_eq!(lexical_ordering(o1, o2), e); - } - for [Less, Equal, Greater].each |&o| { - t(Less, o, Less); - t(Equal, o, o); - t(Greater, o, Greater); - } - } -} diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs deleted file mode 100644 index 59eb915c239..00000000000 --- a/src/libcore/comm.rs +++ /dev/null @@ -1,810 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -Message passing -*/ - -use cast::{transmute, transmute_mut}; -use container::Container; -use either::{Either, Left, Right}; -use kinds::Owned; -use option::{Option, Some, None}; -use uint; -use vec; -use vec::OwnedVector; -use util::replace; -use unstable::sync::{Exclusive, exclusive}; -use rtcomm = rt::comm; -use rt; - -use pipes::{wait_many, PacketHeader}; - -// FIXME #5160: Making this public exposes some plumbing from -// pipes. Needs some refactoring -pub use pipes::Selectable; - -/// A trait for things that can send multiple messages. -pub trait GenericChan<T> { - /// Sends a message. - fn send(&self, x: T); -} - -/// Things that can send multiple messages and can detect when the receiver -/// is closed -pub trait GenericSmartChan<T> { - /// Sends a message, or report if the receiver has closed the connection. - fn try_send(&self, x: T) -> bool; -} - -/// A trait for things that can receive multiple messages. -pub trait GenericPort<T> { - /// Receives a message, or fails if the connection closes. - fn recv(&self) -> T; - - /** Receives a message, or returns `none` if - the connection is closed or closes. - */ - fn try_recv(&self) -> Option<T>; -} - -/// Ports that can `peek` -pub trait Peekable<T> { - /// Returns true if a message is available - fn peek(&self) -> bool; -} - -/// An endpoint that can send many messages. -pub struct Chan<T> { - inner: Either<pipesy::Chan<T>, rtcomm::Chan<T>> -} - -/// An endpoint that can receive many messages. -pub struct Port<T> { - inner: Either<pipesy::Port<T>, rtcomm::Port<T>> -} - -/** Creates a `(Port, Chan)` pair. - -These allow sending or receiving an unlimited number of messages. - -*/ -pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { - let (port, chan) = match rt::context() { - rt::OldTaskContext => match pipesy::stream() { - (p, c) => (Left(p), Left(c)) - }, - _ => match rtcomm::stream() { - (p, c) => (Right(p), Right(c)) - } - }; - let port = Port { inner: port }; - let chan = Chan { inner: chan }; - return (port, chan); -} - -impl<T: Owned> GenericChan<T> for Chan<T> { - fn send(&self, x: T) { - match self.inner { - Left(ref chan) => chan.send(x), - Right(ref chan) => chan.send(x) - } - } -} - -impl<T: Owned> GenericSmartChan<T> for Chan<T> { - fn try_send(&self, x: T) -> bool { - match self.inner { - Left(ref chan) => chan.try_send(x), - Right(ref chan) => chan.try_send(x) - } - } -} - -impl<T: Owned> GenericPort<T> for Port<T> { - fn recv(&self) -> T { - match self.inner { - Left(ref port) => port.recv(), - Right(ref port) => port.recv() - } - } - - fn try_recv(&self) -> Option<T> { - match self.inner { - Left(ref port) => port.try_recv(), - Right(ref port) => port.try_recv() - } - } -} - -impl<T: Owned> Peekable<T> for Port<T> { - fn peek(&self) -> bool { - match self.inner { - Left(ref port) => port.peek(), - Right(ref port) => port.peek() - } - } -} - -impl<T: Owned> Selectable for Port<T> { - fn header(&mut self) -> *mut PacketHeader { - match self.inner { - Left(ref mut port) => port.header(), - Right(_) => fail!("can't select on newsched ports") - } - } -} - -/// Treat many ports as one. -#[unsafe_mut_field(ports)] -pub struct PortSet<T> { - ports: ~[pipesy::Port<T>], -} - -pub impl<T: Owned> PortSet<T> { - fn new() -> PortSet<T> { - PortSet { - ports: ~[] - } - } - - fn add(&self, port: Port<T>) { - let Port { inner } = port; - let port = match inner { - Left(p) => p, - Right(_) => fail!("PortSet not implemented") - }; - unsafe { - let self_ports = transmute_mut(&self.ports); - self_ports.push(port) - } - } - - fn chan(&self) -> Chan<T> { - let (po, ch) = stream(); - self.add(po); - ch - } -} - -impl<T:Owned> GenericPort<T> for PortSet<T> { - fn try_recv(&self) -> Option<T> { - unsafe { - let self_ports = transmute_mut(&self.ports); - let mut result = None; - // we have to swap the ports array so we aren't borrowing - // aliasable mutable memory. - let mut ports = replace(self_ports, ~[]); - while result.is_none() && ports.len() > 0 { - let i = wait_many(ports); - match ports[i].try_recv() { - Some(m) => { - result = Some(m); - } - None => { - // Remove this port. - let _ = ports.swap_remove(i); - } - } - } - *self_ports = ports; - result - } - } - fn recv(&self) -> T { - self.try_recv().expect("port_set: endpoints closed") - } -} - -impl<T: Owned> Peekable<T> for PortSet<T> { - fn peek(&self) -> bool { - // It'd be nice to use self.port.each, but that version isn't - // pure. - for uint::range(0, vec::uniq_len(&const self.ports)) |i| { - let port: &pipesy::Port<T> = &self.ports[i]; - if port.peek() { - return true; - } - } - false - } -} - -/// A channel that can be shared between many senders. -pub struct SharedChan<T> { - ch: Exclusive<pipesy::Chan<T>> -} - -impl<T: Owned> SharedChan<T> { - /// Converts a `chan` into a `shared_chan`. - pub fn new(c: Chan<T>) -> SharedChan<T> { - let Chan { inner } = c; - let c = match inner { - Left(c) => c, - Right(_) => fail!("SharedChan not implemented") - }; - SharedChan { ch: exclusive(c) } - } -} - -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()) - } - } -} - -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()) - } - } -} - -impl<T: Owned> ::clone::Clone for SharedChan<T> { - fn clone(&self) -> SharedChan<T> { - SharedChan { ch: self.ch.clone() } - } -} - -pub struct PortOne<T> { - inner: Either<pipesy::PortOne<T>, rtcomm::PortOne<T>> -} - -pub struct ChanOne<T> { - inner: Either<pipesy::ChanOne<T>, rtcomm::ChanOne<T>> -} - -pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { - let (port, chan) = match rt::context() { - rt::OldTaskContext => match pipesy::oneshot() { - (p, c) => (Left(p), Left(c)), - }, - _ => match rtcomm::oneshot() { - (p, c) => (Right(p), Right(c)) - } - }; - let port = PortOne { inner: port }; - let chan = ChanOne { inner: chan }; - return (port, chan); -} - -impl<T: Owned> PortOne<T> { - pub fn recv(self) -> T { - let PortOne { inner } = self; - match inner { - Left(p) => p.recv(), - Right(p) => p.recv() - } - } - - pub fn try_recv(self) -> Option<T> { - let PortOne { inner } = self; - match inner { - Left(p) => p.try_recv(), - Right(p) => p.try_recv() - } - } -} - -impl<T: Owned> ChanOne<T> { - pub fn send(self, data: T) { - let ChanOne { inner } = self; - match inner { - Left(p) => p.send(data), - Right(p) => p.send(data) - } - } - - pub fn try_send(self, data: T) -> bool { - let ChanOne { inner } = self; - match inner { - Left(p) => p.try_send(data), - Right(p) => p.try_send(data) - } - } -} - -pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { - let PortOne { inner } = port; - match inner { - Left(p) => pipesy::recv_one(p), - Right(p) => p.recv() - } -} - -pub fn try_recv_one<T: Owned>(port: PortOne<T>) -> Option<T> { - let PortOne { inner } = port; - match inner { - Left(p) => pipesy::try_recv_one(p), - Right(p) => p.try_recv() - } -} - -pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { - let ChanOne { inner } = chan; - match inner { - Left(c) => pipesy::send_one(c, data), - Right(c) => c.send(data) - } -} - -pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { - let ChanOne { inner } = chan; - match inner { - Left(c) => pipesy::try_send_one(c, data), - Right(c) => c.try_send(data) - } -} - -mod pipesy { - - use kinds::Owned; - use option::{Option, Some, None}; - use pipes::{recv, try_recv, peek, PacketHeader}; - use super::{GenericChan, GenericSmartChan, GenericPort, Peekable, Selectable}; - use cast::transmute_mut; - use util::replace; - - /*proto! oneshot ( - Oneshot:send<T:Owned> { - send(T) -> ! - } - )*/ - - #[allow(non_camel_case_types)] - pub mod oneshot { - priv use core::kinds::Owned; - use ptr::to_mut_unsafe_ptr; - - pub fn init<T: Owned>() -> (client::Oneshot<T>, server::Oneshot<T>) { - pub use core::pipes::HasBuffer; - - let buffer = ~::core::pipes::Buffer { - header: ::core::pipes::BufferHeader(), - data: __Buffer { - Oneshot: ::core::pipes::mk_packet::<Oneshot<T>>() - }, - }; - do ::core::pipes::entangle_buffer(buffer) |buffer, data| { - data.Oneshot.set_buffer(buffer); - to_mut_unsafe_ptr(&mut data.Oneshot) - } - } - #[allow(non_camel_case_types)] - pub enum Oneshot<T> { pub send(T), } - #[allow(non_camel_case_types)] - pub struct __Buffer<T> { - Oneshot: ::core::pipes::Packet<Oneshot<T>>, - } - - #[allow(non_camel_case_types)] - pub mod client { - - priv use core::kinds::Owned; - - #[allow(non_camel_case_types)] - pub fn try_send<T: Owned>(pipe: Oneshot<T>, x_0: T) -> - ::core::option::Option<()> { - { - use super::send; - let message = send(x_0); - if ::core::pipes::send(pipe, message) { - ::core::pipes::rt::make_some(()) - } else { ::core::pipes::rt::make_none() } - } - } - - #[allow(non_camel_case_types)] - pub fn send<T: Owned>(pipe: Oneshot<T>, x_0: T) { - { - use super::send; - let message = send(x_0); - ::core::pipes::send(pipe, message); - } - } - - #[allow(non_camel_case_types)] - pub type Oneshot<T> = - ::core::pipes::SendPacketBuffered<super::Oneshot<T>, - super::__Buffer<T>>; - } - - #[allow(non_camel_case_types)] - pub mod server { - #[allow(non_camel_case_types)] - pub type Oneshot<T> = - ::core::pipes::RecvPacketBuffered<super::Oneshot<T>, - super::__Buffer<T>>; - } - } - - /// The send end of a oneshot pipe. - pub struct ChanOne<T> { - contents: oneshot::client::Oneshot<T> - } - - impl<T> ChanOne<T> { - pub fn new(contents: oneshot::client::Oneshot<T>) -> ChanOne<T> { - ChanOne { - contents: contents - } - } - } - - /// The receive end of a oneshot pipe. - pub struct PortOne<T> { - contents: oneshot::server::Oneshot<T> - } - - impl<T> PortOne<T> { - pub fn new(contents: oneshot::server::Oneshot<T>) -> PortOne<T> { - PortOne { - contents: contents - } - } - } - - /// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair. - pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) { - let (chan, port) = 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> { - 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> { - match self { - ChanOne { contents: s } => s - } - } - } - - /** - * Receive a message from a oneshot pipe, failing if the connection was - * closed. - */ - pub fn recv_one<T: Owned>(port: PortOne<T>) -> T { - match port { - PortOne { contents: port } => { - let oneshot::send(message) = recv(port); - message - } - } - } - - /// Receive a message from a oneshot pipe unless the connection was closed. - pub fn try_recv_one<T: Owned> (port: PortOne<T>) -> Option<T> { - match port { - PortOne { contents: port } => { - let message = try_recv(port); - - if message.is_none() { - None - } else { - let oneshot::send(message) = message.unwrap(); - Some(message) - } - } - } - } - - /// Send a message on a oneshot pipe, failing if the connection was closed. - pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) { - match chan { - ChanOne { contents: chan } => oneshot::client::send(chan, data), - } - } - - /** - * Send a message on a oneshot pipe, or return false if the connection was - * closed. - */ - pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool { - match chan { - ChanOne { contents: chan } => { - oneshot::client::try_send(chan, data).is_some() - } - } - } - - // Streams - Make pipes a little easier in general. - - /*proto! streamp ( - Open:send<T: Owned> { - data(T) -> Open<T> - } - )*/ - - #[allow(non_camel_case_types)] - pub mod streamp { - priv use core::kinds::Owned; - - pub fn init<T: Owned>() -> (client::Open<T>, server::Open<T>) { - pub use core::pipes::HasBuffer; - ::core::pipes::entangle() - } - - #[allow(non_camel_case_types)] - pub enum Open<T> { pub data(T, server::Open<T>), } - - #[allow(non_camel_case_types)] - pub mod client { - priv use core::kinds::Owned; - - #[allow(non_camel_case_types)] - pub fn try_data<T: Owned>(pipe: Open<T>, x_0: T) -> - ::core::option::Option<Open<T>> { - { - use super::data; - let (c, s) = ::core::pipes::entangle(); - let message = data(x_0, s); - if ::core::pipes::send(pipe, message) { - ::core::pipes::rt::make_some(c) - } else { ::core::pipes::rt::make_none() } - } - } - - #[allow(non_camel_case_types)] - pub fn data<T: Owned>(pipe: Open<T>, x_0: T) -> Open<T> { - { - use super::data; - let (c, s) = ::core::pipes::entangle(); - let message = data(x_0, s); - ::core::pipes::send(pipe, message); - c - } - } - - #[allow(non_camel_case_types)] - pub type Open<T> = ::core::pipes::SendPacket<super::Open<T>>; - } - - #[allow(non_camel_case_types)] - pub mod server { - #[allow(non_camel_case_types)] - pub type Open<T> = ::core::pipes::RecvPacket<super::Open<T>>; - } - } - - /// An endpoint that can send many messages. - #[unsafe_mut_field(endp)] - pub struct Chan<T> { - endp: Option<streamp::client::Open<T>> - } - - /// An endpoint that can receive many messages. - #[unsafe_mut_field(endp)] - pub struct Port<T> { - endp: Option<streamp::server::Open<T>>, - } - - /** Creates a `(Port, Chan)` pair. - - These allow sending or receiving an unlimited number of messages. - - */ - pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { - let (c, s) = streamp::init(); - - (Port { - endp: Some(s) - }, Chan { - endp: Some(c) - }) - } - - impl<T: Owned> GenericChan<T> for Chan<T> { - #[inline(always)] - fn send(&self, x: T) { - unsafe { - let self_endp = transmute_mut(&self.endp); - let endp = replace(self_endp, None); - *self_endp = Some(streamp::client::data(endp.unwrap(), x)) - } - } - } - - impl<T: Owned> GenericSmartChan<T> for Chan<T> { - #[inline(always)] - fn try_send(&self, x: T) -> bool { - unsafe { - let self_endp = transmute_mut(&self.endp); - let endp = replace(self_endp, None); - match streamp::client::try_data(endp.unwrap(), x) { - Some(next) => { - *self_endp = Some(next); - true - } - None => false - } - } - } - } - - impl<T: Owned> GenericPort<T> for Port<T> { - #[inline(always)] - fn recv(&self) -> T { - unsafe { - let self_endp = transmute_mut(&self.endp); - let endp = replace(self_endp, None); - let streamp::data(x, endp) = recv(endp.unwrap()); - *self_endp = Some(endp); - x - } - } - - #[inline(always)] - fn try_recv(&self) -> Option<T> { - unsafe { - let self_endp = transmute_mut(&self.endp); - let endp = replace(self_endp, None); - match try_recv(endp.unwrap()) { - Some(streamp::data(x, endp)) => { - *self_endp = Some(endp); - Some(x) - } - None => None - } - } - } - } - - impl<T: Owned> Peekable<T> for Port<T> { - #[inline(always)] - fn peek(&self) -> bool { - unsafe { - let self_endp = transmute_mut(&self.endp); - let mut endp = replace(self_endp, None); - let peek = match endp { - Some(ref mut endp) => peek(endp), - None => fail!("peeking empty stream") - }; - *self_endp = endp; - peek - } - } - } - - impl<T: Owned> Selectable for Port<T> { - fn header(&mut self) -> *mut PacketHeader { - match self.endp { - Some(ref mut endp) => endp.header(), - None => fail!("peeking empty stream") - } - } -} - -} - -/// Returns the index of an endpoint that is ready to receive. -pub fn selecti<T: Selectable>(endpoints: &mut [T]) -> uint { - wait_many(endpoints) -} - -/// Returns 0 or 1 depending on which endpoint is ready to receive -pub fn select2i<A:Selectable, B:Selectable>(a: &mut A, b: &mut B) - -> Either<(), ()> { - let mut endpoints = [ a.header(), b.header() ]; - match wait_many(endpoints) { - 0 => Left(()), - 1 => Right(()), - _ => fail!("wait returned unexpected index"), - } -} - -/// Receive a message from one of two endpoints. -pub trait Select2<T: Owned, U: Owned> { - /// Receive a message or return `None` if a connection closes. - fn try_select(&mut self) -> Either<Option<T>, Option<U>>; - /// Receive a message or fail if a connection closes. - fn select(&mut self) -> Either<T, U>; -} - -impl<T:Owned, - U:Owned, - Left:Selectable + GenericPort<T>, - Right:Selectable + GenericPort<U>> - Select2<T, U> - for (Left, Right) { - fn select(&mut self) -> Either<T, U> { - // XXX: Bad borrow check workaround. - unsafe { - let this: &(Left, Right) = transmute(self); - match *this { - (ref lp, ref rp) => { - let lp: &mut Left = transmute(lp); - let rp: &mut Right = transmute(rp); - match select2i(lp, rp) { - Left(()) => Left(lp.recv()), - Right(()) => Right(rp.recv()), - } - } - } - } - } - - fn try_select(&mut self) -> Either<Option<T>, Option<U>> { - // XXX: Bad borrow check workaround. - unsafe { - let this: &(Left, Right) = transmute(self); - match *this { - (ref lp, ref rp) => { - let lp: &mut Left = transmute(lp); - let rp: &mut Right = transmute(rp); - match select2i(lp, rp) { - Left(()) => Left (lp.try_recv()), - Right(()) => Right(rp.try_recv()), - } - } - } - } - } -} - -#[cfg(test)] -mod test { - use either::Right; - use super::{Chan, Port, oneshot, stream}; - - #[test] - fn test_select2() { - let (p1, c1) = stream(); - let (p2, c2) = stream(); - - c1.send(~"abc"); - - let mut tuple = (p1, p2); - match tuple.select() { - Right(_) => fail!(), - _ => (), - } - - c2.send(123); - } - - #[test] - fn test_oneshot() { - let (p, c) = oneshot(); - - c.send(()); - - p.recv() - } - - #[test] - fn test_peek_terminated() { - let (port, chan): (Port<int>, Chan<int>) = stream(); - - { - // Destroy the channel - let _chan = chan; - } - - assert!(!port.peek()); - } -} diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs deleted file mode 100644 index baa6722b193..00000000000 --- a/src/libcore/condition.rs +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Condition handling */ - -use prelude::*; -use local_data::{local_data_pop, local_data_set}; - -// helper for transmutation, shown below. -type RustClosure = (int, int); - -pub struct Handler<T, U> { - handle: RustClosure, - prev: Option<@Handler<T, U>>, -} - -pub struct Condition<'self, T, U> { - name: &'static str, - 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> { - unsafe { - let p : *RustClosure = ::cast::transmute(&h); - let prev = local_data::local_data_get(self.key); - let h = @Handler { handle: *p, prev: prev }; - Trap { cond: self, handler: h } - } - } - - 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 { - unsafe { - match local_data_pop(self.key) { - None => { - debug!("Condition.raise: found no handler"); - default() - } - Some(handler) => { - debug!("Condition.raise: found handler"); - match handler.prev { - None => {} - Some(hp) => local_data_set(self.key, hp) - } - let handle : &fn(T) -> U = - ::cast::transmute(handler.handle); - let u = handle(t); - local_data_set(self.key, handler); - u - } - } - } - } -} - -struct Trap<'self, T, U> { - cond: &'self Condition<'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 { - unsafe { - let _g = Guard { cond: self.cond }; - debug!("Trap: pushing handler to TLS"); - local_data_set(self.cond.key, self.handler); - inner() - } - } -} - -struct Guard<'self, T, U> { - cond: &'self Condition<'self, T, U> -} - -#[unsafe_destructor] -impl<'self, T, U> Drop for Guard<'self, T, U> { - fn finalize(&self) { - unsafe { - debug!("Guard: popping handler from TLS"); - let curr = local_data_pop(self.cond.key); - match curr { - None => {} - Some(h) => match h.prev { - None => {} - Some(hp) => local_data_set(self.cond.key, hp) - } - } - } - } -} - -#[cfg(test)] -mod test { - condition! { - sadness: int -> int; - } - - fn trouble(i: int) { - debug!("trouble: raising condition"); - let j = sadness::cond.raise(i); - debug!("trouble: handler recovered with %d", j); - } - - fn nested_trap_test_inner() { - let mut inner_trapped = false; - - do sadness::cond.trap(|_j| { - debug!("nested_trap_test_inner: in handler"); - inner_trapped = true; - 0 - }).in { - debug!("nested_trap_test_inner: in protected block"); - trouble(1); - } - - assert!(inner_trapped); - } - - #[test] - fn nested_trap_test_outer() { - let mut outer_trapped = false; - - do sadness::cond.trap(|_j| { - debug!("nested_trap_test_outer: in handler"); - outer_trapped = true; 0 - }).in { - debug!("nested_guard_test_outer: in protected block"); - nested_trap_test_inner(); - trouble(1); - } - - assert!(outer_trapped); - } - - fn nested_reraise_trap_test_inner() { - let mut inner_trapped = false; - - do sadness::cond.trap(|_j| { - debug!("nested_reraise_trap_test_inner: in handler"); - inner_trapped = true; - let i = 10; - debug!("nested_reraise_trap_test_inner: handler re-raising"); - sadness::cond.raise(i) - }).in { - debug!("nested_reraise_trap_test_inner: in protected block"); - trouble(1); - } - - assert!(inner_trapped); - } - - #[test] - fn nested_reraise_trap_test_outer() { - let mut outer_trapped = false; - - do sadness::cond.trap(|_j| { - debug!("nested_reraise_trap_test_outer: in handler"); - outer_trapped = true; 0 - }).in { - debug!("nested_reraise_trap_test_outer: in protected block"); - nested_reraise_trap_test_inner(); - } - - assert!(outer_trapped); - } - - #[test] - fn test_default() { - let mut trapped = false; - - do sadness::cond.trap(|j| { - debug!("test_default: in handler"); - sadness::cond.raise_default(j, || { trapped=true; 5 }) - }).in { - debug!("test_default: in protected block"); - trouble(1); - } - - assert!(trapped); - } - - // Issue #6009 - mod m { - condition! { - sadness: int -> int; - } - - mod n { - use super::sadness; - - #[test] - fn test_conditions_are_public() { - let mut trapped = false; - do sadness::cond.trap(|_| { - trapped = true; - 0 - }).in { - sadness::cond.raise(0); - } - assert!(trapped); - } - } - } -} diff --git a/src/libcore/container.rs b/src/libcore/container.rs deleted file mode 100644 index 505aa5881c5..00000000000 --- a/src/libcore/container.rs +++ /dev/null @@ -1,101 +0,0 @@ -// 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. - -//! Container traits - -use option::Option; - -pub trait Container { - /// Return the number of elements in the container - fn len(&const self) -> uint; - - /// Return true if the container contains no elements - fn is_empty(&const self) -> bool; -} - -pub trait Mutable: Container { - /// Clear the container, removing all values. - fn clear(&mut self); -} - -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 - fn each<'a>(&'a self, f: &fn(&K, &'a V) -> bool) -> bool; - - /// Visit all keys - fn each_key(&self, f: &fn(&K) -> bool) -> bool; - - /// Visit all values - fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool; - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool; - - /// Return a reference to the value corresponding to the key - fn find<'a>(&'a self, key: &K) -> Option<&'a V>; - - /// Return a mutable reference to the value corresponding to the key - fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V>; - - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - fn insert(&mut self, key: K, value: V) -> bool; - - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - fn remove(&mut self, key: &K) -> bool; - - /// Insert a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, k: K, v: V) -> Option<V>; - - /// Removes a key from the map, returning the value at the key if the key - /// was previously in the map. - fn pop(&mut self, k: &K) -> Option<V>; -} - -pub trait Set<T>: Mutable { - /// Return true if the set contains a value - fn contains(&self, value: &T) -> bool; - - /// Add a value to the set. Return true if the value was not already - /// present in the set. - fn insert(&mut self, value: T) -> bool; - - /// Remove a value from the set. Return true if the value was - /// present in the set. - fn remove(&mut self, value: &T) -> bool; - - /// Return true if the set has no elements in common with `other`. - /// This is equivalent to checking for an empty intersection. - fn is_disjoint(&self, other: &Self) -> bool; - - /// Return true if the set is a subset of another - fn is_subset(&self, other: &Self) -> bool; - - /// Return true if the set is a superset of another - fn is_superset(&self, other: &Self) -> bool; - - /// Visit the values representing the difference - fn difference(&self, other: &Self, f: &fn(&T) -> bool) -> bool; - - /// Visit the values representing the symmetric difference - fn symmetric_difference(&self, other: &Self, f: &fn(&T) -> bool) -> bool; - - /// Visit the values representing the intersection - fn intersection(&self, other: &Self, f: &fn(&T) -> bool) -> bool; - - /// Visit the values representing the union - fn union(&self, other: &Self, f: &fn(&T) -> bool) -> bool; -} diff --git a/src/libcore/core.rc b/src/libcore/core.rc deleted file mode 100644 index 60093ff96bb..00000000000 --- a/src/libcore/core.rc +++ /dev/null @@ -1,226 +0,0 @@ -// 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. - -/*! - -# The Rust core library - -The Rust core 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 -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 -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 - -`core` is imported at the topmost level of every crate by default, as -if the first line of each crate was - - extern mod core; - -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`, -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 -imported into every *module* by default. Implicitly, all modules behave as if -they contained the following prologue: - - use core::prelude::*; - -*/ - - -#[link(name = "core", - vers = "0.7-pre", - uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8", - url = "https://github.com/mozilla/rust/tree/master/src/libcore")]; - -#[comment = "The Rust core library"]; -#[license = "MIT/ASL2"]; -#[crate_type = "lib"]; - - -// Don't link to core. We are core. -#[no_core]; - -#[deny(non_camel_case_types)]; - -// Make core testable by not duplicating lang items. See #2912 -#[cfg(test)] extern mod realcore(name = "core"); -#[cfg(test)] pub use kinds = realcore::kinds; -#[cfg(test)] pub use ops = realcore::ops; -#[cfg(test)] pub use cmp = realcore::cmp; - -// On Linux, link to the runtime with -lrt. -#[cfg(target_os = "linux")] -#[doc(hidden)] -pub mod linkhack { - #[link_args="-lrustrt -lrt"] - #[link_args = "-lpthread"] - extern { - } -} - -// Internal macros -mod macros; - -/* The Prelude. */ - -pub mod prelude; - -/* Primitive types */ - -#[path = "num/int-template.rs"] #[merge = "num/int-template/int.rs"] -pub mod int; -#[path = "num/int-template.rs"] #[merge = "num/int-template/i8.rs"] -pub mod i8; -#[path = "num/int-template.rs"] #[merge = "num/int-template/i16.rs"] -pub mod i16; -#[path = "num/int-template.rs"] #[merge = "num/int-template/i32.rs"] -pub mod i32; -#[path = "num/int-template.rs"] #[merge = "num/int-template/i64.rs"] -pub mod i64; -#[path = "num/uint-template.rs"] #[merge = "num/uint-template/uint.rs"] -pub mod uint; - -#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u8.rs"] -pub mod u8; -#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u16.rs"] -pub mod u16; -#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u32.rs"] -pub mod u32; -#[path = "num/uint-template.rs"] #[merge = "num/uint-template/u64.rs"] -pub mod u64; - -#[path = "num/float.rs"] -pub mod float; -#[path = "num/f32.rs"] -pub mod f32; -#[path = "num/f64.rs"] -pub mod f64; - -pub mod nil; -pub mod bool; -pub mod char; -pub mod tuple; - -pub mod vec; -pub mod at_vec; -pub mod str; - -#[path = "str/ascii.rs"] -pub mod ascii; - -pub mod ptr; -pub mod owned; -pub mod managed; - - -/* Core language traits */ - -#[cfg(not(test))] pub mod kinds; -#[cfg(not(test))] pub mod ops; -#[cfg(not(test))] pub mod cmp; - - -/* Common traits */ - -pub mod from_str; -#[path = "num/num.rs"] -pub mod num; -pub mod iter; -pub mod old_iter; -pub mod iterator; -pub mod to_str; -pub mod to_bytes; -pub mod clone; -pub mod io; -pub mod hash; -pub mod container; - - -/* Common data structures */ - -pub mod option; -pub mod result; -pub mod either; -pub mod hashmap; -pub mod cell; -pub mod trie; - - -/* Tasks and communication */ - -#[path = "task/mod.rs"] -pub mod task; -pub mod comm; -pub mod pipes; -pub mod local_data; - - -/* Runtime and platform support */ - -pub mod gc; -pub mod libc; -pub mod os; -pub mod path; -pub mod rand; -pub mod run; -pub mod sys; -pub mod cast; -pub mod repr; -pub mod cleanup; -pub mod reflect; -pub mod condition; -pub mod logging; -pub mod util; - - -/* Unsupported interfaces */ - -// Private APIs -#[path = "unstable/mod.rs"] -pub mod unstable; - -/* For internal use, not exported */ - -mod unicode; -#[path = "num/cmath.rs"] -mod cmath; -mod stackwalk; - -// XXX: This shouldn't be pub, and it should be reexported under 'unstable' -// but name resolution doesn't work without it being pub. -#[path = "rt/mod.rs"] -pub mod rt; - -// A curious inner-module that's not exported that contains the binding -// 'core' so that macro-expanded references to core::error and such -// can be resolved within libcore. -#[doc(hidden)] -mod core { - pub use clone; - pub use cmp; - pub use condition; - pub use option; - pub use kinds; - pub use sys; - pub use pipes; -} diff --git a/src/libcore/either.rs b/src/libcore/either.rs deleted file mode 100644 index f89bb3b2f90..00000000000 --- a/src/libcore/either.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A type that represents one of two alternatives - -use container::Container; -use cmp::Eq; -use kinds::Copy; -use old_iter::BaseIter; -use result::Result; -use result; -use vec; -use vec::OwnedVector; - -/// The either type -#[deriving(Clone, Eq)] -pub enum Either<T, U> { - Left(T), - Right(U) -} - -/// Applies a function based on the given either value -/// -/// If `value` is left(T) then `f_left` is applied to its contents, if -/// `value` is right(U) then `f_right` is applied to its contents, and the -/// result is returned. -#[inline(always)] -pub fn either<T, U, V>(f_left: &fn(&T) -> V, - f_right: &fn(&U) -> V, value: &Either<T, U>) -> V { - match *value { - Left(ref l) => f_left(l), - Right(ref r) => f_right(r) - } -} - -/// Extracts from a vector of either all the left values -pub fn lefts<T:Copy,U>(eithers: &[Either<T, U>]) -> ~[T] { - do vec::build_sized(eithers.len()) |push| { - for eithers.each |elt| { - match *elt { - Left(ref l) => { push(*l); } - _ => { /* fallthrough */ } - } - } - } -} - -/// Extracts from a vector of either all the right values -pub fn rights<T, U: Copy>(eithers: &[Either<T, U>]) -> ~[U] { - do vec::build_sized(eithers.len()) |push| { - for eithers.each |elt| { - match *elt { - Right(ref r) => { push(*r); } - _ => { /* fallthrough */ } - } - } - } -} - -/// Extracts from a vector of either all the left values and right values -/// -/// Returns a structure containing a vector of left values and a vector of -/// right values. -pub fn partition<T, U>(eithers: ~[Either<T, U>]) -> (~[T], ~[U]) { - let mut lefts: ~[T] = ~[]; - let mut rights: ~[U] = ~[]; - do vec::consume(eithers) |_i, elt| { - match elt { - Left(l) => lefts.push(l), - Right(r) => rights.push(r) - } - } - return (lefts, rights); -} - -/// Flips between left and right of a given either -#[inline(always)] -pub fn flip<T, U>(eith: Either<T, U>) -> Either<U, T> { - match eith { - Right(r) => Left(r), - Left(l) => Right(l) - } -} - -/// Converts either::t to a result::t -/// -/// Converts an `either` type to a `result` type, making the "right" choice -/// an ok result, and the "left" choice a fail -#[inline(always)] -pub fn to_result<T, U>(eith: Either<T, U>) -> Result<U, T> { - match eith { - Right(r) => result::Ok(r), - Left(l) => result::Err(l) - } -} - -/// Checks whether the given value is a left -#[inline(always)] -pub fn is_left<T, U>(eith: &Either<T, U>) -> bool { - match *eith { - Left(_) => true, - _ => false - } -} - -/// Checks whether the given value is a right -#[inline(always)] -pub fn is_right<T, U>(eith: &Either<T, U>) -> bool { - match *eith { - Right(_) => true, - _ => false - } -} - -/// Retrieves the value in the left branch. Fails if the either is Right. -#[inline(always)] -pub fn unwrap_left<T,U>(eith: Either<T,U>) -> T { - match eith { - Left(x) => x, - Right(_) => fail!("either::unwrap_left Right") - } -} - -/// Retrieves the value in the right branch. Fails if the either is Left. -#[inline(always)] -pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U { - match eith { - Right(x) => x, - Left(_) => fail!("either::unwrap_right Left") - } -} - -pub impl<T, U> Either<T, U> { - #[inline(always)] - 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) } - - #[inline(always)] - fn to_result(self) -> Result<U, T> { to_result(self) } - - #[inline(always)] - fn is_left(&self) -> bool { is_left(self) } - - #[inline(always)] - fn is_right(&self) -> bool { is_right(self) } - - #[inline(always)] - fn unwrap_left(self) -> T { unwrap_left(self) } - - #[inline(always)] - fn unwrap_right(self) -> U { unwrap_right(self) } -} - -#[test] -fn test_either_left() { - let val = Left(10); - fn f_left(x: &int) -> bool { *x == 10 } - fn f_right(_x: &uint) -> bool { false } - assert!((either(f_left, f_right, &val))); -} - -#[test] -fn test_either_right() { - let val = Right(10u); - fn f_left(_x: &int) -> bool { false } - fn f_right(x: &uint) -> bool { *x == 10u } - assert!((either(f_left, f_right, &val))); -} - -#[test] -fn test_lefts() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = lefts(input); - assert_eq!(result, ~[10, 12, 14]); -} - -#[test] -fn test_lefts_none() { - let input: ~[Either<int, int>] = ~[Right(10), Right(10)]; - let result = lefts(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_lefts_empty() { - let input: ~[Either<int, int>] = ~[]; - let result = lefts(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_rights() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = rights(input); - assert_eq!(result, ~[11, 13]); -} - -#[test] -fn test_rights_none() { - let input: ~[Either<int, int>] = ~[Left(10), Left(10)]; - let result = rights(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_rights_empty() { - let input: ~[Either<int, int>] = ~[]; - let result = rights(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_partition() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts[0], 10); - assert_eq!(lefts[1], 12); - assert_eq!(lefts[2], 14); - assert_eq!(rights[0], 11); - assert_eq!(rights[1], 13); -} - -#[test] -fn test_partition_no_lefts() { - let input: ~[Either<int, int>] = ~[Right(10), Right(11)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 0u); - assert_eq!(rights.len(), 2u); -} - -#[test] -fn test_partition_no_rights() { - let input: ~[Either<int, int>] = ~[Left(10), Left(11)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 2u); - assert_eq!(rights.len(), 0u); -} - -#[test] -fn test_partition_empty() { - let input: ~[Either<int, int>] = ~[]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 0u); - assert_eq!(rights.len(), 0u); -} diff --git a/src/libcore/from_str.rs b/src/libcore/from_str.rs deleted file mode 100644 index ebf6d212466..00000000000 --- a/src/libcore/from_str.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The trait for types that can be created from strings - -use option::Option; - -pub trait FromStr { - fn from_str(s: &str) -> Option<Self>; -} diff --git a/src/libcore/gc.rs b/src/libcore/gc.rs deleted file mode 100644 index 611b95a7745..00000000000 --- a/src/libcore/gc.rs +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; - -/*! Precise garbage collector - -The precise GC exposes two functions, gc and -cleanup_stack_for_failure. The gc function is the entry point to the -garbage collector itself. The cleanup_stack_for_failure is the entry -point for GC-based cleanup. - -Precise GC depends on changes to LLVM's GC which add support for -automatic rooting and addrspace-based metadata marking. Rather than -explicitly rooting pointers with LLVM's gcroot intrinsic, the GC -merely creates allocas for pointers, and allows an LLVM pass to -automatically infer roots based on the allocas present in a function -(and live at a given location). The compiler communicates the type of -the pointer to LLVM by setting the addrspace of the pointer type. The -compiler then emits a map from addrspace to tydesc, which LLVM then -uses to match pointers with their tydesc. The GC reads the metadata -table produced by LLVM, and uses it to determine which glue functions -to call to free objects on their respective heaps. - -GC-based cleanup is a replacement for landing pads which relies on the -GC infrastructure to find pointers on the stack to cleanup. Whereas -the normal GC needs to walk task-local heap allocations, the cleanup -code needs to walk exchange heap allocations and stack-allocations -with destructors. - -*/ - -use cast; -use container::{Map, Set}; -use io; -use libc::{size_t, uintptr_t}; -use option::{None, Option, Some}; -use ptr; -use hashmap::HashSet; -use stackwalk::walk_stack; -use sys; - -pub use stackwalk::Word; - -// Mirrors rust_stack.h stk_seg -pub struct StackSegment { - prev: *StackSegment, - next: *StackSegment, - end: uintptr_t, - // And other fields which we don't care about... -} - -pub mod rustrt { - use libc::size_t; - use stackwalk::Word; - use super::StackSegment; - - #[link_name = "rustrt"] - pub extern { - #[rust_stack] - pub unsafe fn rust_call_tydesc_glue(root: *Word, - tydesc: *Word, - field: size_t); - - #[rust_stack] - pub unsafe fn rust_gc_metadata() -> *Word; - - pub unsafe fn rust_get_stack_segment() -> *StackSegment; - pub unsafe fn rust_get_c_stack() -> *StackSegment; - } -} - -unsafe fn bump<T, U>(ptr: *T, count: uint) -> *U { - return cast::transmute(ptr::offset(ptr, count)); -} - -unsafe fn align_to_pointer<T>(ptr: *T) -> *T { - let align = sys::min_align_of::<*T>(); - let ptr: uint = cast::transmute(ptr); - let ptr = (ptr + (align - 1)) & -align; - return cast::transmute(ptr); -} - -unsafe fn get_safe_point_count() -> uint { - let module_meta = rustrt::rust_gc_metadata(); - return *module_meta; -} - -struct SafePoint { - sp_meta: *Word, - fn_meta: *Word, -} - -// Returns the safe point metadata for the given program counter, if -// any. -unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> { - let module_meta = rustrt::rust_gc_metadata(); - let num_safe_points = *module_meta; - let safe_points: *Word = bump(module_meta, 1); - - if ptr::is_null(pc) { - return None; - } - - // FIXME (#2997): Use binary rather than linear search. - let mut spi = 0; - while spi < num_safe_points { - let sp: **Word = bump(safe_points, spi*3); - let sp_loc = *sp; - if sp_loc == pc { - return Some(SafePoint { - sp_meta: *bump(sp, 1), - fn_meta: *bump(sp, 2), - }); - } - spi += 1; - } - return None; -} - -type Visitor<'self> = &'self fn(root: **Word, tydesc: *Word) -> bool; - -// Walks the list of roots for the given safe point, and calls visitor -// on each root. -unsafe fn _walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { - let fp_bytes: *u8 = cast::transmute(fp); - let sp_meta: *u32 = cast::transmute(sp.sp_meta); - - let num_stack_roots = *sp_meta as uint; - let num_reg_roots = *ptr::offset(sp_meta, 1) as uint; - - let stack_roots: *u32 = bump(sp_meta, 2); - let reg_roots: *u8 = bump(stack_roots, num_stack_roots); - let addrspaces: *Word = align_to_pointer(bump(reg_roots, num_reg_roots)); - let tydescs: ***Word = bump(addrspaces, num_stack_roots); - - // Stack roots - let mut sri = 0; - while sri < num_stack_roots { - if *ptr::offset(addrspaces, sri) >= 1 { - let root = - ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri) as Word) - as **Word; - let tydescpp = ptr::offset(tydescs, sri); - let tydesc = if ptr::is_not_null(tydescpp) && - ptr::is_not_null(*tydescpp) { - **tydescpp - } else { - ptr::null() - }; - if !visitor(root, tydesc) { return false; } - } - sri += 1; - } - - // Register roots - let mut rri = 0; - while rri < num_reg_roots { - if *ptr::offset(addrspaces, num_stack_roots + rri) == 1 { - // FIXME(#2997): Need to find callee saved registers on the stack. - } - rri += 1; - } - return true; -} - -unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) -> bool { - _walk_safe_point(fp, sp, visitor) -} - -// Is fp contained in segment? -unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool { - let begin: Word = cast::transmute(segment); - let end: Word = cast::transmute((*segment).end); - let frame: Word = cast::transmute(fp); - - return begin <= frame && frame <= end; -} - -struct Segment { segment: *StackSegment, boundary: bool } - -// Find and return the segment containing the given frame pointer. At -// stack segment boundaries, returns true for boundary, so that the -// caller can do any special handling to identify where the correct -// return address is in the stack frame. -unsafe fn find_segment_for_frame(fp: *Word, segment: *StackSegment) - -> Segment { - // Check if frame is in either current frame or previous frame. - let in_segment = is_frame_in_segment(fp, segment); - let in_prev_segment = ptr::is_not_null((*segment).prev) && - is_frame_in_segment(fp, (*segment).prev); - - // If frame is not in either segment, walk down segment list until - // we find the segment containing this frame. - if !in_segment && !in_prev_segment { - let mut segment = segment; - while ptr::is_not_null((*segment).next) && - is_frame_in_segment(fp, (*segment).next) { - segment = (*segment).next; - } - return Segment {segment: segment, boundary: false}; - } - - // If frame is in previous frame, then we're at a boundary. - if !in_segment && in_prev_segment { - return Segment {segment: (*segment).prev, boundary: true}; - } - - // Otherwise, we're somewhere on the inside of the frame. - return Segment {segment: segment, boundary: false}; -} - -type Memory = uint; - -static task_local_heap: Memory = 1; -static exchange_heap: Memory = 2; -static stack: Memory = 4; - -static need_cleanup: Memory = exchange_heap | stack; - -// Walks stack, searching for roots of the requested type, and passes -// each root to the visitor. -unsafe fn _walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) -> bool { - let mut segment = rustrt::rust_get_stack_segment(); - let mut last_ret: *Word = ptr::null(); - // To avoid collecting memory used by the GC itself, skip stack - // frames until past the root GC stack frame. The root GC stack - // frame is marked by a sentinel, which is a box pointer stored on - // the stack. - let mut reached_sentinel = ptr::is_null(sentinel); - for walk_stack |frame| { - let pc = last_ret; - let Segment {segment: next_segment, boundary: boundary} = - find_segment_for_frame(frame.fp, segment); - segment = next_segment; - // Each stack segment is bounded by a morestack frame. The - // morestack frame includes two return addresses, one for - // morestack itself, at the normal offset from the frame - // pointer, and then a second return address for the - // function prologue (which called morestack after - // determining that it had hit the end of the stack). - // Since morestack itself takes two parameters, the offset - // for this second return address is 3 greater than the - // return address for morestack. - let ret_offset = if boundary { 4 } else { 1 }; - last_ret = *ptr::offset(frame.fp, ret_offset) as *Word; - - if ptr::is_null(pc) { - loop; - } - - let mut delay_reached_sentinel = reached_sentinel; - let sp = is_safe_point(pc); - match sp { - Some(sp_info) => { - for walk_safe_point(frame.fp, sp_info) |root, tydesc| { - // Skip roots until we see the sentinel. - if !reached_sentinel { - if root == sentinel { - delay_reached_sentinel = true; - } - loop; - } - - // Skip null pointers, which can occur when a - // unique pointer has already been freed. - if ptr::is_null(*root) { - loop; - } - - if ptr::is_null(tydesc) { - // Root is a generic box. - let refcount = **root; - if mem | task_local_heap != 0 && refcount != -1 { - if !visitor(root, tydesc) { return false; } - } else if mem | exchange_heap != 0 && refcount == -1 { - if !visitor(root, tydesc) { return false; } - } - } else { - // Root is a non-immediate. - if mem | stack != 0 { - if !visitor(root, tydesc) { return false; } - } - } - } - } - None => () - } - reached_sentinel = delay_reached_sentinel; - } - return true; -} - -unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) -> bool { - _walk_gc_roots(mem, sentinel, visitor) -} -pub fn gc() { - unsafe { - // Abort when GC is disabled. - if get_safe_point_count() == 0 { - return; - } - - for walk_gc_roots(task_local_heap, ptr::null()) |_root, _tydesc| { - // FIXME(#2997): Walk roots and mark them. - io::stdout().write([46]); // . - } - } -} - -#[cfg(gc)] -fn expect_sentinel() -> bool { true } - -#[cfg(nogc)] -fn expect_sentinel() -> bool { false } - -// Entry point for GC-based cleanup. Walks stack looking for exchange -// heap and stack allocations requiring drop, and runs all -// destructors. -// -// This should only be called from fail!, as it will drop the roots -// which are *live* on the stack, rather than dropping those that are -// dead. -pub fn cleanup_stack_for_failure() { - unsafe { - // Abort when GC is disabled. - if get_safe_point_count() == 0 { - return; - } - - // Leave a sentinel on the stack to mark the current frame. The - // stack walker will ignore any frames above the sentinel, thus - // avoiding collecting any memory being used by the stack walker - // itself. - // - // However, when core itself is not compiled with GC, then none of - // the functions in core will have GC metadata, which means we - // won't be able to find the sentinel root on the stack. In this - // case, we can safely skip the sentinel since we won't find our - // own stack roots on the stack anyway. - let sentinel_box = ~0; - let sentinel: **Word = if expect_sentinel() { - cast::transmute(&sentinel_box) - } else { - ptr::null() - }; - - let mut roots = HashSet::new(); - for walk_gc_roots(need_cleanup, sentinel) |root, tydesc| { - // Track roots to avoid double frees. - if roots.contains(&*root) { - loop; - } - roots.insert(*root); - - if ptr::is_null(tydesc) { - // FIXME #4420: Destroy this box - // FIXME #4330: Destroy this box - } else { - rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t); - } - } - } -} diff --git a/src/libcore/hash.rs b/src/libcore/hash.rs deleted file mode 100644 index 69312f3a97b..00000000000 --- a/src/libcore/hash.rs +++ /dev/null @@ -1,557 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * Implementation of SipHash 2-4 - * - * See: http://131002.net/siphash/ - * - * Consider this as a main "general-purpose" hash for all hashtables: it - * runs at good speed (competitive with spooky and city) and permits - * cryptographically strong _keyed_ hashing. Key your hashtables from a - * CPRNG like rand::rng. - */ - -use container::Container; -use old_iter::BaseIter; -use rt::io::Writer; -use to_bytes::IterBytes; -use uint; - -// Alias `SipState` to `State`. -pub use State = hash::SipState; - -/** - * Types that can meaningfully be hashed should implement this. - * - * Note that this trait is likely to change somewhat as it is - * closely related to `to_bytes::IterBytes` and in almost all - * cases presently the two are (and must be) used together. - * - * In general, most types only need to implement `IterBytes`, - * and the implementation of `Hash` below will take care of - * the rest. This is the recommended approach, since constructing - * good keyed hash functions is quite difficult. - */ -pub trait Hash { - /** - * Compute a "keyed" hash of the value implementing the trait, - * taking `k0` and `k1` as "keying" parameters that randomize or - * otherwise perturb the hash function in such a way that a - * hash table built using such "keyed hash functions" cannot - * be made to perform linearly by an attacker controlling the - * hashtable's contents. - * - * In practical terms, we implement this using the SipHash 2-4 - * function and require most types to only implement the - * IterBytes trait, that feeds SipHash. - */ - fn hash_keyed(&self, k0: u64, k1: u64) -> u64; -} - -// When we have default methods, won't need this. -pub trait HashUtil { - fn hash(&self) -> u64; -} - -impl<A:Hash> HashUtil for A { - #[inline(always)] - fn hash(&self) -> u64 { self.hash_keyed(0,0) } -} - -/// Streaming hash-functions should implement this. -pub trait Streaming { - fn input(&mut self, &[u8]); - // These can be refactored some when we have default methods. - fn result_bytes(&mut self) -> ~[u8]; - fn result_str(&mut self) -> ~str; - fn result_u64(&mut self) -> u64; - fn reset(&mut self); -} - -impl<A:IterBytes> Hash for A { - #[inline(always)] - fn hash_keyed(&self, k0: u64, k1: u64) -> u64 { - let mut s = State::new(k0, k1); - for self.iter_bytes(true) |bytes| { - s.input(bytes); - } - s.result_u64() - } -} - -fn hash_keyed_2<A: IterBytes, - B: IterBytes>(a: &A, b: &B, k0: u64, k1: u64) -> u64 { - let mut s = State::new(k0, k1); - for a.iter_bytes(true) |bytes| { - s.input(bytes); - } - for b.iter_bytes(true) |bytes| { - s.input(bytes); - } - s.result_u64() -} - -fn hash_keyed_3<A: IterBytes, - B: IterBytes, - C: IterBytes>(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 { - let mut s = State::new(k0, k1); - for a.iter_bytes(true) |bytes| { - s.input(bytes); - } - for b.iter_bytes(true) |bytes| { - s.input(bytes); - } - for c.iter_bytes(true) |bytes| { - s.input(bytes); - } - s.result_u64() -} - -fn hash_keyed_4<A: IterBytes, - B: IterBytes, - C: IterBytes, - D: IterBytes>( - a: &A, - b: &B, - c: &C, - d: &D, - k0: u64, - k1: u64) - -> u64 { - let mut s = State::new(k0, k1); - for a.iter_bytes(true) |bytes| { - s.input(bytes); - } - for b.iter_bytes(true) |bytes| { - s.input(bytes); - } - for c.iter_bytes(true) |bytes| { - s.input(bytes); - } - for d.iter_bytes(true) |bytes| { - s.input(bytes); - } - s.result_u64() -} - -fn hash_keyed_5<A: IterBytes, - B: IterBytes, - C: IterBytes, - D: IterBytes, - E: IterBytes>( - a: &A, - b: &B, - c: &C, - d: &D, - e: &E, - k0: u64, - k1: u64) - -> u64 { - let mut s = State::new(k0, k1); - for a.iter_bytes(true) |bytes| { - s.input(bytes); - } - for b.iter_bytes(true) |bytes| { - s.input(bytes); - } - for c.iter_bytes(true) |bytes| { - s.input(bytes); - } - for d.iter_bytes(true) |bytes| { - s.input(bytes); - } - for e.iter_bytes(true) |bytes| { - s.input(bytes); - } - s.result_u64() -} - -#[inline(always)] -pub fn default_state() -> State { - State::new(0, 0) -} - -struct SipState { - k0: u64, - k1: u64, - length: uint, // how many bytes we've processed - v0: u64, // hash state - v1: u64, - v2: u64, - v3: u64, - tail: [u8, ..8], // unprocessed bytes - ntail: uint, // how many bytes in tail are valid -} - -impl SipState { - #[inline(always)] - fn new(key0: u64, key1: u64) -> SipState { - let mut state = SipState { - k0: key0, - k1: key1, - length: 0, - v0: 0, - v1: 0, - v2: 0, - v3: 0, - tail: [ 0, 0, 0, 0, 0, 0, 0, 0 ], - ntail: 0, - }; - state.reset(); - state - } -} - -// sadly, these macro definitions can't appear later, -// because they're needed in the following defs; -// this design could be improved. - -macro_rules! u8to64_le ( - ($buf:expr, $i:expr) => - ($buf[0+$i] as u64 | - $buf[1+$i] as u64 << 8 | - $buf[2+$i] as u64 << 16 | - $buf[3+$i] as u64 << 24 | - $buf[4+$i] as u64 << 32 | - $buf[5+$i] as u64 << 40 | - $buf[6+$i] as u64 << 48 | - $buf[7+$i] as u64 << 56) -) - -macro_rules! rotl ( - ($x:expr, $b:expr) => - (($x << $b) | ($x >> (64 - $b))) -) - -macro_rules! compress ( - ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => - ({ - $v0 += $v1; $v1 = rotl!($v1, 13); $v1 ^= $v0; - $v0 = rotl!($v0, 32); - $v2 += $v3; $v3 = rotl!($v3, 16); $v3 ^= $v2; - $v0 += $v3; $v3 = rotl!($v3, 21); $v3 ^= $v0; - $v2 += $v1; $v1 = rotl!($v1, 17); $v1 ^= $v2; - $v2 = rotl!($v2, 32); - }) -) - - -impl Writer for SipState { - // Methods for io::writer - #[inline(always)] - fn write(&mut self, msg: &[u8]) { - let length = msg.len(); - self.length += length; - - let mut needed = 0u; - - if self.ntail != 0 { - needed = 8 - self.ntail; - - if length < needed { - let mut t = 0; - while t < length { - self.tail[self.ntail+t] = msg[t]; - t += 1; - } - self.ntail += length; - return; - } - - let mut t = 0; - while t < needed { - self.tail[self.ntail+t] = msg[t]; - t += 1; - } - - let m = u8to64_le!(self.tail, 0); - - self.v3 ^= m; - compress!(self.v0, self.v1, self.v2, self.v3); - compress!(self.v0, self.v1, self.v2, self.v3); - self.v0 ^= m; - - self.ntail = 0; - } - - // Buffered tail is now flushed, process new input. - let len = length - needed; - let end = len & (!0x7); - let left = len & 0x7; - - let mut i = needed; - while i < end { - let mi = u8to64_le!(msg, i); - - self.v3 ^= mi; - compress!(self.v0, self.v1, self.v2, self.v3); - compress!(self.v0, self.v1, self.v2, self.v3); - self.v0 ^= mi; - - i += 8; - } - - let mut t = 0u; - while t < left { - self.tail[t] = msg[i+t]; - t += 1 - } - self.ntail = left; - } - - fn flush(&mut self) { - // No-op - } -} - -impl Streaming for SipState { - #[inline(always)] - fn input(&mut self, buf: &[u8]) { - self.write(buf); - } - - #[inline(always)] - fn result_u64(&mut self) -> u64 { - let mut v0 = self.v0; - let mut v1 = self.v1; - let mut v2 = self.v2; - let mut v3 = self.v3; - - let mut b : u64 = (self.length as u64 & 0xff) << 56; - - if self.ntail > 0 { b |= self.tail[0] as u64 << 0; } - if self.ntail > 1 { b |= self.tail[1] as u64 << 8; } - if self.ntail > 2 { b |= self.tail[2] as u64 << 16; } - if self.ntail > 3 { b |= self.tail[3] as u64 << 24; } - if self.ntail > 4 { b |= self.tail[4] as u64 << 32; } - if self.ntail > 5 { b |= self.tail[5] as u64 << 40; } - if self.ntail > 6 { b |= self.tail[6] as u64 << 48; } - - v3 ^= b; - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - v0 ^= b; - - v2 ^= 0xff; - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - - return (v0 ^ v1 ^ v2 ^ v3); - } - - fn result_bytes(&mut self) -> ~[u8] { - let h = self.result_u64(); - ~[(h >> 0) as u8, - (h >> 8) as u8, - (h >> 16) as u8, - (h >> 24) as u8, - (h >> 32) as u8, - (h >> 40) as u8, - (h >> 48) as u8, - (h >> 56) as u8, - ] - } - - fn result_str(&mut self) -> ~str { - let r = self.result_bytes(); - let mut s = ~""; - for r.each |b| { - s += uint::to_str_radix(*b as uint, 16u); - } - s - } - - #[inline(always)] - fn reset(&mut self) { - self.length = 0; - self.v0 = self.k0 ^ 0x736f6d6570736575; - self.v1 = self.k1 ^ 0x646f72616e646f6d; - self.v2 = self.k0 ^ 0x6c7967656e657261; - self.v3 = self.k1 ^ 0x7465646279746573; - self.ntail = 0; - } -} - -#[cfg(test)] -mod tests { - use super::*; - use prelude::*; - - #[test] - fn test_siphash() { - let vecs : [[u8, ..8], ..64] = [ - [ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ], - [ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ], - [ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ], - [ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ], - [ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ], - [ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ], - [ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ], - [ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ], - [ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ], - [ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ], - [ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ], - [ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ], - [ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ], - [ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ], - [ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ], - [ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ], - [ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ], - [ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ], - [ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ], - [ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ], - [ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ], - [ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ], - [ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ], - [ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ], - [ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ], - [ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ], - [ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ], - [ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ], - [ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ], - [ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ], - [ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ], - [ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ], - [ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ], - [ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ], - [ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ], - [ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ], - [ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ], - [ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ], - [ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ], - [ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ], - [ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ], - [ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ], - [ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ], - [ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ], - [ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ], - [ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ], - [ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ], - [ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ], - [ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ], - [ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ], - [ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ], - [ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ], - [ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ], - [ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ], - [ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ], - [ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ], - [ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ], - [ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ], - [ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ], - [ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ], - [ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ], - [ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ], - [ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ], - [ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ] - ]; - - let k0 = 0x_07_06_05_04_03_02_01_00_u64; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64; - let mut buf : ~[u8] = ~[]; - let mut t = 0; - let mut stream_inc = SipState::new(k0, k1); - let mut stream_full = SipState::new(k0, k1); - - fn to_hex_str(r: &[u8, ..8]) -> ~str { - let mut s = ~""; - for (*r).each |b| { - s += uint::to_str_radix(*b as uint, 16u); - } - s - } - - while t < 64 { - debug!("siphash test %?", t); - let vec = u8to64_le!(vecs[t], 0); - let out = buf.hash_keyed(k0, k1); - debug!("got %?, expected %?", out, vec); - assert_eq!(vec, out); - - stream_full.reset(); - stream_full.input(buf); - let f = stream_full.result_str(); - let i = stream_inc.result_str(); - let v = to_hex_str(&vecs[t]); - debug!("%d: (%s) => inc=%s full=%s", t, v, i, f); - - assert!(f == i && f == v); - - buf += ~[t as u8]; - stream_inc.input(~[t as u8]); - - t += 1; - } - } - - #[test] #[cfg(target_arch = "arm")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!((val as u64).hash() != (val as uint).hash()); - assert_eq!((val as u32).hash(), (val as uint).hash()); - } - #[test] #[cfg(target_arch = "x86_64")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!((val as u64).hash(), (val as uint).hash()); - assert!((val as u32).hash() != (val as uint).hash()); - } - #[test] #[cfg(target_arch = "x86")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!((val as u64).hash() != (val as uint).hash()); - assert_eq!((val as u32).hash(), (val as uint).hash()); - } - - #[test] - fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - val64.hash() == val64.hash(); - let val32 = 0xdeadbeef_u32; - val32.hash() == val32.hash(); - } - - #[test] - fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert!(val.hash() != zero_byte(val, 0).hash()); - assert!(val.hash() != zero_byte(val, 1).hash()); - assert!(val.hash() != zero_byte(val, 2).hash()); - assert!(val.hash() != zero_byte(val, 3).hash()); - assert!(val.hash() != zero_byte(val, 4).hash()); - assert!(val.hash() != zero_byte(val, 5).hash()); - assert!(val.hash() != zero_byte(val, 6).hash()); - assert!(val.hash() != zero_byte(val, 7).hash()); - - fn zero_byte(val: u64, byte: uint) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) - } - } - - #[test] - fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; - - assert!(val.hash() != zero_byte(val, 0).hash()); - assert!(val.hash() != zero_byte(val, 1).hash()); - assert!(val.hash() != zero_byte(val, 2).hash()); - assert!(val.hash() != zero_byte(val, 3).hash()); - - fn zero_byte(val: u32, byte: uint) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) - } - } -} diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs deleted file mode 100644 index e6ccb7a1d6b..00000000000 --- a/src/libcore/hashmap.rs +++ /dev/null @@ -1,989 +0,0 @@ -// 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. - -//! An unordered map and set type implemented as hash tables -//! -//! 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. - -use container::{Container, Mutable, Map, Set}; -use cmp::{Eq, Equiv}; -use hash::Hash; -use old_iter::BaseIter; -use old_iter; -use option::{None, Option, Some}; -use rand::RngUtil; -use rand; -use uint; -use vec; -use kinds::Copy; -use util::{replace, unreachable}; - -static INITIAL_CAPACITY: uint = 32u; // 2^5 - -struct Bucket<K,V> { - hash: uint, - key: K, - value: V, -} - -pub struct HashMap<K,V> { - priv k0: u64, - priv k1: u64, - priv resize_at: uint, - priv size: uint, - priv buckets: ~[Option<Bucket<K, V>>], -} - -// We could rewrite FoundEntry to have type Option<&Bucket<K, V>> -// which would be nifty -enum SearchResult { - FoundEntry(uint), FoundHole(uint), TableFull -} - -#[inline(always)] -fn resize_at(capacity: uint) -> uint { - ((capacity as float) * 3. / 4.) as uint -} - -pub fn linear_map_with_capacity<K:Eq + Hash,V>( - initial_capacity: uint) -> HashMap<K, V> { - let mut r = rand::task_rng(); - linear_map_with_capacity_and_keys(r.gen(), r.gen(), - initial_capacity) -} - -fn linear_map_with_capacity_and_keys<K:Eq + Hash,V>( - k0: u64, k1: u64, - initial_capacity: uint) -> HashMap<K, V> { - HashMap { - k0: k0, k1: k1, - resize_at: resize_at(initial_capacity), - size: 0, - buckets: vec::from_fn(initial_capacity, |_| None) - } -} - -priv 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 - // bits is assumed. SipHash is more than good enough. - h % self.buckets.len() - } - - #[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 - } - - #[inline(always)] - fn bucket_sequence(&self, hash: uint, - op: &fn(uint) -> bool) -> bool { - let start_idx = self.to_bucket(hash); - let len_buckets = self.buckets.len(); - let mut idx = start_idx; - loop { - if !op(idx) { return false; } - idx = self.next_bucket(idx, len_buckets); - if idx == start_idx { - return true; - } - } - } - - #[inline(always)] - fn bucket_for_key(&self, k: &K) -> SearchResult { - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.bucket_for_key_with_hash(hash, k) - } - - #[inline(always)] - fn bucket_for_key_equiv<Q:Hash + Equiv<K>>(&self, k: &Q) - -> SearchResult { - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.bucket_for_key_with_hash_equiv(hash, k) - } - - #[inline(always)] - fn bucket_for_key_with_hash(&self, - hash: uint, - k: &K) - -> SearchResult { - for self.bucket_sequence(hash) |i| { - match self.buckets[i] { - Some(ref bkt) => if bkt.hash == hash && *k == bkt.key { - return FoundEntry(i); - }, - None => return FoundHole(i) - } - } - TableFull - } - - #[inline(always)] - fn bucket_for_key_with_hash_equiv<Q:Equiv<K>>(&self, - hash: uint, - k: &Q) - -> SearchResult { - for self.bucket_sequence(hash) |i| { - match self.buckets[i] { - Some(ref bkt) => { - if bkt.hash == hash && k.equiv(&bkt.key) { - return FoundEntry(i); - } - }, - None => return FoundHole(i) - } - } - TableFull - } - - /// Expand the capacity of the array to the next power of two - /// and re-insert each of the existing buckets. - #[inline(always)] - fn expand(&mut self) { - let new_capacity = self.buckets.len() * 2; - self.resize(new_capacity); - } - - /// Expands the capacity of the array and re-insert each of the - /// existing buckets. - fn resize(&mut self, new_capacity: uint) { - self.resize_at = resize_at(new_capacity); - - let old_buckets = replace(&mut self.buckets, - vec::from_fn(new_capacity, |_| None)); - - self.size = 0; - do vec::consume(old_buckets) |_, bucket| { - self.insert_opt_bucket(bucket); - } - } - - fn insert_opt_bucket(&mut self, bucket: Option<Bucket<K, V>>) { - match bucket { - Some(Bucket{hash: hash, key: key, value: value}) => { - self.insert_internal(hash, key, value); - } - None => {} - } - } - - #[inline(always)] - fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V { - match self.buckets[idx] { - Some(ref bkt) => &bkt.value, - None => fail!("HashMap::find: internal logic error"), - } - } - - #[inline(always)] - fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V { - match self.buckets[idx] { - Some(ref mut bkt) => &mut bkt.value, - None => unreachable() - } - } - - /// Inserts the key value pair into the buckets. - /// Assumes that there will be a bucket. - /// True if there was no previous entry with that key - fn insert_internal(&mut self, hash: uint, k: K, v: V) -> Option<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) => { - b.hash = hash; - b.key = k; - Some(replace(&mut b.value, v)) - } - } - } - } - } - - fn pop_internal(&mut self, hash: uint, k: &K) -> Option<V> { - // Removing from an open-addressed hashtable - // is, well, painful. The problem is that - // the entry may lie on the probe path for other - // entries, so removing it would make you think that - // those probe paths are empty. - // - // To address this we basically have to keep walking, - // re-inserting entries we find until we reach an empty - // bucket. We know we will eventually reach one because - // we insert one ourselves at the beginning (the removed - // entry). - // - // I found this explanation elucidating: - // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf - let mut idx = match self.bucket_for_key_with_hash(hash, k) { - TableFull | FoundHole(_) => return None, - FoundEntry(idx) => idx - }; - - let len_buckets = self.buckets.len(); - let bucket = replace(&mut self.buckets[idx], None); - - let value = match bucket { - None => None, - Some(Bucket{value, _}) => { - Some(value) - }, - }; - - /* re-inserting buckets may cause changes in size, so remember - what our new size is ahead of time before we start insertions */ - let size = self.size - 1; - idx = self.next_bucket(idx, len_buckets); - while self.buckets[idx].is_some() { - let bucket = replace(&mut self.buckets[idx], None); - self.insert_opt_bucket(bucket); - idx = self.next_bucket(idx, len_buckets); - } - self.size = size; - - value - } - - fn search(&self, hash: uint, - op: &fn(x: &Option<Bucket<K, V>>) -> bool) { - let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i])); - } -} - -impl<K:Hash + Eq,V> Container for HashMap<K, V> { - /// Return the number of elements in the map - fn len(&const self) -> uint { self.size } - - /// Return true if the map contains no elements - fn is_empty(&const self) -> bool { self.len() == 0 } -} - -impl<K:Hash + Eq,V> Mutable for HashMap<K, V> { - /// Clear the map, removing all key-value pairs. - fn clear(&mut self) { - for uint::range(0, self.buckets.len()) |idx| { - self.buckets[idx] = None; - } - self.size = 0; - } -} - -impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> { - /// Return true if the map contains a value for the specified key - fn contains_key(&self, k: &K) -> bool { - match self.bucket_for_key(k) { - FoundEntry(_) => {true} - TableFull | FoundHole(_) => {false} - } - } - - /// 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| { - if !blk(&pair.key, &pair.value) { - return false; - } - } - } - return true; - } - - /// Visit all keys - fn each_key(&self, blk: &fn(k: &K) -> bool) -> bool { - self.each(|k, _| blk(k)) - } - - /// Visit all values - fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) -> bool { - self.each(|_, v| blk(v)) - } - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, blk: &fn(&K, &mut V) -> bool) -> bool { - for uint::range(0, self.buckets.len()) |i| { - match self.buckets[i] { - Some(Bucket{key: ref key, value: ref mut value, _}) => { - if !blk(key, value) { return false; } - } - None => () - } - } - return true; - } - - /// Return a reference to the value corresponding to the key - fn find<'a>(&'a self, k: &K) -> Option<&'a V> { - match self.bucket_for_key(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } - } - - /// Return a mutable reference to the value corresponding to the key - fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { - let idx = match self.bucket_for_key(k) { - FoundEntry(idx) => idx, - TableFull | FoundHole(_) => return None - }; - Some(self.mut_value_for_bucket(idx)) - } - - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - fn insert(&mut self, k: K, v: V) -> bool { - self.swap(k, v).is_none() - } - - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - fn remove(&mut self, k: &K) -> bool { - self.pop(k).is_some() - } - - /// Insert a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, k: K, v: V) -> Option<V> { - // this could be faster. - - 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; - self.insert_internal(hash, k, v) - } - - /// Removes a key from the map, returning the value at the key if the key - /// was previously in the map. - fn pop(&mut self, k: &K) -> Option<V> { - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.pop_internal(hash, k) - } -} - -pub impl<K: Hash + Eq, V> HashMap<K, V> { - /// Create an empty HashMap - 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> { - linear_map_with_capacity(capacity) - } - - /// Reserve space for at least `n` elements in the hash table. - 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 { - 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) => { - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; - - self.value_for_bucket(idx) - } - - /// 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 - }, - }; - - self.value_for_bucket(idx) - } - - fn consume(&mut self, f: &fn(K, V)) { - let buckets = replace(&mut self.buckets, ~[]); - self.size = 0; - - do vec::consume(buckets) |_, bucket| { - match bucket { - None => {}, - Some(Bucket{key, value, _}) => { - f(key, value) - } - } - } - } - - fn get<'a>(&'a self, k: &K) -> &'a V { - match self.find(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 { - match self.bucket_for_key_equiv(key) { - FoundEntry(_) => {true} - TableFull | FoundHole(_) => {false} - } - } - - /// 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> { - match self.bucket_for_key_equiv(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } - } -} - -pub 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> { - self.find(k).map_consume(|v| copy *v) - } - - /// Like `get`, but returns a copy of the value. - fn get_copy(&self, k: &K) -> V { - copy *self.get(k) - } -} - -impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> { - fn eq(&self, other: &HashMap<K, V>) -> bool { - if self.len() != other.len() { return false; } - - for self.each |key, value| { - match other.find(key) { - None => return false, - Some(v) => if value != v { return false }, - } - } - - true - } - - fn ne(&self, other: &HashMap<K, V>) -> bool { !self.eq(other) } -} - -pub struct HashSet<T> { - priv map: HashMap<T, ()> -} - -impl<T:Hash + Eq> BaseIter<T> for HashSet<T> { - /// Visit all values in order - fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) } - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -impl<T:Hash + Eq> Eq for HashSet<T> { - fn eq(&self, other: &HashSet<T>) -> bool { self.map == other.map } - fn ne(&self, other: &HashSet<T>) -> bool { self.map != other.map } -} - -impl<T:Hash + Eq> Container for HashSet<T> { - /// Return the number of elements in the set - fn len(&const self) -> uint { self.map.len() } - - /// Return true if the set contains no elements - fn is_empty(&const self) -> bool { self.map.is_empty() } -} - -impl<T:Hash + Eq> Mutable for HashSet<T> { - /// Clear the set, removing all values. - fn clear(&mut self) { self.map.clear() } -} - -impl<T:Hash + Eq> Set<T> for HashSet<T> { - /// Return true if the set contains a value - fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } - - /// Add a value to the set. Return true if the value was not already - /// present in the set. - fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } - - /// Remove a value from the set. Return true if the value was - /// present in the set. - fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } - - /// Return true if the set has no elements in common with `other`. - /// This is equivalent to checking for an empty intersection. - fn is_disjoint(&self, other: &HashSet<T>) -> bool { - old_iter::all(self, |v| !other.contains(v)) - } - - /// Return true if the set is a subset of another - fn is_subset(&self, other: &HashSet<T>) -> bool { - old_iter::all(self, |v| other.contains(v)) - } - - /// Return true if the set is a superset of another - fn is_superset(&self, other: &HashSet<T>) -> bool { - other.is_subset(self) - } - - /// Visit the values representing the difference - fn difference(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.each(|v| other.contains(v) || f(v)) - } - - /// Visit the values representing the symmetric difference - fn symmetric_difference(&self, - other: &HashSet<T>, - f: &fn(&T) -> bool) -> bool { - self.difference(other, f) && other.difference(self, f) - } - - /// Visit the values representing the intersection - fn intersection(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.each(|v| !other.contains(v) || f(v)) - } - - /// Visit the values representing the union - fn union(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool { - self.each(f) && other.each(|v| self.contains(v) || f(v)) - } -} - -pub impl <T:Hash + Eq> HashSet<T> { - /// Create an empty HashSet - 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> { - 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) { - self.map.reserve_at_least(n) - } - - /// Consumes all of the elements in the set, emptying it out - fn consume(&mut self, f: &fn(T)) { - self.map.consume(|k, _| f(k)) - } - - fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool { - self.map.contains_key_equiv(value) - } -} - -#[cfg(test)] -mod test_map { - use container::{Container, Map, Set}; - use option::{None, Some}; - use super::*; - use uint; - - #[test] - fn test_insert() { - let mut m = HashMap::new(); - assert!(m.insert(1, 2)); - assert!(m.insert(2, 4)); - assert_eq!(*m.get(&1), 2); - assert_eq!(*m.get(&2), 4); - } - - #[test] - fn test_find_mut() { - let mut m = HashMap::new(); - assert!(m.insert(1, 12)); - assert!(m.insert(2, 8)); - assert!(m.insert(5, 14)); - let new = 100; - match m.find_mut(&5) { - None => fail!(), Some(x) => *x = new - } - assert_eq!(m.find(&5), Some(&new)); - } - - #[test] - fn test_insert_overwrite() { - let mut m = HashMap::new(); - assert!(m.insert(1, 2)); - assert_eq!(*m.get(&1), 2); - assert!(!m.insert(1, 3)); - assert_eq!(*m.get(&1), 3); - } - - #[test] - fn test_insert_conflicts() { - let mut m = linear_map_with_capacity(4); - assert!(m.insert(1, 2)); - assert!(m.insert(5, 3)); - assert!(m.insert(9, 4)); - assert_eq!(*m.get(&9), 4); - assert_eq!(*m.get(&5), 3); - assert_eq!(*m.get(&1), 2); - } - - #[test] - fn test_conflict_remove() { - let mut m = linear_map_with_capacity(4); - assert!(m.insert(1, 2)); - assert!(m.insert(5, 3)); - assert!(m.insert(9, 4)); - assert!(m.remove(&1)); - assert_eq!(*m.get(&9), 4); - assert_eq!(*m.get(&5), 3); - } - - #[test] - fn test_is_empty() { - let mut m = linear_map_with_capacity(4); - assert!(m.insert(1, 2)); - assert!(!m.is_empty()); - assert!(m.remove(&1)); - assert!(m.is_empty()); - } - - #[test] - fn test_pop() { - let mut m = HashMap::new(); - m.insert(1, 2); - assert_eq!(m.pop(&1), Some(2)); - assert_eq!(m.pop(&1), None); - } - - #[test] - fn test_swap() { - let mut m = HashMap::new(); - assert_eq!(m.swap(1, 2), None); - assert_eq!(m.swap(1, 3), Some(2)); - assert_eq!(m.swap(1, 4), Some(3)); - } - - #[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); - } - - #[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); - } - - #[test] - fn test_consume() { - let mut m = HashMap::new(); - assert!(m.insert(1, 2)); - assert!(m.insert(2, 3)); - let mut m2 = HashMap::new(); - do m.consume |k, v| { - m2.insert(k, v); - } - assert_eq!(m.len(), 0); - assert_eq!(m2.len(), 2); - assert_eq!(m2.get(&1), &2); - assert_eq!(m2.get(&2), &3); - } - - #[test] - fn test_iterate() { - let mut m = linear_map_with_capacity(4); - for uint::range(0, 32) |i| { - assert!(m.insert(i, i*2)); - } - let mut observed = 0; - for m.each |k, v| { - assert_eq!(*v, *k * 2); - observed |= (1 << *k); - } - assert_eq!(observed, 0xFFFF_FFFF); - } - - #[test] - fn test_find() { - let mut m = HashMap::new(); - assert!(m.find(&1).is_none()); - m.insert(1, 2); - match m.find(&1) { - None => fail!(), - Some(v) => assert!(*v == 2) - } - } - - #[test] - fn test_eq() { - let mut m1 = HashMap::new(); - m1.insert(1, 2); - m1.insert(2, 3); - m1.insert(3, 4); - - let mut m2 = HashMap::new(); - m2.insert(1, 2); - m2.insert(2, 3); - - assert!(m1 != m2); - - m2.insert(3, 4); - - assert_eq!(m1, m2); - } - - #[test] - fn test_expand() { - let mut m = HashMap::new(); - - assert_eq!(m.len(), 0); - assert!(m.is_empty()); - - let mut i = 0u; - let old_resize_at = m.resize_at; - while old_resize_at == m.resize_at { - m.insert(i, i); - i += 1; - } - - assert_eq!(m.len(), i); - assert!(!m.is_empty()); - } -} - -#[cfg(test)] -mod test_set { - use super::*; - use container::{Container, Map, Set}; - use vec; - - #[test] - fn test_disjoint() { - let mut xs = HashSet::new(); - let mut ys = HashSet::new(); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(5)); - assert!(ys.insert(11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(7)); - assert!(xs.insert(19)); - assert!(xs.insert(4)); - assert!(ys.insert(2)); - assert!(ys.insert(-11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(ys.insert(7)); - assert!(!xs.is_disjoint(&ys)); - assert!(!ys.is_disjoint(&xs)); - } - - #[test] - fn test_subset_and_superset() { - let mut a = HashSet::new(); - assert!(a.insert(0)); - assert!(a.insert(5)); - assert!(a.insert(11)); - assert!(a.insert(7)); - - let mut b = HashSet::new(); - assert!(b.insert(0)); - assert!(b.insert(7)); - assert!(b.insert(19)); - assert!(b.insert(250)); - assert!(b.insert(11)); - assert!(b.insert(200)); - - assert!(!a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(!b.is_superset(&a)); - - assert!(b.insert(5)); - - assert!(a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(b.is_superset(&a)); - } - - #[test] - fn test_intersection() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(11)); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(77)); - assert!(a.insert(103)); - assert!(a.insert(5)); - assert!(a.insert(-5)); - - assert!(b.insert(2)); - assert!(b.insert(11)); - assert!(b.insert(77)); - assert!(b.insert(-9)); - assert!(b.insert(-42)); - assert!(b.insert(5)); - assert!(b.insert(3)); - - let mut i = 0; - let expected = [3, 5, 11, 77]; - for a.intersection(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(3)); - assert!(b.insert(9)); - - let mut i = 0; - let expected = [1, 5, 11]; - for a.difference(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_symmetric_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(-2)); - assert!(b.insert(3)); - assert!(b.insert(9)); - assert!(b.insert(14)); - assert!(b.insert(22)); - - let mut i = 0; - let expected = [-2, 1, 5, 11, 14, 22]; - for a.symmetric_difference(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_union() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - assert!(a.insert(16)); - assert!(a.insert(19)); - assert!(a.insert(24)); - - assert!(b.insert(-2)); - assert!(b.insert(1)); - assert!(b.insert(5)); - assert!(b.insert(9)); - assert!(b.insert(13)); - assert!(b.insert(19)); - - let mut i = 0; - let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; - for a.union(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert_eq!(i, expected.len()); - } -} diff --git a/src/libcore/io.rs b/src/libcore/io.rs deleted file mode 100644 index aa312742e3e..00000000000 --- a/src/libcore/io.rs +++ /dev/null @@ -1,2105 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The `io` module contains basic input and output routines. - -A quick summary: - -## `Reader` and `Writer` traits - -These traits define the minimal set of methods that anything that can do -input and output should implement. - -## `ReaderUtil` and `WriterUtil` traits - -Richer methods that allow you to do more. `Reader` only lets you read a certain -number of bytes into a buffer, while `ReaderUtil` allows you to read a whole -line, for example. - -Generally, these richer methods are probably the ones you want to actually -use in day-to-day Rust. - -Furthermore, because there is an implementation of `ReaderUtil` for -`<T: Reader>`, when your input or output code implements `Reader`, you get -all of these methods for free. - -## `print` and `println` - -These very useful functions are defined here. You generally don't need to -import them, though, as the prelude already does. - -## `stdin`, `stdout`, and `stderr` - -These functions return references to the classic three file descriptors. They -implement `Reader` and `Writer`, where appropriate. - -*/ - -use result::Result; - -use container::Container; -use int; -use libc; -use libc::{c_int, c_long, c_void, size_t, ssize_t}; -use libc::consts::os::posix88::*; -use os; -use cast; -use path::Path; -use ops::Drop; -use old_iter::{BaseIter, CopyableIter}; -use ptr; -use result; -use str; -use str::StrSlice; -use to_str::ToStr; -use uint; -use vec; -use vec::{OwnedVector, OwnedCopyableVector}; - -#[allow(non_camel_case_types)] // not sure what to do about this -pub type fd_t = c_int; - -pub mod rustrt { - use libc; - - #[abi = "cdecl"] - #[link_name = "rustrt"] - pub extern { - unsafe fn rust_get_stdin() -> *libc::FILE; - unsafe fn rust_get_stdout() -> *libc::FILE; - unsafe fn rust_get_stderr() -> *libc::FILE; - } -} - -// Reading - -// FIXME (#2004): This is all buffered. We might need an unbuffered variant -// as well -/** -* The SeekStyle enum describes the relationship between the position -* we'd like to seek to from our current position. It's used as an argument -* to the `seek` method defined on the `Reader` trait. -* -* There are three seek styles: -* -* 1. `SeekSet` means that the new position should become our position. -* 2. `SeekCur` means that we should seek from the current position. -* 3. `SeekEnd` means that we should seek from the end. -* -* # Examples -* -* None right now. -*/ -pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, } - - -/** -* The core Reader trait. All readers must implement this trait. -* -* # Examples -* -* None right now. -*/ -pub trait Reader { - // FIXME (#2004): Seekable really should be orthogonal. - - // FIXME (#2982): This should probably return an error. - /** - * Reads bytes and puts them into `bytes`, advancing the cursor. Returns the - * number of bytes read. - * - * The number of bytes to be read is `len` or the end of the file, - * whichever comes first. - * - * The buffer must be at least `len` bytes long. - * - * `read` is conceptually similar to C's `fread` function. - * - * # Examples - * - * None right now. - */ - fn read(&self, bytes: &mut [u8], len: uint) -> uint; - - /** - * Reads a single byte, advancing the cursor. - * - * In the case of an EOF or an error, returns a negative value. - * - * `read_byte` is conceptually similar to C's `getc` function. - * - * # Examples - * - * None right now. - */ - fn read_byte(&self) -> int; - - /** - * Returns a boolean value: are we currently at EOF? - * - * `eof` is conceptually similar to C's `feof` function. - * - * # Examples - * - * None right now. - */ - fn eof(&self) -> bool; - - /** - * Seek to a given `position` in the stream. - * - * Takes an optional SeekStyle, which affects how we seek from the - * position. See `SeekStyle` docs for more details. - * - * `seek` is conceptually similar to C's `fseek` function. - * - * # Examples - * - * None right now. - */ - fn seek(&self, position: int, style: SeekStyle); - - /** - * Returns the current position within the stream. - * - * `tell` is conceptually similar to C's `ftell` function. - * - * # Examples - * - * None right now. - */ - fn tell(&self) -> uint; -} - -impl Reader for @Reader { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.read(bytes, len) - } - fn read_byte(&self) -> int { - self.read_byte() - } - fn eof(&self) -> bool { - self.eof() - } - fn seek(&self, position: int, style: SeekStyle) { - self.seek(position, style) - } - fn tell(&self) -> uint { - self.tell() - } -} - -/** -* The `ReaderUtil` trait is a home for many of the utility functions -* a particular Reader should implement. -* -* The default `Reader` trait is focused entirely on bytes. `ReaderUtil` is based -* on higher-level concepts like 'chars' and 'lines.' -* -* # Examples: -* -* None right now. -*/ -pub trait ReaderUtil { - - /** - * Reads `len` number of bytes, and gives you a new vector back. - * - * # Examples - * - * None right now. - */ - fn read_bytes(&self, len: uint) -> ~[u8]; - - /** - * Reads up until a specific byte is seen or EOF. - * - * The `include` parameter specifies if the character should be included - * in the returned string. - * - * # Examples - * - * None right now. - */ - fn read_until(&self, c: u8, include: bool) -> ~str; - - /** - * Reads up until the first '\n' or EOF. - * - * The '\n' is not included in the result. - * - * # Examples - * - * None right now. - */ - fn read_line(&self) -> ~str; - - /** - * Reads `n` chars. - * - * Assumes that those chars are UTF-8 encoded. - * - * The '\n' is not included in the result. - * - * # Examples - * - * None right now. - */ - fn read_chars(&self, n: uint) -> ~[char]; - - /** - * Reads a single UTF-8 encoded char. - * - * # Examples - * - * None right now. - */ - fn read_char(&self) -> char; - - /** - * Reads up until the first null byte or EOF. - * - * The null byte is not returned. - * - * # Examples - * - * None right now. - */ - fn read_c_str(&self) -> ~str; - - /** - * Reads all remaining data in the stream. - * - * # Examples - * - * None right now. - */ - fn read_whole_stream(&self) -> ~[u8]; - - /** - * Iterate over every byte until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_byte(&self, it: &fn(int) -> bool) -> bool; - - /** - * Iterate over every char until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_char(&self, it: &fn(char) -> bool) -> bool; - - /** - * Iterate over every line until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_line(&self, it: &fn(&str) -> bool) -> bool; - - /** - * Reads all of the lines in the stream. - * - * Returns a vector of those lines. - * - * # Examples - * - * None right now. - */ - fn read_lines(&self) -> ~[~str]; - - /** - * Reads `n` little-endian unsigned integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_le_uint_n(&self, nbytes: uint) -> u64; - - /** - * Reads `n` little-endian signed integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_le_int_n(&self, nbytes: uint) -> i64; - - /** - * Reads `n` big-endian unsigned integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_be_uint_n(&self, nbytes: uint) -> u64; - - /** - * Reads `n` big-endian signed integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_be_int_n(&self, nbytes: uint) -> i64; - - /** - * Reads a little-endian unsigned integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_le_uint(&self) -> uint; - - /** - * Reads a little-endian integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_le_int(&self) -> int; - - /** - * Reads a big-endian unsigned integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_be_uint(&self) -> uint; - - /** - * Reads a big-endian integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_be_int(&self) -> int; - - /** - * Reads a big-endian `u64`. - * - * `u64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u64(&self) -> u64; - - /** - * Reads a big-endian `u32`. - * - * `u32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u32(&self) -> u32; - - /** - * Reads a big-endian `u16`. - * - * `u16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u16(&self) -> u16; - - /** - * Reads a big-endian `i64`. - * - * `i64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i64(&self) -> i64; - - /** - * Reads a big-endian `i32`. - * - * `i32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i32(&self) -> i32; - - /** - * Reads a big-endian `i16`. - * - * `i16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i16(&self) -> i16; - - /** - * Reads a big-endian `f64`. - * - * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_be_f64(&self) -> f64; - - /** - * Reads a big-endian `f32`. - * - * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_be_f32(&self) -> f32; - - /** - * Reads a little-endian `u64`. - * - * `u64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u64(&self) -> u64; - - /** - * Reads a little-endian `u32`. - * - * `u32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u32(&self) -> u32; - - /** - * Reads a little-endian `u16`. - * - * `u16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u16(&self) -> u16; - - /** - * Reads a little-endian `i64`. - * - * `i64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i64(&self) -> i64; - - /** - * Reads a little-endian `i32`. - * - * `i32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i32(&self) -> i32; - - /** - * Reads a little-endian `i16`. - * - * `i16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i16(&self) -> i16; - - /** - * Reads a little-endian `f64`. - * - * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_le_f64(&self) -> f64; - - /** - * Reads a little-endian `f32`. - * - * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_le_f32(&self) -> f32; - - /** - * Read a u8. - * - * `u8`s are 1 byte. - * - * # Examples - * - * None right now. - */ - fn read_u8(&self) -> u8; - - /** - * Read an i8. - * - * `i8`s are 1 byte. - * - * # Examples - * - * None right now. - */ - fn read_i8(&self) -> i8; -} - -impl<T:Reader> ReaderUtil for T { - - fn read_bytes(&self,len: uint) -> ~[u8] { - let mut bytes = vec::with_capacity(len); - unsafe { vec::raw::set_len(&mut bytes, len); } - - let count = self.read(bytes, len); - - unsafe { vec::raw::set_len(&mut bytes, count); } - bytes - } - - fn read_until(&self, c: u8, include: bool) -> ~str { - let mut bytes = ~[]; - loop { - let ch = self.read_byte(); - if ch == -1 || ch == c as int { - if include && ch == c as int { - bytes.push(ch as u8); - } - break; - } - bytes.push(ch as u8); - } - str::from_bytes(bytes) - } - - fn read_line(&self) -> ~str { - self.read_until('\n' as u8, false) - } - - fn read_chars(&self, n: uint) -> ~[char] { - // returns the (consumed offset, n_req), appends characters to &chars - fn chars_from_bytes<T:Reader>(bytes: &~[u8], chars: &mut ~[char]) - -> (uint, uint) { - let mut i = 0; - let bytes_len = bytes.len(); - while i < bytes_len { - let b0 = bytes[i]; - let w = str::utf8_char_width(b0); - let end = i + w; - i += 1; - assert!((w > 0)); - if w == 1 { - chars.push(b0 as char); - loop; - } - // can't satisfy this char with the existing data - if end > bytes_len { - return (i - 1, end - bytes_len); - } - let mut val = 0; - while i < end { - let next = bytes[i] as int; - i += 1; - assert!((next > -1)); - assert_eq!(next & 192, 128); - val <<= 6; - val += (next & 63) as uint; - } - // See str::char_at - val += ((b0 << ((w + 1) as u8)) as uint) - << (w - 1) * 6 - w - 1u; - chars.push(val as char); - } - return (i, 0); - } - let mut bytes = ~[]; - let mut chars = ~[]; - // might need more bytes, but reading n will never over-read - let mut nbread = n; - while nbread > 0 { - let data = self.read_bytes(nbread); - if data.is_empty() { - // eof - FIXME (#2004): should we do something if - // we're split in a unicode char? - break; - } - bytes.push_all(data); - let (offset, nbreq) = chars_from_bytes::<T>(&bytes, &mut chars); - let ncreq = n - chars.len(); - // again we either know we need a certain number of bytes - // to complete a character, or we make sure we don't - // over-read by reading 1-byte per char needed - nbread = if ncreq > nbreq { ncreq } else { nbreq }; - if nbread > 0 { - bytes = vec::slice(bytes, offset, bytes.len()).to_vec(); - } - } - chars - } - - fn read_char(&self) -> char { - let c = self.read_chars(1); - if c.len() == 0 { - return -1 as char; // FIXME will this stay valid? // #2004 - } - assert_eq!(c.len(), 1); - return c[0]; - } - - fn read_c_str(&self) -> ~str { - self.read_until(0u8, false) - } - - fn read_whole_stream(&self) -> ~[u8] { - let mut bytes: ~[u8] = ~[]; - while !self.eof() { bytes.push_all(self.read_bytes(2048u)); } - bytes - } - - fn each_byte(&self, it: &fn(int) -> bool) -> bool { - while !self.eof() { - if !it(self.read_byte()) { return false; } - } - return true; - } - - fn each_char(&self, it: &fn(char) -> bool) -> bool { - while !self.eof() { - if !it(self.read_char()) { return false; } - } - return true; - } - - fn each_line(&self, it: &fn(s: &str) -> bool) -> bool { - while !self.eof() { - // include the \n, so that we can distinguish an entirely empty - // line read after "...\n", and the trailing empty line in - // "...\n\n". - let mut line = self.read_until('\n' as u8, true); - - // blank line at the end of the reader is ignored - if self.eof() && line.is_empty() { break; } - - // trim the \n, so that each_line is consistent with read_line - let n = str::len(line); - if line[n-1] == '\n' as u8 { - unsafe { str::raw::set_len(&mut line, n-1); } - } - - if !it(line) { return false; } - } - return true; - } - - fn read_lines(&self) -> ~[~str] { - do vec::build |push| { - for self.each_line |line| { - push(str::to_owned(line)); - } - } - } - - // FIXME int reading methods need to deal with eof - issue #2004 - - fn read_le_uint_n(&self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64, pos = 0, i = nbytes; - while i > 0 { - val += (self.read_u8() as u64) << pos; - pos += 8; - i -= 1; - } - val - } - - fn read_le_int_n(&self, nbytes: uint) -> i64 { - extend_sign(self.read_le_uint_n(nbytes), nbytes) - } - - fn read_be_uint_n(&self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64, i = nbytes; - while i > 0 { - i -= 1; - val += (self.read_u8() as u64) << i * 8; - } - val - } - - fn read_be_int_n(&self, nbytes: uint) -> i64 { - extend_sign(self.read_be_uint_n(nbytes), nbytes) - } - - fn read_le_uint(&self) -> uint { - self.read_le_uint_n(uint::bytes) as uint - } - - fn read_le_int(&self) -> int { - self.read_le_int_n(int::bytes) as int - } - - fn read_be_uint(&self) -> uint { - self.read_be_uint_n(uint::bytes) as uint - } - - fn read_be_int(&self) -> int { - self.read_be_int_n(int::bytes) as int - } - - fn read_be_u64(&self) -> u64 { - self.read_be_uint_n(8) as u64 - } - - fn read_be_u32(&self) -> u32 { - self.read_be_uint_n(4) as u32 - } - - fn read_be_u16(&self) -> u16 { - self.read_be_uint_n(2) as u16 - } - - fn read_be_i64(&self) -> i64 { - self.read_be_int_n(8) as i64 - } - - fn read_be_i32(&self) -> i32 { - self.read_be_int_n(4) as i32 - } - - fn read_be_i16(&self) -> i16 { - self.read_be_int_n(2) as i16 - } - - fn read_be_f64(&self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_be_u64()) - } - } - - fn read_be_f32(&self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_be_u32()) - } - } - - fn read_le_u64(&self) -> u64 { - self.read_le_uint_n(8) as u64 - } - - fn read_le_u32(&self) -> u32 { - self.read_le_uint_n(4) as u32 - } - - fn read_le_u16(&self) -> u16 { - self.read_le_uint_n(2) as u16 - } - - fn read_le_i64(&self) -> i64 { - self.read_le_int_n(8) as i64 - } - - fn read_le_i32(&self) -> i32 { - self.read_le_int_n(4) as i32 - } - - fn read_le_i16(&self) -> i16 { - self.read_le_int_n(2) as i16 - } - - fn read_le_f64(&self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_le_u64()) - } - } - - fn read_le_f32(&self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_le_u32()) - } - } - - fn read_u8(&self) -> u8 { - self.read_byte() as u8 - } - - fn read_i8(&self) -> i8 { - self.read_byte() as i8 - } -} - -fn extend_sign(val: u64, nbytes: uint) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -// Reader implementations - -fn convert_whence(whence: SeekStyle) -> i32 { - return match whence { - SeekSet => 0i32, - SeekCur => 1i32, - SeekEnd => 2i32 - }; -} - -impl Reader for *libc::FILE { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - unsafe { - do vec::as_mut_buf(bytes) |buf_p, buf_len| { - assert!(buf_len >= len); - - let count = libc::fread(buf_p as *mut c_void, 1u as size_t, - len as size_t, *self) as uint; - if count < len { - match libc::ferror(*self) { - 0 => (), - _ => { - error!("error reading buffer"); - error!("%s", os::last_os_error()); - fail!(); - } - } - } - - count - } - } - } - fn read_byte(&self) -> int { - unsafe { - libc::fgetc(*self) as int - } - } - fn eof(&self) -> bool { - unsafe { - return libc::feof(*self) != 0 as c_int; - } - } - fn seek(&self, offset: int, whence: SeekStyle) { - unsafe { - assert!(libc::fseek(*self, - offset as c_long, - convert_whence(whence)) == 0 as c_int); - } - } - fn tell(&self) -> uint { - unsafe { - return libc::ftell(*self) as uint; - } - } -} - -struct Wrapper<T, C> { - base: T, - cleanup: C, -} - -// A forwarding impl of reader that also holds on to a resource for the -// duration of its lifetime. -// FIXME there really should be a better way to do this // #2004 -impl<R:Reader,C> Reader for Wrapper<R, C> { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.base.read(bytes, len) - } - fn read_byte(&self) -> int { self.base.read_byte() } - fn eof(&self) -> bool { self.base.eof() } - fn seek(&self, off: int, whence: SeekStyle) { - self.base.seek(off, whence) - } - fn tell(&self) -> uint { self.base.tell() } -} - -pub struct FILERes { - f: *libc::FILE, -} - -impl Drop for FILERes { - fn finalize(&self) { - unsafe { - libc::fclose(self.f); - } - } -} - -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 - } else { - @f as @Reader - } -} - -// FIXME (#2004): this should either be an trait-less impl, a set of -// top-level functions that take a reader, or a set of default methods on -// reader (which can then be called reader) - -/** -* Gives a `Reader` that allows you to read values from standard input. -* -* # Examples -* ~~~ -* let stdin = core::io::stdin(); -* let line = stdin.read_line(); -* core::io::print(line); -* ~~~ -*/ -pub fn stdin() -> @Reader { - unsafe { - @rustrt::rust_get_stdin() as @Reader - } -} - -pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { - unsafe { - let f = os::as_c_charp(path.to_str(), |pathbuf| { - os::as_c_charp("r", |modebuf| - libc::fopen(pathbuf, modebuf) - ) - }); - return if f as uint == 0u { result::Err(~"error opening " - + path.to_str()) } - else { - result::Ok(FILE_reader(f, true)) - } - } -} - - -// Byte readers -pub struct BytesReader<'self> { - bytes: &'self [u8], - pos: @mut uint -} - -impl<'self> Reader for BytesReader<'self> { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - let count = uint::min(len, self.bytes.len() - *self.pos); - - let view = vec::slice(self.bytes, *self.pos, self.bytes.len()); - vec::bytes::copy_memory(bytes, view, count); - - *self.pos += count; - - count - } - - fn read_byte(&self) -> int { - if *self.pos == self.bytes.len() { - return -1; - } - - let b = self.bytes[*self.pos]; - *self.pos += 1u; - b as int - } - - fn eof(&self) -> bool { - *self.pos == self.bytes.len() - } - - fn seek(&self, offset: int, whence: SeekStyle) { - let pos = *self.pos; - *self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence); - } - - fn tell(&self) -> uint { - *self.pos - } -} - -pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T { - f(@BytesReader { - bytes: bytes, - pos: @mut 0 - } as @Reader) -} - -pub fn with_str_reader<T>(s: &str, f: &fn(@Reader) -> T) -> T { - str::byte_slice(s, |bytes| with_bytes_reader(bytes, f)) -} - -// Writing -pub enum FileFlag { Append, Create, Truncate, NoFlag, } - -// What type of writer are we? -#[deriving(Eq)] -pub enum WriterType { Screen, File } - -// FIXME (#2004): Seekable really should be orthogonal. -// FIXME (#2004): eventually u64 -/// The raw underlying writer trait. All writers must implement this. -pub trait Writer { - - /// Write all of the given bytes. - fn write(&self, v: &[u8]); - - /// Move the current position within the stream. The second parameter - /// determines the position that the first parameter is relative to. - fn seek(&self, int, SeekStyle); - - /// Return the current position within the stream. - fn tell(&self) -> uint; - - /// Flush the output buffer for this stream (if there is one). - fn flush(&self) -> int; - - /// Determine if this Writer is writing to a file or not. - fn get_type(&self) -> WriterType; -} - -impl Writer for @Writer { - fn write(&self, v: &[u8]) { self.write(v) } - fn seek(&self, a: int, b: SeekStyle) { self.seek(a, b) } - fn tell(&self) -> uint { self.tell() } - fn flush(&self) -> int { self.flush() } - fn get_type(&self) -> WriterType { self.get_type() } -} - -impl<W:Writer,C> Writer for Wrapper<W, C> { - fn write(&self, bs: &[u8]) { self.base.write(bs); } - fn seek(&self, off: int, style: SeekStyle) { self.base.seek(off, style); } - fn tell(&self) -> uint { self.base.tell() } - fn flush(&self) -> int { self.base.flush() } - fn get_type(&self) -> WriterType { File } -} - -impl Writer for *libc::FILE { - fn write(&self, v: &[u8]) { - unsafe { - do vec::as_const_buf(v) |vbuf, len| { - let nout = libc::fwrite(vbuf as *c_void, - 1, - len as size_t, - *self); - if nout != len as size_t { - error!("error writing buffer"); - error!("%s", os::last_os_error()); - fail!(); - } - } - } - } - fn seek(&self, offset: int, whence: SeekStyle) { - unsafe { - assert!(libc::fseek(*self, - offset as c_long, - convert_whence(whence)) == 0 as c_int); - } - } - fn tell(&self) -> uint { - unsafe { - libc::ftell(*self) as uint - } - } - fn flush(&self) -> int { - unsafe { - libc::fflush(*self) as int - } - } - fn get_type(&self) -> WriterType { - unsafe { - let fd = libc::fileno(*self); - if libc::isatty(fd) == 0 { File } - else { Screen } - } - } -} - -pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer { - if cleanup { - @Wrapper { base: f, cleanup: FILERes(f) } as @Writer - } else { - @f as @Writer - } -} - -impl Writer for fd_t { - fn write(&self, v: &[u8]) { - unsafe { - let mut count = 0u; - do vec::as_const_buf(v) |vbuf, len| { - while count < len { - let vb = ptr::const_offset(vbuf, count) as *c_void; - let nout = libc::write(*self, vb, len as size_t); - if nout < 0 as ssize_t { - error!("error writing buffer"); - error!("%s", os::last_os_error()); - fail!(); - } - count += nout as uint; - } - } - } - } - fn seek(&self, _offset: int, _whence: SeekStyle) { - error!("need 64-bit foreign calls for seek, sorry"); - fail!(); - } - fn tell(&self) -> uint { - error!("need 64-bit foreign calls for tell, sorry"); - fail!(); - } - fn flush(&self) -> int { 0 } - fn get_type(&self) -> WriterType { - unsafe { - if libc::isatty(*self) == 0 { File } else { Screen } - } - } -} - -pub struct FdRes { - fd: fd_t, -} - -impl Drop for FdRes { - fn finalize(&self) { - unsafe { - libc::close(self.fd); - } - } -} - -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 - } else { - @fd as @Writer - } -} - - -pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) - -> Result<@Writer, ~str> { - #[cfg(windows)] - fn wb() -> c_int { - (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int - } - - #[cfg(unix)] - fn wb() -> c_int { O_WRONLY as c_int } - - let mut fflags: c_int = wb(); - for flags.each |f| { - match *f { - Append => fflags |= O_APPEND as c_int, - Create => fflags |= O_CREAT as c_int, - Truncate => fflags |= O_TRUNC as c_int, - NoFlag => () - } - } - let fd = unsafe { - do os::as_c_charp(path.to_str()) |pathbuf| { - libc::open(pathbuf, fflags, - (S_IRUSR | S_IWUSR) as c_int) - } - }; - if fd < (0 as c_int) { - result::Err(fmt!("error opening %s: %s", path.to_str(), - os::last_os_error())) - } else { - result::Ok(fd_writer(fd, true)) - } -} - -pub fn u64_to_le_bytes<T>(n: u64, size: uint, - f: &fn(v: &[u8]) -> T) -> T { - assert!(size <= 8u); - match size { - 1u => f(&[n as u8]), - 2u => f(&[n as u8, - (n >> 8) as u8]), - 4u => f(&[n as u8, - (n >> 8) as u8, - (n >> 16) as u8, - (n >> 24) as u8]), - 8u => f(&[n as u8, - (n >> 8) as u8, - (n >> 16) as u8, - (n >> 24) as u8, - (n >> 32) as u8, - (n >> 40) as u8, - (n >> 48) as u8, - (n >> 56) as u8]), - _ => { - - let mut bytes: ~[u8] = ~[], i = size, n = n; - while i > 0u { - bytes.push((n & 255_u64) as u8); - n >>= 8_u64; - i -= 1u; - } - f(bytes) - } - } -} - -pub fn u64_to_be_bytes<T>(n: u64, size: uint, - f: &fn(v: &[u8]) -> T) -> T { - assert!(size <= 8u); - match size { - 1u => f(&[n as u8]), - 2u => f(&[(n >> 8) as u8, - n as u8]), - 4u => f(&[(n >> 24) as u8, - (n >> 16) as u8, - (n >> 8) as u8, - n as u8]), - 8u => f(&[(n >> 56) as u8, - (n >> 48) as u8, - (n >> 40) as u8, - (n >> 32) as u8, - (n >> 24) as u8, - (n >> 16) as u8, - (n >> 8) as u8, - n as u8]), - _ => { - let mut bytes: ~[u8] = ~[]; - let mut i = size; - while i > 0u { - let shift = ((i - 1u) * 8u) as u64; - bytes.push((n >> shift) as u8); - i -= 1u; - } - f(bytes) - } - } -} - -pub fn u64_from_be_bytes(data: &[u8], - start: uint, - size: uint) - -> u64 { - let mut sz = size; - assert!((sz <= 8u)); - let mut val = 0_u64; - let mut pos = start; - while sz > 0u { - sz -= 1u; - val += (data[pos] as u64) << ((sz * 8u) as u64); - pos += 1u; - } - return val; -} - -// FIXME: #3048 combine trait+impl (or just move these to -// default methods on writer) -/// Generic utility functions defined on writers. -pub trait WriterUtil { - - /// Write a single utf-8 encoded char. - fn write_char(&self, ch: char); - - /// Write every char in the given str, encoded as utf-8. - fn write_str(&self, s: &str); - - /// Write the given str, as utf-8, followed by '\n'. - fn write_line(&self, s: &str); - - /// Write the result of passing n through `int::to_str_bytes`. - fn write_int(&self, n: int); - - /// Write the result of passing n through `uint::to_str_bytes`. - fn write_uint(&self, n: uint); - - /// Write a little-endian uint (number of bytes depends on system). - fn write_le_uint(&self, n: uint); - - /// Write a little-endian int (number of bytes depends on system). - fn write_le_int(&self, n: int); - - /// Write a big-endian uint (number of bytes depends on system). - fn write_be_uint(&self, n: uint); - - /// Write a big-endian int (number of bytes depends on system). - fn write_be_int(&self, n: int); - - /// Write a big-endian u64 (8 bytes). - fn write_be_u64(&self, n: u64); - - /// Write a big-endian u32 (4 bytes). - fn write_be_u32(&self, n: u32); - - /// Write a big-endian u16 (2 bytes). - fn write_be_u16(&self, n: u16); - - /// Write a big-endian i64 (8 bytes). - fn write_be_i64(&self, n: i64); - - /// Write a big-endian i32 (4 bytes). - fn write_be_i32(&self, n: i32); - - /// Write a big-endian i16 (2 bytes). - fn write_be_i16(&self, n: i16); - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - fn write_be_f64(&self, f: f64); - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - fn write_be_f32(&self, f: f32); - - /// Write a little-endian u64 (8 bytes). - fn write_le_u64(&self, n: u64); - - /// Write a little-endian u32 (4 bytes). - fn write_le_u32(&self, n: u32); - - /// Write a little-endian u16 (2 bytes). - fn write_le_u16(&self, n: u16); - - /// Write a little-endian i64 (8 bytes). - fn write_le_i64(&self, n: i64); - - /// Write a little-endian i32 (4 bytes). - fn write_le_i32(&self, n: i32); - - /// Write a little-endian i16 (2 bytes). - fn write_le_i16(&self, n: i16); - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - fn write_le_f64(&self, f: f64); - - /// Write a litten-endian IEEE754 single-precision floating-point - /// (4 bytes). - fn write_le_f32(&self, f: f32); - - /// Write a u8 (1 byte). - fn write_u8(&self, n: u8); - - /// Write a i8 (1 byte). - fn write_i8(&self, n: i8); -} - -impl<T:Writer> WriterUtil for T { - fn write_char(&self, ch: char) { - if (ch as uint) < 128u { - self.write(&[ch as u8]); - } else { - self.write_str(str::from_char(ch)); - } - } - fn write_str(&self, s: &str) { str::byte_slice(s, |v| self.write(v)) } - fn write_line(&self, s: &str) { - self.write_str(s); - self.write_str(&"\n"); - } - fn write_int(&self, n: int) { - int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - fn write_uint(&self, n: uint) { - uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - fn write_le_uint(&self, n: uint) { - u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - fn write_le_int(&self, n: int) { - u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v)) - } - fn write_be_uint(&self, n: uint) { - u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - fn write_be_int(&self, n: int) { - u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v)) - } - fn write_be_u64(&self, n: u64) { - u64_to_be_bytes(n, 8u, |v| self.write(v)) - } - fn write_be_u32(&self, n: u32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_be_u16(&self, n: u16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_be_i64(&self, n: i64) { - u64_to_be_bytes(n as u64, 8u, |v| self.write(v)) - } - fn write_be_i32(&self, n: i32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_be_i16(&self, n: i16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_be_f64(&self, f:f64) { - unsafe { - self.write_be_u64(cast::transmute(f)) - } - } - fn write_be_f32(&self, f:f32) { - unsafe { - self.write_be_u32(cast::transmute(f)) - } - } - fn write_le_u64(&self, n: u64) { - u64_to_le_bytes(n, 8u, |v| self.write(v)) - } - fn write_le_u32(&self, n: u32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_le_u16(&self, n: u16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_le_i64(&self, n: i64) { - u64_to_le_bytes(n as u64, 8u, |v| self.write(v)) - } - fn write_le_i32(&self, n: i32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_le_i16(&self, n: i16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_le_f64(&self, f:f64) { - unsafe { - self.write_le_u64(cast::transmute(f)) - } - } - fn write_le_f32(&self, f:f32) { - unsafe { - self.write_le_u32(cast::transmute(f)) - } - } - - fn write_u8(&self, n: u8) { self.write([n]) } - fn write_i8(&self, n: i8) { self.write([n as u8]) } - -} - -#[allow(non_implicitly_copyable_typarams)] -pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> { - mk_file_writer(path, flags).chain(|w| result::Ok(w)) -} - - -// FIXME: fileflags // #2004 -pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> { - unsafe { - let f = do os::as_c_charp(path.to_str()) |pathbuf| { - do os::as_c_charp("w") |modebuf| { - libc::fopen(pathbuf, modebuf) - } - }; - return if f as uint == 0u { - result::Err(~"error opening " + path.to_str()) - } else { - result::Ok(FILE_writer(f, true)) - } - } -} - -// FIXME (#2004) it would be great if this could be a const -// FIXME (#2004) why are these different from the way stdin() is -// implemented? - - -/** -* Gives a `Writer` which allows you to write to the standard output. -* -* # Examples -* ~~~ -* let stdout = core::io::stdout(); -* stdout.write_str("hello\n"); -* ~~~ -*/ -pub fn stdout() -> @Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) } - -/** -* Gives a `Writer` which allows you to write to standard error. -* -* # Examples -* ~~~ -* let stderr = core::io::stderr(); -* stderr.write_str("hello\n"); -* ~~~ -*/ -pub fn stderr() -> @Writer { fd_writer(libc::STDERR_FILENO as c_int, false) } - -/** -* Prints a string to standard output. -* -* This string will not have an implicit newline at the end. If you want -* an implicit newline, please see `println`. -* -* # Examples -* ~~~ -* // print is imported into the prelude, and so is always available. -* print("hello"); -* ~~~ -*/ -pub fn print(s: &str) { - stdout().write_str(s); -} - -/** -* Prints a string to standard output, followed by a newline. -* -* If you do not want an implicit newline, please see `print`. -* -* # Examples -* ~~~ -* // println is imported into the prelude, and so is always available. -* println("hello"); -* ~~~ -*/ -pub fn println(s: &str) { - stdout().write_line(s); -} - -pub struct BytesWriter { - bytes: @mut ~[u8], - pos: @mut uint, -} - -impl Writer for BytesWriter { - fn write(&self, v: &[u8]) { - let v_len = v.len(); - - let bytes = &mut *self.bytes; - let count = uint::max(bytes.len(), *self.pos + v_len); - vec::reserve(bytes, count); - - unsafe { - // Silly stage0 borrow check workaround... - let casted: &mut ~[u8] = cast::transmute_copy(&bytes); - vec::raw::set_len(casted, count); - - let view = vec::mut_slice(*bytes, *self.pos, count); - vec::bytes::copy_memory(view, v, v_len); - } - - *self.pos += v_len; - } - - fn seek(&self, offset: int, whence: SeekStyle) { - let pos = *self.pos; - let len = vec::uniq_len(&const *self.bytes); - *self.pos = seek_in_buf(offset, pos, len, whence); - } - - fn tell(&self) -> uint { - *self.pos - } - - fn flush(&self) -> int { - 0 - } - - fn get_type(&self) -> WriterType { - File - } -} - -pub fn BytesWriter() -> BytesWriter { - BytesWriter { - bytes: @mut ~[], - pos: @mut 0 - } -} - -pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] { - let wr = @BytesWriter(); - f(wr as @Writer); - let @BytesWriter { bytes, _ } = wr; - copy *bytes -} - -pub fn with_str_writer(f: &fn(@Writer)) -> ~str { - let mut v = with_bytes_writer(f); - - // Make sure the vector has a trailing null and is proper utf8. - v.push(0); - assert!(str::is_utf8(v)); - - unsafe { - ::cast::transmute(v) - } -} - -// Utility functions -pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> - uint { - let mut bpos = pos as int; - let blen = len as int; - match whence { - SeekSet => bpos = offset, - SeekCur => bpos += offset, - SeekEnd => bpos = blen + offset - } - if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; } - return bpos as uint; -} - -#[allow(non_implicitly_copyable_typarams)] -pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> { - result::chain(read_whole_file(file), |bytes| { - if str::is_utf8(bytes) { - result::Ok(str::from_bytes(bytes)) - } else { - result::Err(file.to_str() + ~" is not UTF-8") - } - }) -} - -// FIXME (#2004): implement this in a low-level way. Going through the -// abstractions is pointless. -#[allow(non_implicitly_copyable_typarams)] -pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> { - result::chain(file_reader(file), |rdr| { - result::Ok(rdr.read_whole_stream()) - }) -} - -// fsync related - -pub mod fsync { - use io::{FILERes, FdRes, fd_t}; - use kinds::Copy; - use libc; - use ops::Drop; - use option::{None, Option, Some}; - use os; - - pub enum Level { - // whatever fsync does on that platform - FSync, - - // fdatasync on linux, similiar or more on other platforms - FDataSync, - - // full fsync - // - // You must additionally sync the parent directory as well! - FullFSync, - } - - - // Artifacts that need to fsync on destruction - pub struct Res<t> { - arg: Arg<t>, - } - - #[unsafe_destructor] - impl<T:Copy> Drop for Res<T> { - fn finalize(&self) { - match self.arg.opt_level { - None => (), - Some(level) => { - // fail hard if not succesful - assert!(((self.arg.fsync_fn)(self.arg.val, level) - != -1)); - } - } - } - } - - pub fn Res<t: Copy>(arg: Arg<t>) -> Res<t>{ - Res { - arg: arg - } - } - - pub struct Arg<t> { - val: t, - opt_level: Option<Level>, - fsync_fn: @fn(f: t, Level) -> int, - } - - // fsync file after executing blk - // FIXME (#2004) find better way to create resources within lifetime of - // outer res - pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>, - blk: &fn(v: Res<*libc::FILE>)) { - blk(Res(Arg { - val: file.f, opt_level: opt_level, - fsync_fn: |file, l| { - unsafe { - os::fsync_fd(libc::fileno(file), l) as int - } - } - })); - } - - // 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 { - val: fd.fd, opt_level: opt_level, - fsync_fn: |fd, l| os::fsync_fd(fd, l) as int - })); - } - - // Type of objects that may want to fsync - pub trait FSyncable { fn fsync(&self, l: Level) -> int; } - - // Call o.fsync after executing blk - pub fn obj_sync(o: @FSyncable, opt_level: Option<Level>, - blk: &fn(v: Res<@FSyncable>)) { - blk(Res(Arg { - val: o, opt_level: opt_level, - fsync_fn: |o, l| o.fsync(l) - })); - } -} - -#[cfg(test)] -mod tests { - use i32; - use io::{BytesWriter, SeekCur, SeekEnd, SeekSet}; - use io; - use path::Path; - use result; - use str; - use u64; - use vec; - - #[test] - fn test_simple() { - let tmpfile = &Path("tmp/lib-io-test-simple.tmp"); - debug!(tmpfile); - let frood: ~str = - ~"A hoopy frood who really knows where his towel is."; - debug!(copy frood); - { - let out: @io::Writer = - result::get( - &io::file_writer(tmpfile, ~[io::Create, io::Truncate])); - out.write_str(frood); - } - let inp: @io::Reader = result::get(&io::file_reader(tmpfile)); - let frood2: ~str = inp.read_c_str(); - debug!(copy frood2); - assert_eq!(frood, frood2); - } - - #[test] - fn test_readchars_empty() { - do io::with_str_reader(~"") |inp| { - let res : ~[char] = inp.read_chars(128); - assert_eq!(res.len(), 0); - } - } - - #[test] - fn test_read_line_utf8() { - do io::with_str_reader(~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤") |inp| { - let line = inp.read_line(); - assert_eq!(line, ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤"); - } - } - - #[test] - fn test_read_lines() { - do io::with_str_reader(~"a\nb\nc\n") |inp| { - assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]); - } - - do io::with_str_reader(~"a\nb\nc") |inp| { - assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]); - } - - do io::with_str_reader(~"") |inp| { - assert!(inp.read_lines().is_empty()); - } - } - - #[test] - fn test_readchars_wide() { - let wide_test = ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤"; - let ivals : ~[int] = ~[ - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748, - 104, 101, 108, 108, 111, - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748]; - fn check_read_ln(len : uint, s: &str, ivals: &[int]) { - do io::with_str_reader(s) |inp| { - let res : ~[char] = inp.read_chars(len); - if len <= ivals.len() { - assert_eq!(res.len(), len); - } - assert!(vec::slice(ivals, 0u, res.len()) == - vec::map(res, |x| *x as int)); - } - } - let mut i = 0; - while i < 8 { - check_read_ln(i, wide_test, ivals); - i += 1; - } - // check a long read for good measure - check_read_ln(128, wide_test, ivals); - } - - #[test] - fn test_readchar() { - do io::with_str_reader(~"生") |inp| { - let res : char = inp.read_char(); - assert_eq!(res as int, 29983); - } - } - - #[test] - fn test_readchar_empty() { - do io::with_str_reader(~"") |inp| { - let res : char = inp.read_char(); - assert_eq!(res as int, -1); - } - } - - #[test] - fn file_reader_not_exist() { - match io::file_reader(&Path("not a file")) { - result::Err(copy e) => { - assert_eq!(e, ~"error opening not a file"); - } - result::Ok(_) => fail!() - } - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_read_buffer_too_small() { - let path = &Path("tmp/lib-io-test-read-buffer-too-small.tmp"); - // ensure the file exists - io::file_writer(path, [io::Create]).get(); - - let file = io::file_reader(path).get(); - let mut buf = vec::from_elem(5, 0); - file.read(buf, 6); // this should fail because buf is too small - } - - #[test] - fn test_read_buffer_big_enough() { - let path = &Path("tmp/lib-io-test-read-buffer-big-enough.tmp"); - // ensure the file exists - io::file_writer(path, [io::Create]).get(); - - let file = io::file_reader(path).get(); - let mut buf = vec::from_elem(5, 0); - file.read(buf, 4); // this should succeed because buf is big enough - } - - #[test] - fn test_write_empty() { - let file = io::file_writer(&Path("tmp/lib-io-test-write-empty.tmp"), - [io::Create]).get(); - file.write([]); - } - - #[test] - fn file_writer_bad_name() { - match io::file_writer(&Path("?/?"), ~[]) { - result::Err(copy e) => { - assert!(str::starts_with(e, "error opening")); - } - result::Ok(_) => fail!() - } - } - - #[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::Ok(_) => fail!() - } - } - - #[test] - fn bytes_buffer_overwrite() { - let wr = BytesWriter(); - wr.write(~[0u8, 1u8, 2u8, 3u8]); - assert!(*wr.bytes == ~[0u8, 1u8, 2u8, 3u8]); - wr.seek(-2, SeekCur); - wr.write(~[4u8, 5u8, 6u8, 7u8]); - assert!(*wr.bytes == ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]); - wr.seek(-2, SeekEnd); - wr.write(~[8u8]); - wr.seek(1, SeekSet); - wr.write(~[9u8]); - assert!(*wr.bytes == ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]); - } - - #[test] - fn test_read_write_le() { - let path = Path("tmp/lib-io-test-read-write-le.tmp"); - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).get(); - for uints.each |i| { - file.write_le_u64(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).get(); - for uints.each |i| { - assert_eq!(file.read_le_u64(), *i); - } - } - } - - #[test] - fn test_read_write_be() { - let path = Path("tmp/lib-io-test-read-write-be.tmp"); - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).get(); - for uints.each |i| { - file.write_be_u64(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).get(); - for uints.each |i| { - assert_eq!(file.read_be_u64(), *i); - } - } - } - - #[test] - fn test_read_be_int_n() { - let path = Path("tmp/lib-io-test-read-be-int-n.tmp"); - let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).get(); - for ints.each |i| { - file.write_be_i32(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).get(); - for ints.each |i| { - // this tests that the sign extension is working - // (comparing the values as i32 would not test this) - assert_eq!(file.read_be_int_n(4), *i as i64); - } - } - } - - #[test] - fn test_read_f32() { - let path = Path("tmp/lib-io-test-read-f32.tmp"); - //big-endian floating-point 8.1250 - let buf = ~[0x41, 0x02, 0x00, 0x00]; - - { - let file = io::file_writer(&path, [io::Create]).get(); - file.write(buf); - } - - { - let file = io::file_reader(&path).get(); - let f = file.read_be_f32(); - assert_eq!(f, 8.1250); - } - } - -#[test] - fn test_read_write_f32() { - let path = Path("tmp/lib-io-test-read-write-f32.tmp"); - let f:f32 = 8.1250; - - { - let file = io::file_writer(&path, [io::Create]).get(); - file.write_be_f32(f); - file.write_le_f32(f); - } - - { - let file = io::file_reader(&path).get(); - assert_eq!(file.read_be_f32(), 8.1250); - assert_eq!(file.read_le_f32(), 8.1250); - } - } -} diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs deleted file mode 100644 index 57a076bb082..00000000000 --- a/src/libcore/iter.rs +++ /dev/null @@ -1,326 +0,0 @@ -// 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. - -/*! Composable internal iterators - -Internal iterators are functions implementing the protocol used by the `for` loop. - -An internal iterator takes `fn(...) -> bool` as a parameter, with returning `false` used to signal -breaking out of iteration. The adaptors in the module work with any such iterator, not just ones -tied to specific traits. For example: - -~~~~ -println(iter::to_vec(|f| uint::range(0, 20, f)).to_str()); -~~~~ - -An external iterator object implementing the interface in the `iterator` module can be used as an -internal iterator by calling the `advance` method. For example: - -~~~~ -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()); -for it.advance |&x: &uint| { - println(x.to_str()); -} -~~~~ - -Internal iterators provide a subset of the functionality of an external iterator. It's not possible -to interleave them to implement algorithms like `zip`, `union` and `merge`. However, they're often -much easier to implement. - -*/ - -use cmp::Ord; -use option::{Option, Some, None}; -use vec::OwnedVector; -use num::{One, Zero}; -use ops::{Add, Mul}; - -pub trait Times { - fn times(&self, it: &fn() -> bool) -> bool; -} - -/** - * Transform an internal iterator into an owned vector. - * - * # Example: - * - * ~~~ - * 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 -} - -/** - * Return true if `predicate` is true for any values yielded by an internal iterator. - * - * Example: - * - * ~~~~ - * let xs = ~[1u, 2, 3, 4, 5]; - * assert!(any(|&x: &uint| x > 2, |f| xs.each(f))); - * assert!(!any(|&x: &uint| x > 5, |f| xs.each(f))); - * ~~~~ - */ -#[inline(always)] -pub fn any<T>(predicate: &fn(T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { - for iter |x| { - if predicate(x) { - return true; - } - } - return false; -} - -/** - * Return true if `predicate` is true for all values yielded by an internal iterator. - * - * # Example: - * - * ~~~~ - * assert!(all(|&x: &uint| x < 6, |f| uint::range(1, 6, f))); - * assert!(!all(|&x: &uint| x < 5, |f| uint::range(1, 6, f))); - * ~~~~ - */ -#[inline(always)] -pub fn all<T>(predicate: &fn(T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> bool { - // If we ever break, iter will return false, so this will only return true - // if predicate returns true for everything. - iter(|x| predicate(x)) -} - -/** - * Return the first element where `predicate` returns `true`. Return `None` if no element is found. - * - * # Example: - * - * ~~~~ - * let xs = ~[1u, 2, 3, 4, 5, 6]; - * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); - * ~~~~ - */ -#[inline(always)] -pub fn find<T>(predicate: &fn(&T) -> bool, - iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> { - for iter |x| { - if predicate(&x) { - return Some(x); - } - } - None -} - -/** - * Return the largest item yielded by an iterator. Return `None` if the iterator is empty. - * - * # Example: - * - * ~~~~ - * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.each(f)).unwrap(), &15); - * ~~~~ - */ -#[inline] -pub fn max<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> { - let mut result = None; - for iter |x| { - match result { - Some(ref mut y) => { - if x > *y { - *y = x; - } - } - None => result = Some(x) - } - } - result -} - -/** - * Return the smallest item yielded by an iterator. Return `None` if the iterator is empty. - * - * # Example: - * - * ~~~~ - * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - * assert_eq!(max(|f| xs.each(f)).unwrap(), &-5); - * ~~~~ - */ -#[inline] -pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> { - let mut result = None; - for iter |x| { - match result { - Some(ref mut y) => { - if x < *y { - *y = x; - } - } - None => result = Some(x) - } - } - result -} - -/** - * Reduce an iterator to an accumulated value. - * - * # Example: - * - * ~~~~ - * assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); - * ~~~~ - */ -#[inline] -pub fn fold<T, U>(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T { - let mut result = start; - for iter |x| { - f(&mut result, x); - } - result -} - -/** - * Reduce an iterator to an accumulated value. - * - * `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it - * forces the iterator to yield borrowed pointers. - * - * # Example: - * - * ~~~~ - * fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - * fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x)) - * } - * ~~~~ - */ -#[inline] -pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T { - let mut result = start; - for iter |x| { - f(&mut result, x); - } - result -} - -/** - * Return the sum of the items yielding by an iterator. - * - * # Example: - * - * ~~~~ - * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do sum |f| { xs.each(f) }, 10); - * ~~~~ - */ -#[inline(always)] -pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - fold_ref(Zero::zero::<T>(), iter, |a, x| *a = a.add(x)) -} - -/** - * Return the product of the items yielded by an iterator. - * - * # Example: - * - * ~~~~ - * let xs: ~[int] = ~[1, 2, 3, 4]; - * assert_eq!(do product |f| { xs.each(f) }, 24); - * ~~~~ - */ -#[inline(always)] -pub fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { - fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x)) -} - -#[cfg(test)] -mod tests { - use super::*; - use prelude::*; - - #[test] - fn test_to_vec() { - let xs = ~[1, 2, 3]; - let ys = do to_vec |f| { xs.each(|x| f(*x)) }; - assert_eq!(xs, ys); - } - - #[test] - fn test_any() { - let xs = ~[1u, 2, 3, 4, 5]; - assert!(any(|&x: &uint| x > 2, |f| xs.each(f))); - assert!(!any(|&x: &uint| x > 5, |f| xs.each(f))); - } - - #[test] - fn test_all() { - assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f))); - assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f))); - } - - #[test] - fn test_find() { - let xs = ~[1u, 2, 3, 4, 5, 6]; - assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); - } - - #[test] - fn test_max() { - let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(max(|f| xs.each(f)).unwrap(), &15); - } - - #[test] - fn test_min() { - let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; - assert_eq!(min(|f| xs.each(f)).unwrap(), &-5); - } - - #[test] - fn test_fold() { - assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); - } - - #[test] - fn test_sum() { - let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do sum |f| { xs.each(f) }, 10); - } - - #[test] - fn test_empty_sum() { - let xs: ~[int] = ~[]; - assert_eq!(do sum |f| { xs.each(f) }, 0); - } - - #[test] - fn test_product() { - let xs: ~[int] = ~[1, 2, 3, 4]; - assert_eq!(do product |f| { xs.each(f) }, 24); - } - - #[test] - fn test_empty_product() { - let xs: ~[int] = ~[]; - assert_eq!(do product |f| { xs.each(f) }, 1); - } -} diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs deleted file mode 100644 index a5679e6dbff..00000000000 --- a/src/libcore/iterator.rs +++ /dev/null @@ -1,719 +0,0 @@ -// 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. - -/*! Composable external iterators - -The `Iterator` trait defines an interface for objects which implement iteration as a state machine. - -Algorithms like `zip` are provided as `Iterator` implementations which wrap other objects -implementing the `Iterator` trait. - -*/ - -use prelude::*; -use num::{Zero, One}; - -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>; -} - -/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also -/// implementations of the `Iterator` trait. -/// -/// 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>; - // FIXME: #5898: should be called map - fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; - fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, Self>; - fn filter_map<'r, B>(self, f: &'r fn(A) -> Option<B>) -> FilterMapIterator<'r, A, B, Self>; - fn enumerate(self) -> EnumerateIterator<Self>; - fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhileIterator<'r, A, Self>; - 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>; - fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>) - -> ScanIterator<'r, A, B, Self, St>; - fn advance(&mut self, f: &fn(A) -> bool) -> bool; - fn to_vec(&mut self) -> ~[A]; - fn nth(&mut self, n: uint) -> Option<A>; - fn last(&mut self) -> Option<A>; - fn fold<B>(&mut self, start: B, f: &fn(B, A) -> B) -> B; - fn count(&mut self) -> uint; - fn all(&mut self, f: &fn(&A) -> bool) -> bool; - fn any(&mut self, f: &fn(&A) -> bool) -> bool; -} - -/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also -/// implementations of the `Iterator` trait. -/// -/// 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> { - ChainIterator{a: self, b: other, flag: false} - } - - #[inline(always)] - fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> { - ZipIterator{a: self, b: other} - } - - // FIXME: #5898: should be called map - #[inline(always)] - fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, T> { - MapIterator{iter: self, f: f} - } - - #[inline(always)] - fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, T> { - FilterIterator{iter: self, predicate: predicate} - } - - #[inline(always)] - fn filter_map<'r, B>(self, f: &'r fn(A) -> Option<B>) -> FilterMapIterator<'r, A, B, T> { - FilterMapIterator { iter: self, f: f } - } - - #[inline(always)] - fn enumerate(self) -> EnumerateIterator<T> { - EnumerateIterator{iter: self, count: 0} - } - - #[inline(always)] - fn skip_while<'r>(self, predicate: &'r fn(&A) -> bool) -> SkipWhileIterator<'r, A, T> { - SkipWhileIterator{iter: self, flag: false, predicate: predicate} - } - - #[inline(always)] - fn take_while<'r>(self, predicate: &'r fn(&A) -> bool) -> TakeWhileIterator<'r, A, T> { - TakeWhileIterator{iter: self, flag: false, predicate: predicate} - } - - #[inline(always)] - fn skip(self, n: uint) -> SkipIterator<T> { - SkipIterator{iter: self, n: n} - } - - #[inline(always)] - fn take(self, n: uint) -> TakeIterator<T> { - TakeIterator{iter: self, n: n} - } - - #[inline(always)] - fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>) - -> ScanIterator<'r, A, B, T, St> { - ScanIterator{iter: self, f: f, state: initial_state} - } - - /// A shim implementing the `for` loop iteration protocol for iterator objects - #[inline] - fn advance(&mut self, f: &fn(A) -> bool) -> bool { - loop { - match self.next() { - Some(x) => { - if !f(x) { return false; } - } - None => { return true; } - } - } - } - - #[inline(always)] - fn to_vec(&mut self) -> ~[A] { - iter::to_vec::<A>(|f| self.advance(f)) - } - - /// Return the `n`th item yielded by an iterator. - #[inline(always)] - fn nth(&mut self, mut n: uint) -> Option<A> { - loop { - match self.next() { - Some(x) => if n == 0 { return Some(x) }, - None => return None - } - n -= 1; - } - } - - /// Return the last item yielded by an iterator. - #[inline(always)] - fn last(&mut self) -> Option<A> { - let mut last = None; - for self.advance |x| { last = Some(x); } - last - } - - /// Reduce an iterator to an accumulated value - #[inline] - fn fold<B>(&mut self, init: B, f: &fn(B, A) -> B) -> B { - let mut accum = init; - loop { - match self.next() { - Some(x) => { accum = f(accum, x); } - None => { break; } - } - } - return accum; - } - - /// Count the number of items yielded by an iterator - #[inline(always)] - 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; } } - return true; - } - - #[inline(always)] - fn any(&mut self, f: &fn(&A) -> bool) -> bool { - for self.advance |x| { if f(&x) { return true; } } - return false; - } -} - -pub trait AdditiveIterator<A> { - fn sum(&mut self) -> A; -} - -impl<A: Add<A, A> + Zero, T: Iterator<A>> AdditiveIterator<A> for T { - #[inline(always)] - fn sum(&mut self) -> A { self.fold(Zero::zero::<A>(), |s, x| s + x) } -} - -pub trait MultiplicativeIterator<A> { - fn product(&mut self) -> A; -} - -impl<A: Mul<A, A> + One, T: Iterator<A>> MultiplicativeIterator<A> for T { - #[inline(always)] - fn product(&mut self) -> A { self.fold(One::one::<A>(), |p, x| p * x) } -} - -pub trait OrdIterator<A> { - fn max(&mut self) -> Option<A>; - fn min(&mut self) -> Option<A>; -} - -impl<A: Ord, T: Iterator<A>> OrdIterator<A> for T { - #[inline(always)] - fn max(&mut self) -> Option<A> { - self.fold(None, |max, x| { - match max { - None => Some(x), - Some(y) => Some(cmp::max(x, y)) - } - }) - } - - #[inline(always)] - fn min(&mut self) -> Option<A> { - self.fold(None, |min, x| { - match min { - None => Some(x), - Some(y) => Some(cmp::min(x, y)) - } - }) - } -} - -pub struct ChainIterator<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> { - #[inline] - fn next(&mut self) -> Option<A> { - if self.flag { - self.b.next() - } else { - match self.a.next() { - Some(x) => return Some(x), - _ => () - } - self.flag = true; - self.b.next() - } - } -} - -pub struct ZipIterator<T, U> { - priv a: T, - priv b: U -} - -impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(A, B)> for ZipIterator<T, U> { - #[inline] - fn next(&mut self) -> Option<(A, B)> { - match (self.a.next(), self.b.next()) { - (Some(x), Some(y)) => Some((x, y)), - _ => None - } - } -} - -pub struct MapIterator<'self, A, B, T> { - priv iter: T, - priv f: &'self fn(A) -> B -} - -impl<'self, A, B, T: Iterator<A>> Iterator<B> for MapIterator<'self, A, B, T> { - #[inline] - fn next(&mut self) -> Option<B> { - match self.iter.next() { - Some(a) => Some((self.f)(a)), - _ => None - } - } -} - -pub struct FilterIterator<'self, A, T> { - priv iter: T, - priv predicate: &'self fn(&A) -> bool -} - -impl<'self, A, T: Iterator<A>> Iterator<A> for FilterIterator<'self, A, T> { - #[inline] - fn next(&mut self) -> Option<A> { - for self.iter.advance |x| { - if (self.predicate)(&x) { - return Some(x); - } else { - loop - } - } - None - } -} - -pub struct FilterMapIterator<'self, A, B, T> { - priv iter: T, - priv f: &'self fn(A) -> Option<B> -} - -impl<'self, A, B, T: Iterator<A>> Iterator<B> for FilterMapIterator<'self, A, B, T> { - #[inline] - fn next(&mut self) -> Option<B> { - for self.iter.advance |x| { - match (self.f)(x) { - Some(y) => return Some(y), - None => () - } - } - None - } -} - -pub struct EnumerateIterator<T> { - priv iter: T, - priv count: uint -} - -impl<A, T: Iterator<A>> Iterator<(uint, A)> for EnumerateIterator<T> { - #[inline] - fn next(&mut self) -> Option<(uint, A)> { - match self.iter.next() { - Some(a) => { - let ret = Some((self.count, a)); - self.count += 1; - ret - } - _ => None - } - } -} - -pub struct SkipWhileIterator<'self, A, T> { - priv iter: T, - priv flag: bool, - priv predicate: &'self fn(&A) -> bool -} - -impl<'self, A, T: Iterator<A>> Iterator<A> for SkipWhileIterator<'self, A, T> { - #[inline] - fn next(&mut self) -> Option<A> { - let mut next = self.iter.next(); - if self.flag { - next - } else { - loop { - match next { - Some(x) => { - if (self.predicate)(&x) { - next = self.iter.next(); - loop - } else { - self.flag = true; - return Some(x) - } - } - None => return None - } - } - } - } -} - -pub struct TakeWhileIterator<'self, A, T> { - priv iter: T, - priv flag: bool, - priv predicate: &'self fn(&A) -> bool -} - -impl<'self, A, T: Iterator<A>> Iterator<A> for TakeWhileIterator<'self, A, T> { - #[inline] - fn next(&mut self) -> Option<A> { - if self.flag { - None - } else { - match self.iter.next() { - Some(x) => { - if (self.predicate)(&x) { - Some(x) - } else { - self.flag = true; - None - } - } - None => None - } - } - } -} - -pub struct SkipIterator<T> { - priv iter: T, - priv n: uint -} - -impl<A, T: Iterator<A>> Iterator<A> for SkipIterator<T> { - #[inline] - fn next(&mut self) -> Option<A> { - let mut next = self.iter.next(); - if self.n == 0 { - next - } else { - let n = self.n; - for n.times { - match next { - Some(_) => { - next = self.iter.next(); - loop - } - None => { - self.n = 0; - return None - } - } - } - self.n = 0; - next - } - } -} - -pub struct TakeIterator<T> { - priv iter: T, - priv n: uint -} - -impl<A, T: Iterator<A>> Iterator<A> for TakeIterator<T> { - #[inline] - fn next(&mut self) -> Option<A> { - let next = self.iter.next(); - if self.n != 0 { - self.n -= 1; - next - } else { - None - } - } -} - -pub struct ScanIterator<'self, A, B, T, St> { - priv iter: T, - priv f: &'self fn(&mut St, A) -> Option<B>, - state: St -} - -impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for ScanIterator<'self, A, B, T, St> { - #[inline] - fn next(&mut self) -> Option<B> { - self.iter.next().chain(|a| (self.f)(&mut self.state, a)) - } -} - -pub struct UnfoldrIterator<'self, A, St> { - priv f: &'self fn(&mut St) -> Option<A>, - state: St -} - -pub impl<'self, A, St> UnfoldrIterator<'self, A, St> { - #[inline] - fn new(f: &'self fn(&mut St) -> Option<A>, initial_state: St) - -> UnfoldrIterator<'self, A, St> { - UnfoldrIterator { - f: f, - state: initial_state - } - } -} - -impl<'self, A, St> Iterator<A> for UnfoldrIterator<'self, A, St> { - #[inline] - fn next(&mut self) -> Option<A> { - (self.f)(&mut self.state) - } -} - -/// An infinite iterator starting at `start` and advancing by `step` with each iteration -pub struct Counter<A> { - state: A, - step: A -} - -pub impl<A> Counter<A> { - #[inline(always)] - fn new(start: A, step: A) -> Counter<A> { - Counter{state: start, step: step} - } -} - -impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> { - #[inline(always)] - fn next(&mut self) -> Option<A> { - let result = self.state.clone(); - self.state = self.state.add(&self.step); // FIXME: #6050 - Some(result) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use prelude::*; - - #[test] - fn test_counter_to_vec() { - let mut it = Counter::new(0, 5).take(10); - let xs = iter::to_vec(|f| it.advance(f)); - assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); - } - - #[test] - fn test_iterator_chain() { - 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 i = 0; - for it.advance |&x: &uint| { - 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 mut i = 0; - for it.advance |x: uint| { - assert_eq!(x, expected[i]); - i += 1; - } - assert_eq!(i, expected.len()); - } - - #[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]); - } - - #[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)| { - assert_eq!(i, x); - } - } - - #[test] - fn test_iterator_take_while() { - let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - 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| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - fn test_iterator_skip_while() { - let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19]; - 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| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - fn test_iterator_skip() { - let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30]; - 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| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - 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 i = 0; - for it.advance |&x: &uint| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - fn test_iterator_scan() { - // test the type inference - fn add(old: &mut int, new: &uint) -> Option<float> { - *old += *new as int; - Some(*old as float) - } - let xs = [0u, 1, 2, 3, 4]; - let ys = [0f, 1f, 3f, 6f, 10f]; - - let mut it = xs.iter().scan(0, add); - let mut i = 0; - for it.advance |x| { - assert_eq!(x, ys[i]); - i += 1; - } - assert_eq!(i, ys.len()); - } - - #[test] - fn test_unfoldr() { - fn count(st: &mut uint) -> Option<uint> { - if *st < 10 { - let ret = Some(*st); - *st += 1; - ret - } else { - None - } - } - - let mut it = UnfoldrIterator::new(count, 0); - let mut i = 0; - for it.advance |counted| { - assert_eq!(counted, i); - i += 1; - } - assert_eq!(i, 10); - } - - #[test] - fn test_iterator_nth() { - let v = &[0, 1, 2, 3, 4]; - for uint::range(0, v.len()) |i| { - assert_eq!(v.iter().nth(i).unwrap(), &v[i]); - } - } - - #[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); - } - - #[test] - fn test_iterator_count() { - let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().count(), 4); - assert_eq!(v.slice(0, 10).iter().count(), 10); - assert_eq!(v.slice(0, 0).iter().count(), 0); - } - - #[test] - fn test_iterator_sum() { - let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).sum(), 6); - assert_eq!(v.iter().transform(|&x| x).sum(), 55); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).sum(), 0); - } - - #[test] - fn test_iterator_product() { - let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).product(), 0); - assert_eq!(v.slice(1, 5).iter().transform(|&x| x).product(), 24); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).product(), 1); - } - - #[test] - fn test_iterator_max() { - let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).max(), Some(3)); - assert_eq!(v.iter().transform(|&x| x).max(), Some(10)); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).max(), None); - } - - #[test] - fn test_iterator_min() { - let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v.slice(0, 4).iter().transform(|&x| x).min(), Some(0)); - assert_eq!(v.iter().transform(|&x| x).min(), Some(0)); - assert_eq!(v.slice(0, 0).iter().transform(|&x| x).min(), None); - } - - #[test] - fn test_all() { - let v = ~&[1, 2, 3, 4, 5]; - assert!(v.iter().all(|&x| *x < 10)); - assert!(!v.iter().all(|&x| x.is_even())); - 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!())); - } -} diff --git a/src/libcore/kinds.rs b/src/libcore/kinds.rs deleted file mode 100644 index d9b3e35b6b9..00000000000 --- a/src/libcore/kinds.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -The kind traits - -Rust types can be classified in various useful ways according to -intrinsic properties of the type. These classifications, often called -'kinds', are represented as traits. - -They cannot be implemented by user code, but are instead implemented -by the compiler automatically for the types to which they apply. - -The 4 kinds are - -* Copy - types that may be copied without allocation. This includes - scalar types and managed pointers, and exludes owned pointers. It - also excludes types that implement `Drop`. - -* Owned - owned types and types containing owned types. These types - may be transferred across task boundaries. - -* Const - types that are deeply immutable. Const types are used for - freezable data structures. - -`Copy` types include both implicitly copyable types that the compiler -will copy automatically and non-implicitly copyable types that require -the `copy` keyword to copy. Types that do not implement `Copy` may -instead implement `Clone`. - -*/ - -#[lang="copy"] -pub trait Copy { - // Empty. -} - -#[lang="owned"] -pub trait Owned { - // Empty. -} - -#[lang="const"] -pub trait Const { - // Empty. -} diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs deleted file mode 100644 index 7ae3f0fd2d4..00000000000 --- a/src/libcore/libc.rs +++ /dev/null @@ -1,2054 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -* Bindings for the C standard library and other platform libraries -* -* This module contains bindings to the C standard library, -* organized into modules by their defining standard. -* Additionally, it contains some assorted platform-specific definitions. -* For convenience, most functions and types are reexported from `core::libc`, -* so `pub use core::libc::*` will import the available -* C bindings as appropriate for the target platform. The exact -* set of functions available are platform specific. -* -* *Note* Rustdoc does not indicate reexports currently. Also, because these -* definitions are platform-specific, some may not -* appear in the generated documentation. -* -* We consider the following specs reasonably normative with respect -* to interoperating with the C standard library (libc/msvcrt): -* -* * ISO 9899:1990 ('C95', 'ANSI C', 'Standard C'), NA1, 1995. -* * ISO 9899:1999 ('C99' or 'C9x'). -* * ISO 9945:1988 / IEEE 1003.1-1988 ('POSIX.1'). -* * ISO 9945:2001 / IEEE 1003.1-2001 ('POSIX:2001', 'SUSv3'). -* * ISO 9945:2008 / IEEE 1003.1-2008 ('POSIX:2008', 'SUSv4'). -* -* Note that any reference to the 1996 revision of POSIX, or any revs -* between 1990 (when '88 was approved at ISO) and 2001 (when the next -* actual revision-revision happened), are merely additions of other -* chapters (1b and 1c) outside the core interfaces. -* -* Despite having several names each, these are *reasonably* coherent -* point-in-time, list-of-definition sorts of specs. You can get each under a -* variety of names but will wind up with the same definition in each case. -* -* See standards(7) in linux-manpages for more details. -* -* Our interface to these libraries is complicated by the non-universality of -* conformance to any of them. About the only thing universally supported is -* the first (C95), beyond that definitions quickly become absent on various -* platforms. -* -* We therefore wind up dividing our module-space up (mostly for the sake of -* sanity while editing, filling-in-details and eliminating duplication) into -* definitions common-to-all (held in modules named c95, c99, posix88, posix01 -* and posix08) and definitions that appear only on *some* platforms (named -* 'extra'). This would be things like significant OSX foundation kit, or -* win32 library kernel32.dll, or various fancy glibc, linux or BSD -* extensions. -* -* In addition to the per-platform 'extra' modules, we define a module of -* 'common BSD' libc routines that never quite made it into POSIX but show up -* in multiple derived systems. This is the 4.4BSD r2 / 1995 release, the -* final one from Berkeley after the lawsuits died down and the CSRG -* dissolved. -*/ - -#[allow(non_camel_case_types)]; - -// Initial glob-exports mean that all the contents of all the modules -// wind up exported, if you're interested in writing platform-specific code. - -pub use libc::types::common::c95::*; -pub use libc::types::common::c99::*; -pub use libc::types::common::posix88::*; -pub use libc::types::common::posix01::*; -pub use libc::types::common::posix08::*; -pub use libc::types::common::bsd44::*; -pub use libc::types::os::common::posix01::*; -pub use libc::types::os::arch::c95::*; -pub use libc::types::os::arch::c99::*; -pub use libc::types::os::arch::posix88::*; -pub use libc::types::os::arch::posix01::*; -pub use libc::types::os::arch::posix08::*; -pub use libc::types::os::arch::bsd44::*; -pub use libc::types::os::arch::extra::*; - -pub use libc::consts::os::c95::*; -pub use libc::consts::os::c99::*; -pub use libc::consts::os::posix88::*; -pub use libc::consts::os::posix01::*; -pub use libc::consts::os::posix08::*; -pub use libc::consts::os::bsd44::*; -pub use libc::consts::os::extra::*; - -pub use libc::funcs::c95::ctype::*; -pub use libc::funcs::c95::stdio::*; -pub use libc::funcs::c95::stdlib::*; -pub use libc::funcs::c95::string::*; - -pub use libc::funcs::posix88::stat_::*; -pub use libc::funcs::posix88::stdio::*; -pub use libc::funcs::posix88::fcntl::*; -pub use libc::funcs::posix88::dirent::*; -pub use libc::funcs::posix88::unistd::*; - -pub use libc::funcs::posix01::stat_::*; -pub use libc::funcs::posix01::unistd::*; -pub use libc::funcs::posix01::glob::*; -pub use libc::funcs::posix08::unistd::*; - -pub use libc::funcs::bsd44::*; -pub use libc::funcs::extra::*; - -#[cfg(target_os = "win32")] -pub use libc::funcs::extra::kernel32::*; -#[cfg(target_os = "win32")] -pub use libc::funcs::extra::msvcrt::*; - -// Explicit export lists for the intersection (provided here) mean that -// you can write more-platform-agnostic code if you stick to just these -// symbols. - -pub use libc::types::common::c95::{FILE, c_void, fpos_t}; -pub use libc::types::common::posix88::{DIR, dirent_t}; -pub use libc::types::os::arch::c95::{c_char, c_double, c_float, c_int}; -pub use libc::types::os::arch::c95::{c_long, c_short, c_uchar, c_ulong}; -pub use libc::types::os::arch::c95::{c_ushort, clock_t, ptrdiff_t}; -pub use libc::types::os::arch::c95::{size_t, time_t}; -pub use libc::types::os::arch::c99::{c_longlong, c_ulonglong, intptr_t}; -pub use libc::types::os::arch::c99::{uintptr_t}; -pub use libc::types::os::arch::posix88::{dev_t, dirent_t, ino_t, mode_t}; -pub use libc::types::os::arch::posix88::{off_t, pid_t, ssize_t}; - -pub use libc::consts::os::c95::{_IOFBF, _IOLBF, _IONBF, BUFSIZ, EOF}; -pub use libc::consts::os::c95::{EXIT_FAILURE, EXIT_SUCCESS}; -pub use libc::consts::os::c95::{FILENAME_MAX, FOPEN_MAX, L_tmpnam}; -pub use libc::consts::os::c95::{RAND_MAX, SEEK_CUR, SEEK_END}; -pub use libc::consts::os::c95::{SEEK_SET, TMP_MAX}; -pub use libc::consts::os::posix88::{F_OK, O_APPEND, O_CREAT, O_EXCL}; -pub use libc::consts::os::posix88::{O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY}; -pub use libc::consts::os::posix88::{R_OK, S_IEXEC, S_IFBLK, S_IFCHR}; -pub use libc::consts::os::posix88::{S_IFDIR, S_IFIFO, S_IFMT, S_IFREG}; -pub use libc::consts::os::posix88::{S_IREAD, S_IRUSR, S_IRWXU, S_IWUSR}; -pub use libc::consts::os::posix88::{STDERR_FILENO, STDIN_FILENO}; -pub use libc::consts::os::posix88::{STDOUT_FILENO, W_OK, X_OK}; - -pub use libc::funcs::c95::ctype::{isalnum, isalpha, iscntrl, isdigit}; -pub use libc::funcs::c95::ctype::{islower, isprint, ispunct, isspace}; -pub use libc::funcs::c95::ctype::{isupper, isxdigit, tolower, toupper}; - -pub use libc::funcs::c95::stdio::{fclose, feof, ferror, fflush, fgetc}; -pub use libc::funcs::c95::stdio::{fgetpos, fgets, fopen, fputc, fputs}; -pub use libc::funcs::c95::stdio::{fread, freopen, fseek, fsetpos, ftell}; -pub use libc::funcs::c95::stdio::{fwrite, perror, puts, remove, rewind}; -pub use libc::funcs::c95::stdio::{setbuf, setvbuf, tmpfile, ungetc}; - -pub use libc::funcs::c95::stdlib::{abort, abs, atof, atoi, calloc, exit}; -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::{strcoll, strcpy, strcspn, strerror}; -pub use libc::funcs::c95::string::{strlen, strncat, strncmp, strncpy}; -pub use libc::funcs::c95::string::{strpbrk, strrchr, strspn, strstr}; -pub use libc::funcs::c95::string::{strtok, strxfrm}; - -pub use libc::funcs::posix88::fcntl::{open, creat}; -pub use libc::funcs::posix88::stat_::{chmod, fstat, mkdir, stat}; -pub use libc::funcs::posix88::stdio::{fdopen, fileno, pclose, popen}; -pub use libc::funcs::posix88::unistd::{access, chdir, close, dup, dup2}; -pub use libc::funcs::posix88::unistd::{execv, execve, execvp, getcwd}; -pub use libc::funcs::posix88::unistd::{getpid, isatty, lseek, pipe, read}; -pub use libc::funcs::posix88::unistd::{rmdir, unlink, write}; - - -pub mod types { - - // Types tend to vary *per architecture* so we pull their definitions out - // into this module. - - // Standard types that are opaque or common, so are not per-target. - pub mod common { - pub mod c95 { - pub enum c_void {} - pub enum FILE {} - pub enum fpos_t {} - } - pub mod c99 { - pub type int8_t = i8; - pub type int16_t = i16; - pub type int32_t = i32; - pub type int64_t = i64; - pub type uint8_t = u8; - pub type uint16_t = u16; - pub type uint32_t = u32; - pub type uint64_t = u64; - } - pub mod posix88 { - pub enum DIR {} - pub enum dirent_t {} - } - pub mod posix01 {} - pub mod posix08 {} - pub mod bsd44 {} - } - - // Standard types that are scalar but vary by OS and arch. - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - pub mod os { - pub mod common { - pub mod posix01 { - use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, size_t}; - pub struct glob_t { - gl_pathc: size_t, - gl_pathv: **c_char, - gl_offs: size_t, - - __unused1: *c_void, - __unused2: *c_void, - __unused3: *c_void, - __unused4: *c_void, - __unused5: *c_void, - } - } - } - - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] - #[cfg(target_arch = "mips")] - pub mod arch { - pub mod c95 { - pub type c_char = i8; - pub type c_schar = i8; - pub type c_uchar = u8; - pub type c_short = i16; - pub type c_ushort = u16; - pub type c_int = i32; - pub type c_uint = u32; - pub type c_long = i32; - pub type c_ulong = u32; - pub type c_float = f32; - pub type c_double = f64; - pub type size_t = u32; - pub type ptrdiff_t = i32; - pub type clock_t = i32; - pub type time_t = i32; - pub type wchar_t = i32; - } - pub mod c99 { - pub type c_longlong = i64; - pub type c_ulonglong = u64; - pub type intptr_t = int; - pub type uintptr_t = uint; - } - pub mod posix88 { - pub type off_t = i32; - pub type dev_t = u64; - pub type ino_t = u32; - pub type pid_t = i32; - pub type uid_t = u32; - pub type gid_t = u32; - pub type useconds_t = u32; - pub type mode_t = u32; - pub type ssize_t = i32; - } - pub mod posix01 { - use libc::types::os::arch::c95::{c_short, c_long, c_ulong, time_t}; - use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; - use libc::types::os::arch::posix88::{mode_t, off_t}; - use libc::types::os::arch::posix88::{uid_t}; - - pub type nlink_t = u32; - pub type blksize_t = i32; - pub type blkcnt_t = i32; - - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] - pub struct stat { - st_dev: dev_t, - __pad1: c_short, - st_ino: ino_t, - st_mode: mode_t, - st_nlink: nlink_t, - st_uid: uid_t, - st_gid: gid_t, - st_rdev: dev_t, - __pad2: c_short, - st_size: off_t, - st_blksize: blksize_t, - st_blocks: blkcnt_t, - st_atime: time_t, - st_atime_nsec: c_long, - st_mtime: time_t, - st_mtime_nsec: c_long, - st_ctime: time_t, - st_ctime_nsec: c_long, - __unused4: c_long, - __unused5: c_long, - } - - #[cfg(target_arch = "mips")] - pub struct stat { - st_dev: c_ulong, - st_pad1: [c_long, ..3], - st_ino: ino_t, - st_mode: mode_t, - st_nlink: nlink_t, - st_uid: uid_t, - st_gid: gid_t, - st_rdev: c_ulong, - st_pad2: [c_long, ..2], - st_size: off_t, - st_pad3: c_long, - st_atime: time_t, - st_atime_nsec: c_long, - st_mtime: time_t, - st_mtime_nsec: c_long, - st_ctime: time_t, - st_ctime_nsec: c_long, - st_blksize: blksize_t, - st_blocks: blkcnt_t, - st_pad5: [c_long, ..14], - } - } - pub mod posix08 {} - pub mod bsd44 {} - pub mod extra {} - } - - #[cfg(target_arch = "x86_64")] - pub mod arch { - pub mod c95 { - pub type c_char = i8; - pub type c_schar = i8; - pub type c_uchar = u8; - pub type c_short = i16; - pub type c_ushort = u16; - pub type c_int = i32; - pub type c_uint = u32; - pub type c_long = i64; - pub type c_ulong = u64; - pub type c_float = f32; - pub type c_double = f64; - pub type size_t = u64; - pub type ptrdiff_t = i64; - pub type clock_t = i64; - pub type time_t = i64; - pub type wchar_t = i32; - } - pub mod c99 { - pub type c_longlong = i64; - pub type c_ulonglong = u64; - pub type intptr_t = int; - pub type uintptr_t = uint; - } - pub mod posix88 { - pub type off_t = i64; - pub type dev_t = u64; - pub type ino_t = u64; - pub type pid_t = i32; - pub type uid_t = u32; - pub type gid_t = u32; - pub type useconds_t = u32; - pub type mode_t = u32; - pub type ssize_t = i64; - } - pub mod posix01 { - use libc::types::os::arch::c95::{c_int, c_long, time_t}; - use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; - use libc::types::os::arch::posix88::{mode_t, off_t}; - use libc::types::os::arch::posix88::{uid_t}; - - pub type nlink_t = u64; - pub type blksize_t = i64; - pub type blkcnt_t = i64; - pub struct stat { - st_dev: dev_t, - st_ino: ino_t, - st_nlink: nlink_t, - st_mode: mode_t, - st_uid: uid_t, - st_gid: gid_t, - __pad0: c_int, - st_rdev: dev_t, - st_size: off_t, - st_blksize: blksize_t, - st_blocks: blkcnt_t, - st_atime: time_t, - st_atime_nsec: c_long, - st_mtime: time_t, - st_mtime_nsec: c_long, - st_ctime: time_t, - st_ctime_nsec: c_long, - __unused: [c_long, ..3], - } - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - } - } - } - - #[cfg(target_os = "freebsd")] - pub mod os { - pub mod common { - pub mod posix01 { - use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_int, size_t}; - pub struct glob_t { - gl_pathc: size_t, - __unused1: size_t, - gl_offs: size_t, - __unused2: c_int, - gl_pathv: **c_char, - - __unused3: *c_void, - - __unused4: *c_void, - __unused5: *c_void, - __unused6: *c_void, - __unused7: *c_void, - __unused8: *c_void, - } - } - } - - #[cfg(target_arch = "x86_64")] - pub mod arch { - pub mod c95 { - pub type c_char = i8; - pub type c_schar = i8; - pub type c_uchar = u8; - pub type c_short = i16; - pub type c_ushort = u16; - pub type c_int = i32; - pub type c_uint = u32; - pub type c_long = i64; - pub type c_ulong = u64; - pub type c_float = f32; - pub type c_double = f64; - pub type size_t = u64; - pub type ptrdiff_t = i64; - pub type clock_t = i32; - pub type time_t = i64; - pub type wchar_t = i32; - } - pub mod c99 { - pub type c_longlong = i64; - pub type c_ulonglong = u64; - pub type intptr_t = int; - pub type uintptr_t = uint; - } - pub mod posix88 { - pub type off_t = i64; - pub type dev_t = u32; - pub type ino_t = u32; - pub type pid_t = i32; - pub type uid_t = u32; - pub type gid_t = u32; - pub type useconds_t = u32; - pub type mode_t = u16; - pub type ssize_t = i64; - } - pub mod posix01 { - use libc::types::common::c99::{uint8_t, uint32_t, int32_t}; - use libc::types::os::arch::c95::{c_long, time_t}; - use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; - use libc::types::os::arch::posix88::{mode_t, off_t}; - use libc::types::os::arch::posix88::{uid_t}; - - pub type nlink_t = u16; - pub type blksize_t = i64; - pub type blkcnt_t = i64; - pub type fflags_t = u32; - pub struct stat { - st_dev: dev_t, - st_ino: ino_t, - st_mode: mode_t, - st_nlink: nlink_t, - st_uid: uid_t, - st_gid: gid_t, - st_rdev: dev_t, - st_atime: time_t, - st_atime_nsec: c_long, - st_mtime: time_t, - st_mtime_nsec: c_long, - st_ctime: time_t, - st_ctime_nsec: c_long, - st_size: off_t, - st_blocks: blkcnt_t, - st_blksize: blksize_t, - st_flags: fflags_t, - st_gen: uint32_t, - st_lspare: int32_t, - st_birthtime: time_t, - st_birthtime_nsec: c_long, - __unused: [uint8_t, ..2], - } - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - } - } - } - - #[cfg(target_os = "win32")] - pub mod os { - pub mod common { - pub mod posix01 { - use libc::types::os::arch::c95::{c_int, c_short}; - use libc::types::os::arch::extra::{int64, time64_t}; - use libc::types::os::arch::posix88::{dev_t, ino_t}; - use libc::types::os::arch::posix88::mode_t; - - // Note: this is the struct called stat64 in win32. Not stat, - // nor stati64. - pub struct stat { - st_dev: dev_t, - st_ino: ino_t, - st_mode: mode_t, - st_nlink: c_short, - st_uid: c_short, - st_gid: c_short, - st_rdev: dev_t, - st_size: int64, - st_atime: time64_t, - st_mtime: time64_t, - st_ctime: time64_t, - } - } - } - - #[cfg(target_arch = "x86")] - pub mod arch { - pub mod c95 { - pub type c_char = i8; - pub type c_schar = i8; - pub type c_uchar = u8; - pub type c_short = i16; - pub type c_ushort = u16; - pub type c_int = i32; - pub type c_uint = u32; - pub type c_long = i32; - pub type c_ulong = u32; - pub type c_float = f32; - pub type c_double = f64; - pub type size_t = u32; - pub type ptrdiff_t = i32; - pub type clock_t = i32; - pub type time_t = i32; - pub type wchar_t = u16; - } - pub mod c99 { - pub type c_longlong = i64; - pub type c_ulonglong = u64; - pub type intptr_t = int; - pub type uintptr_t = uint; - } - pub mod posix88 { - pub type off_t = i32; - pub type dev_t = u32; - pub type ino_t = i16; - pub type pid_t = i32; - pub type useconds_t = u32; - pub type mode_t = u16; - pub type ssize_t = i32; - } - pub mod posix01 { - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - use libc::types::common::c95::c_void; - use libc::types::os::arch::c95::{c_char, c_int, c_uint}; - use libc::types::os::arch::c95::{c_long, c_ulong}; - use libc::types::os::arch::c95::{wchar_t}; - use libc::types::os::arch::c99::{c_ulonglong}; - - pub type BOOL = c_int; - pub type BYTE = u8; - pub type CCHAR = c_char; - pub type CHAR = c_char; - - pub type DWORD = c_ulong; - pub type DWORDLONG = c_ulonglong; - - pub type HANDLE = LPVOID; - pub type HMODULE = c_uint; - - pub type LONG_PTR = c_long; - - pub type LPCWSTR = *WCHAR; - pub type LPCSTR = *CHAR; - pub type LPCTSTR = *CHAR; - pub type LPTCH = *CHAR; - - pub type LPWSTR = *mut WCHAR; - pub type LPSTR = *mut CHAR; - pub type LPTSTR = *mut CHAR; - - // Not really, but opaque to us. - pub type LPSECURITY_ATTRIBUTES = LPVOID; - - pub type LPVOID = *mut c_void; - pub type LPBYTE = *mut BYTE; - pub type LPWORD = *mut WORD; - pub type LPDWORD = *mut DWORD; - pub type LPHANDLE = *mut HANDLE; - - pub type LRESULT = LONG_PTR; - pub type PBOOL = *mut BOOL; - pub type WCHAR = wchar_t; - pub type WORD = u16; - - pub type time64_t = i64; - pub type int64 = i64; - - pub struct STARTUPINFO { - cb: DWORD, - lpReserved: LPTSTR, - lpDesktop: LPTSTR, - lpTitle: LPTSTR, - dwX: DWORD, - dwY: DWORD, - dwXSize: DWORD, - dwYSize: DWORD, - dwXCountChars: DWORD, - dwYCountCharts: DWORD, - dwFillAttribute: DWORD, - dwFlags: DWORD, - wShowWindow: WORD, - cbReserved2: WORD, - lpReserved2: LPBYTE, - hStdInput: HANDLE, - hStdOutput: HANDLE, - hStdError: HANDLE - } - pub type LPSTARTUPINFO = *mut STARTUPINFO; - - pub struct PROCESS_INFORMATION { - hProcess: HANDLE, - hThread: HANDLE, - dwProcessId: DWORD, - dwThreadId: DWORD - } - pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; - } - } - } - - #[cfg(target_os = "macos")] - pub mod os { - pub mod common { - pub mod posix01 { - use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_int, size_t}; - pub struct glob_t { - gl_pathc: size_t, - __unused1: c_int, - gl_offs: size_t, - __unused2: c_int, - gl_pathv: **c_char, - - __unused3: *c_void, - - __unused4: *c_void, - __unused5: *c_void, - __unused6: *c_void, - __unused7: *c_void, - __unused8: *c_void, - } - } - } - - #[cfg(target_arch = "x86")] - pub mod arch { - pub mod c95 { - pub type c_char = i8; - pub type c_schar = i8; - pub type c_uchar = u8; - pub type c_short = i16; - pub type c_ushort = u16; - pub type c_int = i32; - pub type c_uint = u32; - pub type c_long = i32; - pub type c_ulong = u32; - pub type c_float = f32; - pub type c_double = f64; - pub type size_t = u32; - pub type ptrdiff_t = i32; - pub type clock_t = u32; - pub type time_t = i32; - pub type wchar_t = i32; - } - pub mod c99 { - pub type c_longlong = i64; - pub type c_ulonglong = u64; - pub type intptr_t = int; - pub type uintptr_t = uint; - } - pub mod posix88 { - pub type off_t = i64; - pub type dev_t = i32; - pub type ino_t = u64; - pub type pid_t = i32; - pub type uid_t = u32; - pub type gid_t = u32; - pub type useconds_t = u32; - pub type mode_t = u16; - pub type ssize_t = i32; - } - pub mod posix01 { - use libc::types::common::c99::{int32_t, int64_t, uint32_t}; - use libc::types::os::arch::c95::{c_long, time_t}; - use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t, - mode_t, off_t, uid_t}; - - pub type nlink_t = u16; - pub type blksize_t = i64; - pub type blkcnt_t = i32; - - pub struct stat { - st_dev: dev_t, - st_mode: mode_t, - st_nlink: nlink_t, - st_ino: ino_t, - st_uid: uid_t, - st_gid: gid_t, - st_rdev: dev_t, - st_atime: time_t, - st_atime_nsec: c_long, - st_mtime: time_t, - st_mtime_nsec: c_long, - st_ctime: time_t, - st_ctime_nsec: c_long, - st_birthtime: time_t, - st_birthtime_nsec: c_long, - st_size: off_t, - st_blocks: blkcnt_t, - st_blksize: blksize_t, - st_flags: uint32_t, - st_gen: uint32_t, - st_lspare: int32_t, - st_qspare: [int64_t, ..2], - } - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - } - } - - #[cfg(target_arch = "x86_64")] - pub mod arch { - pub mod c95 { - pub type c_char = i8; - pub type c_schar = i8; - pub type c_uchar = u8; - pub type c_short = i16; - pub type c_ushort = u16; - pub type c_int = i32; - pub type c_uint = u32; - pub type c_long = i64; - pub type c_ulong = u64; - pub type c_float = f32; - pub type c_double = f64; - pub type size_t = u64; - pub type ptrdiff_t = i64; - pub type clock_t = u64; - pub type time_t = i64; - pub type wchar_t = i32; - } - pub mod c99 { - pub type c_longlong = i64; - pub type c_ulonglong = u64; - pub type intptr_t = int; - pub type uintptr_t = uint; - } - pub mod posix88 { - pub type off_t = i64; - pub type dev_t = i32; - pub type ino_t = u64; - pub type pid_t = i32; - pub type uid_t = u32; - pub type gid_t = u32; - pub type useconds_t = u32; - pub type mode_t = u16; - pub type ssize_t = i64; - } - pub mod posix01 { - use libc::types::common::c99::{int32_t, int64_t}; - use libc::types::common::c99::{uint32_t}; - use libc::types::os::arch::c95::{c_long, time_t}; - use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; - use libc::types::os::arch::posix88::{mode_t, off_t, uid_t}; - - pub type nlink_t = u16; - pub type blksize_t = i64; - pub type blkcnt_t = i32; - - pub struct stat { - st_dev: dev_t, - st_mode: mode_t, - st_nlink: nlink_t, - st_ino: ino_t, - st_uid: uid_t, - st_gid: gid_t, - st_rdev: dev_t, - st_atime: time_t, - st_atime_nsec: c_long, - st_mtime: time_t, - st_mtime_nsec: c_long, - st_ctime: time_t, - st_ctime_nsec: c_long, - st_birthtime: time_t, - st_birthtime_nsec: c_long, - st_size: off_t, - st_blocks: blkcnt_t, - st_blksize: blksize_t, - st_flags: uint32_t, - st_gen: uint32_t, - st_lspare: int32_t, - st_qspare: [int64_t, ..2], - } - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - } - } - } -} - -pub mod consts { - // Consts tend to vary per OS so we pull their definitions out - // into this module. - - #[cfg(target_os = "win32")] - pub mod os { - pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 32767; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 4; - pub static _IOLBF : int = 64; - pub static BUFSIZ : uint = 512_u; - pub static FOPEN_MAX : uint = 20_u; - pub static FILENAME_MAX : uint = 260_u; - pub static L_tmpnam : uint = 16_u; - pub static TMP_MAX : uint = 32767_u; - } - pub mod c99 { - } - pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 256; - pub static O_EXCL : int = 1024; - pub static O_TRUNC : int = 512; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 12288; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - } - pub mod posix01 { - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - use libc::types::os::arch::extra::{DWORD, BOOL}; - - pub static TRUE : BOOL = 1; - pub static FALSE : BOOL = 0; - - pub static O_TEXT : int = 16384; - pub static O_BINARY : int = 32768; - pub static O_NOINHERIT: int = 128; - - pub static ERROR_SUCCESS : int = 0; - pub static ERROR_INSUFFICIENT_BUFFER : int = 122; - pub static INVALID_HANDLE_VALUE: int = -1; - - pub static DELETE : DWORD = 0x00010000; - pub static READ_CONTROL : DWORD = 0x00020000; - pub static SYNCHRONIZE : DWORD = 0x00100000; - pub static WRITE_DAC : DWORD = 0x00040000; - pub static WRITE_OWNER : DWORD = 0x00080000; - - pub static PROCESS_CREATE_PROCESS : DWORD = 0x0080; - pub static PROCESS_CREATE_THREAD : DWORD = 0x0002; - pub static PROCESS_DUP_HANDLE : DWORD = 0x0040; - pub static PROCESS_QUERY_INFORMATION : DWORD = 0x0400; - pub static PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000; - pub static PROCESS_SET_INFORMATION : DWORD = 0x0200; - pub static PROCESS_SET_QUOTA : DWORD = 0x0100; - pub static PROCESS_SUSPEND_RESUME : DWORD = 0x0800; - pub static PROCESS_TERMINATE : DWORD = 0x0001; - pub static PROCESS_VM_OPERATION : DWORD = 0x0008; - pub static PROCESS_VM_READ : DWORD = 0x0010; - pub static PROCESS_VM_WRITE : DWORD = 0x0020; - - pub static STARTF_FORCEONFEEDBACK : DWORD = 0x00000040; - pub static STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080; - pub static STARTF_PREVENTPINNING : DWORD = 0x00002000; - pub static STARTF_RUNFULLSCREEN : DWORD = 0x00000020; - pub static STARTF_TITLEISAPPID : DWORD = 0x00001000; - pub static STARTF_TITLEISLINKNAME : DWORD = 0x00000800; - pub static STARTF_USECOUNTCHARS : DWORD = 0x00000008; - pub static STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010; - pub static STARTF_USEHOTKEY : DWORD = 0x00000200; - pub static STARTF_USEPOSITION : DWORD = 0x00000004; - pub static STARTF_USESHOWWINDOW : DWORD = 0x00000001; - pub static STARTF_USESIZE : DWORD = 0x00000002; - pub static STARTF_USESTDHANDLES : DWORD = 0x00000100; - - pub static WAIT_ABANDONED : DWORD = 0x00000080; - pub static WAIT_OBJECT_0 : DWORD = 0x00000000; - pub static WAIT_TIMEOUT : DWORD = 0x00000102; - pub static WAIT_FAILED : DWORD = -1; - - pub static DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001; - pub static DUPLICATE_SAME_ACCESS : DWORD = 0x00000002; - - pub static INFINITE : DWORD = -1; - pub static STILL_ACTIVE : DWORD = 259; - } - } - - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - pub mod os { - pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 2147483647; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 2; - pub static _IOLBF : int = 1; - pub static BUFSIZ : uint = 8192_u; - pub static FOPEN_MAX : uint = 16_u; - pub static FILENAME_MAX : uint = 4096_u; - pub static L_tmpnam : uint = 20_u; - pub static TMP_MAX : uint = 238328_u; - } - pub mod c99 { - } - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "x86_64")] - #[cfg(target_arch = "arm")] - pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 1024; - pub static O_CREAT : int = 64; - pub static O_EXCL : int = 128; - pub static O_TRUNC : int = 512; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; - } - #[cfg(target_arch = "mips")] - pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 256; - pub static O_EXCL : int = 1024; - pub static O_TRUNC : int = 512; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; - } - pub mod posix01 { - pub static SIGTRAP : int = 5; - - pub static GLOB_ERR : int = 1 << 0; - pub static GLOB_MARK : int = 1 << 1; - pub static GLOB_NOSORT : int = 1 << 2; - pub static GLOB_DOOFFS : int = 1 << 3; - pub static GLOB_NOCHECK : int = 1 << 4; - pub static GLOB_APPEND : int = 1 << 5; - pub static GLOB_NOESCAPE : int = 1 << 6; - - pub static GLOB_NOSPACE : int = 1; - pub static GLOB_ABORTED : int = 2; - pub static GLOB_NOMATCH : int = 3; - } - pub mod posix08 { - } - pub mod bsd44 { - } - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "x86_64")] - #[cfg(target_arch = "arm")] - pub mod extra { - pub static O_RSYNC : int = 1052672; - pub static O_DSYNC : int = 4096; - pub static O_SYNC : int = 1052672; - } - #[cfg(target_arch = "mips")] - pub mod extra { - pub static O_RSYNC : int = 16400; - pub static O_DSYNC : int = 16; - pub static O_SYNC : int = 16400; - } - } - - #[cfg(target_os = "freebsd")] - pub mod os { - pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 2147483647; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 2; - pub static _IOLBF : int = 1; - pub static BUFSIZ : uint = 1024_u; - pub static FOPEN_MAX : uint = 20_u; - pub static FILENAME_MAX : uint = 1024_u; - pub static L_tmpnam : uint = 1024_u; - pub static TMP_MAX : uint = 308915776_u; - } - pub mod c99 { - } - pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 512; - pub static O_EXCL : int = 2048; - pub static O_TRUNC : int = 1024; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; - } - pub mod posix01 { - pub static SIGTRAP : int = 5; - - pub static GLOB_APPEND : int = 0x0001; - pub static GLOB_DOOFFS : int = 0x0002; - pub static GLOB_ERR : int = 0x0004; - pub static GLOB_MARK : int = 0x0008; - pub static GLOB_NOCHECK : int = 0x0010; - pub static GLOB_NOSORT : int = 0x0020; - pub static GLOB_NOESCAPE : int = 0x2000; - - pub static GLOB_NOSPACE : int = -1; - pub static GLOB_ABORTED : int = -2; - pub static GLOB_NOMATCH : int = -3; - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - pub static O_SYNC : int = 128; - pub static CTL_KERN: int = 1; - pub static KERN_PROC: int = 14; - pub static KERN_PROC_PATHNAME: int = 12; - } - } - - #[cfg(target_os = "macos")] - pub mod os { - pub mod c95 { - pub static EXIT_FAILURE : int = 1; - pub static EXIT_SUCCESS : int = 0; - pub static RAND_MAX : int = 2147483647; - pub static EOF : int = -1; - pub static SEEK_SET : int = 0; - pub static SEEK_CUR : int = 1; - pub static SEEK_END : int = 2; - pub static _IOFBF : int = 0; - pub static _IONBF : int = 2; - pub static _IOLBF : int = 1; - pub static BUFSIZ : uint = 1024_u; - pub static FOPEN_MAX : uint = 20_u; - pub static FILENAME_MAX : uint = 1024_u; - pub static L_tmpnam : uint = 1024_u; - pub static TMP_MAX : uint = 308915776_u; - } - pub mod c99 { - } - pub mod posix88 { - pub static O_RDONLY : int = 0; - pub static O_WRONLY : int = 1; - pub static O_RDWR : int = 2; - pub static O_APPEND : int = 8; - pub static O_CREAT : int = 512; - pub static O_EXCL : int = 2048; - pub static O_TRUNC : int = 1024; - pub static S_IFIFO : int = 4096; - pub static S_IFCHR : int = 8192; - pub static S_IFBLK : int = 24576; - pub static S_IFDIR : int = 16384; - pub static S_IFREG : int = 32768; - pub static S_IFMT : int = 61440; - pub static S_IEXEC : int = 64; - pub static S_IWRITE : int = 128; - pub static S_IREAD : int = 256; - pub static S_IRWXU : int = 448; - pub static S_IXUSR : int = 64; - pub static S_IWUSR : int = 128; - pub static S_IRUSR : int = 256; - pub static F_OK : int = 0; - pub static R_OK : int = 4; - pub static W_OK : int = 2; - pub static X_OK : int = 1; - pub static STDIN_FILENO : int = 0; - pub static STDOUT_FILENO : int = 1; - pub static STDERR_FILENO : int = 2; - pub static F_LOCK : int = 1; - pub static F_TEST : int = 3; - pub static F_TLOCK : int = 2; - pub static F_ULOCK : int = 0; - pub static SIGHUP : int = 1; - pub static SIGINT : int = 2; - pub static SIGQUIT : int = 3; - pub static SIGILL : int = 4; - pub static SIGABRT : int = 6; - pub static SIGFPE : int = 8; - pub static SIGKILL : int = 9; - pub static SIGSEGV : int = 11; - pub static SIGPIPE : int = 13; - pub static SIGALRM : int = 14; - pub static SIGTERM : int = 15; - } - pub mod posix01 { - pub static SIGTRAP : int = 5; - - pub static GLOB_APPEND : int = 0x0001; - pub static GLOB_DOOFFS : int = 0x0002; - pub static GLOB_ERR : int = 0x0004; - pub static GLOB_MARK : int = 0x0008; - pub static GLOB_NOCHECK : int = 0x0010; - pub static GLOB_NOSORT : int = 0x0020; - pub static GLOB_NOESCAPE : int = 0x2000; - - pub static GLOB_NOSPACE : int = -1; - pub static GLOB_ABORTED : int = -2; - pub static GLOB_NOMATCH : int = -3; - } - pub mod posix08 { - } - pub mod bsd44 { - } - pub mod extra { - pub static O_DSYNC : int = 4194304; - pub static O_SYNC : int = 128; - pub static F_FULLFSYNC : int = 51; - } - } -} - - -pub mod funcs { - // Thankfull most of c95 is universally available and does not vary by OS - // or anything. The same is not true of POSIX. - - pub mod c95 { - #[nolink] - #[abi = "cdecl"] - pub mod ctype { - use libc::types::os::arch::c95::{c_char, c_int}; - - pub extern { - unsafe fn isalnum(c: c_int) -> c_int; - unsafe fn isalpha(c: c_int) -> c_int; - unsafe fn iscntrl(c: c_int) -> c_int; - unsafe fn isdigit(c: c_int) -> c_int; - unsafe fn isgraph(c: c_int) -> c_int; - unsafe fn islower(c: c_int) -> c_int; - unsafe fn isprint(c: c_int) -> c_int; - unsafe fn ispunct(c: c_int) -> c_int; - unsafe fn isspace(c: c_int) -> c_int; - unsafe fn isupper(c: c_int) -> c_int; - unsafe fn isxdigit(c: c_int) -> c_int; - unsafe fn tolower(c: c_char) -> c_char; - unsafe fn toupper(c: c_char) -> c_char; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod stdio { - use libc::types::common::c95::{FILE, c_void, fpos_t}; - use libc::types::os::arch::c95::{c_char, c_int, c_long, size_t}; - - pub extern { - unsafe fn fopen(filename: *c_char, mode: *c_char) -> *FILE; - unsafe fn freopen(filename: *c_char, mode: *c_char, - file: *FILE) -> *FILE; - unsafe fn fflush(file: *FILE) -> c_int; - unsafe fn fclose(file: *FILE) -> c_int; - unsafe fn remove(filename: *c_char) -> c_int; - unsafe fn rename(oldname: *c_char, newname: *c_char) -> c_int; - unsafe fn tmpfile() -> *FILE; - unsafe fn setvbuf(stream: *FILE, buffer: *c_char, - mode: c_int, size: size_t) -> c_int; - unsafe fn setbuf(stream: *FILE, buf: *c_char); - // Omitted: printf and scanf variants. - unsafe fn fgetc(stream: *FILE) -> c_int; - #[fast_ffi] - unsafe fn fgets(buf: *mut c_char, n: c_int, - stream: *FILE) -> *c_char; - #[fast_ffi] - unsafe fn fputc(c: c_int, stream: *FILE) -> c_int; - #[fast_ffi] - unsafe fn fputs(s: *c_char, stream: *FILE) -> *c_char; - // Omitted: getc, getchar (might be macros). - - // Omitted: gets, so ridiculously unsafe that it should not - // survive. - - // Omitted: putc, putchar (might be macros). - unsafe fn puts(s: *c_char) -> c_int; - unsafe fn ungetc(c: c_int, stream: *FILE) -> c_int; - #[fast_ffi] - unsafe fn fread(ptr: *mut c_void, size: size_t, - nobj: size_t, stream: *FILE) -> size_t; - #[fast_ffi] - unsafe fn fwrite(ptr: *c_void, size: size_t, - nobj: size_t, stream: *FILE) -> size_t; - unsafe fn fseek(stream: *FILE, offset: c_long, - whence: c_int) -> c_int; - unsafe fn ftell(stream: *FILE) -> c_long; - unsafe fn rewind(stream: *FILE); - unsafe fn fgetpos(stream: *FILE, ptr: *fpos_t) -> c_int; - unsafe fn fsetpos(stream: *FILE, ptr: *fpos_t) -> c_int; - unsafe fn feof(stream: *FILE) -> c_int; - unsafe fn ferror(stream: *FILE) -> c_int; - unsafe fn perror(s: *c_char); - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod stdlib { - use libc::types::common::c95::c_void; - use libc::types::os::arch::c95::{c_char, c_double, c_int}; - use libc::types::os::arch::c95::{c_long, c_uint, c_ulong}; - use libc::types::os::arch::c95::{size_t}; - - pub extern { - unsafe fn abs(i: c_int) -> c_int; - unsafe fn labs(i: c_long) -> c_long; - // Omitted: div, ldiv (return pub type incomplete). - unsafe fn atof(s: *c_char) -> c_double; - unsafe fn atoi(s: *c_char) -> c_int; - unsafe fn strtod(s: *c_char, endp: **c_char) -> c_double; - unsafe fn strtol(s: *c_char, endp: **c_char, base: c_int) - -> c_long; - unsafe fn strtoul(s: *c_char, endp: **c_char, base: c_int) - -> c_ulong; - #[fast_ffi] - unsafe fn calloc(nobj: size_t, size: size_t) -> *c_void; - #[fast_ffi] - unsafe fn malloc(size: size_t) -> *c_void; - #[fast_ffi] - unsafe fn realloc(p: *c_void, size: size_t) -> *c_void; - #[fast_ffi] - unsafe fn free(p: *c_void); - unsafe fn abort() -> !; - unsafe fn exit(status: c_int) -> !; - // Omitted: atexit. - unsafe fn system(s: *c_char) -> c_int; - unsafe fn getenv(s: *c_char) -> *c_char; - // Omitted: bsearch, qsort - unsafe fn rand() -> c_int; - unsafe fn srand(seed: c_uint); - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod string { - use libc::types::common::c95::c_void; - use libc::types::os::arch::c95::{c_char, c_int, size_t}; - use libc::types::os::arch::c95::{wchar_t}; - - pub extern { - unsafe fn strcpy(dst: *c_char, src: *c_char) -> *c_char; - unsafe fn strncpy(dst: *c_char, src: *c_char, n: size_t) - -> *c_char; - unsafe fn strcat(s: *c_char, ct: *c_char) -> *c_char; - unsafe fn strncat(s: *c_char, ct: *c_char, n: size_t) - -> *c_char; - unsafe fn strcmp(cs: *c_char, ct: *c_char) -> c_int; - unsafe fn strncmp(cs: *c_char, ct: *c_char, n: size_t) - -> c_int; - unsafe fn strcoll(cs: *c_char, ct: *c_char) -> c_int; - unsafe fn strchr(cs: *c_char, c: c_int) -> *c_char; - unsafe fn strrchr(cs: *c_char, c: c_int) -> *c_char; - unsafe fn strspn(cs: *c_char, ct: *c_char) -> size_t; - unsafe fn strcspn(cs: *c_char, ct: *c_char) -> size_t; - unsafe fn strpbrk(cs: *c_char, ct: *c_char) -> *c_char; - unsafe fn strstr(cs: *c_char, ct: *c_char) -> *c_char; - unsafe fn strlen(cs: *c_char) -> size_t; - unsafe fn strerror(n: c_int) -> *c_char; - unsafe fn strtok(s: *c_char, t: *c_char) -> *c_char; - unsafe fn strxfrm(s: *c_char, ct: *c_char, n: size_t) - -> size_t; - unsafe fn wcslen(buf: *wchar_t) -> size_t; - - // 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; - } - } - } - - // Microsoft helpfully underscore-qualifies all of its POSIX-like symbols - // to make sure you don't use them accidentally. It also randomly deviates - // from the exact signatures you might otherwise expect, and omits much, - // so be careful when trying to write portable code; it won't always work - // with the same POSIX functions and types as other platforms. - - #[cfg(target_os = "win32")] - pub mod posix88 { - #[nolink] - #[abi = "cdecl"] - pub mod stat_ { - use libc::types::os::common::posix01::stat; - use libc::types::os::arch::c95::{c_int, c_char}; - - pub extern { - #[link_name = "_chmod"] - unsafe fn chmod(path: *c_char, mode: c_int) -> c_int; - - #[link_name = "_mkdir"] - unsafe fn mkdir(path: *c_char) -> c_int; - - #[link_name = "_fstat64"] - unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int; - - #[link_name = "_stat64"] - unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod stdio { - use libc::types::common::c95::FILE; - use libc::types::os::arch::c95::{c_int, c_char}; - - pub extern { - #[link_name = "_popen"] - unsafe fn popen(command: *c_char, mode: *c_char) -> *FILE; - - #[link_name = "_pclose"] - unsafe fn pclose(stream: *FILE) -> c_int; - - #[link_name = "_fdopen"] - #[fast_ffi] - unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE; - - #[link_name = "_fileno"] - unsafe fn fileno(stream: *FILE) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod fcntl { - use libc::types::os::arch::c95::{c_int, c_char}; - pub extern { - #[link_name = "_open"] - unsafe fn open(path: *c_char, oflag: c_int, mode: c_int) - -> c_int; - - #[link_name = "_creat"] - unsafe fn creat(path: *c_char, mode: c_int) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod dirent { - // Not supplied at all. - } - - #[nolink] - #[abi = "cdecl"] - pub mod unistd { - use libc::types::common::c95::c_void; - use libc::types::os::arch::c95::{c_int, c_uint, c_char, - c_long, size_t}; - use libc::types::os::arch::c99::intptr_t; - - pub extern { - #[link_name = "_access"] - unsafe fn access(path: *c_char, amode: c_int) -> c_int; - - #[link_name = "_chdir"] - unsafe fn chdir(dir: *c_char) -> c_int; - - #[link_name = "_close"] - unsafe fn close(fd: c_int) -> c_int; - - #[link_name = "_dup"] - unsafe fn dup(fd: c_int) -> c_int; - - #[link_name = "_dup2"] - unsafe fn dup2(src: c_int, dst: c_int) -> c_int; - - #[link_name = "_execv"] - unsafe fn execv(prog: *c_char, argv: **c_char) -> intptr_t; - - #[link_name = "_execve"] - unsafe fn execve(prog: *c_char, argv: **c_char, - envp: **c_char) -> c_int; - - #[link_name = "_execvp"] - unsafe fn execvp(c: *c_char, argv: **c_char) -> c_int; - - #[link_name = "_execvpe"] - unsafe fn execvpe(c: *c_char, argv: **c_char, - envp: **c_char) -> c_int; - - #[link_name = "_getcwd"] - unsafe fn getcwd(buf: *c_char, size: size_t) -> *c_char; - - #[link_name = "_getpid"] - unsafe fn getpid() -> c_int; - - #[link_name = "_isatty"] - unsafe fn isatty(fd: c_int) -> c_int; - - #[link_name = "_lseek"] - unsafe fn lseek(fd: c_int, offset: c_long, origin: c_int) - -> c_long; - - #[link_name = "_pipe"] - unsafe fn pipe(fds: *mut c_int, psize: c_uint, - textmode: c_int) -> c_int; - - #[link_name = "_read"] - #[fast_ffi] - unsafe fn read(fd: c_int, buf: *mut c_void, count: c_uint) - -> c_int; - - #[link_name = "_rmdir"] - unsafe fn rmdir(path: *c_char) -> c_int; - - #[link_name = "_unlink"] - unsafe fn unlink(c: *c_char) -> c_int; - - #[link_name = "_write"] - #[fast_ffi] - unsafe fn write(fd: c_int, buf: *c_void, count: c_uint) - -> c_int; - } - } - } - - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - pub mod posix88 { - pub mod stat_ { - use libc::types::os::arch::c95::{c_char, c_int}; - use libc::types::os::arch::posix01::stat; - use libc::types::os::arch::posix88::mode_t; - - #[nolink] - #[abi = "cdecl"] - pub extern { - unsafe fn chmod(path: *c_char, mode: mode_t) -> c_int; - unsafe fn fchmod(fd: c_int, mode: mode_t) -> c_int; - - #[cfg(target_os = "linux")] - #[cfg(target_os = "freebsd")] - #[cfg(target_os = "android")] - unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int; - - #[cfg(target_os = "macos")] - #[link_name = "fstat64"] - unsafe fn fstat(fildes: c_int, buf: *mut stat) -> c_int; - - unsafe fn mkdir(path: *c_char, mode: mode_t) -> c_int; - unsafe fn mkfifo(path: *c_char, mode: mode_t) -> c_int; - - #[cfg(target_os = "linux")] - #[cfg(target_os = "freebsd")] - #[cfg(target_os = "android")] - unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int; - - #[cfg(target_os = "macos")] - #[link_name = "stat64"] - unsafe fn stat(path: *c_char, buf: *mut stat) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod stdio { - use libc::types::common::c95::FILE; - use libc::types::os::arch::c95::{c_char, c_int}; - - pub extern { - unsafe fn popen(command: *c_char, mode: *c_char) -> *FILE; - unsafe fn pclose(stream: *FILE) -> c_int; - unsafe fn fdopen(fd: c_int, mode: *c_char) -> *FILE; - unsafe fn fileno(stream: *FILE) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod fcntl { - use libc::types::os::arch::c95::{c_char, c_int}; - use libc::types::os::arch::posix88::mode_t; - - pub extern { - unsafe fn open(path: *c_char, oflag: c_int, mode: c_int) - -> c_int; - unsafe fn creat(path: *c_char, mode: mode_t) -> c_int; - unsafe fn fcntl(fd: c_int, cmd: c_int) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod dirent { - use libc::types::common::posix88::{DIR, dirent_t}; - use libc::types::os::arch::c95::{c_char, c_int, c_long}; - - // NB: On OS X opendir and readdir have two versions, - // one for 32-bit kernelspace and one for 64. - // We should be linking to the 64-bit ones, called - // opendir$INODE64, etc. but for some reason rustc - // doesn't link it correctly on i686, so we're going - // through a C function that mysteriously does work. - pub unsafe fn opendir(dirname: *c_char) -> *DIR { - rust_opendir(dirname) - } - pub unsafe fn readdir(dirp: *DIR) -> *dirent_t { - rust_readdir(dirp) - } - - extern { - unsafe fn rust_opendir(dirname: *c_char) -> *DIR; - unsafe fn rust_readdir(dirp: *DIR) -> *dirent_t; - } - - pub extern { - unsafe fn closedir(dirp: *DIR) -> c_int; - unsafe fn rewinddir(dirp: *DIR); - unsafe fn seekdir(dirp: *DIR, loc: c_long); - unsafe fn telldir(dirp: *DIR) -> c_long; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod unistd { - use libc::types::common::c95::c_void; - use libc::types::os::arch::c95::{c_char, c_int, c_long, c_uint}; - use libc::types::os::arch::c95::{size_t}; - use libc::types::os::arch::posix88::{gid_t, off_t, pid_t}; - use libc::types::os::arch::posix88::{ssize_t, uid_t}; - - pub extern { - unsafe fn access(path: *c_char, amode: c_int) -> c_int; - unsafe fn alarm(seconds: c_uint) -> c_uint; - unsafe fn chdir(dir: *c_char) -> c_int; - unsafe fn chown(path: *c_char, uid: uid_t, gid: gid_t) - -> c_int; - unsafe fn close(fd: c_int) -> c_int; - unsafe fn dup(fd: c_int) -> c_int; - unsafe fn dup2(src: c_int, dst: c_int) -> c_int; - unsafe fn execv(prog: *c_char, argv: **c_char) -> c_int; - unsafe fn execve(prog: *c_char, - argv: **c_char, - envp: **c_char) - -> c_int; - unsafe fn execvp(c: *c_char, argv: **c_char) -> c_int; - unsafe fn fork() -> pid_t; - unsafe fn fpathconf(filedes: c_int, name: c_int) -> c_long; - unsafe fn getcwd(buf: *c_char, size: size_t) -> *c_char; - unsafe fn getegid() -> gid_t; - unsafe fn geteuid() -> uid_t; - unsafe fn getgid() -> gid_t ; - unsafe fn getgroups(ngroups_max: c_int, groups: *mut gid_t) - -> c_int; - unsafe fn getlogin() -> *c_char; - unsafe fn getopt(argc: c_int, argv: **c_char, optstr: *c_char) - -> c_int; - unsafe fn getpgrp() -> pid_t; - unsafe fn getpid() -> pid_t; - unsafe fn getppid() -> pid_t; - unsafe fn getuid() -> uid_t; - unsafe fn isatty(fd: c_int) -> c_int; - unsafe fn link(src: *c_char, dst: *c_char) -> c_int; - unsafe fn lseek(fd: c_int, offset: off_t, whence: c_int) - -> off_t; - unsafe fn pathconf(path: *c_char, name: c_int) -> c_long; - unsafe fn pause() -> c_int; - unsafe fn pipe(fds: *mut c_int) -> c_int; - #[fast_ffi] - unsafe fn read(fd: c_int, buf: *mut c_void, - count: size_t) -> ssize_t; - unsafe fn rmdir(path: *c_char) -> c_int; - unsafe fn setgid(gid: gid_t) -> c_int; - unsafe fn setpgid(pid: pid_t, pgid: pid_t) -> c_int; - unsafe fn setsid() -> pid_t; - unsafe fn setuid(uid: uid_t) -> c_int; - unsafe fn sleep(secs: c_uint) -> c_uint; - unsafe fn sysconf(name: c_int) -> c_long; - unsafe fn tcgetpgrp(fd: c_int) -> pid_t; - unsafe fn ttyname(fd: c_int) -> *c_char; - unsafe fn unlink(c: *c_char) -> c_int; - #[fast_ffi] - unsafe fn write(fd: c_int, buf: *c_void, count: size_t) - -> ssize_t; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod signal { - use libc::types::os::arch::c95::{c_int}; - use libc::types::os::arch::posix88::{pid_t}; - - pub extern { - unsafe fn kill(pid: pid_t, sig: c_int) -> c_int; - } - } - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - pub mod posix01 { - #[nolink] - #[abi = "cdecl"] - pub mod stat_ { - use libc::types::os::arch::c95::{c_char, c_int}; - use libc::types::os::arch::posix01::stat; - - pub extern { - #[cfg(target_os = "linux")] - #[cfg(target_os = "freebsd")] - #[cfg(target_os = "android")] - unsafe fn lstat(path: *c_char, buf: *mut stat) -> c_int; - - #[cfg(target_os = "macos")] - #[link_name = "lstat64"] - unsafe fn lstat(path: *c_char, buf: *mut stat) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod unistd { - use libc::types::os::arch::c95::{c_char, c_int, size_t}; - use libc::types::os::arch::posix88::{ssize_t}; - - pub extern { - unsafe fn readlink(path: *c_char, buf: *mut c_char, - bufsz: size_t) -> ssize_t; - - unsafe fn fsync(fd: c_int) -> c_int; - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - unsafe fn fdatasync(fd: c_int) -> c_int; - - unsafe fn setenv(name: *c_char, val: *c_char, - overwrite: c_int) -> c_int; - unsafe fn unsetenv(name: *c_char) -> c_int; - unsafe fn putenv(string: *c_char) -> c_int; - - unsafe fn symlink(path1: *c_char, path2: *c_char) -> c_int; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod wait { - use libc::types::os::arch::c95::{c_int}; - use libc::types::os::arch::posix88::{pid_t}; - - pub extern { - unsafe fn waitpid(pid: pid_t, - status: *mut c_int, - options: c_int) - -> pid_t; - } - } - - #[nolink] - #[abi = "cdecl"] - pub mod glob { - use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_int}; - use libc::types::os::common::posix01::{glob_t}; - - pub extern { - unsafe fn glob(pattern: *c_char, flags: c_int, - errfunc: *c_void, // XXX callback - pglob: *mut glob_t); - unsafe fn globfree(pglob: *mut glob_t); - } - } - } - - #[cfg(target_os = "win32")] - pub mod posix01 { - pub mod stat_ { - } - - pub mod unistd { - } - - pub mod glob { - } - } - - - #[cfg(target_os = "win32")] - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - pub mod posix08 { - pub mod unistd { - } - } - - - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - pub mod bsd44 { - use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t}; - - #[abi = "cdecl"] - pub extern { - unsafe fn sysctl(name: *c_int, namelen: c_uint, - oldp: *mut c_void, oldlenp: *mut size_t, - newp: *c_void, newlen: size_t) -> c_int; - - unsafe fn sysctlbyname(name: *c_char, - oldp: *mut c_void, oldlenp: *mut size_t, - newp: *c_void, newlen: size_t) -> c_int; - - unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int, - sizep: *mut size_t) -> c_int; - - unsafe fn getdtablesize() -> c_int; - } - } - - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - pub mod bsd44 { - use libc::types::os::arch::c95::{c_int}; - - #[abi = "cdecl"] - pub extern { - unsafe fn getdtablesize() -> c_int; - } - } - - - #[cfg(target_os = "win32")] - pub mod bsd44 { - } - - #[cfg(target_os = "macos")] - #[nolink] - pub mod extra { - use libc::types::os::arch::c95::{c_char, c_int}; - - #[abi = "cdecl"] - pub extern { - unsafe fn _NSGetExecutablePath(buf: *mut c_char, - bufsize: *mut u32) - -> c_int; - } - } - - #[cfg(target_os = "freebsd")] - pub mod extra { - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - pub mod extra { - } - - - #[cfg(target_os = "win32")] - pub mod extra { - - pub mod kernel32 { - use libc::types::os::arch::c95::{c_uint}; - use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE}; - use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR, - LPTSTR, LPTCH, LPDWORD, LPVOID}; - use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO, - LPPROCESS_INFORMATION}; - use libc::types::os::arch::extra::{HANDLE, LPHANDLE}; - - #[abi = "stdcall"] - pub extern "stdcall" { - unsafe fn GetEnvironmentVariableW(n: LPCWSTR, - v: LPWSTR, - nsize: DWORD) - -> DWORD; - unsafe fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) - -> BOOL; - unsafe fn GetEnvironmentStringsA() -> LPTCH; - unsafe fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL; - - unsafe fn GetModuleFileNameW(hModule: HMODULE, - lpFilename: LPWSTR, - nSize: DWORD) - -> DWORD; - unsafe fn CreateDirectoryW(lpPathName: LPCWSTR, - lpSecurityAttributes: - LPSECURITY_ATTRIBUTES) - -> BOOL; - unsafe fn CopyFileW(lpExistingFileName: LPCWSTR, - lpNewFileName: LPCWSTR, - bFailIfExists: BOOL) - -> BOOL; - unsafe fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; - unsafe fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL; - unsafe fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; - - unsafe fn GetLastError() -> DWORD; - unsafe fn FindFirstFileW(fileName: *u16, - findFileData: HANDLE) - -> HANDLE; - unsafe fn FindNextFileW(findFile: HANDLE, - findFileData: HANDLE) - -> BOOL; - unsafe fn FindClose(findFile: HANDLE) -> BOOL; - unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE, - hSourceHandle: HANDLE, - hTargetProcessHandle: HANDLE, - lpTargetHandle: LPHANDLE, - dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwOptions: DWORD) -> BOOL; - unsafe fn CloseHandle(hObject: HANDLE) -> BOOL; - unsafe fn OpenProcess(dwDesiredAccess: DWORD, - bInheritHandle: BOOL, - dwProcessId: DWORD) -> HANDLE; - unsafe fn GetCurrentProcess() -> HANDLE; - unsafe fn CreateProcessA(lpApplicationName: LPCTSTR, - lpCommandLine: LPTSTR, - lpProcessAttributes: LPSECURITY_ATTRIBUTES, - lpThreadAttributes: LPSECURITY_ATTRIBUTES, - bInheritHandles: BOOL, - dwCreationFlags: DWORD, - lpEnvironment: LPVOID, - lpCurrentDirectory: LPCTSTR, - lpStartupInfo: LPSTARTUPINFO, - lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL; - unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; - unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL; - unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; - } - } - - pub mod msvcrt { - use libc::types::os::arch::c95::{c_int, c_long}; - - #[abi = "cdecl"] - #[nolink] - pub extern { - #[link_name = "_commit"] - unsafe fn commit(fd: c_int) -> c_int; - - #[link_name = "_get_osfhandle"] - unsafe fn get_osfhandle(fd: c_int) -> c_long; - } - } - } -} diff --git a/src/libcore/local_data.rs b/src/libcore/local_data.rs deleted file mode 100644 index 2cbf8b9f05e..00000000000 --- a/src/libcore/local_data.rs +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -Task local data management - -Allows storing boxes with arbitrary types inside, to be accessed -anywhere within a task, keyed by a pointer to a global finaliser -function. Useful for dynamic variables, singletons, and interfacing -with foreign code with bad callback interfaces. - -To use, declare a monomorphic global function at the type to store, -and use it as the 'key' when accessing. See the 'tls' tests below for -examples. - -Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation -magic. - -*/ - -use prelude::*; -use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handle}; - -/** - * 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 - * task-local data slot (and use class destructors, not code inside the - * function, if specific teardown is needed). DO NOT use multiple - * instantiations of a single polymorphic function to index data of different - * types; arbitrary type coercion is possible this way. - * - * One other exception is that this global state can be used in a destructor - * context to create a circular @-box reference, which will crash during task - * failure (see issue #3039). - * - * These two cases aside, the interface is safe. - */ -pub type LocalDataKey<'self,T> = &'self fn(v: @T); - -/** - * Remove a task-local data value from the table, returning the - * reference that was originally created to insert it. - */ -pub unsafe fn local_data_pop<T: 'static>( - key: LocalDataKey<T>) -> Option<@T> { - - local_pop(Handle::new(), key) -} -/** - * Retrieve a task-local data value. It will also be kept alive in the - * table until explicitly removed. - */ -pub unsafe fn local_data_get<T: 'static>( - key: LocalDataKey<T>) -> Option<@T> { - - local_get(Handle::new(), key) -} -/** - * Store a value in task-local data. If this key already has a value, - * that value is overwritten (and its destructor is run). - */ -pub unsafe fn local_data_set<T: 'static>( - key: LocalDataKey<T>, data: @T) { - - local_set(Handle::new(), key, data) -} -/** - * Modify a task-local data value. If the function returns 'None', the - * data is removed (and its reference dropped). - */ -pub unsafe fn local_data_modify<T: 'static>( - key: LocalDataKey<T>, - modify_fn: &fn(Option<@T>) -> Option<@T>) { - - local_modify(Handle::new(), key, modify_fn) -} - -#[test] -fn test_tls_multitask() { - unsafe { - fn my_key(_x: @~str) { } - local_data_set(my_key, @~"parent data"); - do task::spawn { - unsafe { - // TLS shouldn't carry over. - assert!(local_data_get(my_key).is_none()); - local_data_set(my_key, @~"child data"); - assert!(*(local_data_get(my_key).get()) == - ~"child data"); - // should be cleaned up for us - } - } - // Must work multiple times - assert!(*(local_data_get(my_key).get()) == ~"parent data"); - assert!(*(local_data_get(my_key).get()) == ~"parent data"); - assert!(*(local_data_get(my_key).get()) == ~"parent data"); - } -} - -#[test] -fn test_tls_overwrite() { - unsafe { - fn my_key(_x: @~str) { } - local_data_set(my_key, @~"first data"); - local_data_set(my_key, @~"next data"); // Shouldn't leak. - assert!(*(local_data_get(my_key).get()) == ~"next data"); - } -} - -#[test] -fn test_tls_pop() { - unsafe { - fn my_key(_x: @~str) { } - local_data_set(my_key, @~"weasel"); - assert!(*(local_data_pop(my_key).get()) == ~"weasel"); - // Pop must remove the data from the map. - assert!(local_data_pop(my_key).is_none()); - } -} - -#[test] -fn test_tls_modify() { - unsafe { - fn my_key(_x: @~str) { } - local_data_modify(my_key, |data| { - match data { - Some(@ref val) => fail!("unwelcome value: %s", *val), - None => Some(@~"first data") - } - }); - local_data_modify(my_key, |data| { - match data { - Some(@~"first data") => Some(@~"next data"), - Some(@ref val) => fail!("wrong value: %s", *val), - None => fail!("missing value") - } - }); - assert!(*(local_data_pop(my_key).get()) == ~"next data"); - } -} - -#[test] -fn test_tls_crust_automorestack_memorial_bug() { - // This might result in a stack-canary clobber if the runtime fails to - // set sp_limit to 0 when calling the cleanup extern - it might - // automatically jump over to the rust stack, which causes next_c_sp - // to get recorded as something within a rust stack segment. Then a - // subsequent upcall (esp. for logging, think vsnprintf) would run on - // a stack smaller than 1 MB. - fn my_key(_x: @~str) { } - do task::spawn { - unsafe { local_data_set(my_key, @~"hax"); } - } -} - -#[test] -fn test_tls_multiple_types() { - fn str_key(_x: @~str) { } - fn box_key(_x: @@()) { } - fn int_key(_x: @int) { } - do task::spawn { - unsafe { - local_data_set(str_key, @~"string data"); - local_data_set(box_key, @@()); - local_data_set(int_key, @42); - } - } -} - -#[test] -fn test_tls_overwrite_multiple_types() { - fn str_key(_x: @~str) { } - fn box_key(_x: @@()) { } - fn int_key(_x: @int) { } - do task::spawn { - unsafe { - local_data_set(str_key, @~"string data"); - local_data_set(int_key, @42); - // This could cause a segfault if overwriting-destruction is done - // with the crazy polymorphic transmute rather than the provided - // finaliser. - local_data_set(int_key, @31337); - } - } -} - -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_tls_cleanup_on_failure() { - unsafe { - fn str_key(_x: @~str) { } - fn box_key(_x: @@()) { } - fn int_key(_x: @int) { } - local_data_set(str_key, @~"parent data"); - local_data_set(box_key, @@()); - do task::spawn { - unsafe { // spawn_linked - local_data_set(str_key, @~"string data"); - local_data_set(box_key, @@()); - local_data_set(int_key, @42); - fail!(); - } - } - // Not quite nondeterministic. - local_data_set(int_key, @31337); - fail!(); - } -} - -#[test] -fn test_static_pointer() { - unsafe { - fn key(_x: @&'static int) { } - static VALUE: int = 0; - local_data_set(key, @&VALUE); - } -} diff --git a/src/libcore/logging.rs b/src/libcore/logging.rs deleted file mode 100644 index be71714a048..00000000000 --- a/src/libcore/logging.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Logging - -use option::*; -use either::*; -use rt; -use rt::logging::{Logger, StdErrLogger}; -use cast; -use str; - -/// Turns on logging to stdout globally -pub fn console_on() { - unsafe { - rustrt::rust_log_console_on(); - } -} - -/** - * Turns off logging to stdout globally - * - * Turns off the console unless the user has overridden the - * runtime environment's logging spec, e.g. by setting - * the RUST_LOG environment variable - */ -pub fn console_off() { - unsafe { - rustrt::rust_log_console_off(); - } -} - -#[cfg(not(test))] -#[lang="log_type"] -pub fn log_type<T>(level: u32, object: &T) { - use container::Container; - use io; - use libc; - use repr; - use vec; - - let bytes = do io::with_bytes_writer |writer| { - repr::write_repr(writer, object); - }; - - match rt::context() { - rt::OldTaskContext => { - unsafe { - let len = bytes.len() as libc::size_t; - rustrt::rust_log_str(level, cast::transmute(vec::raw::to_ptr(bytes)), len); - } - } - _ => { - // XXX: Bad allocation - let msg = str::from_bytes(bytes); - newsched_log_str(msg); - } - } -} - -fn newsched_log_str(msg: ~str) { - use rt::task::Task; - use rt::local::Local; - - unsafe { - match Local::try_unsafe_borrow::<Task>() { - Some(local) => { - // Use the available logger - (*local).logger.log(Left(msg)); - } - None => { - // There is no logger anywhere, just write to stderr - let mut logger = StdErrLogger; - logger.log(Left(msg)); - } - } - } -} - -pub mod rustrt { - use libc; - - pub extern { - unsafe fn rust_log_console_on(); - unsafe fn rust_log_console_off(); - unsafe fn rust_log_str(level: u32, - string: *libc::c_char, - size: libc::size_t); - } -} diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs deleted file mode 100644 index fda48b6ffb7..00000000000 --- a/src/libcore/macros.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[macro_escape]; - -// Some basic logging -macro_rules! rtdebug_ ( - ($( $arg:expr),+) => ( { - dumb_println(fmt!( $($arg),+ )); - - fn dumb_println(s: &str) { - use io::WriterUtil; - let dbg = ::libc::STDERR_FILENO as ::io::fd_t; - dbg.write_str(s); - dbg.write_str("\n"); - } - - } ) -) - -// An alternate version with no output, for turning off logging -macro_rules! rtdebug ( - ($( $arg:expr),+) => ( $(let _ = $arg)*; ) -) - -macro_rules! rtassert ( - ( $arg:expr ) => ( { - if !$arg { - abort!("assertion failed: %s", stringify!($arg)); - } - } ) -) - -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(); } - } - } ) -) diff --git a/src/libcore/managed.rs b/src/libcore/managed.rs deleted file mode 100644 index ecde1eb1917..00000000000 --- a/src/libcore/managed.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations on managed box types - -use ptr::to_unsafe_ptr; - -#[cfg(not(test))] use cmp::{Eq, Ord}; - -pub mod raw { - use intrinsic::TyDesc; - - pub static RC_EXCHANGE_UNIQUE : uint = (-1) as uint; - pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; - pub static RC_IMMORTAL : uint = 0x77777777; - - pub struct BoxHeaderRepr { - ref_count: uint, - type_desc: *TyDesc, - prev: *BoxRepr, - next: *BoxRepr, - } - - pub struct BoxRepr { - header: BoxHeaderRepr, - data: u8 - } - -} - -/// 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); - 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); - a_ptr == b_ptr -} - -#[cfg(not(test))] -impl<T:Eq> Eq for @T { - #[inline(always)] - fn eq(&self, other: &@T) -> bool { *(*self) == *(*other) } - #[inline(always)] - fn ne(&self, other: &@T) -> bool { *(*self) != *(*other) } -} - -#[cfg(not(test))] -impl<T:Eq> Eq for @mut T { - #[inline(always)] - fn eq(&self, other: &@mut T) -> bool { *(*self) == *(*other) } - #[inline(always)] - fn ne(&self, other: &@mut T) -> bool { *(*self) != *(*other) } -} - -#[cfg(not(test))] -impl<T:Ord> Ord for @T { - #[inline(always)] - fn lt(&self, other: &@T) -> bool { *(*self) < *(*other) } - #[inline(always)] - fn le(&self, other: &@T) -> bool { *(*self) <= *(*other) } - #[inline(always)] - fn ge(&self, other: &@T) -> bool { *(*self) >= *(*other) } - #[inline(always)] - fn gt(&self, other: &@T) -> bool { *(*self) > *(*other) } -} - -#[cfg(not(test))] -impl<T:Ord> Ord for @mut T { - #[inline(always)] - fn lt(&self, other: &@mut T) -> bool { *(*self) < *(*other) } - #[inline(always)] - fn le(&self, other: &@mut T) -> bool { *(*self) <= *(*other) } - #[inline(always)] - fn ge(&self, other: &@mut T) -> bool { *(*self) >= *(*other) } - #[inline(always)] - fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) } -} - -#[test] -fn test() { - let x = @3; - let y = @3; - assert!((ptr_eq::<int>(x, x))); - assert!((ptr_eq::<int>(y, y))); - assert!((!ptr_eq::<int>(x, y))); - assert!((!ptr_eq::<int>(y, x))); -} diff --git a/src/libcore/nil.rs b/src/libcore/nil.rs deleted file mode 100644 index 833bd3459ce..00000000000 --- a/src/libcore/nil.rs +++ /dev/null @@ -1,50 +0,0 @@ -// 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. - -/*! - -Functions for the unit type. - -*/ - -#[cfg(not(test))] -use prelude::*; - -#[cfg(not(test))] -impl Eq for () { - #[inline(always)] - fn eq(&self, _other: &()) -> bool { true } - #[inline(always)] - fn ne(&self, _other: &()) -> bool { false } -} - -#[cfg(not(test))] -impl Ord for () { - #[inline(always)] - fn lt(&self, _other: &()) -> bool { false } - #[inline(always)] - fn le(&self, _other: &()) -> bool { true } - #[inline(always)] - fn ge(&self, _other: &()) -> bool { true } - #[inline(always)] - fn gt(&self, _other: &()) -> bool { false } -} - -#[cfg(not(test))] -impl TotalOrd for () { - #[inline(always)] - fn cmp(&self, _other: &()) -> Ordering { Equal } -} - -#[cfg(not(test))] -impl TotalEq for () { - #[inline(always)] - fn equals(&self, _other: &()) -> bool { true } -} diff --git a/src/libcore/num/cmath.rs b/src/libcore/num/cmath.rs deleted file mode 100644 index a80703fafa3..00000000000 --- a/src/libcore/num/cmath.rs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; // FIXME #3538 - -// function names are almost identical to C's libmath, a few have been -// renamed, grep for "rename:" - -pub mod c_double_utils { - use libc::{c_double, c_int}; - - #[link_name = "m"] - #[abi = "cdecl"] - pub extern { - // Alpabetically sorted by link_name - - unsafe fn acos(n: c_double) -> c_double; - unsafe fn asin(n: c_double) -> c_double; - unsafe fn atan(n: c_double) -> c_double; - unsafe fn atan2(a: c_double, b: c_double) -> c_double; - unsafe fn cbrt(n: c_double) -> c_double; - unsafe fn ceil(n: c_double) -> c_double; - unsafe fn copysign(x: c_double, y: c_double) -> c_double; - unsafe fn cos(n: c_double) -> c_double; - unsafe fn cosh(n: c_double) -> c_double; - unsafe fn erf(n: c_double) -> c_double; - unsafe fn erfc(n: c_double) -> c_double; - unsafe fn exp(n: c_double) -> c_double; - // rename: for consistency with underscore usage elsewhere - #[link_name="expm1"] unsafe fn exp_m1(n: c_double) -> c_double; - unsafe fn exp2(n: c_double) -> c_double; - #[link_name="fabs"] unsafe fn abs(n: c_double) -> c_double; - // rename: for clarity and consistency with add/sub/mul/div - #[link_name="fdim"] - unsafe fn abs_sub(a: c_double, b: c_double) -> c_double; - unsafe fn floor(n: c_double) -> c_double; - // rename: for clarity and consistency with add/sub/mul/div - #[link_name="fma"] - unsafe fn mul_add(a: c_double, b: c_double, c: c_double) -> c_double; - #[link_name="fmax"] - unsafe fn fmax(a: c_double, b: c_double) -> c_double; - #[link_name="fmin"] - unsafe fn fmin(a: c_double, b: c_double) -> c_double; - #[link_name="nextafter"] - unsafe fn next_after(x: c_double, y: c_double) -> c_double; - unsafe fn frexp(n: c_double, value: &mut c_int) -> c_double; - unsafe fn hypot(x: c_double, y: c_double) -> c_double; - unsafe fn ldexp(x: c_double, n: c_int) -> c_double; - #[cfg(unix)] - #[link_name="lgamma_r"] - unsafe fn lgamma(n: c_double, sign: &mut c_int) -> c_double; - #[cfg(windows)] - #[link_name="__lgamma_r"] - unsafe fn lgamma(n: c_double, sign: &mut c_int) -> c_double; - // renamed: log is a reserved keyword; ln seems more natural, too - #[link_name="log"] unsafe fn ln(n: c_double) -> c_double; - // renamed: "logb" /often/ is confused for log2 by beginners - #[link_name="logb"] unsafe fn log_radix(n: c_double) -> c_double; - // renamed: to be consitent with log as ln - #[link_name="log1p"] unsafe fn ln_1p(n: c_double) -> c_double; - unsafe fn log10(n: c_double) -> c_double; - unsafe fn log2(n: c_double) -> c_double; - #[link_name="ilogb"] unsafe fn ilog_radix(n: c_double) -> c_int; - unsafe fn modf(n: c_double, iptr: &mut c_double) -> c_double; - unsafe fn pow(n: c_double, e: c_double) -> c_double; - // FIXME (#1379): enable when rounding modes become available - // unsafe fn rint(n: c_double) -> c_double; - unsafe fn round(n: c_double) -> c_double; - // rename: for consistency with logradix - #[link_name="scalbn"] unsafe fn ldexp_radix(n: c_double, i: c_int) -> - c_double; - unsafe fn sin(n: c_double) -> c_double; - unsafe fn sinh(n: c_double) -> c_double; - unsafe fn sqrt(n: c_double) -> c_double; - unsafe fn tan(n: c_double) -> c_double; - unsafe fn tanh(n: c_double) -> c_double; - unsafe fn tgamma(n: c_double) -> c_double; - unsafe fn trunc(n: c_double) -> c_double; - - // These are commonly only available for doubles - - unsafe fn j0(n: c_double) -> c_double; - unsafe fn j1(n: c_double) -> c_double; - unsafe fn jn(i: c_int, n: c_double) -> c_double; - - unsafe fn y0(n: c_double) -> c_double; - unsafe fn y1(n: c_double) -> c_double; - unsafe fn yn(i: c_int, n: c_double) -> c_double; - } -} - -pub mod c_float_utils { - use libc::{c_float, c_int}; - - #[link_name = "m"] - #[abi = "cdecl"] - pub extern { - // Alpabetically sorted by link_name - - #[link_name="acosf"] unsafe fn acos(n: c_float) -> c_float; - #[link_name="asinf"] unsafe fn asin(n: c_float) -> c_float; - #[link_name="atanf"] unsafe fn atan(n: c_float) -> c_float; - #[link_name="atan2f"] - unsafe fn atan2(a: c_float, b: c_float) -> c_float; - #[link_name="cbrtf"] unsafe fn cbrt(n: c_float) -> c_float; - #[link_name="ceilf"] unsafe fn ceil(n: c_float) -> c_float; - #[link_name="copysignf"] unsafe fn copysign(x: c_float, - y: c_float) -> c_float; - #[link_name="cosf"] unsafe fn cos(n: c_float) -> c_float; - #[link_name="coshf"] unsafe fn cosh(n: c_float) -> c_float; - #[link_name="erff"] unsafe fn erf(n: c_float) -> c_float; - #[link_name="erfcf"] unsafe fn erfc(n: c_float) -> c_float; - #[link_name="expf"] unsafe fn exp(n: c_float) -> c_float; - #[link_name="expm1f"]unsafe fn exp_m1(n: c_float) -> c_float; - #[link_name="exp2f"] unsafe fn exp2(n: c_float) -> c_float; - #[link_name="fabsf"] unsafe fn abs(n: c_float) -> c_float; - #[link_name="fdimf"] - unsafe fn abs_sub(a: c_float, b: c_float) -> c_float; - #[link_name="floorf"] unsafe fn floor(n: c_float) -> c_float; - #[link_name="frexpf"] unsafe fn frexp(n: c_float, - value: &mut c_int) -> c_float; - #[link_name="fmaf"] - unsafe fn mul_add(a: c_float, b: c_float, c: c_float) -> c_float; - #[link_name="fmaxf"] - unsafe fn fmax(a: c_float, b: c_float) -> c_float; - #[link_name="fminf"] - unsafe fn fmin(a: c_float, b: c_float) -> c_float; - #[link_name="nextafterf"] - unsafe fn next_after(x: c_float, y: c_float) -> c_float; - #[link_name="hypotf"] - unsafe fn hypot(x: c_float, y: c_float) -> c_float; - #[link_name="ldexpf"] - unsafe fn ldexp(x: c_float, n: c_int) -> c_float; - - #[cfg(unix)] - #[link_name="lgammaf_r"] unsafe fn lgamma(n: c_float, - sign: &mut c_int) -> c_float; - - #[cfg(windows)] - #[link_name="__lgammaf_r"] - unsafe fn lgamma(n: c_float, sign: &mut c_int) -> c_float; - - #[link_name="logf"] unsafe fn ln(n: c_float) -> c_float; - #[link_name="logbf"] unsafe fn log_radix(n: c_float) -> c_float; - #[link_name="log1pf"] unsafe fn ln_1p(n: c_float) -> c_float; - #[link_name="log2f"] unsafe fn log2(n: c_float) -> c_float; - #[link_name="log10f"] unsafe fn log10(n: c_float) -> c_float; - #[link_name="ilogbf"] unsafe fn ilog_radix(n: c_float) -> c_int; - #[link_name="modff"] unsafe fn modf(n: c_float, - iptr: &mut c_float) -> c_float; - #[link_name="powf"] unsafe fn pow(n: c_float, e: c_float) -> c_float; - // FIXME (#1379): enable when rounding modes become available - // #[link_name="rintf"] unsafe fn rint(n: c_float) -> c_float; - #[link_name="roundf"] unsafe fn round(n: c_float) -> c_float; - #[link_name="scalbnf"] unsafe fn ldexp_radix(n: c_float, i: c_int) - -> c_float; - #[link_name="sinf"] unsafe fn sin(n: c_float) -> c_float; - #[link_name="sinhf"] unsafe fn sinh(n: c_float) -> c_float; - #[link_name="sqrtf"] unsafe fn sqrt(n: c_float) -> c_float; - #[link_name="tanf"] unsafe fn tan(n: c_float) -> c_float; - #[link_name="tanhf"] unsafe fn tanh(n: c_float) -> c_float; - #[link_name="tgammaf"] unsafe fn tgamma(n: c_float) -> c_float; - #[link_name="truncf"] unsafe fn trunc(n: c_float) -> c_float; - } -} - -// PORT check these by running src/etc/machconsts.c for your architecture - -// FIXME obtain machine float/math constants automatically (Issue #1986) - -pub mod c_float_targ_consts { - pub static radix: uint = 2u; - pub static mantissa_digits: uint = 24u; - pub static digits: uint = 6u; - pub static min_exp: uint = -125u; - pub static max_exp: uint = 128u; - pub static min_10_exp: int = -37; - pub static max_10_exp: int = 38; - // FIXME (#1433): this is wrong, replace with hexadecimal (%a) staticants - // below. - pub static min_value: f32 = 1.175494e-38_f32; - pub static max_value: f32 = 3.402823e+38_f32; - pub static epsilon: f32 = 0.000000_f32; -} - -pub mod c_double_targ_consts { - pub static radix: uint = 2u; - pub static mantissa_digits: uint = 53u; - pub static digits: uint = 15u; - pub static min_exp: uint = -1021u; - pub static max_exp: uint = 1024u; - pub static min_10_exp: int = -307; - pub static max_10_exp: int = 308; - // FIXME (#1433): this is wrong, replace with hexadecimal (%a) staticants - // below. - pub static min_value: f64 = 2.225074e-308_f64; - pub static max_value: f64 = 1.797693e+308_f64; - pub static epsilon: f64 = 2.220446e-16_f64; -} - -/* - -FIXME use these once they can be parsed (see Issue #1433) - -pub mod c_float_math_consts { - pub static pi: c_float = 0x1.921fb6p+1_f32; - pub static div_1_pi: c_float = 0x1.45f306p-2_f32; - pub static div_2_pi: c_float = 0x1.45f306p-1_f32; - pub static div_pi_2: c_float = 0x1.921fb6p+0_f32; - pub static div_pi_4: c_float = 0x1.921fb6p-1_f32; - pub static div_2_sqrtpi: c_float = 0x1.20dd76p+0_f32; - pub static e: c_float = 0x1.5bf0a8p+1_f32; - pub static log2_e: c_float = 0x1.715476p+0_f32; - pub static log10_e: c_float = 0x1.bcb7b2p-2_f32; - pub static ln_2: c_float = 0x1.62e43p-1_f32; - pub static ln_10: c_float = 0x1.26bb1cp+1_f32; - pub static sqrt2: c_float = 0x1.6a09e6p+0_f32; - pub static div_1_sqrt2: c_float = 0x1.6a09e6p-1_f32; -} - -pub mod c_double_math_consts { - pub static pi: c_double = 0x1.921fb54442d18p+1_f64; - pub static div_1_pi: c_double = 0x1.45f306dc9c883p-2_f64; - pub static div_2_pi: c_double = 0x1.45f306dc9c883p-1_f64; - pub static div_pi_2: c_double = 0x1.921fb54442d18p+0_f64; - pub static div_pi_4: c_double = 0x1.921fb54442d18p-1_f64; - pub static div_2_sqrtpi: c_double = 0x1.20dd750429b6dp+0_f64; - pub static e: c_double = 0x1.5bf0a8b145769p+1_f64; - pub static log2_e: c_double = 0x1.71547652b82fep+0_f64; - pub static log10_e: c_double = 0x1.bcb7b1526e50ep-2_f64; - pub static ln_2: c_double = 0x1.62e42fefa39efp-1_f64; - pub static ln_10: c_double = 0x1.26bb1bbb55516p+1_f64; - pub static sqrt2: c_double = 0x1.6a09e667f3bcdp+0_f64; - pub static div_1_sqrt2: c_double = 0x1.6a09e667f3bcdp-1_f64; -} - -pub mod c_float_targ_consts { - pub static radix: uint = 2u; - pub static mantissa_digits: uint = 24u; - pub static digits: uint = 6u; - pub static min_exp: int = -125; - pub static max_exp: int = 128; - pub static min_10_exp: int = -37; - pub static max_10_exp: int = 38; - pub static min_value: c_float = 0x1p-126_f32; - pub static max_value: c_float = 0x1.fffffep+127_f32; - pub static epsilon: c_float = 0x1p-23_f32; -} - -pub mod c_double_targ_consts { - pub static radix: uint = 2u; - pub static mantissa_digits: uint = 53u; - pub static digits: uint = 15u; - pub static min_exp: int = -1021; - pub static max_exp: int = 1024; - pub static min_10_exp: int = -307; - pub static max_10_exp: int = 308; - pub static min_value: c_double = 0x1p-1022_f64; - pub static max_value: c_double = 0x1.fffffffffffffp+1023_f64; - pub static epsilon: c_double = 0x1p-52_f64; -} - -*/ diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs deleted file mode 100644 index d5dc0dd4730..00000000000 --- a/src/libcore/num/f32.rs +++ /dev/null @@ -1,1250 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `f32` - -use libc::c_int; -use num::{Zero, One, strconv}; -use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; -use prelude::*; - -pub use cmath::c_float_targ_consts::*; - -// An inner module is required to get the #[inline(always)] attribute on the -// functions. -pub use self::delegated::*; - -macro_rules! delegate( - ( - $( - fn $name:ident( - $( - $arg:ident : $arg_ty:ty - ),* - ) -> $rv:ty = $bound_name:path - ),* - ) => ( - mod delegated { - use cmath::c_float_utils; - use libc::{c_float, c_int}; - use unstable::intrinsics; - - $( - #[inline(always)] - pub fn $name($( $arg : $arg_ty ),*) -> $rv { - unsafe { - $bound_name($( $arg ),*) - } - } - )* - } - ) -) - -delegate!( - // intrinsics - fn abs(n: f32) -> f32 = intrinsics::fabsf32, - fn cos(n: f32) -> f32 = intrinsics::cosf32, - fn exp(n: f32) -> f32 = intrinsics::expf32, - fn exp2(n: f32) -> f32 = intrinsics::exp2f32, - fn floor(x: f32) -> f32 = intrinsics::floorf32, - fn ln(n: f32) -> f32 = intrinsics::logf32, - fn log10(n: f32) -> f32 = intrinsics::log10f32, - fn log2(n: f32) -> f32 = intrinsics::log2f32, - fn mul_add(a: f32, b: f32, c: f32) -> f32 = intrinsics::fmaf32, - fn pow(n: f32, e: f32) -> f32 = intrinsics::powf32, - fn powi(n: f32, e: c_int) -> f32 = intrinsics::powif32, - fn sin(n: f32) -> f32 = intrinsics::sinf32, - fn sqrt(n: f32) -> f32 = intrinsics::sqrtf32, - - // LLVM 3.3 required to use intrinsics for these four - fn ceil(n: c_float) -> c_float = c_float_utils::ceil, - fn trunc(n: c_float) -> c_float = c_float_utils::trunc, - /* - fn ceil(n: f32) -> f32 = intrinsics::ceilf32, - fn trunc(n: f32) -> f32 = intrinsics::truncf32, - fn rint(n: f32) -> f32 = intrinsics::rintf32, - fn nearbyint(n: f32) -> f32 = intrinsics::nearbyintf32, - */ - - // cmath - fn acos(n: c_float) -> c_float = c_float_utils::acos, - fn asin(n: c_float) -> c_float = c_float_utils::asin, - fn atan(n: c_float) -> c_float = c_float_utils::atan, - fn atan2(a: c_float, b: c_float) -> c_float = c_float_utils::atan2, - fn cbrt(n: c_float) -> c_float = c_float_utils::cbrt, - fn copysign(x: c_float, y: c_float) -> c_float = c_float_utils::copysign, - fn cosh(n: c_float) -> c_float = c_float_utils::cosh, - fn erf(n: c_float) -> c_float = c_float_utils::erf, - fn erfc(n: c_float) -> c_float = c_float_utils::erfc, - fn exp_m1(n: c_float) -> c_float = c_float_utils::exp_m1, - fn abs_sub(a: c_float, b: c_float) -> c_float = c_float_utils::abs_sub, - fn fmax(a: c_float, b: c_float) -> c_float = c_float_utils::fmax, - fn fmin(a: c_float, b: c_float) -> c_float = c_float_utils::fmin, - fn next_after(x: c_float, y: c_float) -> c_float = c_float_utils::next_after, - fn frexp(n: c_float, value: &mut c_int) -> c_float = c_float_utils::frexp, - fn hypot(x: c_float, y: c_float) -> c_float = c_float_utils::hypot, - fn ldexp(x: c_float, n: c_int) -> c_float = c_float_utils::ldexp, - fn lgamma(n: c_float, sign: &mut c_int) -> c_float = c_float_utils::lgamma, - fn log_radix(n: c_float) -> c_float = c_float_utils::log_radix, - fn ln_1p(n: c_float) -> c_float = c_float_utils::ln_1p, - fn ilog_radix(n: c_float) -> c_int = c_float_utils::ilog_radix, - fn modf(n: c_float, iptr: &mut c_float) -> c_float = c_float_utils::modf, - fn round(n: c_float) -> c_float = c_float_utils::round, - fn ldexp_radix(n: c_float, i: c_int) -> c_float = c_float_utils::ldexp_radix, - fn sinh(n: c_float) -> c_float = c_float_utils::sinh, - fn tan(n: c_float) -> c_float = c_float_utils::tan, - fn tanh(n: c_float) -> c_float = c_float_utils::tanh, - fn tgamma(n: c_float) -> c_float = c_float_utils::tgamma -) - -// These are not defined inside consts:: for consistency with -// the integer types - -pub static NaN: f32 = 0.0_f32/0.0_f32; - -pub static infinity: f32 = 1.0_f32/0.0_f32; - -pub static neg_infinity: f32 = -1.0_f32/0.0_f32; - -#[inline(always)] -pub fn add(x: f32, y: f32) -> f32 { return x + y; } - -#[inline(always)] -pub fn sub(x: f32, y: f32) -> f32 { return x - y; } - -#[inline(always)] -pub fn mul(x: f32, y: f32) -> f32 { return x * y; } - -#[inline(always)] -pub fn div(x: f32, y: f32) -> f32 { return x / y; } - -#[inline(always)] -pub fn rem(x: f32, y: f32) -> f32 { return x % y; } - -#[inline(always)] -pub fn lt(x: f32, y: f32) -> bool { return x < y; } - -#[inline(always)] -pub fn le(x: f32, y: f32) -> bool { return x <= y; } - -#[inline(always)] -pub fn eq(x: f32, y: f32) -> bool { return x == y; } - -#[inline(always)] -pub fn ne(x: f32, y: f32) -> bool { return x != y; } - -#[inline(always)] -pub fn ge(x: f32, y: f32) -> bool { return x >= y; } - -#[inline(always)] -pub fn gt(x: f32, y: f32) -> bool { return x > y; } - - -// FIXME (#1999): replace the predicates below with llvm intrinsics or -// calls to the libmath macros in the rust runtime for performance. - -// FIXME (#1999): add is_normal, is_subnormal, and fpclassify. - -/* Module: consts */ -pub mod consts { - // FIXME (requires Issue #1433 to fix): replace with mathematical - // staticants from cmath. - /// Archimedes' staticant - pub static pi: f32 = 3.14159265358979323846264338327950288_f32; - - /// pi/2.0 - pub static frac_pi_2: f32 = 1.57079632679489661923132169163975144_f32; - - /// pi/4.0 - pub static frac_pi_4: f32 = 0.785398163397448309615660845819875721_f32; - - /// 1.0/pi - pub static frac_1_pi: f32 = 0.318309886183790671537767526745028724_f32; - - /// 2.0/pi - pub static frac_2_pi: f32 = 0.636619772367581343075535053490057448_f32; - - /// 2.0/sqrt(pi) - pub static frac_2_sqrtpi: f32 = 1.12837916709551257389615890312154517_f32; - - /// sqrt(2.0) - pub static sqrt2: f32 = 1.41421356237309504880168872420969808_f32; - - /// 1.0/sqrt(2.0) - pub static frac_1_sqrt2: f32 = 0.707106781186547524400844362104849039_f32; - - /// Euler's number - pub static e: f32 = 2.71828182845904523536028747135266250_f32; - - /// log2(e) - pub static log2_e: f32 = 1.44269504088896340735992468100189214_f32; - - /// log10(e) - pub static log10_e: f32 = 0.434294481903251827651128918916605082_f32; - - /// ln(2.0) - pub static ln_2: f32 = 0.693147180559945309417232121458176568_f32; - - /// ln(10.0) - pub static ln_10: f32 = 2.30258509299404568401799145468436421_f32; -} - -impl Num for f32 {} - -#[cfg(not(test))] -impl Eq for f32 { - #[inline(always)] - fn eq(&self, other: &f32) -> bool { (*self) == (*other) } - #[inline(always)] - fn ne(&self, other: &f32) -> bool { (*self) != (*other) } -} - -#[cfg(not(test))] -impl ApproxEq<f32> for f32 { - #[inline(always)] - fn approx_epsilon() -> f32 { 1.0e-6 } - - #[inline(always)] - fn approx_eq(&self, other: &f32) -> bool { - self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f32, f32>()) - } - - #[inline(always)] - fn approx_eq_eps(&self, other: &f32, approx_epsilon: &f32) -> bool { - (*self - *other).abs() < *approx_epsilon - } -} - -#[cfg(not(test))] -impl Ord for f32 { - #[inline(always)] - fn lt(&self, other: &f32) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &f32) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &f32) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &f32) -> bool { (*self) > (*other) } -} - -impl Orderable for f32 { - /// Returns `NaN` if either of the numbers are `NaN`. - #[inline(always)] - fn min(&self, other: &f32) -> f32 { - if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmin(*self, *other) } - } - - /// Returns `NaN` if either of the numbers are `NaN`. - #[inline(always)] - fn max(&self, other: &f32) -> f32 { - if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmax(*self, *other) } - } - - /// Returns the number constrained within the range `mn <= self <= mx`. - /// If any of the numbers are `NaN` then `NaN` is returned. - #[inline(always)] - fn clamp(&self, mn: &f32, mx: &f32) -> f32 { - cond!( - (self.is_NaN()) { *self } - (!(*self <= *mx)) { *mx } - (!(*self >= *mn)) { *mn } - _ { *self } - ) - } -} - -impl Zero for f32 { - #[inline(always)] - fn zero() -> f32 { 0.0 } - - /// Returns true if the number is equal to either `0.0` or `-0.0` - #[inline(always)] - fn is_zero(&self) -> bool { *self == 0.0 || *self == -0.0 } -} - -impl One for f32 { - #[inline(always)] - fn one() -> f32 { 1.0 } -} - -#[cfg(not(test))] -impl Add<f32,f32> for f32 { - #[inline(always)] - fn add(&self, other: &f32) -> f32 { *self + *other } -} - -#[cfg(not(test))] -impl Sub<f32,f32> for f32 { - #[inline(always)] - fn sub(&self, other: &f32) -> f32 { *self - *other } -} - -#[cfg(not(test))] -impl Mul<f32,f32> for f32 { - #[inline(always)] - fn mul(&self, other: &f32) -> f32 { *self * *other } -} - -#[cfg(not(test))] -impl Div<f32,f32> for f32 { - #[inline(always)] - fn div(&self, other: &f32) -> f32 { *self / *other } -} - -#[cfg(not(test))] -impl Rem<f32,f32> for f32 { - #[inline(always)] - fn rem(&self, other: &f32) -> f32 { *self % *other } -} - -#[cfg(not(test))] -impl Neg<f32> for f32 { - #[inline(always)] - fn neg(&self) -> f32 { -*self } -} - -impl Signed for f32 { - /// Computes the absolute value. Returns `NaN` if the number is `NaN`. - #[inline(always)] - fn abs(&self) -> f32 { abs(*self) } - - /// - /// The positive difference of two numbers. Returns `0.0` if the number is less than or - /// equal to `other`, otherwise the difference between`self` and `other` is returned. - /// - #[inline(always)] - fn abs_sub(&self, other: &f32) -> f32 { abs_sub(*self, *other) } - - /// - /// # Returns - /// - /// - `1.0` if the number is positive, `+0.0` or `infinity` - /// - `-1.0` if the number is negative, `-0.0` or `neg_infinity` - /// - `NaN` if the number is NaN - /// - #[inline(always)] - fn signum(&self) -> f32 { - if self.is_NaN() { NaN } else { copysign(1.0, *self) } - } - - /// Returns `true` if the number is positive, including `+0.0` and `infinity` - #[inline(always)] - fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == infinity } - - /// Returns `true` if the number is negative, including `-0.0` and `neg_infinity` - #[inline(always)] - fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } -} - -impl Round for f32 { - /// Round half-way cases toward `neg_infinity` - #[inline(always)] - fn floor(&self) -> f32 { floor(*self) } - - /// Round half-way cases toward `infinity` - #[inline(always)] - fn ceil(&self) -> f32 { ceil(*self) } - - /// Round half-way cases away from `0.0` - #[inline(always)] - fn round(&self) -> f32 { round(*self) } - - /// The integer part of the number (rounds towards `0.0`) - #[inline(always)] - fn trunc(&self) -> f32 { trunc(*self) } - - /// - /// The fractional part of the number, satisfying: - /// - /// ~~~ - /// assert!(x == trunc(x) + fract(x)) - /// ~~~ - /// - #[inline(always)] - fn fract(&self) -> f32 { *self - self.trunc() } -} - -impl Fractional for f32 { - /// The reciprocal (multiplicative inverse) of the number - #[inline(always)] - fn recip(&self) -> f32 { 1.0 / *self } -} - -impl Algebraic for f32 { - #[inline(always)] - fn pow(&self, n: f32) -> f32 { pow(*self, n) } - - #[inline(always)] - fn sqrt(&self) -> f32 { sqrt(*self) } - - #[inline(always)] - fn rsqrt(&self) -> f32 { self.sqrt().recip() } - - #[inline(always)] - fn cbrt(&self) -> f32 { cbrt(*self) } - - #[inline(always)] - fn hypot(&self, other: f32) -> f32 { hypot(*self, other) } -} - -impl Trigonometric for f32 { - #[inline(always)] - fn sin(&self) -> f32 { sin(*self) } - - #[inline(always)] - fn cos(&self) -> f32 { cos(*self) } - - #[inline(always)] - fn tan(&self) -> f32 { tan(*self) } - - #[inline(always)] - fn asin(&self) -> f32 { asin(*self) } - - #[inline(always)] - fn acos(&self) -> f32 { acos(*self) } - - #[inline(always)] - fn atan(&self) -> f32 { atan(*self) } - - #[inline(always)] - fn atan2(&self, other: f32) -> f32 { atan2(*self, other) } - - /// Simultaneously computes the sine and cosine of the number - #[inline(always)] - fn sin_cos(&self) -> (f32, f32) { - (self.sin(), self.cos()) - } -} - -impl Exponential for f32 { - /// Returns the exponential of the number - #[inline(always)] - fn exp(&self) -> f32 { exp(*self) } - - /// Returns 2 raised to the power of the number - #[inline(always)] - fn exp2(&self) -> f32 { exp2(*self) } - - /// Returns the natural logarithm of the number - #[inline(always)] - fn ln(&self) -> f32 { ln(*self) } - - /// Returns the logarithm of the number with respect to an arbitrary base - #[inline(always)] - fn log(&self, base: f32) -> f32 { self.ln() / base.ln() } - - /// Returns the base 2 logarithm of the number - #[inline(always)] - fn log2(&self) -> f32 { log2(*self) } - - /// Returns the base 10 logarithm of the number - #[inline(always)] - fn log10(&self) -> f32 { log10(*self) } -} - -impl Hyperbolic for f32 { - #[inline(always)] - fn sinh(&self) -> f32 { sinh(*self) } - - #[inline(always)] - fn cosh(&self) -> f32 { cosh(*self) } - - #[inline(always)] - fn tanh(&self) -> f32 { tanh(*self) } - - /// - /// Inverse hyperbolic sine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic sine of `self` will be returned - /// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity` - /// - `NaN` if `self` is `NaN` - /// - #[inline(always)] - fn asinh(&self) -> f32 { - match *self { - neg_infinity => neg_infinity, - x => (x + ((x * x) + 1.0).sqrt()).ln(), - } - } - - /// - /// Inverse hyperbolic cosine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic cosine of `self` will be returned - /// - `infinity` if `self` is `infinity` - /// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`) - /// - #[inline(always)] - fn acosh(&self) -> f32 { - match *self { - x if x < 1.0 => Float::NaN(), - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } - } - - /// - /// Inverse hyperbolic tangent - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic tangent of `self` will be returned - /// - `self` if `self` is `0.0` or `-0.0` - /// - `infinity` if `self` is `1.0` - /// - `neg_infinity` if `self` is `-1.0` - /// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0` - /// (including `infinity` and `neg_infinity`) - /// - #[inline(always)] - fn atanh(&self) -> f32 { - 0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p() - } -} - -impl Real for f32 { - /// Archimedes' constant - #[inline(always)] - fn pi() -> f32 { 3.14159265358979323846264338327950288 } - - /// 2.0 * pi - #[inline(always)] - fn two_pi() -> f32 { 6.28318530717958647692528676655900576 } - - /// pi / 2.0 - #[inline(always)] - fn frac_pi_2() -> f32 { 1.57079632679489661923132169163975144 } - - /// pi / 3.0 - #[inline(always)] - fn frac_pi_3() -> f32 { 1.04719755119659774615421446109316763 } - - /// pi / 4.0 - #[inline(always)] - fn frac_pi_4() -> f32 { 0.785398163397448309615660845819875721 } - - /// pi / 6.0 - #[inline(always)] - fn frac_pi_6() -> f32 { 0.52359877559829887307710723054658381 } - - /// pi / 8.0 - #[inline(always)] - fn frac_pi_8() -> f32 { 0.39269908169872415480783042290993786 } - - /// 1 .0/ pi - #[inline(always)] - fn frac_1_pi() -> f32 { 0.318309886183790671537767526745028724 } - - /// 2.0 / pi - #[inline(always)] - fn frac_2_pi() -> f32 { 0.636619772367581343075535053490057448 } - - /// 2.0 / sqrt(pi) - #[inline(always)] - fn frac_2_sqrtpi() -> f32 { 1.12837916709551257389615890312154517 } - - /// sqrt(2.0) - #[inline(always)] - fn sqrt2() -> f32 { 1.41421356237309504880168872420969808 } - - /// 1.0 / sqrt(2.0) - #[inline(always)] - fn frac_1_sqrt2() -> f32 { 0.707106781186547524400844362104849039 } - - /// Euler's number - #[inline(always)] - fn e() -> f32 { 2.71828182845904523536028747135266250 } - - /// log2(e) - #[inline(always)] - fn log2_e() -> f32 { 1.44269504088896340735992468100189214 } - - /// log10(e) - #[inline(always)] - fn log10_e() -> f32 { 0.434294481903251827651128918916605082 } - - /// ln(2.0) - #[inline(always)] - fn ln_2() -> f32 { 0.693147180559945309417232121458176568 } - - /// ln(10.0) - #[inline(always)] - fn ln_10() -> f32 { 2.30258509299404568401799145468436421 } - - /// Converts to degrees, assuming the number is in radians - #[inline(always)] - fn to_degrees(&self) -> f32 { *self * (180.0 / Real::pi::<f32>()) } - - /// Converts to radians, assuming the number is in degrees - #[inline(always)] - fn to_radians(&self) -> f32 { *self * (Real::pi::<f32>() / 180.0) } -} - -impl Bounded for f32 { - #[inline(always)] - fn min_value() -> f32 { 1.17549435e-38 } - - #[inline(always)] - fn max_value() -> f32 { 3.40282347e+38 } -} - -impl Primitive for f32 { - #[inline(always)] - fn bits() -> uint { 32 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<f32>() / 8 } -} - -impl Float for f32 { - #[inline(always)] - fn NaN() -> f32 { 0.0 / 0.0 } - - #[inline(always)] - fn infinity() -> f32 { 1.0 / 0.0 } - - #[inline(always)] - fn neg_infinity() -> f32 { -1.0 / 0.0 } - - #[inline(always)] - fn neg_zero() -> f32 { -0.0 } - - /// Returns `true` if the number is NaN - #[inline(always)] - fn is_NaN(&self) -> bool { *self != *self } - - /// Returns `true` if the number is infinite - #[inline(always)] - fn is_infinite(&self) -> bool { - *self == Float::infinity() || *self == Float::neg_infinity() - } - - /// Returns `true` if the number is neither infinite or NaN - #[inline(always)] - fn is_finite(&self) -> bool { - !(self.is_NaN() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN - #[inline(always)] - fn is_normal(&self) -> bool { - self.classify() == FPNormal - } - - /// Returns the floating point category of the number. If only one property is going to - /// be tested, it is generally faster to use the specific predicate instead. - fn classify(&self) -> FPCategory { - static EXP_MASK: u32 = 0x7f800000; - static MAN_MASK: u32 = 0x007fffff; - - match ( - unsafe { ::cast::transmute::<f32,u32>(*self) } & MAN_MASK, - unsafe { ::cast::transmute::<f32,u32>(*self) } & EXP_MASK, - ) { - (0, 0) => FPZero, - (_, 0) => FPSubnormal, - (0, EXP_MASK) => FPInfinite, - (_, EXP_MASK) => FPNaN, - _ => FPNormal, - } - } - - #[inline(always)] - fn mantissa_digits() -> uint { 24 } - - #[inline(always)] - fn digits() -> uint { 6 } - - #[inline(always)] - fn epsilon() -> f32 { 1.19209290e-07 } - - #[inline(always)] - fn min_exp() -> int { -125 } - - #[inline(always)] - fn max_exp() -> int { 128 } - - #[inline(always)] - fn min_10_exp() -> int { -37 } - - #[inline(always)] - fn max_10_exp() -> int { 38 } - - /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` - #[inline(always)] - fn ldexp(x: f32, exp: int) -> f32 { - ldexp(x, exp as c_int) - } - - /// - /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: - /// - /// - `self = x * pow(2, exp)` - /// - `0.5 <= abs(x) < 1.0` - /// - #[inline(always)] - fn frexp(&self) -> (f32, int) { - let mut exp = 0; - let x = frexp(*self, &mut exp); - (x, exp as int) - } - - /// - /// Returns the exponential of the number, minus `1`, in a way that is accurate - /// even if the number is close to zero - /// - #[inline(always)] - fn exp_m1(&self) -> f32 { exp_m1(*self) } - - /// - /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately - /// than if the operations were performed separately - /// - #[inline(always)] - fn ln_1p(&self) -> f32 { ln_1p(*self) } - - /// - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This - /// produces a more accurate result with better performance than a separate multiplication - /// operation followed by an add. - /// - #[inline(always)] - fn mul_add(&self, a: f32, b: f32) -> f32 { - mul_add(*self, a, b) - } - - /// Returns the next representable floating-point value in the direction of `other` - #[inline(always)] - fn next_after(&self, other: f32) -> f32 { - next_after(*self, other) - } -} - -// -// Section: String Conversions -// - -/// -/// Converts a float to a string -/// -/// # Arguments -/// -/// * num - The float value -/// -#[inline(always)] -pub fn to_str(num: f32) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigAll); - r -} - -/// -/// Converts a float to a string in hexadecimal format -/// -/// # Arguments -/// -/// * num - The float value -/// -#[inline(always)] -pub fn to_str_hex(num: f32) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 16u, true, strconv::SignNeg, strconv::DigAll); - r -} - -/// -/// Converts a float to a string in a given radix -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -/// -/// # Failure -/// -/// Fails if called on a special value like `inf`, `-inf` or `NaN` due to -/// possible misinterpretation of the result at higher bases. If those values -/// are expected, use `to_str_radix_special()` instead. -/// -#[inline(always)] -pub fn to_str_radix(num: f32, rdx: uint) -> ~str { - let (r, special) = strconv::to_str_common( - &num, rdx, true, strconv::SignNeg, strconv::DigAll); - if special { fail!("number has a special value, \ - try to_str_radix_special() if those are expected") } - r -} - -/// -/// Converts a float to a string in a given radix, and a flag indicating -/// whether it's a special value -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -/// -#[inline(always)] -pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) { - strconv::to_str_common(&num, rdx, true, - strconv::SignNeg, strconv::DigAll) -} - -/// -/// Converts a float to a string with exactly the number of -/// provided significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -/// -#[inline(always)] -pub fn to_str_exact(num: f32, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); - r -} - -/// -/// Converts a float to a string with a maximum number of -/// significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -/// -#[inline(always)] -pub fn to_str_digits(num: f32, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); - r -} - -impl to_str::ToStr for f32 { - #[inline(always)] - fn to_str(&self) -> ~str { to_str_digits(*self, 8) } -} - -impl num::ToStrRadix for f32 { - #[inline(always)] - fn to_str_radix(&self, rdx: uint) -> ~str { - to_str_radix(*self, rdx) - } -} - -/// -/// Convert a string in base 10 to a float. -/// Accepts a optional decimal exponent. -/// -/// This function accepts strings such as -/// -/// * '3.14' -/// * '+3.14', equivalent to '3.14' -/// * '-3.14' -/// * '2.5E10', or equivalently, '2.5e10' -/// * '2.5E-10' -/// * '.' (understood as 0) -/// * '5.' -/// * '.5', or, equivalently, '0.5' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `num`. -/// -#[inline(always)] -pub fn from_str(num: &str) -> Option<f32> { - strconv::from_str_common(num, 10u, true, true, true, - strconv::ExpDec, false, false) -} - -/// -/// Convert a string in base 16 to a float. -/// Accepts a optional binary exponent. -/// -/// This function accepts strings such as -/// -/// * 'a4.fe' -/// * '+a4.fe', equivalent to 'a4.fe' -/// * '-a4.fe' -/// * '2b.aP128', or equivalently, '2b.ap128' -/// * '2b.aP-128' -/// * '.' (understood as 0) -/// * 'c.' -/// * '.c', or, equivalently, '0.c' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `[num]`. -/// -#[inline(always)] -pub fn from_str_hex(num: &str) -> Option<f32> { - strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false, false) -} - -/// -/// Convert a string in an given base to a float. -/// -/// Due to possible conflicts, this function does **not** accept -/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** -/// does it recognize exponents of any kind. -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// * radix - The base to use. Must lie in the range [2 .. 36] -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `num`. -/// -#[inline(always)] -pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> { - strconv::from_str_common(num, rdx, true, true, false, - strconv::ExpNone, false, false) -} - -impl FromStr for f32 { - #[inline(always)] - fn from_str(val: &str) -> Option<f32> { from_str(val) } -} - -impl num::FromStrRadix for f32 { - #[inline(always)] - fn from_str_radix(val: &str, rdx: uint) -> Option<f32> { - from_str_radix(val, rdx) - } -} - -#[cfg(test)] -mod tests { - use f32::*; - use num::*; - use super::*; - use prelude::*; - - #[test] - fn test_num() { - num::test_num(10f32, 2f32); - } - - #[test] - fn test_min() { - assert_eq!(1f32.min(&2f32), 1f32); - assert_eq!(2f32.min(&1f32), 1f32); - } - - #[test] - fn test_max() { - assert_eq!(1f32.max(&2f32), 2f32); - assert_eq!(2f32.max(&1f32), 2f32); - } - - #[test] - fn test_clamp() { - assert_eq!(1f32.clamp(&2f32, &4f32), 2f32); - assert_eq!(8f32.clamp(&2f32, &4f32), 4f32); - assert_eq!(3f32.clamp(&2f32, &4f32), 3f32); - assert!(3f32.clamp(&Float::NaN::<f32>(), &4f32).is_NaN()); - assert!(3f32.clamp(&2f32, &Float::NaN::<f32>()).is_NaN()); - assert!(Float::NaN::<f32>().clamp(&2f32, &4f32).is_NaN()); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f32.floor(), 1.0f32); - assert_approx_eq!(1.3f32.floor(), 1.0f32); - assert_approx_eq!(1.5f32.floor(), 1.0f32); - assert_approx_eq!(1.7f32.floor(), 1.0f32); - assert_approx_eq!(0.0f32.floor(), 0.0f32); - assert_approx_eq!((-0.0f32).floor(), -0.0f32); - assert_approx_eq!((-1.0f32).floor(), -1.0f32); - assert_approx_eq!((-1.3f32).floor(), -2.0f32); - assert_approx_eq!((-1.5f32).floor(), -2.0f32); - assert_approx_eq!((-1.7f32).floor(), -2.0f32); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f32.ceil(), 1.0f32); - assert_approx_eq!(1.3f32.ceil(), 2.0f32); - assert_approx_eq!(1.5f32.ceil(), 2.0f32); - assert_approx_eq!(1.7f32.ceil(), 2.0f32); - assert_approx_eq!(0.0f32.ceil(), 0.0f32); - assert_approx_eq!((-0.0f32).ceil(), -0.0f32); - assert_approx_eq!((-1.0f32).ceil(), -1.0f32); - assert_approx_eq!((-1.3f32).ceil(), -1.0f32); - assert_approx_eq!((-1.5f32).ceil(), -1.0f32); - assert_approx_eq!((-1.7f32).ceil(), -1.0f32); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f32.round(), 1.0f32); - assert_approx_eq!(1.3f32.round(), 1.0f32); - assert_approx_eq!(1.5f32.round(), 2.0f32); - assert_approx_eq!(1.7f32.round(), 2.0f32); - assert_approx_eq!(0.0f32.round(), 0.0f32); - assert_approx_eq!((-0.0f32).round(), -0.0f32); - assert_approx_eq!((-1.0f32).round(), -1.0f32); - assert_approx_eq!((-1.3f32).round(), -1.0f32); - assert_approx_eq!((-1.5f32).round(), -2.0f32); - assert_approx_eq!((-1.7f32).round(), -2.0f32); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f32.trunc(), 1.0f32); - assert_approx_eq!(1.3f32.trunc(), 1.0f32); - assert_approx_eq!(1.5f32.trunc(), 1.0f32); - assert_approx_eq!(1.7f32.trunc(), 1.0f32); - assert_approx_eq!(0.0f32.trunc(), 0.0f32); - assert_approx_eq!((-0.0f32).trunc(), -0.0f32); - assert_approx_eq!((-1.0f32).trunc(), -1.0f32); - assert_approx_eq!((-1.3f32).trunc(), -1.0f32); - assert_approx_eq!((-1.5f32).trunc(), -1.0f32); - assert_approx_eq!((-1.7f32).trunc(), -1.0f32); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f32.fract(), 0.0f32); - assert_approx_eq!(1.3f32.fract(), 0.3f32); - assert_approx_eq!(1.5f32.fract(), 0.5f32); - assert_approx_eq!(1.7f32.fract(), 0.7f32); - assert_approx_eq!(0.0f32.fract(), 0.0f32); - assert_approx_eq!((-0.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.3f32).fract(), -0.3f32); - assert_approx_eq!((-1.5f32).fract(), -0.5f32); - assert_approx_eq!((-1.7f32).fract(), -0.7f32); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f32.asinh(), 0.0f32); - assert_eq!((-0.0f32).asinh(), -0.0f32); - assert_eq!(Float::infinity::<f32>().asinh(), Float::infinity::<f32>()); - assert_eq!(Float::neg_infinity::<f32>().asinh(), Float::neg_infinity::<f32>()); - assert!(Float::NaN::<f32>().asinh().is_NaN()); - assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); - assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f32.acosh(), 0.0f32); - assert!(0.999f32.acosh().is_NaN()); - assert_eq!(Float::infinity::<f32>().acosh(), Float::infinity::<f32>()); - assert!(Float::neg_infinity::<f32>().acosh().is_NaN()); - assert!(Float::NaN::<f32>().acosh().is_NaN()); - assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); - assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f32.atanh(), 0.0f32); - assert_eq!((-0.0f32).atanh(), -0.0f32); - assert_eq!(1.0f32.atanh(), Float::infinity::<f32>()); - assert_eq!((-1.0f32).atanh(), Float::neg_infinity::<f32>()); - assert!(2f64.atanh().atanh().is_NaN()); - assert!((-2f64).atanh().atanh().is_NaN()); - assert!(Float::infinity::<f64>().atanh().is_NaN()); - assert!(Float::neg_infinity::<f64>().atanh().is_NaN()); - assert!(Float::NaN::<f32>().atanh().is_NaN()); - assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); - assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); - } - - #[test] - fn test_real_consts() { - assert_approx_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>()); - assert_approx_eq!(Real::frac_pi_2::<f32>(), Real::pi::<f32>() / 2f32); - assert_approx_eq!(Real::frac_pi_3::<f32>(), Real::pi::<f32>() / 3f32); - assert_approx_eq!(Real::frac_pi_4::<f32>(), Real::pi::<f32>() / 4f32); - assert_approx_eq!(Real::frac_pi_6::<f32>(), Real::pi::<f32>() / 6f32); - assert_approx_eq!(Real::frac_pi_8::<f32>(), Real::pi::<f32>() / 8f32); - assert_approx_eq!(Real::frac_1_pi::<f32>(), 1f32 / Real::pi::<f32>()); - assert_approx_eq!(Real::frac_2_pi::<f32>(), 2f32 / Real::pi::<f32>()); - assert_approx_eq!(Real::frac_2_sqrtpi::<f32>(), 2f32 / Real::pi::<f32>().sqrt()); - assert_approx_eq!(Real::sqrt2::<f32>(), 2f32.sqrt()); - assert_approx_eq!(Real::frac_1_sqrt2::<f32>(), 1f32 / 2f32.sqrt()); - assert_approx_eq!(Real::log2_e::<f32>(), Real::e::<f32>().log2()); - assert_approx_eq!(Real::log10_e::<f32>(), Real::e::<f32>().log10()); - assert_approx_eq!(Real::ln_2::<f32>(), 2f32.ln()); - assert_approx_eq!(Real::ln_10::<f32>(), 10f32.ln()); - } - - #[test] - pub fn test_abs() { - assert_eq!(infinity.abs(), infinity); - assert_eq!(1f32.abs(), 1f32); - assert_eq!(0f32.abs(), 0f32); - assert_eq!((-0f32).abs(), 0f32); - assert_eq!((-1f32).abs(), 1f32); - assert_eq!(neg_infinity.abs(), infinity); - assert_eq!((1f32/neg_infinity).abs(), 0f32); - assert!(NaN.abs().is_NaN()); - } - - #[test] - fn test_abs_sub() { - assert_eq!((-1f32).abs_sub(&1f32), 0f32); - assert_eq!(1f32.abs_sub(&1f32), 0f32); - assert_eq!(1f32.abs_sub(&0f32), 1f32); - assert_eq!(1f32.abs_sub(&-1f32), 2f32); - assert_eq!(neg_infinity.abs_sub(&0f32), 0f32); - assert_eq!(infinity.abs_sub(&1f32), infinity); - assert_eq!(0f32.abs_sub(&neg_infinity), infinity); - assert_eq!(0f32.abs_sub(&infinity), 0f32); - assert!(NaN.abs_sub(&-1f32).is_NaN()); - assert!(1f32.abs_sub(&NaN).is_NaN()); - } - - #[test] - fn test_signum() { - assert_eq!(infinity.signum(), 1f32); - assert_eq!(1f32.signum(), 1f32); - assert_eq!(0f32.signum(), 1f32); - assert_eq!((-0f32).signum(), -1f32); - assert_eq!((-1f32).signum(), -1f32); - assert_eq!(neg_infinity.signum(), -1f32); - assert_eq!((1f32/neg_infinity).signum(), -1f32); - assert!(NaN.signum().is_NaN()); - } - - #[test] - fn test_is_positive() { - assert!(infinity.is_positive()); - assert!(1f32.is_positive()); - assert!(0f32.is_positive()); - assert!(!(-0f32).is_positive()); - assert!(!(-1f32).is_positive()); - assert!(!neg_infinity.is_positive()); - assert!(!(1f32/neg_infinity).is_positive()); - assert!(!NaN.is_positive()); - } - - #[test] - fn test_is_negative() { - assert!(!infinity.is_negative()); - assert!(!1f32.is_negative()); - assert!(!0f32.is_negative()); - assert!((-0f32).is_negative()); - assert!((-1f32).is_negative()); - assert!(neg_infinity.is_negative()); - assert!((1f32/neg_infinity).is_negative()); - assert!(!NaN.is_negative()); - } - - #[test] - fn test_approx_eq() { - assert!(1.0f32.approx_eq(&1f32)); - assert!(0.9999999f32.approx_eq(&1f32)); - assert!(1.000001f32.approx_eq_eps(&1f32, &1.0e-5)); - assert!(1.0000001f32.approx_eq_eps(&1f32, &1.0e-6)); - assert!(!1.0000001f32.approx_eq_eps(&1f32, &1.0e-7)); - } - - #[test] - fn test_primitive() { - assert_eq!(Primitive::bits::<f32>(), sys::size_of::<f32>() * 8); - assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>()); - } - - #[test] - fn test_is_normal() { - assert!(!Float::NaN::<f32>().is_normal()); - assert!(!Float::infinity::<f32>().is_normal()); - assert!(!Float::neg_infinity::<f32>().is_normal()); - assert!(!Zero::zero::<f32>().is_normal()); - assert!(!Float::neg_zero::<f32>().is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); - } - - #[test] - fn test_classify() { - assert_eq!(Float::NaN::<f32>().classify(), FPNaN); - assert_eq!(Float::infinity::<f32>().classify(), FPInfinite); - assert_eq!(Float::neg_infinity::<f32>().classify(), FPInfinite); - assert_eq!(Zero::zero::<f32>().classify(), FPZero); - assert_eq!(Float::neg_zero::<f32>().classify(), FPZero); - assert_eq!(1f32.classify(), FPNormal); - assert_eq!(1e-37f32.classify(), FPNormal); - assert_eq!(1e-38f32.classify(), FPSubnormal); - } - - #[test] - fn test_ldexp() { - // We have to use from_str until base-2 exponents - // are supported in floating-point literals - let f1: f32 = from_str_hex("1p-123").unwrap(); - let f2: f32 = from_str_hex("1p-111").unwrap(); - assert_eq!(Float::ldexp(1f32, -123), f1); - assert_eq!(Float::ldexp(1f32, -111), f2); - - assert_eq!(Float::ldexp(0f32, -123), 0f32); - assert_eq!(Float::ldexp(-0f32, -123), -0f32); - assert_eq!(Float::ldexp(Float::infinity::<f32>(), -123), - Float::infinity::<f32>()); - assert_eq!(Float::ldexp(Float::neg_infinity::<f32>(), -123), - Float::neg_infinity::<f32>()); - assert!(Float::ldexp(Float::NaN::<f32>(), -123).is_NaN()); - } - - #[test] - fn test_frexp() { - // We have to use from_str until base-2 exponents - // are supported in floating-point literals - let f1: f32 = from_str_hex("1p-123").unwrap(); - let f2: f32 = from_str_hex("1p-111").unwrap(); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - assert_eq!((x1, exp1), (0.5f32, -122)); - assert_eq!((x2, exp2), (0.5f32, -110)); - assert_eq!(Float::ldexp(x1, exp1), f1); - assert_eq!(Float::ldexp(x2, exp2), f2); - - assert_eq!(0f32.frexp(), (0f32, 0)); - assert_eq!((-0f32).frexp(), (-0f32, 0)); - assert_eq!(match Float::infinity::<f32>().frexp() { (x, _) => x }, - Float::infinity::<f32>()) - assert_eq!(match Float::neg_infinity::<f32>().frexp() { (x, _) => x }, - Float::neg_infinity::<f32>()) - assert!(match Float::NaN::<f32>().frexp() { (x, _) => x.is_NaN() }) - } -} diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs deleted file mode 100644 index 6e2496e2e45..00000000000 --- a/src/libcore/num/f64.rs +++ /dev/null @@ -1,1295 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `f64` - -use libc::c_int; -use num::{Zero, One, strconv}; -use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; -use prelude::*; - -pub use cmath::c_double_targ_consts::*; -pub use cmp::{min, max}; - -// An inner module is required to get the #[inline(always)] attribute on the -// functions. -pub use self::delegated::*; - -macro_rules! delegate( - ( - $( - fn $name:ident( - $( - $arg:ident : $arg_ty:ty - ),* - ) -> $rv:ty = $bound_name:path - ),* - ) => ( - mod delegated { - use cmath::c_double_utils; - use libc::{c_double, c_int}; - use unstable::intrinsics; - - $( - #[inline(always)] - pub fn $name($( $arg : $arg_ty ),*) -> $rv { - unsafe { - $bound_name($( $arg ),*) - } - } - )* - } - ) -) - -delegate!( - // intrinsics - fn abs(n: f64) -> f64 = intrinsics::fabsf64, - fn cos(n: f64) -> f64 = intrinsics::cosf64, - fn exp(n: f64) -> f64 = intrinsics::expf64, - fn exp2(n: f64) -> f64 = intrinsics::exp2f64, - fn floor(x: f64) -> f64 = intrinsics::floorf64, - fn ln(n: f64) -> f64 = intrinsics::logf64, - fn log10(n: f64) -> f64 = intrinsics::log10f64, - fn log2(n: f64) -> f64 = intrinsics::log2f64, - fn mul_add(a: f64, b: f64, c: f64) -> f64 = intrinsics::fmaf64, - fn pow(n: f64, e: f64) -> f64 = intrinsics::powf64, - fn powi(n: f64, e: c_int) -> f64 = intrinsics::powif64, - fn sin(n: f64) -> f64 = intrinsics::sinf64, - fn sqrt(n: f64) -> f64 = intrinsics::sqrtf64, - - // LLVM 3.3 required to use intrinsics for these four - fn ceil(n: c_double) -> c_double = c_double_utils::ceil, - fn trunc(n: c_double) -> c_double = c_double_utils::trunc, - /* - fn ceil(n: f64) -> f64 = intrinsics::ceilf64, - fn trunc(n: f64) -> f64 = intrinsics::truncf64, - fn rint(n: c_double) -> c_double = intrinsics::rintf64, - fn nearbyint(n: c_double) -> c_double = intrinsics::nearbyintf64, - */ - - // cmath - fn acos(n: c_double) -> c_double = c_double_utils::acos, - fn asin(n: c_double) -> c_double = c_double_utils::asin, - fn atan(n: c_double) -> c_double = c_double_utils::atan, - fn atan2(a: c_double, b: c_double) -> c_double = c_double_utils::atan2, - fn cbrt(n: c_double) -> c_double = c_double_utils::cbrt, - fn copysign(x: c_double, y: c_double) -> c_double = c_double_utils::copysign, - fn cosh(n: c_double) -> c_double = c_double_utils::cosh, - fn erf(n: c_double) -> c_double = c_double_utils::erf, - fn erfc(n: c_double) -> c_double = c_double_utils::erfc, - fn exp_m1(n: c_double) -> c_double = c_double_utils::exp_m1, - fn abs_sub(a: c_double, b: c_double) -> c_double = c_double_utils::abs_sub, - fn fmax(a: c_double, b: c_double) -> c_double = c_double_utils::fmax, - fn fmin(a: c_double, b: c_double) -> c_double = c_double_utils::fmin, - fn next_after(x: c_double, y: c_double) -> c_double = c_double_utils::next_after, - fn frexp(n: c_double, value: &mut c_int) -> c_double = c_double_utils::frexp, - fn hypot(x: c_double, y: c_double) -> c_double = c_double_utils::hypot, - fn ldexp(x: c_double, n: c_int) -> c_double = c_double_utils::ldexp, - fn lgamma(n: c_double, sign: &mut c_int) -> c_double = c_double_utils::lgamma, - fn log_radix(n: c_double) -> c_double = c_double_utils::log_radix, - fn ln_1p(n: c_double) -> c_double = c_double_utils::ln_1p, - fn ilog_radix(n: c_double) -> c_int = c_double_utils::ilog_radix, - fn modf(n: c_double, iptr: &mut c_double) -> c_double = c_double_utils::modf, - fn round(n: c_double) -> c_double = c_double_utils::round, - fn ldexp_radix(n: c_double, i: c_int) -> c_double = c_double_utils::ldexp_radix, - fn sinh(n: c_double) -> c_double = c_double_utils::sinh, - fn tan(n: c_double) -> c_double = c_double_utils::tan, - fn tanh(n: c_double) -> c_double = c_double_utils::tanh, - fn tgamma(n: c_double) -> c_double = c_double_utils::tgamma, - fn j0(n: c_double) -> c_double = c_double_utils::j0, - fn j1(n: c_double) -> c_double = c_double_utils::j1, - fn jn(i: c_int, n: c_double) -> c_double = c_double_utils::jn, - fn y0(n: c_double) -> c_double = c_double_utils::y0, - fn y1(n: c_double) -> c_double = c_double_utils::y1, - fn yn(i: c_int, n: c_double) -> c_double = c_double_utils::yn -) - -// FIXME (#1433): obtain these in a different way - -// These are not defined inside consts:: for consistency with -// the integer types - -pub static radix: uint = 2u; - -pub static mantissa_digits: uint = 53u; -pub static digits: uint = 15u; - -pub static epsilon: f64 = 2.2204460492503131e-16_f64; - -pub static min_value: f64 = 2.2250738585072014e-308_f64; -pub static max_value: f64 = 1.7976931348623157e+308_f64; - -pub static min_exp: int = -1021; -pub static max_exp: int = 1024; - -pub static min_10_exp: int = -307; -pub static max_10_exp: int = 308; - -pub static NaN: f64 = 0.0_f64/0.0_f64; - -pub static infinity: f64 = 1.0_f64/0.0_f64; - -pub static neg_infinity: f64 = -1.0_f64/0.0_f64; - -#[inline(always)] -pub fn add(x: f64, y: f64) -> f64 { return x + y; } - -#[inline(always)] -pub fn sub(x: f64, y: f64) -> f64 { return x - y; } - -#[inline(always)] -pub fn mul(x: f64, y: f64) -> f64 { return x * y; } - -#[inline(always)] -pub fn div(x: f64, y: f64) -> f64 { return x / y; } - -#[inline(always)] -pub fn rem(x: f64, y: f64) -> f64 { return x % y; } - -#[inline(always)] -pub fn lt(x: f64, y: f64) -> bool { return x < y; } - -#[inline(always)] -pub fn le(x: f64, y: f64) -> bool { return x <= y; } - -#[inline(always)] -pub fn eq(x: f64, y: f64) -> bool { return x == y; } - -#[inline(always)] -pub fn ne(x: f64, y: f64) -> bool { return x != y; } - -#[inline(always)] -pub fn ge(x: f64, y: f64) -> bool { return x >= y; } - -#[inline(always)] -pub fn gt(x: f64, y: f64) -> bool { return x > y; } - - -// FIXME (#1999): add is_normal, is_subnormal, and fpclassify - -/* Module: consts */ -pub mod consts { - // FIXME (requires Issue #1433 to fix): replace with mathematical - // constants from cmath. - /// Archimedes' constant - pub static pi: f64 = 3.14159265358979323846264338327950288_f64; - - /// pi/2.0 - pub static frac_pi_2: f64 = 1.57079632679489661923132169163975144_f64; - - /// pi/4.0 - pub static frac_pi_4: f64 = 0.785398163397448309615660845819875721_f64; - - /// 1.0/pi - pub static frac_1_pi: f64 = 0.318309886183790671537767526745028724_f64; - - /// 2.0/pi - pub static frac_2_pi: f64 = 0.636619772367581343075535053490057448_f64; - - /// 2.0/sqrt(pi) - pub static frac_2_sqrtpi: f64 = 1.12837916709551257389615890312154517_f64; - - /// sqrt(2.0) - pub static sqrt2: f64 = 1.41421356237309504880168872420969808_f64; - - /// 1.0/sqrt(2.0) - pub static frac_1_sqrt2: f64 = 0.707106781186547524400844362104849039_f64; - - /// Euler's number - pub static e: f64 = 2.71828182845904523536028747135266250_f64; - - /// log2(e) - pub static log2_e: f64 = 1.44269504088896340735992468100189214_f64; - - /// log10(e) - pub static log10_e: f64 = 0.434294481903251827651128918916605082_f64; - - /// ln(2.0) - pub static ln_2: f64 = 0.693147180559945309417232121458176568_f64; - - /// ln(10.0) - pub static ln_10: f64 = 2.30258509299404568401799145468436421_f64; -} - -impl Num for f64 {} - -#[cfg(not(test))] -impl Eq for f64 { - #[inline(always)] - fn eq(&self, other: &f64) -> bool { (*self) == (*other) } - #[inline(always)] - fn ne(&self, other: &f64) -> bool { (*self) != (*other) } -} - -#[cfg(not(test))] -impl ApproxEq<f64> for f64 { - #[inline(always)] - fn approx_epsilon() -> f64 { 1.0e-6 } - - #[inline(always)] - fn approx_eq(&self, other: &f64) -> bool { - self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f64, f64>()) - } - - #[inline(always)] - fn approx_eq_eps(&self, other: &f64, approx_epsilon: &f64) -> bool { - (*self - *other).abs() < *approx_epsilon - } -} - -#[cfg(not(test))] -impl Ord for f64 { - #[inline(always)] - fn lt(&self, other: &f64) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &f64) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &f64) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &f64) -> bool { (*self) > (*other) } -} - -impl Orderable for f64 { - /// Returns `NaN` if either of the numbers are `NaN`. - #[inline(always)] - fn min(&self, other: &f64) -> f64 { - if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmin(*self, *other) } - } - - /// Returns `NaN` if either of the numbers are `NaN`. - #[inline(always)] - fn max(&self, other: &f64) -> f64 { - if self.is_NaN() || other.is_NaN() { Float::NaN() } else { fmax(*self, *other) } - } - - /// Returns the number constrained within the range `mn <= self <= mx`. - /// If any of the numbers are `NaN` then `NaN` is returned. - #[inline(always)] - fn clamp(&self, mn: &f64, mx: &f64) -> f64 { - cond!( - (self.is_NaN()) { *self } - (!(*self <= *mx)) { *mx } - (!(*self >= *mn)) { *mn } - _ { *self } - ) - } -} - -impl Zero for f64 { - #[inline(always)] - fn zero() -> f64 { 0.0 } - - /// Returns true if the number is equal to either `0.0` or `-0.0` - #[inline(always)] - fn is_zero(&self) -> bool { *self == 0.0 || *self == -0.0 } -} - -impl One for f64 { - #[inline(always)] - fn one() -> f64 { 1.0 } -} - -#[cfg(not(test))] -impl Add<f64,f64> for f64 { - fn add(&self, other: &f64) -> f64 { *self + *other } -} -#[cfg(not(test))] -impl Sub<f64,f64> for f64 { - fn sub(&self, other: &f64) -> f64 { *self - *other } -} -#[cfg(not(test))] -impl Mul<f64,f64> for f64 { - fn mul(&self, other: &f64) -> f64 { *self * *other } -} -#[cfg(not(test))] -impl Div<f64,f64> for f64 { - fn div(&self, other: &f64) -> f64 { *self / *other } -} -#[cfg(not(test))] -impl Rem<f64,f64> for f64 { - #[inline(always)] - fn rem(&self, other: &f64) -> f64 { *self % *other } -} -#[cfg(not(test))] -impl Neg<f64> for f64 { - fn neg(&self) -> f64 { -*self } -} - -impl Signed for f64 { - /// Computes the absolute value. Returns `NaN` if the number is `NaN`. - #[inline(always)] - fn abs(&self) -> f64 { abs(*self) } - - /// - /// The positive difference of two numbers. Returns `0.0` if the number is less than or - /// equal to `other`, otherwise the difference between`self` and `other` is returned. - /// - #[inline(always)] - fn abs_sub(&self, other: &f64) -> f64 { abs_sub(*self, *other) } - - /// - /// # Returns - /// - /// - `1.0` if the number is positive, `+0.0` or `infinity` - /// - `-1.0` if the number is negative, `-0.0` or `neg_infinity` - /// - `NaN` if the number is NaN - /// - #[inline(always)] - fn signum(&self) -> f64 { - if self.is_NaN() { NaN } else { copysign(1.0, *self) } - } - - /// Returns `true` if the number is positive, including `+0.0` and `infinity` - #[inline(always)] - fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == infinity } - - /// Returns `true` if the number is negative, including `-0.0` and `neg_infinity` - #[inline(always)] - fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } -} - -impl Round for f64 { - /// Round half-way cases toward `neg_infinity` - #[inline(always)] - fn floor(&self) -> f64 { floor(*self) } - - /// Round half-way cases toward `infinity` - #[inline(always)] - fn ceil(&self) -> f64 { ceil(*self) } - - /// Round half-way cases away from `0.0` - #[inline(always)] - fn round(&self) -> f64 { round(*self) } - - /// The integer part of the number (rounds towards `0.0`) - #[inline(always)] - fn trunc(&self) -> f64 { trunc(*self) } - - /// - /// The fractional part of the number, satisfying: - /// - /// ~~~ - /// assert!(x == trunc(x) + fract(x)) - /// ~~~ - /// - #[inline(always)] - fn fract(&self) -> f64 { *self - self.trunc() } -} - -impl Fractional for f64 { - /// The reciprocal (multiplicative inverse) of the number - #[inline(always)] - fn recip(&self) -> f64 { 1.0 / *self } -} - -impl Algebraic for f64 { - #[inline(always)] - fn pow(&self, n: f64) -> f64 { pow(*self, n) } - - #[inline(always)] - fn sqrt(&self) -> f64 { sqrt(*self) } - - #[inline(always)] - fn rsqrt(&self) -> f64 { self.sqrt().recip() } - - #[inline(always)] - fn cbrt(&self) -> f64 { cbrt(*self) } - - #[inline(always)] - fn hypot(&self, other: f64) -> f64 { hypot(*self, other) } -} - -impl Trigonometric for f64 { - #[inline(always)] - fn sin(&self) -> f64 { sin(*self) } - - #[inline(always)] - fn cos(&self) -> f64 { cos(*self) } - - #[inline(always)] - fn tan(&self) -> f64 { tan(*self) } - - #[inline(always)] - fn asin(&self) -> f64 { asin(*self) } - - #[inline(always)] - fn acos(&self) -> f64 { acos(*self) } - - #[inline(always)] - fn atan(&self) -> f64 { atan(*self) } - - #[inline(always)] - fn atan2(&self, other: f64) -> f64 { atan2(*self, other) } - - /// Simultaneously computes the sine and cosine of the number - #[inline(always)] - fn sin_cos(&self) -> (f64, f64) { - (self.sin(), self.cos()) - } -} - -impl Exponential for f64 { - /// Returns the exponential of the number - #[inline(always)] - fn exp(&self) -> f64 { exp(*self) } - - /// Returns 2 raised to the power of the number - #[inline(always)] - fn exp2(&self) -> f64 { exp2(*self) } - - /// Returns the natural logarithm of the number - #[inline(always)] - fn ln(&self) -> f64 { ln(*self) } - - /// Returns the logarithm of the number with respect to an arbitrary base - #[inline(always)] - fn log(&self, base: f64) -> f64 { self.ln() / base.ln() } - - /// Returns the base 2 logarithm of the number - #[inline(always)] - fn log2(&self) -> f64 { log2(*self) } - - /// Returns the base 10 logarithm of the number - #[inline(always)] - fn log10(&self) -> f64 { log10(*self) } -} - -impl Hyperbolic for f64 { - #[inline(always)] - fn sinh(&self) -> f64 { sinh(*self) } - - #[inline(always)] - fn cosh(&self) -> f64 { cosh(*self) } - - #[inline(always)] - fn tanh(&self) -> f64 { tanh(*self) } - - /// - /// Inverse hyperbolic sine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic sine of `self` will be returned - /// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity` - /// - `NaN` if `self` is `NaN` - /// - #[inline(always)] - fn asinh(&self) -> f64 { - match *self { - neg_infinity => neg_infinity, - x => (x + ((x * x) + 1.0).sqrt()).ln(), - } - } - - /// - /// Inverse hyperbolic cosine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic cosine of `self` will be returned - /// - `infinity` if `self` is `infinity` - /// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`) - /// - #[inline(always)] - fn acosh(&self) -> f64 { - match *self { - x if x < 1.0 => Float::NaN(), - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } - } - - /// - /// Inverse hyperbolic tangent - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic tangent of `self` will be returned - /// - `self` if `self` is `0.0` or `-0.0` - /// - `infinity` if `self` is `1.0` - /// - `neg_infinity` if `self` is `-1.0` - /// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0` - /// (including `infinity` and `neg_infinity`) - /// - #[inline(always)] - fn atanh(&self) -> f64 { - 0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p() - } -} - -impl Real for f64 { - /// Archimedes' constant - #[inline(always)] - fn pi() -> f64 { 3.14159265358979323846264338327950288 } - - /// 2.0 * pi - #[inline(always)] - fn two_pi() -> f64 { 6.28318530717958647692528676655900576 } - - /// pi / 2.0 - #[inline(always)] - fn frac_pi_2() -> f64 { 1.57079632679489661923132169163975144 } - - /// pi / 3.0 - #[inline(always)] - fn frac_pi_3() -> f64 { 1.04719755119659774615421446109316763 } - - /// pi / 4.0 - #[inline(always)] - fn frac_pi_4() -> f64 { 0.785398163397448309615660845819875721 } - - /// pi / 6.0 - #[inline(always)] - fn frac_pi_6() -> f64 { 0.52359877559829887307710723054658381 } - - /// pi / 8.0 - #[inline(always)] - fn frac_pi_8() -> f64 { 0.39269908169872415480783042290993786 } - - /// 1.0 / pi - #[inline(always)] - fn frac_1_pi() -> f64 { 0.318309886183790671537767526745028724 } - - /// 2.0 / pi - #[inline(always)] - fn frac_2_pi() -> f64 { 0.636619772367581343075535053490057448 } - - /// 2.0 / sqrt(pi) - #[inline(always)] - fn frac_2_sqrtpi() -> f64 { 1.12837916709551257389615890312154517 } - - /// sqrt(2.0) - #[inline(always)] - fn sqrt2() -> f64 { 1.41421356237309504880168872420969808 } - - /// 1.0 / sqrt(2.0) - #[inline(always)] - fn frac_1_sqrt2() -> f64 { 0.707106781186547524400844362104849039 } - - /// Euler's number - #[inline(always)] - fn e() -> f64 { 2.71828182845904523536028747135266250 } - - /// log2(e) - #[inline(always)] - fn log2_e() -> f64 { 1.44269504088896340735992468100189214 } - - /// log10(e) - #[inline(always)] - fn log10_e() -> f64 { 0.434294481903251827651128918916605082 } - - /// ln(2.0) - #[inline(always)] - fn ln_2() -> f64 { 0.693147180559945309417232121458176568 } - - /// ln(10.0) - #[inline(always)] - fn ln_10() -> f64 { 2.30258509299404568401799145468436421 } - - /// Converts to degrees, assuming the number is in radians - #[inline(always)] - fn to_degrees(&self) -> f64 { *self * (180.0 / Real::pi::<f64>()) } - - /// Converts to radians, assuming the number is in degrees - #[inline(always)] - fn to_radians(&self) -> f64 { *self * (Real::pi::<f64>() / 180.0) } -} - -impl RealExt for f64 { - #[inline(always)] - fn lgamma(&self) -> (int, f64) { - let mut sign = 0; - let result = lgamma(*self, &mut sign); - (sign as int, result) - } - - #[inline(always)] - fn tgamma(&self) -> f64 { tgamma(*self) } - - #[inline(always)] - fn j0(&self) -> f64 { j0(*self) } - - #[inline(always)] - fn j1(&self) -> f64 { j1(*self) } - - #[inline(always)] - fn jn(&self, n: int) -> f64 { jn(n as c_int, *self) } - - #[inline(always)] - fn y0(&self) -> f64 { y0(*self) } - - #[inline(always)] - fn y1(&self) -> f64 { y1(*self) } - - #[inline(always)] - fn yn(&self, n: int) -> f64 { yn(n as c_int, *self) } -} - -impl Bounded for f64 { - #[inline(always)] - fn min_value() -> f64 { 2.2250738585072014e-308 } - - #[inline(always)] - fn max_value() -> f64 { 1.7976931348623157e+308 } -} - -impl Primitive for f64 { - #[inline(always)] - fn bits() -> uint { 64 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<f64>() / 8 } -} - -impl Float for f64 { - #[inline(always)] - fn NaN() -> f64 { 0.0 / 0.0 } - - #[inline(always)] - fn infinity() -> f64 { 1.0 / 0.0 } - - #[inline(always)] - fn neg_infinity() -> f64 { -1.0 / 0.0 } - - #[inline(always)] - fn neg_zero() -> f64 { -0.0 } - - /// Returns `true` if the number is NaN - #[inline(always)] - fn is_NaN(&self) -> bool { *self != *self } - - /// Returns `true` if the number is infinite - #[inline(always)] - fn is_infinite(&self) -> bool { - *self == Float::infinity() || *self == Float::neg_infinity() - } - - /// Returns `true` if the number is neither infinite or NaN - #[inline(always)] - fn is_finite(&self) -> bool { - !(self.is_NaN() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN - #[inline(always)] - fn is_normal(&self) -> bool { - self.classify() == FPNormal - } - - /// Returns the floating point category of the number. If only one property is going to - /// be tested, it is generally faster to use the specific predicate instead. - fn classify(&self) -> FPCategory { - static EXP_MASK: u64 = 0x7ff0000000000000; - static MAN_MASK: u64 = 0x000fffffffffffff; - - match ( - unsafe { ::cast::transmute::<f64,u64>(*self) } & MAN_MASK, - unsafe { ::cast::transmute::<f64,u64>(*self) } & EXP_MASK, - ) { - (0, 0) => FPZero, - (_, 0) => FPSubnormal, - (0, EXP_MASK) => FPInfinite, - (_, EXP_MASK) => FPNaN, - _ => FPNormal, - } - } - - #[inline(always)] - fn mantissa_digits() -> uint { 53 } - - #[inline(always)] - fn digits() -> uint { 15 } - - #[inline(always)] - fn epsilon() -> f64 { 2.2204460492503131e-16 } - - #[inline(always)] - fn min_exp() -> int { -1021 } - - #[inline(always)] - fn max_exp() -> int { 1024 } - - #[inline(always)] - fn min_10_exp() -> int { -307 } - - #[inline(always)] - fn max_10_exp() -> int { 308 } - - /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` - #[inline(always)] - fn ldexp(x: f64, exp: int) -> f64 { - ldexp(x, exp as c_int) - } - - /// - /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: - /// - /// - `self = x * pow(2, exp)` - /// - `0.5 <= abs(x) < 1.0` - /// - #[inline(always)] - fn frexp(&self) -> (f64, int) { - let mut exp = 0; - let x = frexp(*self, &mut exp); - (x, exp as int) - } - - /// - /// Returns the exponential of the number, minus `1`, in a way that is accurate - /// even if the number is close to zero - /// - #[inline(always)] - fn exp_m1(&self) -> f64 { exp_m1(*self) } - - /// - /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately - /// than if the operations were performed separately - /// - #[inline(always)] - fn ln_1p(&self) -> f64 { ln_1p(*self) } - - /// - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This - /// produces a more accurate result with better performance than a separate multiplication - /// operation followed by an add. - /// - #[inline(always)] - fn mul_add(&self, a: f64, b: f64) -> f64 { - mul_add(*self, a, b) - } - - /// Returns the next representable floating-point value in the direction of `other` - #[inline(always)] - fn next_after(&self, other: f64) -> f64 { - next_after(*self, other) - } -} - -// -// Section: String Conversions -// - -/// -/// Converts a float to a string -/// -/// # Arguments -/// -/// * num - The float value -/// -#[inline(always)] -pub fn to_str(num: f64) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigAll); - r -} - -/// -/// Converts a float to a string in hexadecimal format -/// -/// # Arguments -/// -/// * num - The float value -/// -#[inline(always)] -pub fn to_str_hex(num: f64) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 16u, true, strconv::SignNeg, strconv::DigAll); - r -} - -/// -/// Converts a float to a string in a given radix -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -/// -/// # Failure -/// -/// Fails if called on a special value like `inf`, `-inf` or `NaN` due to -/// possible misinterpretation of the result at higher bases. If those values -/// are expected, use `to_str_radix_special()` instead. -/// -#[inline(always)] -pub fn to_str_radix(num: f64, rdx: uint) -> ~str { - let (r, special) = strconv::to_str_common( - &num, rdx, true, strconv::SignNeg, strconv::DigAll); - if special { fail!("number has a special value, \ - try to_str_radix_special() if those are expected") } - r -} - -/// -/// Converts a float to a string in a given radix, and a flag indicating -/// whether it's a special value -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -/// -#[inline(always)] -pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) { - strconv::to_str_common(&num, rdx, true, - strconv::SignNeg, strconv::DigAll) -} - -/// -/// Converts a float to a string with exactly the number of -/// provided significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -/// -#[inline(always)] -pub fn to_str_exact(num: f64, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigExact(dig)); - r -} - -/// -/// Converts a float to a string with a maximum number of -/// significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -/// -#[inline(always)] -pub fn to_str_digits(num: f64, dig: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigMax(dig)); - r -} - -impl to_str::ToStr for f64 { - #[inline(always)] - fn to_str(&self) -> ~str { to_str_digits(*self, 8) } -} - -impl num::ToStrRadix for f64 { - #[inline(always)] - fn to_str_radix(&self, rdx: uint) -> ~str { - to_str_radix(*self, rdx) - } -} - -/// -/// Convert a string in base 10 to a float. -/// Accepts a optional decimal exponent. -/// -/// This function accepts strings such as -/// -/// * '3.14' -/// * '+3.14', equivalent to '3.14' -/// * '-3.14' -/// * '2.5E10', or equivalently, '2.5e10' -/// * '2.5E-10' -/// * '.' (understood as 0) -/// * '5.' -/// * '.5', or, equivalently, '0.5' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `num`. -/// -#[inline(always)] -pub fn from_str(num: &str) -> Option<f64> { - strconv::from_str_common(num, 10u, true, true, true, - strconv::ExpDec, false, false) -} - -/// -/// Convert a string in base 16 to a float. -/// Accepts a optional binary exponent. -/// -/// This function accepts strings such as -/// -/// * 'a4.fe' -/// * '+a4.fe', equivalent to 'a4.fe' -/// * '-a4.fe' -/// * '2b.aP128', or equivalently, '2b.ap128' -/// * '2b.aP-128' -/// * '.' (understood as 0) -/// * 'c.' -/// * '.c', or, equivalently, '0.c' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `[num]`. -/// -#[inline(always)] -pub fn from_str_hex(num: &str) -> Option<f64> { - strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false, false) -} - -/// -/// Convert a string in an given base to a float. -/// -/// Due to possible conflicts, this function does **not** accept -/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** -/// does it recognize exponents of any kind. -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// * radix - The base to use. Must lie in the range [2 .. 36] -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `num`. -/// -#[inline(always)] -pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> { - strconv::from_str_common(num, rdx, true, true, false, - strconv::ExpNone, false, false) -} - -impl FromStr for f64 { - #[inline(always)] - fn from_str(val: &str) -> Option<f64> { from_str(val) } -} - -impl num::FromStrRadix for f64 { - #[inline(always)] - fn from_str_radix(val: &str, rdx: uint) -> Option<f64> { - from_str_radix(val, rdx) - } -} - -#[cfg(test)] -mod tests { - use f64::*; - use num::*; - use super::*; - use prelude::*; - - #[test] - fn test_num() { - num::test_num(10f64, 2f64); - } - - #[test] - fn test_min() { - assert_eq!(1f64.min(&2f64), 1f64); - assert_eq!(2f64.min(&1f64), 1f64); - assert!(1f64.min(&Float::NaN::<f64>()).is_NaN()); - assert!(Float::NaN::<f64>().min(&1f64).is_NaN()); - } - - #[test] - fn test_max() { - assert_eq!(1f64.max(&2f64), 2f64); - assert_eq!(2f64.max(&1f64), 2f64); - assert!(1f64.max(&Float::NaN::<f64>()).is_NaN()); - assert!(Float::NaN::<f64>().max(&1f64).is_NaN()); - } - - #[test] - fn test_clamp() { - assert_eq!(1f64.clamp(&2f64, &4f64), 2f64); - assert_eq!(8f64.clamp(&2f64, &4f64), 4f64); - assert_eq!(3f64.clamp(&2f64, &4f64), 3f64); - assert!(3f64.clamp(&Float::NaN::<f64>(), &4f64).is_NaN()); - assert!(3f64.clamp(&2f64, &Float::NaN::<f64>()).is_NaN()); - assert!(Float::NaN::<f64>().clamp(&2f64, &4f64).is_NaN()); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f64.floor(), 1.0f64); - assert_approx_eq!(1.3f64.floor(), 1.0f64); - assert_approx_eq!(1.5f64.floor(), 1.0f64); - assert_approx_eq!(1.7f64.floor(), 1.0f64); - assert_approx_eq!(0.0f64.floor(), 0.0f64); - assert_approx_eq!((-0.0f64).floor(), -0.0f64); - assert_approx_eq!((-1.0f64).floor(), -1.0f64); - assert_approx_eq!((-1.3f64).floor(), -2.0f64); - assert_approx_eq!((-1.5f64).floor(), -2.0f64); - assert_approx_eq!((-1.7f64).floor(), -2.0f64); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f64.ceil(), 1.0f64); - assert_approx_eq!(1.3f64.ceil(), 2.0f64); - assert_approx_eq!(1.5f64.ceil(), 2.0f64); - assert_approx_eq!(1.7f64.ceil(), 2.0f64); - assert_approx_eq!(0.0f64.ceil(), 0.0f64); - assert_approx_eq!((-0.0f64).ceil(), -0.0f64); - assert_approx_eq!((-1.0f64).ceil(), -1.0f64); - assert_approx_eq!((-1.3f64).ceil(), -1.0f64); - assert_approx_eq!((-1.5f64).ceil(), -1.0f64); - assert_approx_eq!((-1.7f64).ceil(), -1.0f64); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f64.round(), 1.0f64); - assert_approx_eq!(1.3f64.round(), 1.0f64); - assert_approx_eq!(1.5f64.round(), 2.0f64); - assert_approx_eq!(1.7f64.round(), 2.0f64); - assert_approx_eq!(0.0f64.round(), 0.0f64); - assert_approx_eq!((-0.0f64).round(), -0.0f64); - assert_approx_eq!((-1.0f64).round(), -1.0f64); - assert_approx_eq!((-1.3f64).round(), -1.0f64); - assert_approx_eq!((-1.5f64).round(), -2.0f64); - assert_approx_eq!((-1.7f64).round(), -2.0f64); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f64.trunc(), 1.0f64); - assert_approx_eq!(1.3f64.trunc(), 1.0f64); - assert_approx_eq!(1.5f64.trunc(), 1.0f64); - assert_approx_eq!(1.7f64.trunc(), 1.0f64); - assert_approx_eq!(0.0f64.trunc(), 0.0f64); - assert_approx_eq!((-0.0f64).trunc(), -0.0f64); - assert_approx_eq!((-1.0f64).trunc(), -1.0f64); - assert_approx_eq!((-1.3f64).trunc(), -1.0f64); - assert_approx_eq!((-1.5f64).trunc(), -1.0f64); - assert_approx_eq!((-1.7f64).trunc(), -1.0f64); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f64.fract(), 0.0f64); - assert_approx_eq!(1.3f64.fract(), 0.3f64); - assert_approx_eq!(1.5f64.fract(), 0.5f64); - assert_approx_eq!(1.7f64.fract(), 0.7f64); - assert_approx_eq!(0.0f64.fract(), 0.0f64); - assert_approx_eq!((-0.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.3f64).fract(), -0.3f64); - assert_approx_eq!((-1.5f64).fract(), -0.5f64); - assert_approx_eq!((-1.7f64).fract(), -0.7f64); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f64.asinh(), 0.0f64); - assert_eq!((-0.0f64).asinh(), -0.0f64); - assert_eq!(Float::infinity::<f64>().asinh(), Float::infinity::<f64>()); - assert_eq!(Float::neg_infinity::<f64>().asinh(), Float::neg_infinity::<f64>()); - assert!(Float::NaN::<f64>().asinh().is_NaN()); - assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); - assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f64.acosh(), 0.0f64); - assert!(0.999f64.acosh().is_NaN()); - assert_eq!(Float::infinity::<f64>().acosh(), Float::infinity::<f64>()); - assert!(Float::neg_infinity::<f64>().acosh().is_NaN()); - assert!(Float::NaN::<f64>().acosh().is_NaN()); - assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); - assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f64.atanh(), 0.0f64); - assert_eq!((-0.0f64).atanh(), -0.0f64); - assert_eq!(1.0f64.atanh(), Float::infinity::<f64>()); - assert_eq!((-1.0f64).atanh(), Float::neg_infinity::<f64>()); - assert!(2f64.atanh().atanh().is_NaN()); - assert!((-2f64).atanh().atanh().is_NaN()); - assert!(Float::infinity::<f64>().atanh().is_NaN()); - assert!(Float::neg_infinity::<f64>().atanh().is_NaN()); - assert!(Float::NaN::<f64>().atanh().is_NaN()); - assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); - assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); - } - - #[test] - fn test_real_consts() { - assert_approx_eq!(Real::two_pi::<f64>(), 2.0 * Real::pi::<f64>()); - assert_approx_eq!(Real::frac_pi_2::<f64>(), Real::pi::<f64>() / 2f64); - assert_approx_eq!(Real::frac_pi_3::<f64>(), Real::pi::<f64>() / 3f64); - assert_approx_eq!(Real::frac_pi_4::<f64>(), Real::pi::<f64>() / 4f64); - assert_approx_eq!(Real::frac_pi_6::<f64>(), Real::pi::<f64>() / 6f64); - assert_approx_eq!(Real::frac_pi_8::<f64>(), Real::pi::<f64>() / 8f64); - assert_approx_eq!(Real::frac_1_pi::<f64>(), 1f64 / Real::pi::<f64>()); - assert_approx_eq!(Real::frac_2_pi::<f64>(), 2f64 / Real::pi::<f64>()); - assert_approx_eq!(Real::frac_2_sqrtpi::<f64>(), 2f64 / Real::pi::<f64>().sqrt()); - assert_approx_eq!(Real::sqrt2::<f64>(), 2f64.sqrt()); - assert_approx_eq!(Real::frac_1_sqrt2::<f64>(), 1f64 / 2f64.sqrt()); - assert_approx_eq!(Real::log2_e::<f64>(), Real::e::<f64>().log2()); - assert_approx_eq!(Real::log10_e::<f64>(), Real::e::<f64>().log10()); - assert_approx_eq!(Real::ln_2::<f64>(), 2f64.ln()); - assert_approx_eq!(Real::ln_10::<f64>(), 10f64.ln()); - } - - #[test] - pub fn test_abs() { - assert_eq!(infinity.abs(), infinity); - assert_eq!(1f64.abs(), 1f64); - assert_eq!(0f64.abs(), 0f64); - assert_eq!((-0f64).abs(), 0f64); - assert_eq!((-1f64).abs(), 1f64); - assert_eq!(neg_infinity.abs(), infinity); - assert_eq!((1f64/neg_infinity).abs(), 0f64); - assert!(NaN.abs().is_NaN()); - } - - #[test] - fn test_abs_sub() { - assert_eq!((-1f64).abs_sub(&1f64), 0f64); - assert_eq!(1f64.abs_sub(&1f64), 0f64); - assert_eq!(1f64.abs_sub(&0f64), 1f64); - assert_eq!(1f64.abs_sub(&-1f64), 2f64); - assert_eq!(neg_infinity.abs_sub(&0f64), 0f64); - assert_eq!(infinity.abs_sub(&1f64), infinity); - assert_eq!(0f64.abs_sub(&neg_infinity), infinity); - assert_eq!(0f64.abs_sub(&infinity), 0f64); - assert!(NaN.abs_sub(&-1f64).is_NaN()); - assert!(1f64.abs_sub(&NaN).is_NaN()); - } - - #[test] - fn test_signum() { - assert_eq!(infinity.signum(), 1f64); - assert_eq!(1f64.signum(), 1f64); - assert_eq!(0f64.signum(), 1f64); - assert_eq!((-0f64).signum(), -1f64); - assert_eq!((-1f64).signum(), -1f64); - assert_eq!(neg_infinity.signum(), -1f64); - assert_eq!((1f64/neg_infinity).signum(), -1f64); - assert!(NaN.signum().is_NaN()); - } - - #[test] - fn test_is_positive() { - assert!(infinity.is_positive()); - assert!(1f64.is_positive()); - assert!(0f64.is_positive()); - assert!(!(-0f64).is_positive()); - assert!(!(-1f64).is_positive()); - assert!(!neg_infinity.is_positive()); - assert!(!(1f64/neg_infinity).is_positive()); - assert!(!NaN.is_positive()); - } - - #[test] - fn test_is_negative() { - assert!(!infinity.is_negative()); - assert!(!1f64.is_negative()); - assert!(!0f64.is_negative()); - assert!((-0f64).is_negative()); - assert!((-1f64).is_negative()); - assert!(neg_infinity.is_negative()); - assert!((1f64/neg_infinity).is_negative()); - assert!(!NaN.is_negative()); - } - - #[test] - fn test_approx_eq() { - assert!(1.0f64.approx_eq(&1f64)); - assert!(0.9999999f64.approx_eq(&1f64)); - assert!(1.000001f64.approx_eq_eps(&1f64, &1.0e-5)); - assert!(1.0000001f64.approx_eq_eps(&1f64, &1.0e-6)); - assert!(!1.0000001f64.approx_eq_eps(&1f64, &1.0e-7)); - } - - #[test] - fn test_primitive() { - assert_eq!(Primitive::bits::<f64>(), sys::size_of::<f64>() * 8); - assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>()); - } - - #[test] - fn test_is_normal() { - assert!(!Float::NaN::<f64>().is_normal()); - assert!(!Float::infinity::<f64>().is_normal()); - assert!(!Float::neg_infinity::<f64>().is_normal()); - assert!(!Zero::zero::<f64>().is_normal()); - assert!(!Float::neg_zero::<f64>().is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); - } - - #[test] - fn test_classify() { - assert_eq!(Float::NaN::<f64>().classify(), FPNaN); - assert_eq!(Float::infinity::<f64>().classify(), FPInfinite); - assert_eq!(Float::neg_infinity::<f64>().classify(), FPInfinite); - assert_eq!(Zero::zero::<f64>().classify(), FPZero); - assert_eq!(Float::neg_zero::<f64>().classify(), FPZero); - assert_eq!(1e-307f64.classify(), FPNormal); - assert_eq!(1e-308f64.classify(), FPSubnormal); - } - - #[test] - fn test_ldexp() { - // We have to use from_str until base-2 exponents - // are supported in floating-point literals - let f1: f64 = from_str_hex("1p-123").unwrap(); - let f2: f64 = from_str_hex("1p-111").unwrap(); - assert_eq!(Float::ldexp(1f64, -123), f1); - assert_eq!(Float::ldexp(1f64, -111), f2); - - assert_eq!(Float::ldexp(0f64, -123), 0f64); - assert_eq!(Float::ldexp(-0f64, -123), -0f64); - assert_eq!(Float::ldexp(Float::infinity::<f64>(), -123), - Float::infinity::<f64>()); - assert_eq!(Float::ldexp(Float::neg_infinity::<f64>(), -123), - Float::neg_infinity::<f64>()); - assert!(Float::ldexp(Float::NaN::<f64>(), -123).is_NaN()); - } - - #[test] - fn test_frexp() { - // We have to use from_str until base-2 exponents - // are supported in floating-point literals - let f1: f64 = from_str_hex("1p-123").unwrap(); - let f2: f64 = from_str_hex("1p-111").unwrap(); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - assert_eq!((x1, exp1), (0.5f64, -122)); - assert_eq!((x2, exp2), (0.5f64, -110)); - assert_eq!(Float::ldexp(x1, exp1), f1); - assert_eq!(Float::ldexp(x2, exp2), f2); - - assert_eq!(0f64.frexp(), (0f64, 0)); - assert_eq!((-0f64).frexp(), (-0f64, 0)); - assert_eq!(match Float::infinity::<f64>().frexp() { (x, _) => x }, - Float::infinity::<f64>()) - assert_eq!(match Float::neg_infinity::<f64>().frexp() { (x, _) => x }, - Float::neg_infinity::<f64>()) - assert!(match Float::NaN::<f64>().frexp() { (x, _) => x.is_NaN() }) - } -} diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs deleted file mode 100644 index 681aafaab88..00000000000 --- a/src/libcore/num/float.rs +++ /dev/null @@ -1,1387 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `float` - -// Even though this module exports everything defined in it, -// because it contains re-exports, we also have to explicitly -// export locally defined things. That's a bit annoying. - - -// export when m_float == c_double - - -// PORT this must match in width according to architecture - -use libc::c_int; -use num::{Zero, One, strconv}; -use num::FPCategory; -use prelude::*; - -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}; -pub use f64::{erf, erfc, exp, exp_m1, exp2, abs_sub}; -pub use f64::{mul_add, fmax, fmin, next_after, frexp, hypot, ldexp}; -pub use f64::{lgamma, ln, log_radix, ln_1p, log10, log2, ilog_radix}; -pub use f64::{modf, pow, powi, round, sinh, tanh, tgamma, trunc}; -pub use f64::{j0, j1, jn, y0, y1, yn}; - -pub static NaN: float = 0.0/0.0; - -pub static infinity: float = 1.0/0.0; - -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 - pub static pi: float = 3.14159265358979323846264338327950288; - - /// pi/2.0 - pub static frac_pi_2: float = 1.57079632679489661923132169163975144; - - /// pi/4.0 - pub static frac_pi_4: float = 0.785398163397448309615660845819875721; - - /// 1.0/pi - pub static frac_1_pi: float = 0.318309886183790671537767526745028724; - - /// 2.0/pi - pub static frac_2_pi: float = 0.636619772367581343075535053490057448; - - /// 2.0/sqrt(pi) - pub static frac_2_sqrtpi: float = 1.12837916709551257389615890312154517; - - /// sqrt(2.0) - pub static sqrt2: float = 1.41421356237309504880168872420969808; - - /// 1.0/sqrt(2.0) - pub static frac_1_sqrt2: float = 0.707106781186547524400844362104849039; - - /// Euler's number - pub static e: float = 2.71828182845904523536028747135266250; - - /// log2(e) - pub static log2_e: float = 1.44269504088896340735992468100189214; - - /// log10(e) - pub static log10_e: float = 0.434294481903251827651128918916605082; - - /// ln(2.0) - pub static ln_2: float = 0.693147180559945309417232121458176568; - - /// ln(10.0) - pub static ln_10: float = 2.30258509299404568401799145468436421; -} - -// -// Section: String Conversions -// - -/// -/// Converts a float to a string -/// -/// # Arguments -/// -/// * num - The float value -/// -#[inline(always)] -pub fn to_str(num: float) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigAll); - r -} - -/// -/// Converts a float to a string in hexadecimal format -/// -/// # Arguments -/// -/// * num - The float value -/// -#[inline(always)] -pub fn to_str_hex(num: float) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 16u, true, strconv::SignNeg, strconv::DigAll); - r -} - -/// -/// Converts a float to a string in a given radix -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -/// -/// # Failure -/// -/// Fails if called on a special value like `inf`, `-inf` or `NaN` due to -/// possible misinterpretation of the result at higher bases. If those values -/// are expected, use `to_str_radix_special()` instead. -/// -#[inline(always)] -pub fn to_str_radix(num: float, radix: uint) -> ~str { - let (r, special) = strconv::to_str_common( - &num, radix, true, strconv::SignNeg, strconv::DigAll); - if special { fail!("number has a special value, \ - try to_str_radix_special() if those are expected") } - r -} - -/// -/// Converts a float to a string in a given radix, and a flag indicating -/// whether it's a special value -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -/// -#[inline(always)] -pub fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) { - strconv::to_str_common(&num, radix, true, - strconv::SignNeg, strconv::DigAll) -} - -/// -/// Converts a float to a string with exactly the number of -/// provided significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -/// -#[inline(always)] -pub fn to_str_exact(num: float, digits: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigExact(digits)); - r -} - -/// -/// Converts a float to a string with a maximum number of -/// significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -/// -#[inline(always)] -pub fn to_str_digits(num: float, digits: uint) -> ~str { - let (r, _) = strconv::to_str_common( - &num, 10u, true, strconv::SignNeg, strconv::DigMax(digits)); - r -} - -impl to_str::ToStr for float { - #[inline(always)] - fn to_str(&self) -> ~str { to_str_digits(*self, 8) } -} - -impl num::ToStrRadix for float { - #[inline(always)] - fn to_str_radix(&self, radix: uint) -> ~str { - to_str_radix(*self, radix) - } -} - -/// -/// Convert a string in base 10 to a float. -/// Accepts a optional decimal exponent. -/// -/// This function accepts strings such as -/// -/// * '3.14' -/// * '+3.14', equivalent to '3.14' -/// * '-3.14' -/// * '2.5E10', or equivalently, '2.5e10' -/// * '2.5E-10' -/// * '.' (understood as 0) -/// * '5.' -/// * '.5', or, equivalently, '0.5' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `num`. -/// -#[inline(always)] -pub fn from_str(num: &str) -> Option<float> { - strconv::from_str_common(num, 10u, true, true, true, - strconv::ExpDec, false, false) -} - -/// -/// Convert a string in base 16 to a float. -/// Accepts a optional binary exponent. -/// -/// This function accepts strings such as -/// -/// * 'a4.fe' -/// * '+a4.fe', equivalent to 'a4.fe' -/// * '-a4.fe' -/// * '2b.aP128', or equivalently, '2b.ap128' -/// * '2b.aP-128' -/// * '.' (understood as 0) -/// * 'c.' -/// * '.c', or, equivalently, '0.c' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `[num]`. -/// -#[inline(always)] -pub fn from_str_hex(num: &str) -> Option<float> { - strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false, false) -} - -/// -/// Convert a string in an given base to a float. -/// -/// Due to possible conflicts, this function does **not** accept -/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** -/// does it recognize exponents of any kind. -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// * radix - The base to use. Must lie in the range [2 .. 36] -/// -/// # Return value -/// -/// `none` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `num`. -/// -#[inline(always)] -pub fn from_str_radix(num: &str, radix: uint) -> Option<float> { - strconv::from_str_common(num, radix, true, true, false, - strconv::ExpNone, false, false) -} - -impl FromStr for float { - #[inline(always)] - fn from_str(val: &str) -> Option<float> { from_str(val) } -} - -impl num::FromStrRadix for float { - #[inline(always)] - fn from_str_radix(val: &str, radix: uint) -> Option<float> { - from_str_radix(val, radix) - } -} - -// -// Section: Arithmetics -// - -/// -/// Compute the exponentiation of an integer by another integer as a float -/// -/// # Arguments -/// -/// * x - The base -/// * pow - The exponent -/// -/// # Return value -/// -/// `NaN` if both `x` and `pow` are `0u`, otherwise `x^pow` -/// -pub fn pow_with_uint(base: uint, pow: uint) -> float { - if base == 0u { - if pow == 0u { - return NaN as float; - } - return 0.; - } - let mut my_pow = pow; - let mut total = 1f; - let mut multiplier = base as float; - while (my_pow > 0u) { - if my_pow % 2u == 1u { - total = total * multiplier; - } - my_pow /= 2u; - multiplier *= multiplier; - } - return total; -} - -#[inline(always)] -pub fn abs(x: float) -> float { - f64::abs(x as f64) as float -} -#[inline(always)] -pub fn sqrt(x: float) -> float { - f64::sqrt(x as f64) as float -} -#[inline(always)] -pub fn atan(x: float) -> float { - f64::atan(x as f64) as float -} -#[inline(always)] -pub fn sin(x: float) -> float { - f64::sin(x as f64) as float -} -#[inline(always)] -pub fn cos(x: float) -> float { - f64::cos(x as f64) as float -} -#[inline(always)] -pub fn tan(x: float) -> float { - f64::tan(x as f64) as float -} - -impl Num for float {} - -#[cfg(not(test))] -impl Eq for float { - #[inline(always)] - fn eq(&self, other: &float) -> bool { (*self) == (*other) } - #[inline(always)] - fn ne(&self, other: &float) -> bool { (*self) != (*other) } -} - -#[cfg(not(test))] -impl ApproxEq<float> for float { - #[inline(always)] - fn approx_epsilon() -> float { 1.0e-6 } - - #[inline(always)] - fn approx_eq(&self, other: &float) -> bool { - self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<float, float>()) - } - - #[inline(always)] - fn approx_eq_eps(&self, other: &float, approx_epsilon: &float) -> bool { - (*self - *other).abs() < *approx_epsilon - } -} - -#[cfg(not(test))] -impl Ord for float { - #[inline(always)] - fn lt(&self, other: &float) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &float) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &float) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &float) -> bool { (*self) > (*other) } -} - -impl Orderable for float { - /// Returns `NaN` if either of the numbers are `NaN`. - #[inline(always)] - fn min(&self, other: &float) -> float { - (*self as f64).min(&(*other as f64)) as float - } - - /// Returns `NaN` if either of the numbers are `NaN`. - #[inline(always)] - fn max(&self, other: &float) -> float { - (*self as f64).max(&(*other as f64)) as float - } - - /// Returns the number constrained within the range `mn <= self <= mx`. - /// If any of the numbers are `NaN` then `NaN` is returned. - #[inline(always)] - fn clamp(&self, mn: &float, mx: &float) -> float { - (*self as f64).clamp(&(*mn as f64), &(*mx as f64)) as float - } -} - -impl Zero for float { - #[inline(always)] - fn zero() -> float { 0.0 } - - /// Returns true if the number is equal to either `0.0` or `-0.0` - #[inline(always)] - fn is_zero(&self) -> bool { *self == 0.0 || *self == -0.0 } -} - -impl One for float { - #[inline(always)] - fn one() -> float { 1.0 } -} - -impl Round for float { - /// Round half-way cases toward `neg_infinity` - #[inline(always)] - fn floor(&self) -> float { floor(*self as f64) as float } - - /// Round half-way cases toward `infinity` - #[inline(always)] - fn ceil(&self) -> float { ceil(*self as f64) as float } - - /// Round half-way cases away from `0.0` - #[inline(always)] - fn round(&self) -> float { round(*self as f64) as float } - - /// The integer part of the number (rounds towards `0.0`) - #[inline(always)] - fn trunc(&self) -> float { trunc(*self as f64) as float } - - /// - /// The fractional part of the number, satisfying: - /// - /// ~~~ - /// assert!(x == trunc(x) + fract(x)) - /// ~~~ - /// - #[inline(always)] - fn fract(&self) -> float { *self - self.trunc() } -} - -impl Fractional for float { - /// The reciprocal (multiplicative inverse) of the number - #[inline(always)] - fn recip(&self) -> float { 1.0 / *self } -} - -impl Algebraic for float { - #[inline(always)] - fn pow(&self, n: float) -> float { - (*self as f64).pow(n as f64) as float - } - - #[inline(always)] - fn sqrt(&self) -> float { - (*self as f64).sqrt() as float - } - - #[inline(always)] - fn rsqrt(&self) -> float { - (*self as f64).rsqrt() as float - } - - #[inline(always)] - fn cbrt(&self) -> float { - (*self as f64).cbrt() as float - } - - #[inline(always)] - fn hypot(&self, other: float) -> float { - (*self as f64).hypot(other as f64) as float - } -} - -impl Trigonometric for float { - #[inline(always)] - fn sin(&self) -> float { - (*self as f64).sin() as float - } - - #[inline(always)] - fn cos(&self) -> float { - (*self as f64).cos() as float - } - - #[inline(always)] - fn tan(&self) -> float { - (*self as f64).tan() as float - } - - #[inline(always)] - fn asin(&self) -> float { - (*self as f64).asin() as float - } - - #[inline(always)] - fn acos(&self) -> float { - (*self as f64).acos() as float - } - - #[inline(always)] - fn atan(&self) -> float { - (*self as f64).atan() as float - } - - #[inline(always)] - fn atan2(&self, other: float) -> float { - (*self as f64).atan2(other as f64) as float - } - - /// Simultaneously computes the sine and cosine of the number - #[inline(always)] - fn sin_cos(&self) -> (float, float) { - match (*self as f64).sin_cos() { - (s, c) => (s as float, c as float) - } - } -} - -impl Exponential for float { - /// Returns the exponential of the number - #[inline(always)] - fn exp(&self) -> float { - (*self as f64).exp() as float - } - - /// Returns 2 raised to the power of the number - #[inline(always)] - fn exp2(&self) -> float { - (*self as f64).exp2() as float - } - - /// Returns the natural logarithm of the number - #[inline(always)] - fn ln(&self) -> float { - (*self as f64).ln() as 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 - } - - /// Returns the base 2 logarithm of the number - #[inline(always)] - fn log2(&self) -> float { - (*self as f64).log2() as float - } - - /// Returns the base 10 logarithm of the number - #[inline(always)] - fn log10(&self) -> float { - (*self as f64).log10() as float - } -} - -impl Hyperbolic for float { - #[inline(always)] - fn sinh(&self) -> float { - (*self as f64).sinh() as float - } - - #[inline(always)] - fn cosh(&self) -> float { - (*self as f64).cosh() as float - } - - #[inline(always)] - fn tanh(&self) -> float { - (*self as f64).tanh() as float - } - - /// - /// Inverse hyperbolic sine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic sine of `self` will be returned - /// - `self` if `self` is `0.0`, `-0.0`, `infinity`, or `neg_infinity` - /// - `NaN` if `self` is `NaN` - /// - #[inline(always)] - fn asinh(&self) -> float { - (*self as f64).asinh() as float - } - - /// - /// Inverse hyperbolic cosine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic cosine of `self` will be returned - /// - `infinity` if `self` is `infinity` - /// - `NaN` if `self` is `NaN` or `self < 1.0` (including `neg_infinity`) - /// - #[inline(always)] - fn acosh(&self) -> float { - (*self as f64).acosh() as float - } - - /// - /// Inverse hyperbolic tangent - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic tangent of `self` will be returned - /// - `self` if `self` is `0.0` or `-0.0` - /// - `infinity` if `self` is `1.0` - /// - `neg_infinity` if `self` is `-1.0` - /// - `NaN` if the `self` is `NaN` or outside the domain of `-1.0 <= self <= 1.0` - /// (including `infinity` and `neg_infinity`) - /// - #[inline(always)] - fn atanh(&self) -> float { - (*self as f64).atanh() as float - } -} - -impl Real for float { - /// Archimedes' constant - #[inline(always)] - fn pi() -> float { 3.14159265358979323846264338327950288 } - - /// 2.0 * pi - #[inline(always)] - fn two_pi() -> float { 6.28318530717958647692528676655900576 } - - /// pi / 2.0 - #[inline(always)] - fn frac_pi_2() -> float { 1.57079632679489661923132169163975144 } - - /// pi / 3.0 - #[inline(always)] - fn frac_pi_3() -> float { 1.04719755119659774615421446109316763 } - - /// pi / 4.0 - #[inline(always)] - fn frac_pi_4() -> float { 0.785398163397448309615660845819875721 } - - /// pi / 6.0 - #[inline(always)] - fn frac_pi_6() -> float { 0.52359877559829887307710723054658381 } - - /// pi / 8.0 - #[inline(always)] - fn frac_pi_8() -> float { 0.39269908169872415480783042290993786 } - - /// 1.0 / pi - #[inline(always)] - fn frac_1_pi() -> float { 0.318309886183790671537767526745028724 } - - /// 2.0 / pi - #[inline(always)] - fn frac_2_pi() -> float { 0.636619772367581343075535053490057448 } - - /// 2 .0/ sqrt(pi) - #[inline(always)] - fn frac_2_sqrtpi() -> float { 1.12837916709551257389615890312154517 } - - /// sqrt(2.0) - #[inline(always)] - fn sqrt2() -> float { 1.41421356237309504880168872420969808 } - - /// 1.0 / sqrt(2.0) - #[inline(always)] - fn frac_1_sqrt2() -> float { 0.707106781186547524400844362104849039 } - - /// Euler's number - #[inline(always)] - fn e() -> float { 2.71828182845904523536028747135266250 } - - /// log2(e) - #[inline(always)] - fn log2_e() -> float { 1.44269504088896340735992468100189214 } - - /// log10(e) - #[inline(always)] - fn log10_e() -> float { 0.434294481903251827651128918916605082 } - - /// ln(2.0) - #[inline(always)] - fn ln_2() -> float { 0.693147180559945309417232121458176568 } - - /// ln(10.0) - #[inline(always)] - fn ln_10() -> float { 2.30258509299404568401799145468436421 } - - /// Converts to degrees, assuming the number is in radians - #[inline(always)] - fn to_degrees(&self) -> float { (*self as f64).to_degrees() as float } - - /// Converts to radians, assuming the number is in degrees - #[inline(always)] - fn to_radians(&self) -> float { (*self as f64).to_radians() as float } -} - -impl RealExt for float { - #[inline(always)] - fn lgamma(&self) -> (int, float) { - let mut sign = 0; - let result = lgamma(*self as f64, &mut sign); - (sign as int, result as float) - } - - #[inline(always)] - fn tgamma(&self) -> float { tgamma(*self as f64) as float } - - #[inline(always)] - fn j0(&self) -> float { j0(*self as f64) as float } - - #[inline(always)] - fn j1(&self) -> float { j1(*self as f64) as float } - - #[inline(always)] - fn jn(&self, n: int) -> float { jn(n as c_int, *self as f64) as float } - - #[inline(always)] - fn y0(&self) -> float { y0(*self as f64) as float } - - #[inline(always)] - fn y1(&self) -> float { y1(*self as f64) as float } - - #[inline(always)] - fn yn(&self, n: int) -> float { yn(n as c_int, *self as f64) as float } -} - -#[cfg(not(test))] -impl Add<float,float> for float { - #[inline(always)] - fn add(&self, other: &float) -> float { *self + *other } -} - -#[cfg(not(test))] -impl Sub<float,float> for float { - #[inline(always)] - fn sub(&self, other: &float) -> float { *self - *other } -} - -#[cfg(not(test))] -impl Mul<float,float> for float { - #[inline(always)] - fn mul(&self, other: &float) -> float { *self * *other } -} - -#[cfg(not(test))] -impl Div<float,float> for float { - #[inline(always)] - fn div(&self, other: &float) -> float { *self / *other } -} - -#[cfg(not(test))] -impl Rem<float,float> for float { - #[inline(always)] - fn rem(&self, other: &float) -> float { *self % *other } -} -#[cfg(not(test))] -impl Neg<float> for float { - #[inline(always)] - fn neg(&self) -> float { -*self } -} - -impl Signed for float { - /// Computes the absolute value. Returns `NaN` if the number is `NaN`. - #[inline(always)] - fn abs(&self) -> float { abs(*self) } - - /// - /// The positive difference of two numbers. Returns `0.0` if the number is less than or - /// equal to `other`, otherwise the difference between`self` and `other` is returned. - /// - #[inline(always)] - fn abs_sub(&self, other: &float) -> float { - (*self as f64).abs_sub(&(*other as f64)) as float - } - - /// - /// # Returns - /// - /// - `1.0` if the number is positive, `+0.0` or `infinity` - /// - `-1.0` if the number is negative, `-0.0` or `neg_infinity` - /// - `NaN` if the number is NaN - /// - #[inline(always)] - fn signum(&self) -> float { - if self.is_NaN() { NaN } else { f64::copysign(1.0, *self as f64) as float } - } - - /// Returns `true` if the number is positive, including `+0.0` and `infinity` - #[inline(always)] - fn is_positive(&self) -> bool { *self > 0.0 || (1.0 / *self) == infinity } - - /// Returns `true` if the number is negative, including `-0.0` and `neg_infinity` - #[inline(always)] - fn is_negative(&self) -> bool { *self < 0.0 || (1.0 / *self) == neg_infinity } -} - -impl Bounded for float { - #[inline(always)] - fn min_value() -> float { Bounded::min_value::<f64>() as float } - - #[inline(always)] - fn max_value() -> float { Bounded::max_value::<f64>() as float } -} - -impl Primitive for float { - #[inline(always)] - fn bits() -> uint { Primitive::bits::<f64>() } - - #[inline(always)] - fn bytes() -> uint { Primitive::bytes::<f64>() } -} - -impl Float for float { - #[inline(always)] - fn NaN() -> float { Float::NaN::<f64>() as float } - - #[inline(always)] - fn infinity() -> float { Float::infinity::<f64>() as float } - - #[inline(always)] - fn neg_infinity() -> float { Float::neg_infinity::<f64>() as float } - - #[inline(always)] - fn neg_zero() -> float { Float::neg_zero::<f64>() as float } - - /// Returns `true` if the number is NaN - #[inline(always)] - fn is_NaN(&self) -> bool { (*self as f64).is_NaN() } - - /// Returns `true` if the number is infinite - #[inline(always)] - fn is_infinite(&self) -> bool { (*self as f64).is_infinite() } - - /// Returns `true` if the number is neither infinite or NaN - #[inline(always)] - fn is_finite(&self) -> bool { (*self as f64).is_finite() } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN - #[inline(always)] - fn is_normal(&self) -> bool { (*self as f64).is_normal() } - - /// Returns the floating point category of the number. If only one property is going to - /// be tested, it is generally faster to use the specific predicate instead. - #[inline(always)] - fn classify(&self) -> FPCategory { (*self as f64).classify() } - - #[inline(always)] - fn mantissa_digits() -> uint { Float::mantissa_digits::<f64>() } - - #[inline(always)] - fn digits() -> uint { Float::digits::<f64>() } - - #[inline(always)] - fn epsilon() -> float { Float::epsilon::<f64>() as float } - - #[inline(always)] - fn min_exp() -> int { Float::min_exp::<f64>() } - - #[inline(always)] - fn max_exp() -> int { Float::max_exp::<f64>() } - - #[inline(always)] - fn min_10_exp() -> int { Float::min_10_exp::<f64>() } - - #[inline(always)] - fn max_10_exp() -> int { Float::max_10_exp::<f64>() } - - /// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp` - #[inline(always)] - fn ldexp(x: float, exp: int) -> float { - Float::ldexp(x as f64, exp) as float - } - - /// - /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying: - /// - /// - `self = x * pow(2, exp)` - /// - `0.5 <= abs(x) < 1.0` - /// - #[inline(always)] - fn frexp(&self) -> (float, int) { - match (*self as f64).frexp() { - (x, exp) => (x as float, exp) - } - } - - /// - /// Returns the exponential of the number, minus `1`, in a way that is accurate - /// even if the number is close to zero - /// - #[inline(always)] - fn exp_m1(&self) -> float { - (*self as f64).exp_m1() as float - } - - /// - /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately - /// than if the operations were performed separately - /// - #[inline(always)] - fn ln_1p(&self) -> float { - (*self as f64).ln_1p() as float - } - - /// - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This - /// produces a more accurate result with better performance than a separate multiplication - /// operation followed by an add. - /// - #[inline(always)] - fn mul_add(&self, a: float, b: float) -> float { - mul_add(*self as f64, a as f64, b as f64) as float - } - - /// Returns the next representable floating-point value in the direction of `other` - #[inline(always)] - fn next_after(&self, other: float) -> float { - next_after(*self as f64, other as f64) as float - } -} - -#[cfg(test)] -mod tests { - use num::*; - use super::*; - use prelude::*; - - #[test] - fn test_num() { - num::test_num(10f, 2f); - } - - #[test] - fn test_min() { - assert_eq!(1f.min(&2f), 1f); - assert_eq!(2f.min(&1f), 1f); - } - - #[test] - fn test_max() { - assert_eq!(1f.max(&2f), 2f); - assert_eq!(2f.max(&1f), 2f); - } - - #[test] - fn test_clamp() { - assert_eq!(1f.clamp(&2f, &4f), 2f); - assert_eq!(8f.clamp(&2f, &4f), 4f); - assert_eq!(3f.clamp(&2f, &4f), 3f); - assert!(3f.clamp(&Float::NaN::<float>(), &4f).is_NaN()); - assert!(3f.clamp(&2f, &Float::NaN::<float>()).is_NaN()); - assert!(Float::NaN::<float>().clamp(&2f, &4f).is_NaN()); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f.floor(), 1.0f); - assert_approx_eq!(1.3f.floor(), 1.0f); - assert_approx_eq!(1.5f.floor(), 1.0f); - assert_approx_eq!(1.7f.floor(), 1.0f); - assert_approx_eq!(0.0f.floor(), 0.0f); - assert_approx_eq!((-0.0f).floor(), -0.0f); - assert_approx_eq!((-1.0f).floor(), -1.0f); - assert_approx_eq!((-1.3f).floor(), -2.0f); - assert_approx_eq!((-1.5f).floor(), -2.0f); - assert_approx_eq!((-1.7f).floor(), -2.0f); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f.ceil(), 1.0f); - assert_approx_eq!(1.3f.ceil(), 2.0f); - assert_approx_eq!(1.5f.ceil(), 2.0f); - assert_approx_eq!(1.7f.ceil(), 2.0f); - assert_approx_eq!(0.0f.ceil(), 0.0f); - assert_approx_eq!((-0.0f).ceil(), -0.0f); - assert_approx_eq!((-1.0f).ceil(), -1.0f); - assert_approx_eq!((-1.3f).ceil(), -1.0f); - assert_approx_eq!((-1.5f).ceil(), -1.0f); - assert_approx_eq!((-1.7f).ceil(), -1.0f); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f.round(), 1.0f); - assert_approx_eq!(1.3f.round(), 1.0f); - assert_approx_eq!(1.5f.round(), 2.0f); - assert_approx_eq!(1.7f.round(), 2.0f); - assert_approx_eq!(0.0f.round(), 0.0f); - assert_approx_eq!((-0.0f).round(), -0.0f); - assert_approx_eq!((-1.0f).round(), -1.0f); - assert_approx_eq!((-1.3f).round(), -1.0f); - assert_approx_eq!((-1.5f).round(), -2.0f); - assert_approx_eq!((-1.7f).round(), -2.0f); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f.trunc(), 1.0f); - assert_approx_eq!(1.3f.trunc(), 1.0f); - assert_approx_eq!(1.5f.trunc(), 1.0f); - assert_approx_eq!(1.7f.trunc(), 1.0f); - assert_approx_eq!(0.0f.trunc(), 0.0f); - assert_approx_eq!((-0.0f).trunc(), -0.0f); - assert_approx_eq!((-1.0f).trunc(), -1.0f); - assert_approx_eq!((-1.3f).trunc(), -1.0f); - assert_approx_eq!((-1.5f).trunc(), -1.0f); - assert_approx_eq!((-1.7f).trunc(), -1.0f); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f.fract(), 0.0f); - assert_approx_eq!(1.3f.fract(), 0.3f); - assert_approx_eq!(1.5f.fract(), 0.5f); - assert_approx_eq!(1.7f.fract(), 0.7f); - assert_approx_eq!(0.0f.fract(), 0.0f); - assert_approx_eq!((-0.0f).fract(), -0.0f); - assert_approx_eq!((-1.0f).fract(), -0.0f); - assert_approx_eq!((-1.3f).fract(), -0.3f); - assert_approx_eq!((-1.5f).fract(), -0.5f); - assert_approx_eq!((-1.7f).fract(), -0.7f); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f.asinh(), 0.0f); - assert_eq!((-0.0f).asinh(), -0.0f); - assert_eq!(Float::infinity::<float>().asinh(), Float::infinity::<float>()); - assert_eq!(Float::neg_infinity::<float>().asinh(), Float::neg_infinity::<float>()); - assert!(Float::NaN::<float>().asinh().is_NaN()); - assert_approx_eq!(2.0f.asinh(), 1.443635475178810342493276740273105f); - assert_approx_eq!((-2.0f).asinh(), -1.443635475178810342493276740273105f); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f.acosh(), 0.0f); - assert!(0.999f.acosh().is_NaN()); - assert_eq!(Float::infinity::<float>().acosh(), Float::infinity::<float>()); - assert!(Float::neg_infinity::<float>().acosh().is_NaN()); - assert!(Float::NaN::<float>().acosh().is_NaN()); - assert_approx_eq!(2.0f.acosh(), 1.31695789692481670862504634730796844f); - assert_approx_eq!(3.0f.acosh(), 1.76274717403908605046521864995958461f); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f.atanh(), 0.0f); - assert_eq!((-0.0f).atanh(), -0.0f); - assert_eq!(1.0f.atanh(), Float::infinity::<float>()); - assert_eq!((-1.0f).atanh(), Float::neg_infinity::<float>()); - assert!(2f64.atanh().atanh().is_NaN()); - assert!((-2f64).atanh().atanh().is_NaN()); - assert!(Float::infinity::<f64>().atanh().is_NaN()); - assert!(Float::neg_infinity::<f64>().atanh().is_NaN()); - assert!(Float::NaN::<float>().atanh().is_NaN()); - assert_approx_eq!(0.5f.atanh(), 0.54930614433405484569762261846126285f); - assert_approx_eq!((-0.5f).atanh(), -0.54930614433405484569762261846126285f); - } - - #[test] - fn test_real_consts() { - assert_approx_eq!(Real::two_pi::<float>(), 2f * Real::pi::<float>()); - assert_approx_eq!(Real::frac_pi_2::<float>(), Real::pi::<float>() / 2f); - assert_approx_eq!(Real::frac_pi_3::<float>(), Real::pi::<float>() / 3f); - assert_approx_eq!(Real::frac_pi_4::<float>(), Real::pi::<float>() / 4f); - assert_approx_eq!(Real::frac_pi_6::<float>(), Real::pi::<float>() / 6f); - assert_approx_eq!(Real::frac_pi_8::<float>(), Real::pi::<float>() / 8f); - assert_approx_eq!(Real::frac_1_pi::<float>(), 1f / Real::pi::<float>()); - assert_approx_eq!(Real::frac_2_pi::<float>(), 2f / Real::pi::<float>()); - assert_approx_eq!(Real::frac_2_sqrtpi::<float>(), 2f / Real::pi::<float>().sqrt()); - assert_approx_eq!(Real::sqrt2::<float>(), 2f.sqrt()); - assert_approx_eq!(Real::frac_1_sqrt2::<float>(), 1f / 2f.sqrt()); - assert_approx_eq!(Real::log2_e::<float>(), Real::e::<float>().log2()); - assert_approx_eq!(Real::log10_e::<float>(), Real::e::<float>().log10()); - assert_approx_eq!(Real::ln_2::<float>(), 2f.ln()); - assert_approx_eq!(Real::ln_10::<float>(), 10f.ln()); - } - - #[test] - fn test_abs() { - assert_eq!(infinity.abs(), infinity); - assert_eq!(1f.abs(), 1f); - assert_eq!(0f.abs(), 0f); - assert_eq!((-0f).abs(), 0f); - assert_eq!((-1f).abs(), 1f); - assert_eq!(neg_infinity.abs(), infinity); - assert_eq!((1f/neg_infinity).abs(), 0f); - assert!(NaN.abs().is_NaN()); - } - - #[test] - fn test_abs_sub() { - assert_eq!((-1f).abs_sub(&1f), 0f); - assert_eq!(1f.abs_sub(&1f), 0f); - assert_eq!(1f.abs_sub(&0f), 1f); - assert_eq!(1f.abs_sub(&-1f), 2f); - assert_eq!(neg_infinity.abs_sub(&0f), 0f); - assert_eq!(infinity.abs_sub(&1f), infinity); - assert_eq!(0f.abs_sub(&neg_infinity), infinity); - assert_eq!(0f.abs_sub(&infinity), 0f); - assert!(NaN.abs_sub(&-1f).is_NaN()); - assert!(1f.abs_sub(&NaN).is_NaN()); - } - - #[test] - fn test_signum() { - assert_eq!(infinity.signum(), 1f); - assert_eq!(1f.signum(), 1f); - assert_eq!(0f.signum(), 1f); - assert_eq!((-0f).signum(), -1f); - assert_eq!((-1f).signum(), -1f); - assert_eq!(neg_infinity.signum(), -1f); - assert_eq!((1f/neg_infinity).signum(), -1f); - assert!(NaN.signum().is_NaN()); - } - - #[test] - fn test_is_positive() { - assert!(infinity.is_positive()); - assert!(1f.is_positive()); - assert!(0f.is_positive()); - assert!(!(-0f).is_positive()); - assert!(!(-1f).is_positive()); - assert!(!neg_infinity.is_positive()); - assert!(!(1f/neg_infinity).is_positive()); - assert!(!NaN.is_positive()); - } - - #[test] - fn test_is_negative() { - assert!(!infinity.is_negative()); - assert!(!1f.is_negative()); - assert!(!0f.is_negative()); - assert!((-0f).is_negative()); - assert!((-1f).is_negative()); - assert!(neg_infinity.is_negative()); - assert!((1f/neg_infinity).is_negative()); - assert!(!NaN.is_negative()); - } - - #[test] - fn test_approx_eq() { - assert!(1.0f.approx_eq(&1f)); - assert!(0.9999999f.approx_eq(&1f)); - assert!(1.000001f.approx_eq_eps(&1f, &1.0e-5)); - assert!(1.0000001f.approx_eq_eps(&1f, &1.0e-6)); - assert!(!1.0000001f.approx_eq_eps(&1f, &1.0e-7)); - } - - #[test] - fn test_primitive() { - assert_eq!(Primitive::bits::<float>(), sys::size_of::<float>() * 8); - assert_eq!(Primitive::bytes::<float>(), sys::size_of::<float>()); - } - - #[test] - fn test_is_normal() { - assert!(!Float::NaN::<float>().is_normal()); - assert!(!Float::infinity::<float>().is_normal()); - assert!(!Float::neg_infinity::<float>().is_normal()); - assert!(!Zero::zero::<float>().is_normal()); - assert!(!Float::neg_zero::<float>().is_normal()); - assert!(1f.is_normal()); - assert!(1e-307f.is_normal()); - assert!(!1e-308f.is_normal()); - } - - #[test] - fn test_classify() { - assert_eq!(Float::NaN::<float>().classify(), FPNaN); - assert_eq!(Float::infinity::<float>().classify(), FPInfinite); - assert_eq!(Float::neg_infinity::<float>().classify(), FPInfinite); - assert_eq!(Zero::zero::<float>().classify(), FPZero); - assert_eq!(Float::neg_zero::<float>().classify(), FPZero); - assert_eq!(1f.classify(), FPNormal); - assert_eq!(1e-307f.classify(), FPNormal); - assert_eq!(1e-308f.classify(), FPSubnormal); - } - - #[test] - fn test_ldexp() { - // We have to use from_str until base-2 exponents - // are supported in floating-point literals - let f1: float = from_str_hex("1p-123").unwrap(); - let f2: float = from_str_hex("1p-111").unwrap(); - assert_eq!(Float::ldexp(1f, -123), f1); - assert_eq!(Float::ldexp(1f, -111), f2); - - assert_eq!(Float::ldexp(0f, -123), 0f); - assert_eq!(Float::ldexp(-0f, -123), -0f); - assert_eq!(Float::ldexp(Float::infinity::<float>(), -123), - Float::infinity::<float>()); - assert_eq!(Float::ldexp(Float::neg_infinity::<float>(), -123), - Float::neg_infinity::<float>()); - assert!(Float::ldexp(Float::NaN::<float>(), -123).is_NaN()); - } - - #[test] - fn test_frexp() { - // We have to use from_str until base-2 exponents - // are supported in floating-point literals - let f1: float = from_str_hex("1p-123").unwrap(); - let f2: float = from_str_hex("1p-111").unwrap(); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - assert_eq!((x1, exp1), (0.5f, -122)); - assert_eq!((x2, exp2), (0.5f, -110)); - assert_eq!(Float::ldexp(x1, exp1), f1); - assert_eq!(Float::ldexp(x2, exp2), f2); - - assert_eq!(0f.frexp(), (0f, 0)); - assert_eq!((-0f).frexp(), (-0f, 0)); - assert_eq!(match Float::infinity::<float>().frexp() { (x, _) => x }, - Float::infinity::<float>()) - assert_eq!(match Float::neg_infinity::<float>().frexp() { (x, _) => x }, - Float::neg_infinity::<float>()) - assert!(match Float::NaN::<float>().frexp() { (x, _) => x.is_NaN() }) - } - - #[test] - pub fn test_to_str_exact_do_decimal() { - let s = to_str_exact(5.0, 4u); - assert_eq!(s, ~"5.0000"); - } - - #[test] - pub fn test_from_str() { - assert_eq!(from_str(~"3"), Some(3.)); - assert_eq!(from_str(~"3.14"), Some(3.14)); - assert_eq!(from_str(~"+3.14"), Some(3.14)); - assert_eq!(from_str(~"-3.14"), Some(-3.14)); - assert_eq!(from_str(~"2.5E10"), Some(25000000000.)); - assert_eq!(from_str(~"2.5e10"), Some(25000000000.)); - assert_eq!(from_str(~"25000000000.E-10"), Some(2.5)); - assert_eq!(from_str(~"."), Some(0.)); - assert_eq!(from_str(~".e1"), Some(0.)); - assert_eq!(from_str(~".e-1"), Some(0.)); - assert_eq!(from_str(~"5."), Some(5.)); - assert_eq!(from_str(~".5"), Some(0.5)); - assert_eq!(from_str(~"0.5"), Some(0.5)); - assert_eq!(from_str(~"-.5"), Some(-0.5)); - assert_eq!(from_str(~"-5"), Some(-5.)); - assert_eq!(from_str(~"inf"), Some(infinity)); - assert_eq!(from_str(~"+inf"), Some(infinity)); - assert_eq!(from_str(~"-inf"), Some(neg_infinity)); - // note: NaN != NaN, hence this slightly complex test - match from_str(~"NaN") { - Some(f) => assert!(f.is_NaN()), - None => fail!() - } - // note: -0 == 0, hence these slightly more complex tests - match from_str(~"-0") { - Some(v) if v.is_zero() => assert!(v.is_negative()), - _ => fail!() - } - match from_str(~"0") { - Some(v) if v.is_zero() => assert!(v.is_positive()), - _ => fail!() - } - - assert!(from_str(~"").is_none()); - assert!(from_str(~"x").is_none()); - assert!(from_str(~" ").is_none()); - assert!(from_str(~" ").is_none()); - assert!(from_str(~"e").is_none()); - assert!(from_str(~"E").is_none()); - assert!(from_str(~"E1").is_none()); - assert!(from_str(~"1e1e1").is_none()); - assert!(from_str(~"1e1.1").is_none()); - assert!(from_str(~"1e1-1").is_none()); - } - - #[test] - pub fn test_from_str_hex() { - assert_eq!(from_str_hex(~"a4"), Some(164.)); - assert_eq!(from_str_hex(~"a4.fe"), Some(164.9921875)); - assert_eq!(from_str_hex(~"-a4.fe"), Some(-164.9921875)); - assert_eq!(from_str_hex(~"+a4.fe"), Some(164.9921875)); - assert_eq!(from_str_hex(~"ff0P4"), Some(0xff00 as float)); - assert_eq!(from_str_hex(~"ff0p4"), Some(0xff00 as float)); - assert_eq!(from_str_hex(~"ff0p-4"), Some(0xff as float)); - assert_eq!(from_str_hex(~"."), Some(0.)); - assert_eq!(from_str_hex(~".p1"), Some(0.)); - assert_eq!(from_str_hex(~".p-1"), Some(0.)); - assert_eq!(from_str_hex(~"f."), Some(15.)); - assert_eq!(from_str_hex(~".f"), Some(0.9375)); - assert_eq!(from_str_hex(~"0.f"), Some(0.9375)); - assert_eq!(from_str_hex(~"-.f"), Some(-0.9375)); - assert_eq!(from_str_hex(~"-f"), Some(-15.)); - assert_eq!(from_str_hex(~"inf"), Some(infinity)); - assert_eq!(from_str_hex(~"+inf"), Some(infinity)); - assert_eq!(from_str_hex(~"-inf"), Some(neg_infinity)); - // note: NaN != NaN, hence this slightly complex test - match from_str_hex(~"NaN") { - Some(f) => assert!(f.is_NaN()), - None => fail!() - } - // note: -0 == 0, hence these slightly more complex tests - match from_str_hex(~"-0") { - Some(v) if v.is_zero() => assert!(v.is_negative()), - _ => fail!() - } - match from_str_hex(~"0") { - Some(v) if v.is_zero() => assert!(v.is_positive()), - _ => fail!() - } - assert_eq!(from_str_hex(~"e"), Some(14.)); - assert_eq!(from_str_hex(~"E"), Some(14.)); - assert_eq!(from_str_hex(~"E1"), Some(225.)); - assert_eq!(from_str_hex(~"1e1e1"), Some(123361.)); - assert_eq!(from_str_hex(~"1e1.1"), Some(481.0625)); - - assert!(from_str_hex(~"").is_none()); - assert!(from_str_hex(~"x").is_none()); - assert!(from_str_hex(~" ").is_none()); - assert!(from_str_hex(~" ").is_none()); - assert!(from_str_hex(~"p").is_none()); - assert!(from_str_hex(~"P").is_none()); - assert!(from_str_hex(~"P1").is_none()); - assert!(from_str_hex(~"1p1p1").is_none()); - assert!(from_str_hex(~"1p1.1").is_none()); - assert!(from_str_hex(~"1p1-1").is_none()); - } - - #[test] - pub fn test_to_str_hex() { - assert_eq!(to_str_hex(164.), ~"a4"); - assert_eq!(to_str_hex(164.9921875), ~"a4.fe"); - assert_eq!(to_str_hex(-164.9921875), ~"-a4.fe"); - assert_eq!(to_str_hex(0xff00 as float), ~"ff00"); - assert_eq!(to_str_hex(-(0xff00 as float)), ~"-ff00"); - assert_eq!(to_str_hex(0.), ~"0"); - assert_eq!(to_str_hex(15.), ~"f"); - assert_eq!(to_str_hex(-15.), ~"-f"); - assert_eq!(to_str_hex(0.9375), ~"0.f"); - assert_eq!(to_str_hex(-0.9375), ~"-0.f"); - assert_eq!(to_str_hex(infinity), ~"inf"); - assert_eq!(to_str_hex(neg_infinity), ~"-inf"); - assert_eq!(to_str_hex(NaN), ~"NaN"); - assert_eq!(to_str_hex(0.), ~"0"); - assert_eq!(to_str_hex(-0.), ~"-0"); - } - - #[test] - pub fn test_to_str_radix() { - assert_eq!(to_str_radix(36., 36u), ~"10"); - assert_eq!(to_str_radix(8.125, 2u), ~"1000.001"); - } - - #[test] - pub fn test_from_str_radix() { - assert_eq!(from_str_radix(~"10", 36u), Some(36.)); - assert_eq!(from_str_radix(~"1000.001", 2u), Some(8.125)); - } - - #[test] - pub fn test_to_str_inf() { - assert_eq!(to_str_digits(infinity, 10u), ~"inf"); - assert_eq!(to_str_digits(-infinity, 10u), ~"-inf"); - } -} diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs deleted file mode 100644 index 3c31a7d5745..00000000000 --- a/src/libcore/num/int-template.rs +++ /dev/null @@ -1,929 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use T = self::inst::T; - -use num::{ToStrRadix, FromStrRadix}; -use num::{Zero, One, strconv}; -use prelude::*; - -pub use cmp::{min, max}; - -pub static bits : uint = inst::bits; -pub static bytes : uint = (inst::bits / 8); - -pub static min_value: T = (-1 as T) << (bits - 1); -pub static max_value: T = min_value - 1 as T; - -#[inline(always)] -pub fn add(x: T, y: T) -> T { x + y } -#[inline(always)] -pub fn sub(x: T, y: T) -> T { x - y } -#[inline(always)] -pub fn mul(x: T, y: T) -> T { x * y } -#[inline(always)] -pub fn div(x: T, y: T) -> T { x / y } - -/// -/// Returns the remainder of y / x. -/// -/// # Examples -/// ~~~ -/// assert!(int::rem(5 / 2) == 1); -/// ~~~ -/// -/// When faced with negative numbers, the result copies the sign of the -/// dividend. -/// -/// ~~~ -/// assert!(int::rem(2 / -3) == 2); -/// ~~~ -/// -/// ~~~ -/// assert!(int::rem(-2 / 3) == -2); -/// ~~~ -/// -/// -#[inline(always)] -pub fn rem(x: T, y: T) -> T { x % y } - -#[inline(always)] -pub fn lt(x: T, y: T) -> bool { x < y } -#[inline(always)] -pub fn le(x: T, y: T) -> bool { x <= y } -#[inline(always)] -pub fn eq(x: T, y: T) -> bool { x == y } -#[inline(always)] -pub fn ne(x: T, y: T) -> bool { x != y } -#[inline(always)] -pub fn ge(x: T, y: T) -> bool { x >= y } -#[inline(always)] -pub fn gt(x: T, y: T) -> bool { x > y } - -/// -/// Iterate over the range [`lo`..`hi`) -/// -/// # Arguments -/// -/// * `lo` - lower bound, inclusive -/// * `hi` - higher bound, exclusive -/// -/// # Examples -/// ~~~ -/// let mut sum = 0; -/// for int::range(1, 5) |i| { -/// sum += i; -/// } -/// assert!(sum == 10); -/// ~~~ -/// -#[inline(always)] -/// Iterate over the range [`start`,`start`+`step`..`stop`) -pub fn _range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) -> bool { - let mut i = start; - if step == 0 { - fail!("range_step called with step == 0"); - } else if step > 0 { // ascending - while i < stop { - if !it(i) { return false; } - // avoiding overflow. break if i + step > max_value - if i > max_value - step { return true; } - i += step; - } - } else { // descending - while i > stop { - if !it(i) { return false; } - // avoiding underflow. break if i + step < min_value - if i < min_value - step { return true; } - i += step; - } - } - return true; -} - -pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) -> bool { - _range_step(start, stop, step, it) -} - -#[inline(always)] -/// Iterate over the range [`lo`..`hi`) -pub fn range(lo: T, hi: T, it: &fn(T) -> bool) -> bool { - range_step(lo, hi, 1 as T, it) -} - -#[inline(always)] -/// Iterate over the range [`hi`..`lo`) -pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) -> bool { - range_step(hi, lo, -1 as T, it) -} - -/// Computes the bitwise complement -#[inline(always)] -pub fn compl(i: T) -> T { - -1 as T ^ i -} - -/// Computes the absolute value -#[inline(always)] -pub fn abs(i: T) -> T { i.abs() } - -impl Num for T {} - -#[cfg(not(test))] -impl Ord for T { - #[inline(always)] - fn lt(&self, other: &T) -> bool { return (*self) < (*other); } - #[inline(always)] - fn le(&self, other: &T) -> bool { return (*self) <= (*other); } - #[inline(always)] - fn ge(&self, other: &T) -> bool { return (*self) >= (*other); } - #[inline(always)] - fn gt(&self, other: &T) -> bool { return (*self) > (*other); } -} - -#[cfg(not(test))] -impl Eq for T { - #[inline(always)] - fn eq(&self, other: &T) -> bool { return (*self) == (*other); } - #[inline(always)] - fn ne(&self, other: &T) -> bool { return (*self) != (*other); } -} - -impl Orderable for T { - #[inline(always)] - fn min(&self, other: &T) -> T { - if *self < *other { *self } else { *other } - } - - #[inline(always)] - fn max(&self, other: &T) -> T { - if *self > *other { *self } else { *other } - } - - /// Returns the number constrained within the range `mn <= self <= mx`. - #[inline(always)] - fn clamp(&self, mn: &T, mx: &T) -> T { - cond!( - (*self > *mx) { *mx } - (*self < *mn) { *mn } - _ { *self } - ) - } -} - -impl Zero for T { - #[inline(always)] - fn zero() -> T { 0 } - - #[inline(always)] - fn is_zero(&self) -> bool { *self == 0 } -} - -impl One for T { - #[inline(always)] - fn one() -> T { 1 } -} - -#[cfg(not(test))] -impl Add<T,T> for T { - #[inline(always)] - fn add(&self, other: &T) -> T { *self + *other } -} - -#[cfg(not(test))] -impl Sub<T,T> for T { - #[inline(always)] - fn sub(&self, other: &T) -> T { *self - *other } -} - -#[cfg(not(test))] -impl Mul<T,T> for T { - #[inline(always)] - fn mul(&self, other: &T) -> T { *self * *other } -} - -#[cfg(not(test))] -impl Div<T,T> for T { - /// - /// Integer division, truncated towards 0. As this behaviour reflects the underlying - /// machine implementation it is more efficient than `Integer::div_floor`. - /// - /// # Examples - /// - /// ~~~ - /// assert!( 8 / 3 == 2); - /// assert!( 8 / -3 == -2); - /// assert!(-8 / 3 == -2); - /// assert!(-8 / -3 == 2); - - /// assert!( 1 / 2 == 0); - /// assert!( 1 / -2 == 0); - /// assert!(-1 / 2 == 0); - /// assert!(-1 / -2 == 0); - /// ~~~ - /// - #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } -} - -#[cfg(not(test))] -impl Rem<T,T> for T { - /// - /// Returns the integer remainder after division, satisfying: - /// - /// ~~~ - /// assert!((n / d) * d + (n % d) == n) - /// ~~~ - /// - /// # Examples - /// - /// ~~~ - /// assert!( 8 % 3 == 2); - /// assert!( 8 % -3 == 2); - /// assert!(-8 % 3 == -2); - /// assert!(-8 % -3 == -2); - - /// assert!( 1 % 2 == 1); - /// assert!( 1 % -2 == 1); - /// assert!(-1 % 2 == -1); - /// assert!(-1 % -2 == -1); - /// ~~~ - /// - #[inline(always)] - fn rem(&self, other: &T) -> T { *self % *other } -} - -#[cfg(not(test))] -impl Neg<T> for T { - #[inline(always)] - fn neg(&self) -> T { -*self } -} - -impl Signed for T { - /// Computes the absolute value - #[inline(always)] - fn abs(&self) -> T { - if self.is_negative() { -*self } else { *self } - } - - /// - /// The positive difference of two numbers. Returns `0` if the number is less than or - /// equal to `other`, otherwise the difference between`self` and `other` is returned. - /// - #[inline(always)] - fn abs_sub(&self, other: &T) -> T { - if *self <= *other { 0 } else { *self - *other } - } - - /// - /// # Returns - /// - /// - `0` if the number is zero - /// - `1` if the number is positive - /// - `-1` if the number is negative - /// - #[inline(always)] - fn signum(&self) -> T { - match *self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } - } - - /// Returns true if the number is positive - #[inline(always)] - fn is_positive(&self) -> bool { *self > 0 } - - /// Returns true if the number is negative - #[inline(always)] - fn is_negative(&self) -> bool { *self < 0 } -} - -impl Integer for T { - /// - /// Floored integer division - /// - /// # Examples - /// - /// ~~~ - /// assert!(( 8).div_floor( 3) == 2); - /// assert!(( 8).div_floor(-3) == -3); - /// assert!((-8).div_floor( 3) == -3); - /// assert!((-8).div_floor(-3) == 2); - /// - /// assert!(( 1).div_floor( 2) == 0); - /// assert!(( 1).div_floor(-2) == -1); - /// assert!((-1).div_floor( 2) == -1); - /// assert!((-1).div_floor(-2) == 0); - /// ~~~ - /// - #[inline(always)] - fn div_floor(&self, other: &T) -> T { - // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, - // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => d - 1, - (d, _) => d, - } - } - - /// - /// Integer modulo, satisfying: - /// - /// ~~~ - /// assert!(n.div_floor(d) * d + n.mod_floor(d) == n) - /// ~~~ - /// - /// # Examples - /// - /// ~~~ - /// assert!(( 8).mod_floor( 3) == 2); - /// assert!(( 8).mod_floor(-3) == -1); - /// assert!((-8).mod_floor( 3) == 1); - /// assert!((-8).mod_floor(-3) == -2); - /// - /// assert!(( 1).mod_floor( 2) == 1); - /// assert!(( 1).mod_floor(-2) == -1); - /// assert!((-1).mod_floor( 2) == 1); - /// assert!((-1).mod_floor(-2) == -1); - /// ~~~ - /// - #[inline(always)] - fn mod_floor(&self, other: &T) -> T { - // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, - // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match *self % *other { - r if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => r + *other, - r => r, - } - } - - /// Calculates `div_floor` and `mod_floor` simultaneously - #[inline(always)] - fn div_mod_floor(&self, other: &T) -> (T,T) { - // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, - // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.div_rem(other) { - (d, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => (d - 1, r + *other), - (d, r) => (d, r), - } - } - - /// Calculates `div` (`\`) and `rem` (`%`) simultaneously - #[inline(always)] - fn div_rem(&self, other: &T) -> (T,T) { - (*self / *other, *self % *other) - } - - /// - /// Calculates the Greatest Common Divisor (GCD) of the number and `other` - /// - /// The result is always positive - /// - #[inline(always)] - fn gcd(&self, other: &T) -> T { - // Use Euclid's algorithm - let mut m = *self, n = *other; - while m != 0 { - let temp = m; - m = n % temp; - n = temp; - } - n.abs() - } - - /// - /// Calculates the Lowest Common Multiple (LCM) of the number and `other` - /// - #[inline(always)] - fn lcm(&self, other: &T) -> T { - ((*self * *other) / self.gcd(other)).abs() // should not have to recaluculate abs - } - - /// Returns `true` if the number can be divided by `other` without leaving a remainder - #[inline(always)] - fn is_multiple_of(&self, other: &T) -> bool { *self % *other == 0 } - - /// Returns `true` if the number is divisible by `2` - #[inline(always)] - fn is_even(&self) -> bool { self.is_multiple_of(&2) } - - /// Returns `true` if the number is not divisible by `2` - #[inline(always)] - fn is_odd(&self) -> bool { !self.is_even() } -} - -impl Bitwise for T {} - -#[cfg(not(test))] -impl BitOr<T,T> for T { - #[inline(always)] - fn bitor(&self, other: &T) -> T { *self | *other } -} - -#[cfg(not(test))] -impl BitAnd<T,T> for T { - #[inline(always)] - fn bitand(&self, other: &T) -> T { *self & *other } -} - -#[cfg(not(test))] -impl BitXor<T,T> for T { - #[inline(always)] - fn bitxor(&self, other: &T) -> T { *self ^ *other } -} - -#[cfg(not(test))] -impl Shl<T,T> for T { - #[inline(always)] - fn shl(&self, other: &T) -> T { *self << *other } -} - -#[cfg(not(test))] -impl Shr<T,T> for T { - #[inline(always)] - fn shr(&self, other: &T) -> T { *self >> *other } -} - -#[cfg(not(test))] -impl Not<T> for T { - #[inline(always)] - fn not(&self) -> T { !*self } -} - -impl Bounded for T { - #[inline(always)] - fn min_value() -> T { min_value } - - #[inline(always)] - fn max_value() -> T { max_value } -} - -impl Int for T {} - -// String conversion functions and impl str -> num - -/// Parse a string as a number in base 10. -#[inline(always)] -pub fn from_str(s: &str) -> Option<T> { - strconv::from_str_common(s, 10u, true, false, false, - strconv::ExpNone, false, false) -} - -/// Parse a string as a number in the given base. -#[inline(always)] -pub fn from_str_radix(s: &str, radix: uint) -> Option<T> { - strconv::from_str_common(s, radix, true, false, false, - strconv::ExpNone, false, false) -} - -/// Parse a byte slice as a number in the given base. -#[inline(always)] -pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> { - strconv::from_str_bytes_common(buf, radix, true, false, false, - strconv::ExpNone, false, false) -} - -impl FromStr for T { - #[inline(always)] - fn from_str(s: &str) -> Option<T> { - from_str(s) - } -} - -impl FromStrRadix for T { - #[inline(always)] - fn from_str_radix(s: &str, radix: uint) -> Option<T> { - from_str_radix(s, radix) - } -} - -// String conversion functions and impl num -> str - -/// Convert to a string as a byte slice in a given base. -#[inline(always)] -pub fn to_str_bytes<U>(n: T, radix: uint, f: &fn(v: &[u8]) -> U) -> U { - let (buf, _) = strconv::to_str_bytes_common(&n, radix, false, - strconv::SignNeg, strconv::DigAll); - f(buf) -} - -/// Convert to a string in base 10. -#[inline(always)] -pub fn to_str(num: T) -> ~str { - let (buf, _) = strconv::to_str_common(&num, 10u, false, - strconv::SignNeg, strconv::DigAll); - buf -} - -/// Convert to a string in a given base. -#[inline(always)] -pub fn to_str_radix(num: T, radix: uint) -> ~str { - let (buf, _) = strconv::to_str_common(&num, radix, false, - strconv::SignNeg, strconv::DigAll); - buf -} - -impl ToStr for T { - #[inline(always)] - fn to_str(&self) -> ~str { - to_str(*self) - } -} - -impl ToStrRadix for T { - #[inline(always)] - fn to_str_radix(&self, radix: uint) -> ~str { - to_str_radix(*self, radix) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use super::inst::T; - use prelude::*; - - #[test] - fn test_num() { - num::test_num(10 as T, 2 as T); - } - - #[test] - fn test_orderable() { - assert_eq!((1 as T).min(&(2 as T)), 1 as T); - assert_eq!((2 as T).min(&(1 as T)), 1 as T); - assert_eq!((1 as T).max(&(2 as T)), 2 as T); - assert_eq!((2 as T).max(&(1 as T)), 2 as T); - assert_eq!((1 as T).clamp(&(2 as T), &(4 as T)), 2 as T); - assert_eq!((8 as T).clamp(&(2 as T), &(4 as T)), 4 as T); - assert_eq!((3 as T).clamp(&(2 as T), &(4 as T)), 3 as T); - } - - #[test] - pub fn test_abs() { - assert_eq!((1 as T).abs(), 1 as T); - assert_eq!((0 as T).abs(), 0 as T); - assert_eq!((-1 as T).abs(), 1 as T); - } - - #[test] - fn test_abs_sub() { - assert_eq!((-1 as T).abs_sub(&(1 as T)), 0 as T); - assert_eq!((1 as T).abs_sub(&(1 as T)), 0 as T); - assert_eq!((1 as T).abs_sub(&(0 as T)), 1 as T); - assert_eq!((1 as T).abs_sub(&(-1 as T)), 2 as T); - } - - #[test] - fn test_signum() { - assert_eq!((1 as T).signum(), 1 as T); - assert_eq!((0 as T).signum(), 0 as T); - assert_eq!((-0 as T).signum(), 0 as T); - assert_eq!((-1 as T).signum(), -1 as T); - } - - #[test] - fn test_is_positive() { - assert!((1 as T).is_positive()); - assert!(!(0 as T).is_positive()); - assert!(!(-0 as T).is_positive()); - assert!(!(-1 as T).is_positive()); - } - - #[test] - fn test_is_negative() { - assert!(!(1 as T).is_negative()); - assert!(!(0 as T).is_negative()); - assert!(!(-0 as T).is_negative()); - assert!((-1 as T).is_negative()); - } - - /// - /// Checks that the division rule holds for: - /// - /// - `n`: numerator (dividend) - /// - `d`: denominator (divisor) - /// - `qr`: quotient and remainder - /// - #[cfg(test)] - fn test_division_rule((n,d): (T,T), (q,r): (T,T)) { - assert_eq!(d * q + r, n); - } - - #[test] - fn test_div_rem() { - fn test_nd_dr(nd: (T,T), qr: (T,T)) { - let (n,d) = nd; - let separate_div_rem = (n / d, n % d); - let combined_div_rem = n.div_rem(&d); - - assert_eq!(separate_div_rem, qr); - assert_eq!(combined_div_rem, qr); - - test_division_rule(nd, separate_div_rem); - test_division_rule(nd, combined_div_rem); - } - - test_nd_dr(( 8, 3), ( 2, 2)); - test_nd_dr(( 8, -3), (-2, 2)); - test_nd_dr((-8, 3), (-2, -2)); - test_nd_dr((-8, -3), ( 2, -2)); - - test_nd_dr(( 1, 2), ( 0, 1)); - test_nd_dr(( 1, -2), ( 0, 1)); - test_nd_dr((-1, 2), ( 0, -1)); - test_nd_dr((-1, -2), ( 0, -1)); - } - - #[test] - fn test_div_mod_floor() { - fn test_nd_dm(nd: (T,T), dm: (T,T)) { - let (n,d) = nd; - let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); - let combined_div_mod_floor = n.div_mod_floor(&d); - - assert_eq!(separate_div_mod_floor, dm); - assert_eq!(combined_div_mod_floor, dm); - - test_division_rule(nd, separate_div_mod_floor); - test_division_rule(nd, combined_div_mod_floor); - } - - test_nd_dm(( 8, 3), ( 2, 2)); - test_nd_dm(( 8, -3), (-3, -1)); - test_nd_dm((-8, 3), (-3, 1)); - test_nd_dm((-8, -3), ( 2, -2)); - - test_nd_dm(( 1, 2), ( 0, 1)); - test_nd_dm(( 1, -2), (-1, -1)); - test_nd_dm((-1, 2), (-1, 1)); - test_nd_dm((-1, -2), ( 0, -1)); - } - - #[test] - fn test_gcd() { - assert_eq!((10 as T).gcd(&2), 2 as T); - assert_eq!((10 as T).gcd(&3), 1 as T); - assert_eq!((0 as T).gcd(&3), 3 as T); - assert_eq!((3 as T).gcd(&3), 3 as T); - assert_eq!((56 as T).gcd(&42), 14 as T); - assert_eq!((3 as T).gcd(&-3), 3 as T); - assert_eq!((-6 as T).gcd(&3), 3 as T); - assert_eq!((-4 as T).gcd(&-2), 2 as T); - } - - #[test] - fn test_lcm() { - assert_eq!((1 as T).lcm(&0), 0 as T); - assert_eq!((0 as T).lcm(&1), 0 as T); - assert_eq!((1 as T).lcm(&1), 1 as T); - assert_eq!((-1 as T).lcm(&1), 1 as T); - assert_eq!((1 as T).lcm(&-1), 1 as T); - assert_eq!((-1 as T).lcm(&-1), 1 as T); - assert_eq!((8 as T).lcm(&9), 72 as T); - assert_eq!((11 as T).lcm(&5), 55 as T); - } - - #[test] - fn test_bitwise() { - assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T))); - assert_eq!(0b1000 as T, (0b1100 as T).bitand(&(0b1010 as T))); - assert_eq!(0b0110 as T, (0b1100 as T).bitxor(&(0b1010 as T))); - assert_eq!(0b1110 as T, (0b0111 as T).shl(&(1 as T))); - assert_eq!(0b0111 as T, (0b1110 as T).shr(&(1 as T))); - assert_eq!(-(0b11 as T) - (1 as T), (0b11 as T).not()); - } - - #[test] - fn test_multiple_of() { - assert!((6 as T).is_multiple_of(&(6 as T))); - assert!((6 as T).is_multiple_of(&(3 as T))); - assert!((6 as T).is_multiple_of(&(1 as T))); - assert!((-8 as T).is_multiple_of(&(4 as T))); - assert!((8 as T).is_multiple_of(&(-1 as T))); - assert!((-8 as T).is_multiple_of(&(-2 as T))); - } - - #[test] - fn test_even() { - assert_eq!((-4 as T).is_even(), true); - assert_eq!((-3 as T).is_even(), false); - assert_eq!((-2 as T).is_even(), true); - assert_eq!((-1 as T).is_even(), false); - assert_eq!((0 as T).is_even(), true); - assert_eq!((1 as T).is_even(), false); - assert_eq!((2 as T).is_even(), true); - assert_eq!((3 as T).is_even(), false); - assert_eq!((4 as T).is_even(), true); - } - - #[test] - fn test_odd() { - assert_eq!((-4 as T).is_odd(), false); - assert_eq!((-3 as T).is_odd(), true); - assert_eq!((-2 as T).is_odd(), false); - assert_eq!((-1 as T).is_odd(), true); - assert_eq!((0 as T).is_odd(), false); - assert_eq!((1 as T).is_odd(), true); - assert_eq!((2 as T).is_odd(), false); - assert_eq!((3 as T).is_odd(), true); - assert_eq!((4 as T).is_odd(), false); - } - - #[test] - fn test_bitcount() { - assert_eq!((0b010101 as T).population_count(), 3); - } - - #[test] - fn test_primitive() { - assert_eq!(Primitive::bits::<T>(), sys::size_of::<T>() * 8); - assert_eq!(Primitive::bytes::<T>(), sys::size_of::<T>()); - } - - #[test] - fn test_from_str() { - assert_eq!(from_str(~"0"), Some(0 as T)); - assert_eq!(from_str(~"3"), Some(3 as T)); - assert_eq!(from_str(~"10"), Some(10 as T)); - assert_eq!(i32::from_str(~"123456789"), Some(123456789 as i32)); - assert_eq!(from_str(~"00100"), Some(100 as T)); - - assert_eq!(from_str(~"-1"), Some(-1 as T)); - assert_eq!(from_str(~"-3"), Some(-3 as T)); - assert_eq!(from_str(~"-10"), Some(-10 as T)); - assert_eq!(i32::from_str(~"-123456789"), Some(-123456789 as i32)); - assert_eq!(from_str(~"-00100"), Some(-100 as T)); - - assert!(from_str(~" ").is_none()); - assert!(from_str(~"x").is_none()); - } - - #[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()); - } - - #[test] - fn test_to_str() { - assert_eq!(to_str_radix(0 as T, 10u), ~"0"); - assert_eq!(to_str_radix(1 as T, 10u), ~"1"); - assert_eq!(to_str_radix(-1 as T, 10u), ~"-1"); - assert_eq!(to_str_radix(127 as T, 16u), ~"7f"); - assert_eq!(to_str_radix(100 as T, 10u), ~"100"); - - } - - #[test] - fn test_int_to_str_overflow() { - let mut i8_val: i8 = 127_i8; - assert_eq!(i8::to_str(i8_val), ~"127"); - - i8_val += 1 as i8; - assert_eq!(i8::to_str(i8_val), ~"-128"); - - let mut i16_val: i16 = 32_767_i16; - assert_eq!(i16::to_str(i16_val), ~"32767"); - - i16_val += 1 as i16; - assert_eq!(i16::to_str(i16_val), ~"-32768"); - - let mut i32_val: i32 = 2_147_483_647_i32; - assert_eq!(i32::to_str(i32_val), ~"2147483647"); - - i32_val += 1 as i32; - assert_eq!(i32::to_str(i32_val), ~"-2147483648"); - - let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert_eq!(i64::to_str(i64_val), ~"9223372036854775807"); - - i64_val += 1 as i64; - assert_eq!(i64::to_str(i64_val), ~"-9223372036854775808"); - } - - #[test] - fn test_int_from_str_overflow() { - let mut i8_val: i8 = 127_i8; - assert_eq!(i8::from_str(~"127"), Some(i8_val)); - assert!(i8::from_str(~"128").is_none()); - - i8_val += 1 as i8; - assert_eq!(i8::from_str(~"-128"), Some(i8_val)); - assert!(i8::from_str(~"-129").is_none()); - - let mut i16_val: i16 = 32_767_i16; - assert_eq!(i16::from_str(~"32767"), Some(i16_val)); - assert!(i16::from_str(~"32768").is_none()); - - i16_val += 1 as i16; - assert_eq!(i16::from_str(~"-32768"), Some(i16_val)); - assert!(i16::from_str(~"-32769").is_none()); - - let mut i32_val: i32 = 2_147_483_647_i32; - assert_eq!(i32::from_str(~"2147483647"), Some(i32_val)); - assert!(i32::from_str(~"2147483648").is_none()); - - i32_val += 1 as i32; - assert_eq!(i32::from_str(~"-2147483648"), Some(i32_val)); - assert!(i32::from_str(~"-2147483649").is_none()); - - let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert_eq!(i64::from_str(~"9223372036854775807"), Some(i64_val)); - assert!(i64::from_str(~"9223372036854775808").is_none()); - - i64_val += 1 as i64; - assert_eq!(i64::from_str(~"-9223372036854775808"), Some(i64_val)); - assert!(i64::from_str(~"-9223372036854775809").is_none()); - } - - #[test] - fn test_ranges() { - let mut l = ~[]; - - for range(0,3) |i| { - l.push(i); - } - for range_rev(13,10) |i| { - l.push(i); - } - for range_step(20,26,2) |i| { - l.push(i); - } - for range_step(36,30,-2) |i| { - l.push(i); - } - for range_step(max_value - 2, max_value, 2) |i| { - l.push(i); - } - for range_step(max_value - 3, max_value, 2) |i| { - l.push(i); - } - for range_step(min_value + 2, min_value, -2) |i| { - l.push(i); - } - for range_step(min_value + 3, min_value, -2) |i| { - l.push(i); - } - assert_eq!(l, ~[0,1,2, - 13,12,11, - 20,22,24, - 36,34,32, - max_value-2, - max_value-3,max_value-1, - min_value+2, - min_value+3,min_value+1]); - - // None of the `fail`s should execute. - for range(10,0) |_i| { - fail!("unreachable"); - } - for range_rev(0,10) |_i| { - fail!("unreachable"); - } - for range_step(10,0,1) |_i| { - fail!("unreachable"); - } - for range_step(0,10,-1) |_i| { - fail!("unreachable"); - } - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_range_step_zero_step() { - for range_step(0,10,0) |_i| {} - } -} diff --git a/src/libcore/num/int-template/i16.rs b/src/libcore/num/int-template/i16.rs deleted file mode 100644 index 28263378555..00000000000 --- a/src/libcore/num/int-template/i16.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `i16` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = i16; - pub static bits: uint = ::u16::bits; - - impl Primitive for i16 { - #[inline(always)] - fn bits() -> uint { 16 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<i16>() / 8 } - } - - impl BitCount for i16 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> i16 { unsafe { intrinsics::ctpop16(*self) } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> i16 { unsafe { intrinsics::ctlz16(*self) } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> i16 { unsafe { intrinsics::cttz16(*self) } } - } -} diff --git a/src/libcore/num/int-template/i32.rs b/src/libcore/num/int-template/i32.rs deleted file mode 100644 index 959cf8f7d77..00000000000 --- a/src/libcore/num/int-template/i32.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `i32` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = i32; - pub static bits: uint = ::u32::bits; - - impl Primitive for i32 { - #[inline(always)] - fn bits() -> uint { 32 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<i32>() / 8 } - } - - impl BitCount for i32 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> i32 { unsafe { intrinsics::ctpop32(*self) } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> i32 { unsafe { intrinsics::ctlz32(*self) } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> i32 { unsafe { intrinsics::cttz32(*self) } } - } -} diff --git a/src/libcore/num/int-template/i64.rs b/src/libcore/num/int-template/i64.rs deleted file mode 100644 index 3b51c70be12..00000000000 --- a/src/libcore/num/int-template/i64.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `i64` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = i64; - pub static bits: uint = ::u64::bits; - - impl Primitive for i64 { - #[inline(always)] - fn bits() -> uint { 64 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<i64>() / 8 } - } - - impl BitCount for i64 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> i64 { unsafe { intrinsics::ctpop64(*self) } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> i64 { unsafe { intrinsics::ctlz64(*self) } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> i64 { unsafe { intrinsics::cttz64(*self) } } - } -} diff --git a/src/libcore/num/int-template/i8.rs b/src/libcore/num/int-template/i8.rs deleted file mode 100644 index 896fb4dbf50..00000000000 --- a/src/libcore/num/int-template/i8.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `i8` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = i8; - pub static bits: uint = ::u8::bits; - - impl Primitive for i8 { - #[inline(always)] - fn bits() -> uint { 8 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<i8>() / 8 } - } - - impl BitCount for i8 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> i8 { unsafe { intrinsics::ctpop8(*self) } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> i8 { unsafe { intrinsics::ctlz8(*self) } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> i8 { unsafe { intrinsics::cttz8(*self) } } - } -} diff --git a/src/libcore/num/int-template/int.rs b/src/libcore/num/int-template/int.rs deleted file mode 100644 index 64f6f2d2a9a..00000000000 --- a/src/libcore/num/int-template/int.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `int` - -pub use self::inst::pow; - -mod inst { - use num::{Primitive, BitCount}; - - pub type T = int; - pub static bits: uint = ::uint::bits; - - impl Primitive for int { - #[cfg(target_word_size = "32")] - #[inline(always)] - fn bits() -> uint { 32 } - - #[cfg(target_word_size = "64")] - #[inline(always)] - fn bits() -> uint { 64 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<int>() / 8 } - } - - #[cfg(target_word_size = "32")] - #[inline(always)] - impl BitCount for int { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> int { (*self as i32).population_count() as int } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> int { (*self as i32).leading_zeros() as int } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> int { (*self as i32).trailing_zeros() as int } - } - - #[cfg(target_word_size = "64")] - #[inline(always)] - impl BitCount for int { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> int { (*self as i64).population_count() as int } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> int { (*self as i64).leading_zeros() as int } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> int { (*self as i64).trailing_zeros() as int } - } - - /// Returns `base` raised to the power of `exponent` - pub fn pow(base: int, exponent: uint) -> int { - if exponent == 0u { - //Not mathemtically true if ~[base == 0] - return 1; - } - if base == 0 { return 0; } - let mut my_pow = exponent; - let mut acc = 1; - let mut multiplier = base; - while(my_pow > 0u) { - if my_pow % 2u == 1u { - acc *= multiplier; - } - my_pow /= 2u; - multiplier *= multiplier; - } - return acc; - } - - #[test] - fn test_pow() { - assert_eq!(pow(0, 0u), 1); - assert_eq!(pow(0, 1u), 0); - assert_eq!(pow(0, 2u), 0); - assert_eq!(pow(-1, 0u), 1); - assert_eq!(pow(1, 0u), 1); - assert_eq!(pow(-3, 2u), 9); - assert_eq!(pow(-3, 3u), -27); - assert_eq!(pow(4, 9u), 262144); - } - - #[test] - fn test_overflows() { - assert!((::int::max_value > 0)); - assert!((::int::min_value <= 0)); - assert_eq!(::int::min_value + ::int::max_value + 1, 0); - } -} diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs deleted file mode 100644 index 96b302d3174..00000000000 --- a/src/libcore/num/num.rs +++ /dev/null @@ -1,494 +0,0 @@ -// 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. - -//! An interface for numeric types -use cmp::{Eq, ApproxEq, Ord}; -use ops::{Add, Sub, Mul, Div, Rem, Neg}; -use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; -use option::Option; -use kinds::Copy; - -pub mod strconv; - -/// -/// The base trait for numeric types -/// -pub trait Num: Eq + Zero + One - + Neg<Self> - + Add<Self,Self> - + Sub<Self,Self> - + Mul<Self,Self> - + Div<Self,Self> - + Rem<Self,Self> {} - -pub trait IntConvertible { - fn to_int(&self) -> int; - fn from_int(n: int) -> Self; -} - -pub trait Orderable: Ord { - // These should be methods on `Ord`, with overridable default implementations. We don't want - // to encumber all implementors of Ord by requiring them to implement these functions, but at - // the same time we want to be able to take advantage of the speed of the specific numeric - // functions (like the `fmin` and `fmax` intrinsics). - fn min(&self, other: &Self) -> Self; - fn max(&self, other: &Self) -> Self; - fn clamp(&self, mn: &Self, mx: &Self) -> Self; -} - -pub trait Zero { - fn zero() -> Self; // FIXME (#5527): This should be an associated constant - fn is_zero(&self) -> bool; -} - -pub trait One { - fn one() -> Self; // FIXME (#5527): This should be an associated constant -} - -pub trait Signed: Num - + Neg<Self> { - fn abs(&self) -> Self; - fn abs_sub(&self, other: &Self) -> Self; - fn signum(&self) -> Self; - - fn is_positive(&self) -> bool; - fn is_negative(&self) -> bool; -} - -pub trait Unsigned: Num {} - -// This should be moved into the default implementation for Signed::abs -pub fn abs<T:Ord + Zero + Neg<T>>(v: T) -> T { - if v < Zero::zero() { v.neg() } else { v } -} - -pub trait Integer: Num - + Orderable - + Div<Self,Self> - + Rem<Self,Self> { - fn div_rem(&self, other: &Self) -> (Self,Self); - - fn div_floor(&self, other: &Self) -> Self; - fn mod_floor(&self, other: &Self) -> Self; - fn div_mod_floor(&self, other: &Self) -> (Self,Self); - - fn gcd(&self, other: &Self) -> Self; - fn lcm(&self, other: &Self) -> Self; - - fn is_multiple_of(&self, other: &Self) -> bool; - fn is_even(&self) -> bool; - fn is_odd(&self) -> bool; -} - -pub trait Round { - fn floor(&self) -> Self; - fn ceil(&self) -> Self; - fn round(&self) -> Self; - fn trunc(&self) -> Self; - fn fract(&self) -> Self; -} - -pub trait Fractional: Num - + Orderable - + Round - + Div<Self,Self> { - fn recip(&self) -> Self; -} - -pub trait Algebraic { - fn pow(&self, n: Self) -> Self; - fn sqrt(&self) -> Self; - fn rsqrt(&self) -> Self; - fn cbrt(&self) -> Self; - fn hypot(&self, other: Self) -> Self; -} - -pub trait Trigonometric { - fn sin(&self) -> Self; - fn cos(&self) -> Self; - fn tan(&self) -> Self; - fn asin(&self) -> Self; - fn acos(&self) -> Self; - fn atan(&self) -> Self; - fn atan2(&self, other: Self) -> Self; - fn sin_cos(&self) -> (Self, Self); -} - -pub trait Exponential { - fn exp(&self) -> Self; - fn exp2(&self) -> Self; - fn ln(&self) -> Self; - fn log(&self, base: Self) -> Self; - fn log2(&self) -> Self; - fn log10(&self) -> Self; -} - -pub trait Hyperbolic: Exponential { - fn sinh(&self) -> Self; - fn cosh(&self) -> Self; - fn tanh(&self) -> Self; - fn asinh(&self) -> Self; - fn acosh(&self) -> Self; - fn atanh(&self) -> Self; -} - -/// -/// Defines constants and methods common to real numbers -/// -pub trait Real: Signed - + Fractional - + Algebraic - + Trigonometric - + Hyperbolic { - // Common Constants - // FIXME (#5527): These should be associated constants - fn pi() -> Self; - fn two_pi() -> Self; - fn frac_pi_2() -> Self; - fn frac_pi_3() -> Self; - fn frac_pi_4() -> Self; - fn frac_pi_6() -> Self; - fn frac_pi_8() -> Self; - fn frac_1_pi() -> Self; - fn frac_2_pi() -> Self; - fn frac_2_sqrtpi() -> Self; - fn sqrt2() -> Self; - fn frac_1_sqrt2() -> Self; - fn e() -> Self; - fn log2_e() -> Self; - fn log10_e() -> Self; - fn ln_2() -> Self; - fn ln_10() -> Self; - - // Angular conversions - fn to_degrees(&self) -> Self; - fn to_radians(&self) -> Self; -} - -/// -/// Methods that are harder to implement and not commonly used. -/// -pub trait RealExt: Real { - // FIXME (#5527): usages of `int` should be replaced with an associated - // integer type once these are implemented - - // Gamma functions - fn lgamma(&self) -> (int, Self); - fn tgamma(&self) -> Self; - - // Bessel functions - fn j0(&self) -> Self; - fn j1(&self) -> Self; - fn jn(&self, n: int) -> Self; - fn y0(&self) -> Self; - fn y1(&self) -> Self; - fn yn(&self, n: int) -> Self; -} - -/// -/// Collects the bitwise operators under one trait. -/// -pub trait Bitwise: Not<Self> - + BitAnd<Self,Self> - + BitOr<Self,Self> - + BitXor<Self,Self> - + Shl<Self,Self> - + Shr<Self,Self> {} - -pub trait BitCount { - fn population_count(&self) -> Self; - fn leading_zeros(&self) -> Self; - fn trailing_zeros(&self) -> Self; -} - -pub trait Bounded { - // FIXME (#5527): These should be associated constants - fn min_value() -> Self; - fn max_value() -> Self; -} - -/// -/// Specifies the available operations common to all of Rust's core numeric primitives. -/// These may not always make sense from a purely mathematical point of view, but -/// may be useful for systems programming. -/// -pub trait Primitive: Num - + NumCast - + Bounded - + Neg<Self> - + Add<Self,Self> - + Sub<Self,Self> - + Mul<Self,Self> - + Div<Self,Self> - + Rem<Self,Self> { - // FIXME (#5527): These should be associated constants - fn bits() -> uint; - fn bytes() -> uint; -} - -/// -/// A collection of traits relevant to primitive signed and unsigned integers -/// -pub trait Int: Integer - + Primitive - + Bitwise - + BitCount {} - -/// -/// Used for representing the classification of floating point numbers -/// -#[deriving(Eq)] -pub enum FPCategory { - /// "Not a Number", often obtained by dividing by zero - FPNaN, - /// Positive or negative infinity - FPInfinite , - /// Positive or negative zero - FPZero, - /// De-normalized floating point representation (less precise than `FPNormal`) - FPSubnormal, - /// A regular floating point number - FPNormal, -} - -/// -/// Primitive floating point numbers -/// -pub trait Float: Real - + Signed - + Primitive - + ApproxEq<Self> { - // FIXME (#5527): These should be associated constants - fn NaN() -> Self; - fn infinity() -> Self; - fn neg_infinity() -> Self; - fn neg_zero() -> Self; - - fn is_NaN(&self) -> bool; - fn is_infinite(&self) -> bool; - fn is_finite(&self) -> bool; - fn is_normal(&self) -> bool; - fn classify(&self) -> FPCategory; - - fn mantissa_digits() -> uint; - fn digits() -> uint; - fn epsilon() -> Self; - fn min_exp() -> int; - fn max_exp() -> int; - fn min_10_exp() -> int; - fn max_10_exp() -> int; - - fn ldexp(x: Self, exp: int) -> Self; - fn frexp(&self) -> (Self, int); - - fn exp_m1(&self) -> Self; - fn ln_1p(&self) -> Self; - fn mul_add(&self, a: Self, b: Self) -> Self; - fn next_after(&self, other: Self) -> Self; -} - -/// -/// Cast from one machine scalar to another -/// -/// # Example -/// -/// ~~~ -/// let twenty: f32 = num::cast(0x14); -/// assert_eq!(twenty, 20f32); -/// ~~~ -/// -#[inline(always)] -pub fn cast<T:NumCast,U:NumCast>(n: T) -> U { - NumCast::from(n) -} - -/// -/// An interface for casting between machine scalars -/// -pub trait NumCast { - fn from<T:NumCast>(n: T) -> Self; - - fn to_u8(&self) -> u8; - fn to_u16(&self) -> u16; - fn to_u32(&self) -> u32; - fn to_u64(&self) -> u64; - fn to_uint(&self) -> uint; - - fn to_i8(&self) -> i8; - fn to_i16(&self) -> i16; - fn to_i32(&self) -> i32; - fn to_i64(&self) -> i64; - fn to_int(&self) -> int; - - fn to_f32(&self) -> f32; - fn to_f64(&self) -> f64; - fn to_float(&self) -> float; -} - -macro_rules! impl_num_cast( - ($T:ty, $conv:ident) => ( - impl NumCast for $T { - #[inline(always)] - fn from<N:NumCast>(n: N) -> $T { - // `$conv` could be generated using `concat_idents!`, but that - // macro seems to be broken at the moment - n.$conv() - } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } - } - ) -) - -impl_num_cast!(u8, to_u8) -impl_num_cast!(u16, to_u16) -impl_num_cast!(u32, to_u32) -impl_num_cast!(u64, to_u64) -impl_num_cast!(uint, to_uint) -impl_num_cast!(i8, to_i8) -impl_num_cast!(i16, to_i16) -impl_num_cast!(i32, to_i32) -impl_num_cast!(i64, to_i64) -impl_num_cast!(int, to_int) -impl_num_cast!(f32, to_f32) -impl_num_cast!(f64, to_f64) -impl_num_cast!(float, to_float) - -pub trait ToStrRadix { - pub fn to_str_radix(&self, radix: uint) -> ~str; -} - -pub trait FromStrRadix { - pub fn from_str_radix(str: &str, radix: uint) -> Option<Self>; -} - -/// -/// Calculates a power to a given radix, optimized for uint `pow` and `radix`. -/// -/// Returns `radix^pow` as `T`. -/// -/// Note: -/// Also returns `1` for `0^0`, despite that technically being an -/// undefined number. The reason for this is twofold: -/// - If code written to use this function cares about that special case, it's -/// probably going to catch it before making the call. -/// - If code written to use this function doesn't care about it, it's -/// probably assuming that `x^0` always equals `1`. -/// -pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(radix: uint, pow: uint) -> T { - let _0: T = Zero::zero(); - let _1: T = One::one(); - - if pow == 0u { return _1; } - if radix == 0u { return _0; } - let mut my_pow = pow; - let mut total = _1; - let mut multiplier = cast(radix); - while (my_pow > 0u) { - if my_pow % 2u == 1u { - total *= multiplier; - } - my_pow /= 2u; - multiplier *= multiplier; - } - total -} - -/// Helper function for testing numeric operations -#[cfg(test)] -pub fn test_num<T:Num + NumCast>(ten: T, two: T) { - assert_eq!(ten.add(&two), cast(12)); - assert_eq!(ten.sub(&two), cast(8)); - assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.div(&two), cast(5)); - assert_eq!(ten.rem(&two), cast(0)); - - assert_eq!(ten.add(&two), ten + two); - assert_eq!(ten.sub(&two), ten - two); - assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); - assert_eq!(ten.rem(&two), ten % two); -} - -macro_rules! test_cast_20( - ($_20:expr) => ({ - let _20 = $_20; - - assert_eq!(20u, _20.to_uint()); - assert_eq!(20u8, _20.to_u8()); - assert_eq!(20u16, _20.to_u16()); - assert_eq!(20u32, _20.to_u32()); - assert_eq!(20u64, _20.to_u64()); - assert_eq!(20i, _20.to_int()); - assert_eq!(20i8, _20.to_i8()); - assert_eq!(20i16, _20.to_i16()); - assert_eq!(20i32, _20.to_i32()); - assert_eq!(20i64, _20.to_i64()); - assert_eq!(20f, _20.to_float()); - assert_eq!(20f32, _20.to_f32()); - assert_eq!(20f64, _20.to_f64()); - - assert_eq!(_20, NumCast::from(20u)); - assert_eq!(_20, NumCast::from(20u8)); - assert_eq!(_20, NumCast::from(20u16)); - assert_eq!(_20, NumCast::from(20u32)); - assert_eq!(_20, NumCast::from(20u64)); - assert_eq!(_20, NumCast::from(20i)); - assert_eq!(_20, NumCast::from(20i8)); - assert_eq!(_20, NumCast::from(20i16)); - assert_eq!(_20, NumCast::from(20i32)); - assert_eq!(_20, NumCast::from(20i64)); - assert_eq!(_20, NumCast::from(20f)); - assert_eq!(_20, NumCast::from(20f32)); - assert_eq!(_20, NumCast::from(20f64)); - - assert_eq!(_20, cast(20u)); - assert_eq!(_20, cast(20u8)); - assert_eq!(_20, cast(20u16)); - assert_eq!(_20, cast(20u32)); - assert_eq!(_20, cast(20u64)); - assert_eq!(_20, cast(20i)); - assert_eq!(_20, cast(20i8)); - assert_eq!(_20, cast(20i16)); - assert_eq!(_20, cast(20i32)); - assert_eq!(_20, cast(20i64)); - assert_eq!(_20, cast(20f)); - assert_eq!(_20, cast(20f32)); - assert_eq!(_20, cast(20f64)); - }) -) - -#[test] fn test_u8_cast() { test_cast_20!(20u8) } -#[test] fn test_u16_cast() { test_cast_20!(20u16) } -#[test] fn test_u32_cast() { test_cast_20!(20u32) } -#[test] fn test_u64_cast() { test_cast_20!(20u64) } -#[test] fn test_uint_cast() { test_cast_20!(20u) } -#[test] fn test_i8_cast() { test_cast_20!(20i8) } -#[test] fn test_i16_cast() { test_cast_20!(20i16) } -#[test] fn test_i32_cast() { test_cast_20!(20i32) } -#[test] fn test_i64_cast() { test_cast_20!(20i64) } -#[test] fn test_int_cast() { test_cast_20!(20i) } -#[test] fn test_f32_cast() { test_cast_20!(20f32) } -#[test] fn test_f64_cast() { test_cast_20!(20f64) } -#[test] fn test_float_cast() { test_cast_20!(20f) } diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs deleted file mode 100644 index 1d65b84b7ce..00000000000 --- a/src/libcore/num/strconv.rs +++ /dev/null @@ -1,673 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use 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 kinds::Copy; -use vec; -use vec::{CopyableVector, ImmutableVector}; -use vec::OwnedVector; -use num::{NumCast, Zero, One, cast, pow_with_uint}; -use f64; - -pub enum ExponentFormat { - ExpNone, - ExpDec, - ExpBin -} - -pub enum SignificantDigits { - DigAll, - DigMax(uint), - DigExact(uint) -} - -pub enum SignFormat { - SignNone, - SignNeg, - SignAll -} - -#[inline(always)] -fn is_NaN<T:Eq>(num: &T) -> bool { - *num != *num -} - -#[inline(always)] -fn is_inf<T:Eq+NumStrConv>(num: &T) -> bool { - match NumStrConv::inf() { - None => false, - Some(n) => *num == n - } -} - -#[inline(always)] -fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool { - match NumStrConv::neg_inf() { - None => false, - Some(n) => *num == n - } -} - -#[inline(always)] -fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Div<T,T>>(num: &T) -> bool { - let _0: T = Zero::zero(); - let _1: T = One::one(); - - *num == _0 && is_neg_inf(&(_1 / *num)) -} - -pub trait NumStrConv { - fn NaN() -> Option<Self>; - fn inf() -> Option<Self>; - fn neg_inf() -> Option<Self>; - fn neg_zero() -> Option<Self>; - - fn round_to_zero(&self) -> Self; - fn fractional_part(&self) -> Self; -} - -macro_rules! impl_NumStrConv_Floating (($t:ty) => ( - impl NumStrConv for $t { - #[inline(always)] - fn NaN() -> Option<$t> { Some( 0.0 / 0.0) } - #[inline(always)] - fn inf() -> Option<$t> { Some( 1.0 / 0.0) } - #[inline(always)] - fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) } - #[inline(always)] - fn neg_zero() -> Option<$t> { Some(-0.0 ) } - - #[inline(always)] - fn round_to_zero(&self) -> $t { - ( if *self < 0.0 { f64::ceil(*self as f64) } - else { f64::floor(*self as f64) } - ) as $t - } - - #[inline(always)] - fn fractional_part(&self) -> $t { - *self - self.round_to_zero() - } - } -)) - -macro_rules! impl_NumStrConv_Integer (($t:ty) => ( - impl NumStrConv for $t { - #[inline(always)] fn NaN() -> Option<$t> { None } - #[inline(always)] fn inf() -> Option<$t> { None } - #[inline(always)] fn neg_inf() -> Option<$t> { None } - #[inline(always)] fn neg_zero() -> Option<$t> { None } - - #[inline(always)] fn round_to_zero(&self) -> $t { *self } - #[inline(always)] fn fractional_part(&self) -> $t { 0 } - } -)) - -// FIXME: #4955 -// Replace by two generic impls for traits 'Integral' and 'Floating' -impl_NumStrConv_Floating!(float) -impl_NumStrConv_Floating!(f32) -impl_NumStrConv_Floating!(f64) - -impl_NumStrConv_Integer!(int) -impl_NumStrConv_Integer!(i8) -impl_NumStrConv_Integer!(i16) -impl_NumStrConv_Integer!(i32) -impl_NumStrConv_Integer!(i64) - -impl_NumStrConv_Integer!(uint) -impl_NumStrConv_Integer!(u8) -impl_NumStrConv_Integer!(u16) -impl_NumStrConv_Integer!(u32) -impl_NumStrConv_Integer!(u64) - - -// Special value strings as [u8] consts. -static inf_buf: [u8, ..3] = ['i' as u8, 'n' as u8, 'f' as u8]; -static positive_inf_buf: [u8, ..4] = ['+' as u8, 'i' as u8, 'n' as u8, - 'f' as u8]; -static negative_inf_buf: [u8, ..4] = ['-' as u8, 'i' as u8, 'n' as u8, - 'f' as u8]; -static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8]; - -/** - * Converts a number to its string representation as a byte vector. - * This is meant to be a common base implementation for all numeric string - * conversion functions like `to_str()` or `to_str_radix()`. - * - * # Arguments - * - `num` - The number to convert. Accepts any number that - * implements the numeric traits. - * - `radix` - Base to use. Accepts only the values 2-36. - * - `negative_zero` - Whether to treat the special value `-0` as - * `-0` or as `+0`. - * - `sign` - How to emit the sign. Options are: - * - `SignNone`: No sign at all. Basically emits `abs(num)`. - * - `SignNeg`: Only `-` on negative values. - * - `SignAll`: Both `+` on positive, and `-` on negative numbers. - * - `digits` - The amount of digits to use for emitting the - * fractional part, if any. Options are: - * - `DigAll`: All calculatable digits. Beware of bignums or - * fractions! - * - `DigMax(uint)`: Maximum N digits, truncating any trailing zeros. - * - `DigExact(uint)`: Exactly N digits. - * - * # Return value - * A tuple containing the byte vector, and a boolean flag indicating - * whether it represents a special value like `inf`, `-inf`, `NaN` or not. - * It returns a tuple because there can be ambiguity between a special value - * and a number representation at higher bases. - * - * # Failure - * - Fails if `radix` < 2 or `radix` > 36. - */ -pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ - Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( - num: &T, radix: uint, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) { - if (radix as int) < 2 { - fail!("to_str_bytes_common: radix %? to low, must lie in the range [2, 36]", radix); - } else if radix as int > 36 { - fail!("to_str_bytes_common: radix %? to high, must lie in the range [2, 36]", radix); - } - - let _0: T = Zero::zero(); - let _1: T = One::one(); - - if is_NaN(num) { - return (str::to_bytes("NaN"), true); - } - else if is_inf(num){ - return match sign { - SignAll => (str::to_bytes("+inf"), true), - _ => (str::to_bytes("inf"), true) - } - } - else if is_neg_inf(num) { - return match sign { - SignNone => (str::to_bytes("inf"), true), - _ => (str::to_bytes("-inf"), true), - } - } - - let neg = *num < _0 || (negative_zero && is_neg_zero(num)); - let mut buf: ~[u8] = ~[]; - let radix_gen: T = cast(radix as int); - - let mut deccum; - - // First emit the non-fractional part, looping at least once to make - // sure at least a `0` gets emitted. - deccum = num.round_to_zero(); - loop { - // Calculate the absolute value of each digit instead of only - // doing it once for the whole number because a - // representable negative number doesn't necessary have an - // representable additive inverse of the same type - // (See twos complement). But we assume that for the - // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit_signed = deccum % radix_gen; - let current_digit = if current_digit_signed < _0 { - -current_digit_signed - } else { - current_digit_signed - }; - - // Decrease the deccumulator one digit at a time - deccum /= radix_gen; - deccum = deccum.round_to_zero(); - - buf.push(char::from_digit(current_digit.to_int() as uint, radix) - .unwrap() as u8); - - // No more digits to calculate for the non-fractional part -> break - if deccum == _0 { break; } - } - - // If limited digits, calculate one digit more for rounding. - let (limit_digits, digit_count, exact) = match digits { - DigAll => (false, 0u, false), - DigMax(count) => (true, count+1, false), - DigExact(count) => (true, count+1, true) - }; - - // Decide what sign to put in front - match sign { - SignNeg | SignAll if neg => { - buf.push('-' as u8); - } - SignAll => { - buf.push('+' as u8); - } - _ => () - } - - vec::reverse(buf); - - // Remember start of the fractional digits. - // Points one beyond end of buf if none get generated, - // or at the '.' otherwise. - let start_fractional_digits = buf.len(); - - // Now emit the fractional part, if any - deccum = num.fractional_part(); - if deccum != _0 || (limit_digits && exact && digit_count > 0) { - buf.push('.' as u8); - let mut dig = 0u; - - // calculate new digits while - // - there is no limit and there are digits left - // - or there is a limit, it's not reached yet and - // - it's exact - // - or it's a maximum, and there are still digits left - while (!limit_digits && deccum != _0) - || (limit_digits && dig < digit_count && ( - exact - || (!exact && deccum != _0) - ) - ) { - // Shift first fractional digit into the integer part - deccum *= radix_gen; - - // Calculate the absolute value of each digit. - // See note in first loop. - let current_digit_signed = deccum.round_to_zero(); - let current_digit = if current_digit_signed < _0 { - -current_digit_signed - } else { - current_digit_signed - }; - - buf.push(char::from_digit( - current_digit.to_int() as uint, radix).unwrap() as u8); - - // Decrease the deccumulator one fractional digit at a time - deccum = deccum.fractional_part(); - dig += 1u; - } - - // If digits are limited, and that limit has been reached, - // cut off the one extra digit, and depending on its value - // round the remaining ones. - if limit_digits && dig == digit_count { - let ascii2value = |chr: u8| { - char::to_digit(chr as char, radix).unwrap() as uint - }; - let value2ascii = |val: uint| { - char::from_digit(val, radix).unwrap() as u8 - }; - - let extra_digit = ascii2value(buf.pop()); - if extra_digit >= radix / 2 { // -> need to round - let mut i: int = buf.len() as int - 1; - loop { - // If reached left end of number, have to - // insert additional digit: - if i < 0 - || buf[i] == '-' as u8 - || buf[i] == '+' as u8 { - buf.insert((i + 1) as uint, value2ascii(1)); - break; - } - - // Skip the '.' - if buf[i] == '.' as u8 { i -= 1; loop; } - - // Either increment the digit, - // or set to 0 if max and carry the 1. - let current_digit = ascii2value(buf[i]); - if current_digit < (radix - 1) { - buf[i] = value2ascii(current_digit+1); - break; - } else { - buf[i] = value2ascii(0); - i -= 1; - } - } - } - } - } - - // if number of digits is not exact, remove all trailing '0's up to - // and including the '.' - if !exact { - let buf_max_i = buf.len() - 1; - - // index to truncate from - let mut i = buf_max_i; - - // discover trailing zeros of fractional part - while i > start_fractional_digits && buf[i] == '0' as u8 { - i -= 1; - } - - // Only attempt to truncate digits if buf has fractional digits - if i >= start_fractional_digits { - // If buf ends with '.', cut that too. - if buf[i] == '.' as u8 { i -= 1 } - - // only resize buf if we actually remove digits - if i < buf_max_i { - buf = buf.slice(0, i + 1).to_owned(); - } - } - } // If exact and trailing '.', just cut that - else { - let max_i = buf.len() - 1; - if buf[max_i] == '.' as u8 { - buf = buf.slice(0, max_i).to_owned(); - } - } - - (buf, false) -} - -/** - * Converts a number to its string representation. This is a wrapper for - * `to_str_bytes_common()`, for details see there. - */ -#[inline(always)] -pub fn to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+ - Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>( - num: &T, radix: uint, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits) -> (~str, bool) { - let (bytes, special) = to_str_bytes_common(num, radix, - negative_zero, sign, digits); - (str::from_bytes(bytes), special) -} - -// Some constants for from_str_bytes_common's input validation, -// they define minimum radix values for which the character is a valid digit. -priv static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u; -priv static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u; -priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; - -/** - * Parses a byte slice as a number. This is meant to - * be a common base implementation for all numeric string conversion - * functions like `from_str()` or `from_str_radix()`. - * - * # Arguments - * - `buf` - The byte slice to parse. - * - `radix` - Which base to parse the number as. Accepts 2-36. - * - `negative` - Whether to accept negative numbers. - * - `fractional` - Whether to accept numbers with fractional parts. - * - `special` - Whether to accept special values like `inf` - * and `NaN`. Can conflict with `radix`, see Failure. - * - `exponent` - Which exponent format to accept. Options are: - * - `ExpNone`: No Exponent, accepts just plain numbers like `42` or - * `-8.2`. - * - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or - * `8.2E-2`. The exponent string itself is always base 10. - * Can conflict with `radix`, see Failure. - * - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or - * `FFp128`. The exponent string itself is always base 10. - * Can conflict with `radix`, see Failure. - * - `empty_zero` - Whether to accept a empty `buf` as a 0 or not. - * - `ignore_underscores` - Whether all underscores within the string should - * be ignored. - * - * # Return value - * Returns `Some(n)` if `buf` parses to a number n without overflowing, and - * `None` otherwise, depending on the constraints set by the remaining - * arguments. - * - * # Failure - * - Fails if `radix` < 2 or `radix` > 36. - * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict - * between digit and exponent sign `'e'`. - * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict - * between digit and exponent sign `'p'`. - * - Fails if `radix` > 18 and `special == true` due to conflict - * between digit and lowest first character in `inf` and `NaN`, the `'i'`. - */ -pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+ - Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+ - NumStrConv>( - buf: &[u8], radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool, - ignore_underscores: bool - ) -> Option<T> { - match exponent { - ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' - => fail!("from_str_bytes_common: radix %? incompatible with \ - use of 'e' as decimal exponent", radix), - ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' - => fail!("from_str_bytes_common: radix %? incompatible with \ - use of 'p' as binary exponent", radix), - _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf' - => fail!("from_str_bytes_common: radix %? incompatible with \ - special values 'inf' and 'NaN'", radix), - _ if (radix as int) < 2 - => fail!("from_str_bytes_common: radix %? to low, \ - must lie in the range [2, 36]", radix), - _ if (radix as int) > 36 - => fail!("from_str_bytes_common: radix %? to high, \ - must lie in the range [2, 36]", radix), - _ => () - } - - let _0: T = Zero::zero(); - let _1: T = One::one(); - let radix_gen: T = cast(radix as int); - - let len = buf.len(); - - if len == 0 { - if empty_zero { - return Some(_0); - } else { - return None; - } - } - - if special { - if buf == inf_buf || buf == positive_inf_buf { - return NumStrConv::inf(); - } else if buf == negative_inf_buf { - if negative { - return NumStrConv::neg_inf(); - } else { - return None; - } - } else if buf == nan_buf { - return NumStrConv::NaN(); - } - } - - let (start, accum_positive) = match buf[0] as char { - '-' if !negative => return None, - '-' => (1u, false), - '+' => (1u, true), - _ => (0u, true) - }; - - // Initialize accumulator with signed zero for floating point parsing to - // work - let mut accum = if accum_positive { _0 } else { -_1 * _0}; - let mut last_accum = accum; // Necessary to detect overflow - let mut i = start; - let mut exp_found = false; - - // Parse integer part of number - while i < len { - let c = buf[i] as char; - - match char::to_digit(c, radix) { - Some(digit) => { - // shift accum one digit left - accum *= radix_gen; - - // add/subtract current digit depending on sign - if accum_positive { - accum += cast(digit as int); - } else { - accum -= cast(digit as int); - } - - // Detect overflow by comparing to last value, except - // if we've not seen any non-zero digits. - if last_accum != _0 { - if accum_positive && accum <= last_accum { return None; } - if !accum_positive && accum >= last_accum { return None; } - } - last_accum = accum; - } - None => match c { - '_' if ignore_underscores => {} - 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - '.' if fractional => { - i += 1u; // skip the '.' - break; // start of fractional part - } - _ => return None // invalid number - } - } - - i += 1u; - } - - // Parse fractional part of number - // Skip if already reached start of exponent - if !exp_found { - let mut power = _1; - - while i < len { - let c = buf[i] as char; - - match char::to_digit(c, radix) { - Some(digit) => { - // Decrease power one order of magnitude - power /= radix_gen; - - let digit_t: T = cast(digit); - - // add/subtract current digit depending on sign - if accum_positive { - accum += digit_t * power; - } else { - accum -= digit_t * power; - } - - // Detect overflow by comparing to last value - if accum_positive && accum < last_accum { return None; } - if !accum_positive && accum > last_accum { return None; } - last_accum = accum; - } - None => match c { - '_' if ignore_underscores => {} - 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - _ => return None // invalid number - } - } - - i += 1u; - } - } - - // Special case: buf not empty, but does not contain any digit in front - // of the exponent sign -> number is empty string - if i == start { - if empty_zero { - return Some(_0); - } else { - return None; - } - } - - let mut multiplier = _1; - - if exp_found { - let c = buf[i] as char; - let base = match (c, exponent) { - // c is never _ so don't need to handle specially - ('e', ExpDec) | ('E', ExpDec) => 10u, - ('p', ExpBin) | ('P', ExpBin) => 2u, - _ => return None // char doesn't fit given exponent format - }; - - // parse remaining bytes as decimal integer, - // skipping the exponent char - let exp: Option<int> = from_str_bytes_common( - buf.slice(i+1, len), 10, true, false, false, ExpNone, false, - ignore_underscores); - - match exp { - Some(exp_pow) => { - multiplier = if exp_pow < 0 { - _1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint) - } else { - pow_with_uint::<T>(base, exp_pow.to_int() as uint) - } - } - None => return None // invalid exponent -> invalid number - } - } - - Some(accum * multiplier) -} - -/** - * Parses a string as a number. This is a wrapper for - * `from_str_bytes_common()`, for details see there. - */ -#[inline(always)] -pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+ - Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>( - buf: &str, radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool, - ignore_underscores: bool - ) -> Option<T> { - from_str_bytes_common(str::to_bytes(buf), radix, negative, - fractional, special, exponent, empty_zero, - ignore_underscores) -} - -#[cfg(test)] -mod test { - use super::*; - use option::*; - - #[test] - fn from_str_ignore_underscores() { - let s : Option<u8> = from_str_common("__1__", 2, false, false, false, - ExpNone, false, true); - assert_eq!(s, Some(1u8)); - - let n : Option<u8> = from_str_common("__1__", 2, false, false, false, - ExpNone, false, false); - assert_eq!(n, None); - - let f : Option<f32> = from_str_common("_1_._5_e_1_", 10, false, true, false, - ExpDec, false, true); - assert_eq!(f, Some(1.5e1f32)); - } - - #[test] - fn from_str_issue5770() { - // try to parse 0b1_1111_1111 = 511 as a u8. Caused problems - // since 255*2+1 == 255 (mod 256) so the overflow wasn't - // detected. - let n : Option<u8> = from_str_common("111111111", 2, false, false, false, - ExpNone, false, false); - assert_eq!(n, None); - } -} diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs deleted file mode 100644 index 66ff16cbeb1..00000000000 --- a/src/libcore/num/uint-template.rs +++ /dev/null @@ -1,641 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use T = self::inst::T; -use T_SIGNED = self::inst::T_SIGNED; - -use num::{ToStrRadix, FromStrRadix}; -use num::{Zero, One, strconv}; -use prelude::*; - -pub use cmp::{min, max}; - -pub static bits : uint = inst::bits; -pub static bytes : uint = (inst::bits / 8); - -pub static min_value: T = 0 as T; -pub static max_value: T = 0 as T - 1 as T; - -#[inline(always)] -pub fn add(x: T, y: T) -> T { x + y } -#[inline(always)] -pub fn sub(x: T, y: T) -> T { x - y } -#[inline(always)] -pub fn mul(x: T, y: T) -> T { x * y } -#[inline(always)] -pub fn div(x: T, y: T) -> T { x / y } -#[inline(always)] -pub fn rem(x: T, y: T) -> T { x % y } - -#[inline(always)] -pub fn lt(x: T, y: T) -> bool { x < y } -#[inline(always)] -pub fn le(x: T, y: T) -> bool { x <= y } -#[inline(always)] -pub fn eq(x: T, y: T) -> bool { x == y } -#[inline(always)] -pub fn ne(x: T, y: T) -> bool { x != y } -#[inline(always)] -pub fn ge(x: T, y: T) -> bool { x >= y } -#[inline(always)] -pub fn gt(x: T, y: T) -> bool { x > y } - -#[inline(always)] -/// -/// Iterate over the range [`start`,`start`+`step`..`stop`) -/// -pub fn _range_step(start: T, - stop: T, - step: T_SIGNED, - it: &fn(T) -> bool) -> bool { - let mut i = start; - if step == 0 { - fail!("range_step called with step == 0"); - } - if step >= 0 { - while i < stop { - if !it(i) { return false; } - // avoiding overflow. break if i + step > max_value - if i > max_value - (step as T) { return true; } - i += step as T; - } - } else { - while i > stop { - if !it(i) { return false; } - // avoiding underflow. break if i + step < min_value - if i < min_value + ((-step) as T) { return true; } - i -= -step as T; - } - } - return true; -} - -pub fn range_step(start: T, stop: T, step: T_SIGNED, it: &fn(T) -> bool) -> bool { - _range_step(start, stop, step, it) -} - -#[inline(always)] -/// Iterate over the range [`lo`..`hi`) -pub fn range(lo: T, hi: T, it: &fn(T) -> bool) -> bool { - range_step(lo, hi, 1 as T_SIGNED, it) -} - -#[inline(always)] -/// Iterate over the range [`hi`..`lo`) -pub fn range_rev(hi: T, lo: T, it: &fn(T) -> bool) -> bool { - range_step(hi, lo, -1 as T_SIGNED, it) -} - -/// Computes the bitwise complement -#[inline(always)] -pub fn compl(i: T) -> T { - max_value ^ i -} - -impl Num for T {} - -#[cfg(not(test))] -impl Ord for T { - #[inline(always)] - fn lt(&self, other: &T) -> bool { (*self) < (*other) } - #[inline(always)] - fn le(&self, other: &T) -> bool { (*self) <= (*other) } - #[inline(always)] - fn ge(&self, other: &T) -> bool { (*self) >= (*other) } - #[inline(always)] - fn gt(&self, other: &T) -> bool { (*self) > (*other) } -} - -#[cfg(not(test))] -impl Eq for T { - #[inline(always)] - fn eq(&self, other: &T) -> bool { return (*self) == (*other); } - #[inline(always)] - fn ne(&self, other: &T) -> bool { return (*self) != (*other); } -} - -impl Orderable for T { - #[inline(always)] - fn min(&self, other: &T) -> T { - if *self < *other { *self } else { *other } - } - - #[inline(always)] - fn max(&self, other: &T) -> T { - if *self > *other { *self } else { *other } - } - - /// Returns the number constrained within the range `mn <= self <= mx`. - #[inline(always)] - fn clamp(&self, mn: &T, mx: &T) -> T { - cond!( - (*self > *mx) { *mx } - (*self < *mn) { *mn } - _ { *self } - ) - } -} - -impl Zero for T { - #[inline(always)] - fn zero() -> T { 0 } - - #[inline(always)] - fn is_zero(&self) -> bool { *self == 0 } -} - -impl One for T { - #[inline(always)] - fn one() -> T { 1 } -} - -#[cfg(not(test))] -impl Add<T,T> for T { - #[inline(always)] - fn add(&self, other: &T) -> T { *self + *other } -} - -#[cfg(not(test))] -impl Sub<T,T> for T { - #[inline(always)] - fn sub(&self, other: &T) -> T { *self - *other } -} - -#[cfg(not(test))] -impl Mul<T,T> for T { - #[inline(always)] - fn mul(&self, other: &T) -> T { *self * *other } -} - -#[cfg(not(test))] -impl Div<T,T> for T { - #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } -} - -#[cfg(not(test))] -impl Rem<T,T> for T { - #[inline(always)] - fn rem(&self, other: &T) -> T { *self % *other } -} - -#[cfg(not(test))] -impl Neg<T> for T { - #[inline(always)] - fn neg(&self) -> T { -*self } -} - -impl Unsigned for T {} - -impl Integer for T { - /// Calculates `div` (`\`) and `rem` (`%`) simultaneously - #[inline(always)] - fn div_rem(&self, other: &T) -> (T,T) { - (*self / *other, *self % *other) - } - - /// Unsigned integer division. Returns the same result as `div` (`/`). - #[inline(always)] - fn div_floor(&self, other: &T) -> T { *self / *other } - - /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). - #[inline(always)] - fn mod_floor(&self, other: &T) -> T { *self / *other } - - /// Calculates `div_floor` and `modulo_floor` simultaneously - #[inline(always)] - fn div_mod_floor(&self, other: &T) -> (T,T) { - (*self / *other, *self % *other) - } - - /// Calculates the Greatest Common Divisor (GCD) of the number and `other` - #[inline(always)] - fn gcd(&self, other: &T) -> T { - // Use Euclid's algorithm - let mut m = *self, n = *other; - while m != 0 { - let temp = m; - m = n % temp; - n = temp; - } - n - } - - /// Calculates the Lowest Common Multiple (LCM) of the number and `other` - #[inline(always)] - fn lcm(&self, other: &T) -> T { - (*self * *other) / self.gcd(other) - } - - /// Returns `true` if the number can be divided by `other` without leaving a remainder - #[inline(always)] - fn is_multiple_of(&self, other: &T) -> bool { *self % *other == 0 } - - /// Returns `true` if the number is divisible by `2` - #[inline(always)] - fn is_even(&self) -> bool { self.is_multiple_of(&2) } - - /// Returns `true` if the number is not divisible by `2` - #[inline(always)] - fn is_odd(&self) -> bool { !self.is_even() } -} - -impl Bitwise for T {} - -#[cfg(not(test))] -impl BitOr<T,T> for T { - #[inline(always)] - fn bitor(&self, other: &T) -> T { *self | *other } -} - -#[cfg(not(test))] -impl BitAnd<T,T> for T { - #[inline(always)] - fn bitand(&self, other: &T) -> T { *self & *other } -} - -#[cfg(not(test))] -impl BitXor<T,T> for T { - #[inline(always)] - fn bitxor(&self, other: &T) -> T { *self ^ *other } -} - -#[cfg(not(test))] -impl Shl<T,T> for T { - #[inline(always)] - fn shl(&self, other: &T) -> T { *self << *other } -} - -#[cfg(not(test))] -impl Shr<T,T> for T { - #[inline(always)] - fn shr(&self, other: &T) -> T { *self >> *other } -} - -#[cfg(not(test))] -impl Not<T> for T { - #[inline(always)] - fn not(&self) -> T { !*self } -} - -impl Bounded for T { - #[inline(always)] - fn min_value() -> T { min_value } - - #[inline(always)] - fn max_value() -> T { max_value } -} - -impl Int for T {} - -// String conversion functions and impl str -> num - -/// Parse a string as a number in base 10. -#[inline(always)] -pub fn from_str(s: &str) -> Option<T> { - strconv::from_str_common(s, 10u, false, false, false, - strconv::ExpNone, false, false) -} - -/// Parse a string as a number in the given base. -#[inline(always)] -pub fn from_str_radix(s: &str, radix: uint) -> Option<T> { - strconv::from_str_common(s, radix, false, false, false, - strconv::ExpNone, false, false) -} - -/// Parse a byte slice as a number in the given base. -#[inline(always)] -pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> { - strconv::from_str_bytes_common(buf, radix, false, false, false, - strconv::ExpNone, false, false) -} - -impl FromStr for T { - #[inline(always)] - fn from_str(s: &str) -> Option<T> { - from_str(s) - } -} - -impl FromStrRadix for T { - #[inline(always)] - fn from_str_radix(s: &str, radix: uint) -> Option<T> { - from_str_radix(s, radix) - } -} - -// String conversion functions and impl num -> str - -/// Convert to a string as a byte slice in a given base. -#[inline(always)] -pub fn to_str_bytes<U>(n: T, radix: uint, f: &fn(v: &[u8]) -> U) -> U { - let (buf, _) = strconv::to_str_bytes_common(&n, radix, false, - strconv::SignNeg, strconv::DigAll); - f(buf) -} - -/// Convert to a string in base 10. -#[inline(always)] -pub fn to_str(num: T) -> ~str { - let (buf, _) = strconv::to_str_common(&num, 10u, false, - strconv::SignNeg, strconv::DigAll); - buf -} - -/// Convert to a string in a given base. -#[inline(always)] -pub fn to_str_radix(num: T, radix: uint) -> ~str { - let (buf, _) = strconv::to_str_common(&num, radix, false, - strconv::SignNeg, strconv::DigAll); - buf -} - -impl ToStr for T { - #[inline(always)] - fn to_str(&self) -> ~str { - to_str(*self) - } -} - -impl ToStrRadix for T { - #[inline(always)] - fn to_str_radix(&self, radix: uint) -> ~str { - to_str_radix(*self, radix) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use super::inst::T; - use prelude::*; - - #[test] - fn test_num() { - num::test_num(10 as T, 2 as T); - } - - #[test] - fn test_orderable() { - assert_eq!((1 as T).min(&(2 as T)), 1 as T); - assert_eq!((2 as T).min(&(1 as T)), 1 as T); - assert_eq!((1 as T).max(&(2 as T)), 2 as T); - assert_eq!((2 as T).max(&(1 as T)), 2 as T); - assert_eq!((1 as T).clamp(&(2 as T), &(4 as T)), 2 as T); - assert_eq!((8 as T).clamp(&(2 as T), &(4 as T)), 4 as T); - assert_eq!((3 as T).clamp(&(2 as T), &(4 as T)), 3 as T); - } - - #[test] - fn test_gcd() { - assert_eq!((10 as T).gcd(&2), 2 as T); - assert_eq!((10 as T).gcd(&3), 1 as T); - assert_eq!((0 as T).gcd(&3), 3 as T); - assert_eq!((3 as T).gcd(&3), 3 as T); - assert_eq!((56 as T).gcd(&42), 14 as T); - } - - #[test] - fn test_lcm() { - assert_eq!((1 as T).lcm(&0), 0 as T); - assert_eq!((0 as T).lcm(&1), 0 as T); - assert_eq!((1 as T).lcm(&1), 1 as T); - assert_eq!((8 as T).lcm(&9), 72 as T); - assert_eq!((11 as T).lcm(&5), 55 as T); - assert_eq!((99 as T).lcm(&17), 1683 as T); - } - - #[test] - fn test_multiple_of() { - assert!((6 as T).is_multiple_of(&(6 as T))); - assert!((6 as T).is_multiple_of(&(3 as T))); - assert!((6 as T).is_multiple_of(&(1 as T))); - } - - #[test] - fn test_even() { - assert_eq!((0 as T).is_even(), true); - assert_eq!((1 as T).is_even(), false); - assert_eq!((2 as T).is_even(), true); - assert_eq!((3 as T).is_even(), false); - assert_eq!((4 as T).is_even(), true); - } - - #[test] - fn test_odd() { - assert_eq!((0 as T).is_odd(), false); - assert_eq!((1 as T).is_odd(), true); - assert_eq!((2 as T).is_odd(), false); - assert_eq!((3 as T).is_odd(), true); - assert_eq!((4 as T).is_odd(), false); - } - - #[test] - fn test_bitwise() { - assert_eq!(0b1110 as T, (0b1100 as T).bitor(&(0b1010 as T))); - assert_eq!(0b1000 as T, (0b1100 as T).bitand(&(0b1010 as T))); - assert_eq!(0b0110 as T, (0b1100 as T).bitxor(&(0b1010 as T))); - assert_eq!(0b1110 as T, (0b0111 as T).shl(&(1 as T))); - assert_eq!(0b0111 as T, (0b1110 as T).shr(&(1 as T))); - assert_eq!(max_value - (0b1011 as T), (0b1011 as T).not()); - } - - #[test] - fn test_bitcount() { - assert_eq!((0b010101 as T).population_count(), 3); - } - - #[test] - fn test_primitive() { - assert_eq!(Primitive::bits::<T>(), sys::size_of::<T>() * 8); - assert_eq!(Primitive::bytes::<T>(), sys::size_of::<T>()); - } - - #[test] - pub fn test_to_str() { - assert_eq!(to_str_radix(0 as T, 10u), ~"0"); - assert_eq!(to_str_radix(1 as T, 10u), ~"1"); - assert_eq!(to_str_radix(2 as T, 10u), ~"2"); - assert_eq!(to_str_radix(11 as T, 10u), ~"11"); - assert_eq!(to_str_radix(11 as T, 16u), ~"b"); - assert_eq!(to_str_radix(255 as T, 16u), ~"ff"); - assert_eq!(to_str_radix(0xff as T, 10u), ~"255"); - } - - #[test] - pub fn test_from_str() { - assert_eq!(from_str(~"0"), Some(0u as T)); - assert_eq!(from_str(~"3"), Some(3u as T)); - assert_eq!(from_str(~"10"), Some(10u as T)); - assert_eq!(u32::from_str(~"123456789"), Some(123456789 as u32)); - assert_eq!(from_str(~"00100"), Some(100u as T)); - - assert!(from_str(~"").is_none()); - assert!(from_str(~" ").is_none()); - assert!(from_str(~"x").is_none()); - } - - #[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()); - } - - #[test] - fn test_uint_to_str_overflow() { - let mut u8_val: u8 = 255_u8; - assert_eq!(u8::to_str(u8_val), ~"255"); - - u8_val += 1 as u8; - assert_eq!(u8::to_str(u8_val), ~"0"); - - let mut u16_val: u16 = 65_535_u16; - assert_eq!(u16::to_str(u16_val), ~"65535"); - - u16_val += 1 as u16; - assert_eq!(u16::to_str(u16_val), ~"0"); - - let mut u32_val: u32 = 4_294_967_295_u32; - assert_eq!(u32::to_str(u32_val), ~"4294967295"); - - u32_val += 1 as u32; - assert_eq!(u32::to_str(u32_val), ~"0"); - - let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; - assert_eq!(u64::to_str(u64_val), ~"18446744073709551615"); - - u64_val += 1 as u64; - assert_eq!(u64::to_str(u64_val), ~"0"); - } - - #[test] - fn test_uint_from_str_overflow() { - let mut u8_val: u8 = 255_u8; - assert_eq!(u8::from_str(~"255"), Some(u8_val)); - assert!(u8::from_str(~"256").is_none()); - - u8_val += 1 as u8; - assert_eq!(u8::from_str(~"0"), Some(u8_val)); - assert!(u8::from_str(~"-1").is_none()); - - let mut u16_val: u16 = 65_535_u16; - assert_eq!(u16::from_str(~"65535"), Some(u16_val)); - assert!(u16::from_str(~"65536").is_none()); - - u16_val += 1 as u16; - assert_eq!(u16::from_str(~"0"), Some(u16_val)); - assert!(u16::from_str(~"-1").is_none()); - - let mut u32_val: u32 = 4_294_967_295_u32; - assert_eq!(u32::from_str(~"4294967295"), Some(u32_val)); - assert!(u32::from_str(~"4294967296").is_none()); - - u32_val += 1 as u32; - assert_eq!(u32::from_str(~"0"), Some(u32_val)); - assert!(u32::from_str(~"-1").is_none()); - - let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; - assert_eq!(u64::from_str(~"18446744073709551615"), Some(u64_val)); - assert!(u64::from_str(~"18446744073709551616").is_none()); - - u64_val += 1 as u64; - assert_eq!(u64::from_str(~"0"), Some(u64_val)); - assert!(u64::from_str(~"-1").is_none()); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - pub fn to_str_radix1() { - uint::to_str_radix(100u, 1u); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - pub fn to_str_radix37() { - uint::to_str_radix(100u, 37u); - } - - #[test] - pub fn test_ranges() { - let mut l = ~[]; - - for range(0,3) |i| { - l.push(i); - } - for range_rev(13,10) |i| { - l.push(i); - } - for range_step(20,26,2) |i| { - l.push(i); - } - for range_step(36,30,-2) |i| { - l.push(i); - } - for range_step(max_value - 2, max_value, 2) |i| { - l.push(i); - } - for range_step(max_value - 3, max_value, 2) |i| { - l.push(i); - } - for range_step(min_value + 2, min_value, -2) |i| { - l.push(i); - } - for range_step(min_value + 3, min_value, -2) |i| { - l.push(i); - } - - assert_eq!(l, ~[0,1,2, - 13,12,11, - 20,22,24, - 36,34,32, - max_value-2, - max_value-3,max_value-1, - min_value+2, - min_value+3,min_value+1]); - - // None of the `fail`s should execute. - for range(0,0) |_i| { - fail!("unreachable"); - } - for range_rev(0,0) |_i| { - fail!("unreachable"); - } - for range_step(10,0,1) |_i| { - fail!("unreachable"); - } - for range_step(0,1,-10) |_i| { - fail!("unreachable"); - } - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_range_step_zero_step_up() { - for range_step(0,10,0) |_i| {} - } - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_range_step_zero_step_down() { - for range_step(0,-10,0) |_i| {} - } -} diff --git a/src/libcore/num/uint-template/u16.rs b/src/libcore/num/uint-template/u16.rs deleted file mode 100644 index cc262f6b4de..00000000000 --- a/src/libcore/num/uint-template/u16.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `u16` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = u16; - #[allow(non_camel_case_types)] - pub type T_SIGNED = i16; - pub static bits: uint = 16; - - impl Primitive for u16 { - #[inline(always)] - fn bits() -> uint { 16 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<u16>() / 8 } - } - - impl BitCount for u16 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> u16 { unsafe { intrinsics::ctpop16(*self as i16) as u16 } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> u16 { unsafe { intrinsics::ctlz16(*self as i16) as u16 } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> u16 { unsafe { intrinsics::cttz16(*self as i16) as u16 } } - } -} diff --git a/src/libcore/num/uint-template/u32.rs b/src/libcore/num/uint-template/u32.rs deleted file mode 100644 index 7d7c8e3be30..00000000000 --- a/src/libcore/num/uint-template/u32.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `u32` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = u32; - #[allow(non_camel_case_types)] - pub type T_SIGNED = i32; - pub static bits: uint = 32; - - impl Primitive for u32 { - #[inline(always)] - fn bits() -> uint { 32 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<u32>() / 8 } - } - - impl BitCount for u32 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> u32 { unsafe { intrinsics::ctpop32(*self as i32) as u32 } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlp` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> u32 { unsafe { intrinsics::ctlz32(*self as i32) as u32 } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttp` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> u32 { unsafe { intrinsics::cttz32(*self as i32) as u32 } } - } -} diff --git a/src/libcore/num/uint-template/u64.rs b/src/libcore/num/uint-template/u64.rs deleted file mode 100644 index 756c29950c3..00000000000 --- a/src/libcore/num/uint-template/u64.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `u64` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = u64; - #[allow(non_camel_case_types)] - pub type T_SIGNED = i64; - pub static bits: uint = 64; - - impl Primitive for u64 { - #[inline(always)] - fn bits() -> uint { 64 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<u64>() / 8 } - } - - impl BitCount for u64 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> u64 { unsafe { intrinsics::ctpop64(*self as i64) as u64 } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> u64 { unsafe { intrinsics::ctlz64(*self as i64) as u64 } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> u64 { unsafe { intrinsics::cttz64(*self as i64) as u64 } } - } -} diff --git a/src/libcore/num/uint-template/u8.rs b/src/libcore/num/uint-template/u8.rs deleted file mode 100644 index 5ac860c0359..00000000000 --- a/src/libcore/num/uint-template/u8.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `u8` - -mod inst { - use num::{Primitive, BitCount}; - use unstable::intrinsics; - - pub type T = u8; - #[allow(non_camel_case_types)] - pub type T_SIGNED = i8; - pub static bits: uint = 8; - - impl Primitive for u8 { - #[inline(always)] - fn bits() -> uint { 8 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<u8>() / 8 } - } - - impl BitCount for u8 { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> u8 { unsafe { intrinsics::ctpop8(*self as i8) as u8 } } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> u8 { unsafe { intrinsics::ctlz8(*self as i8) as u8 } } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> u8 { unsafe { intrinsics::cttz8(*self as i8) as u8 } } - } -} diff --git a/src/libcore/num/uint-template/uint.rs b/src/libcore/num/uint-template/uint.rs deleted file mode 100644 index 763c305f221..00000000000 --- a/src/libcore/num/uint-template/uint.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for `uint` - -pub use self::inst::{ - div_ceil, div_round, div_floor, iterate, - next_power_of_two -}; - -pub mod inst { - use iter; - use num::{Primitive, BitCount}; - use sys; - - pub type T = uint; - #[allow(non_camel_case_types)] - pub type T_SIGNED = int; - - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] - #[cfg(target_arch = "mips")] - pub static bits: uint = 32; - - #[cfg(target_arch = "x86_64")] - pub static bits: uint = 64; - - impl Primitive for uint { - #[cfg(target_word_size = "32")] - #[inline(always)] - fn bits() -> uint { 32 } - - #[cfg(target_word_size = "64")] - #[inline(always)] - fn bits() -> uint { 64 } - - #[inline(always)] - fn bytes() -> uint { Primitive::bits::<uint>() / 8 } - } - - #[cfg(target_word_size = "32")] - #[inline(always)] - impl BitCount for uint { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> uint { (*self as i32).population_count() as uint } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> uint { (*self as i32).leading_zeros() as uint } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> uint { (*self as i32).trailing_zeros() as uint } - } - - #[cfg(target_word_size = "64")] - #[inline(always)] - impl BitCount for uint { - /// Counts the number of bits set. Wraps LLVM's `ctpop` intrinsic. - #[inline(always)] - fn population_count(&self) -> uint { (*self as i64).population_count() as uint } - - /// Counts the number of leading zeros. Wraps LLVM's `ctlz` intrinsic. - #[inline(always)] - fn leading_zeros(&self) -> uint { (*self as i64).leading_zeros() as uint } - - /// Counts the number of trailing zeros. Wraps LLVM's `cttz` intrinsic. - #[inline(always)] - fn trailing_zeros(&self) -> uint { (*self as i64).trailing_zeros() as uint } - } - - /// - /// Divide two numbers, return the result, rounded up. - /// - /// # Arguments - /// - /// * x - an integer - /// * y - an integer distinct from 0u - /// - /// # Return value - /// - /// The smallest integer `q` such that `x/y <= q`. - /// - pub fn div_ceil(x: uint, y: uint) -> uint { - let div = x / y; - if x % y == 0u { div } - else { div + 1u } - } - - /// - /// Divide two numbers, return the result, rounded to the closest integer. - /// - /// # Arguments - /// - /// * x - an integer - /// * y - an integer distinct from 0u - /// - /// # Return value - /// - /// The integer `q` closest to `x/y`. - /// - pub fn div_round(x: uint, y: uint) -> uint { - let div = x / y; - if x % y * 2u < y { div } - else { div + 1u } - } - - /// - /// Divide two numbers, return the result, rounded down. - /// - /// Note: This is the same function as `div`. - /// - /// # Arguments - /// - /// * x - an integer - /// * y - an integer distinct from 0u - /// - /// # Return value - /// - /// The smallest integer `q` such that `x/y <= q`. This - /// is either `x/y` or `x/y + 1`. - /// - pub fn div_floor(x: uint, y: uint) -> uint { return x / y; } - - /// - /// Iterate over the range [`lo`..`hi`), or stop when requested - /// - /// # Arguments - /// - /// * lo - The integer at which to start the loop (included) - /// * hi - The integer at which to stop the loop (excluded) - /// * it - A block to execute with each consecutive integer of the range. - /// 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 iterate(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool { - let mut i = lo; - while i < hi { - if (!it(i)) { return false; } - i += 1u; - } - return true; - } - - impl iter::Times for uint { - #[inline(always)] - /// - /// A convenience form for basic iteration. Given a uint `x`, - /// `for x.times { ... }` executes the given block x times. - /// - /// Equivalent to `for uint::range(0, x) |_| { ... }`. - /// - /// Not defined on all integer types to permit unambiguous - /// use with integer literals of inferred integer-type as - /// the self-value (eg. `for 100.times { ... }`). - /// - fn times(&self, it: &fn() -> bool) -> bool { - let mut i = *self; - while i > 0 { - if !it() { return false; } - i -= 1; - } - return true; - } - } - - /// Returns the smallest power of 2 greater than or equal to `n` - #[inline(always)] - pub fn next_power_of_two(n: uint) -> uint { - let halfbits: uint = sys::size_of::<uint>() * 4u; - let mut tmp: uint = n - 1u; - let mut shift: uint = 1u; - while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; } - return tmp + 1u; - } - - #[test] - fn test_next_power_of_two() { - assert_eq!(next_power_of_two(0u), 0u); - assert_eq!(next_power_of_two(1u), 1u); - assert_eq!(next_power_of_two(2u), 2u); - assert_eq!(next_power_of_two(3u), 4u); - assert_eq!(next_power_of_two(4u), 4u); - assert_eq!(next_power_of_two(5u), 8u); - assert_eq!(next_power_of_two(6u), 8u); - assert_eq!(next_power_of_two(7u), 8u); - assert_eq!(next_power_of_two(8u), 8u); - assert_eq!(next_power_of_two(9u), 16u); - assert_eq!(next_power_of_two(10u), 16u); - assert_eq!(next_power_of_two(11u), 16u); - assert_eq!(next_power_of_two(12u), 16u); - assert_eq!(next_power_of_two(13u), 16u); - assert_eq!(next_power_of_two(14u), 16u); - assert_eq!(next_power_of_two(15u), 16u); - assert_eq!(next_power_of_two(16u), 16u); - assert_eq!(next_power_of_two(17u), 32u); - assert_eq!(next_power_of_two(18u), 32u); - assert_eq!(next_power_of_two(19u), 32u); - assert_eq!(next_power_of_two(20u), 32u); - assert_eq!(next_power_of_two(21u), 32u); - assert_eq!(next_power_of_two(22u), 32u); - assert_eq!(next_power_of_two(23u), 32u); - assert_eq!(next_power_of_two(24u), 32u); - assert_eq!(next_power_of_two(25u), 32u); - assert_eq!(next_power_of_two(26u), 32u); - assert_eq!(next_power_of_two(27u), 32u); - assert_eq!(next_power_of_two(28u), 32u); - assert_eq!(next_power_of_two(29u), 32u); - assert_eq!(next_power_of_two(30u), 32u); - assert_eq!(next_power_of_two(31u), 32u); - assert_eq!(next_power_of_two(32u), 32u); - assert_eq!(next_power_of_two(33u), 64u); - assert_eq!(next_power_of_two(34u), 64u); - assert_eq!(next_power_of_two(35u), 64u); - assert_eq!(next_power_of_two(36u), 64u); - assert_eq!(next_power_of_two(37u), 64u); - assert_eq!(next_power_of_two(38u), 64u); - assert_eq!(next_power_of_two(39u), 64u); - } - - #[test] - fn test_overflows() { - use uint; - assert!((uint::max_value > 0u)); - assert!((uint::min_value <= 0u)); - assert_eq!(uint::min_value + uint::max_value + 1u, 0u); - } - - #[test] - fn test_div() { - assert_eq!(div_floor(3u, 4u), 0u); - assert_eq!(div_ceil(3u, 4u), 1u); - assert_eq!(div_round(3u, 4u), 1u); - } - - #[test] - pub fn test_times() { - use iter::Times; - let ten = 10 as uint; - let mut accum = 0; - for ten.times { accum += 1; } - assert_eq!(accum, 10); - } -} diff --git a/src/libcore/old_iter.rs b/src/libcore/old_iter.rs deleted file mode 100644 index 389b643572c..00000000000 --- a/src/libcore/old_iter.rs +++ /dev/null @@ -1,348 +0,0 @@ -// 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. - -/*! - -**Deprecated** iteration traits and common implementations. - -*/ - -use cmp::{Eq, Ord}; -use kinds::Copy; -use option::{None, Option, Some}; -use vec; - -/// A function used to initialize the elements of a sequence -pub type InitOp<'self,T> = &'self fn(uint) -> T; - -pub trait BaseIter<A> { - fn each(&self, blk: &fn(v: &A) -> bool) -> bool; - fn size_hint(&self) -> Option<uint>; -} - -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; - fn any(&self, blk: &fn(&A) -> bool) -> bool; - fn foldl<B>(&self, b0: B, blk: &fn(&B, &A) -> B) -> B; - fn position(&self, f: &fn(&A) -> bool) -> Option<uint>; - fn map_to_vec<B>(&self, op: &fn(&A) -> B) -> ~[B]; - 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; -} - -pub trait CopyableIter<A:Copy> { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A]; - fn to_vec(&self) -> ~[A]; - fn find(&self, p: &fn(&A) -> bool) -> Option<A>; -} - -pub trait CopyableOrderedIter<A:Copy + Ord> { - fn min(&self) -> A; - 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> { - /** - * Builds a buildable sequence by calling a provided function with - * an argument function that pushes an element onto the back of - * the sequence. - * This version takes an initial size for the sequence. - * - * # Arguments - * - * * size - A hint for an initial size of the sequence - * * builder - A function that will construct the sequence. It receives - * as an argument a function that will push an element - * onto the sequence being constructed. - */ - fn build_sized(size: uint, builder: &fn(push: &fn(A))) -> Self; -} - -#[inline(always)] -pub fn _eachi<A,IA:BaseIter<A>>(this: &IA, blk: &fn(uint, &A) -> bool) -> bool { - let mut i = 0; - for this.each |a| { - if !blk(i, a) { - return false; - } - i += 1; - } - return true; -} - -pub fn eachi<A,IA:BaseIter<A>>(this: &IA, blk: &fn(uint, &A) -> bool) -> bool { - _eachi(this, blk) -} - -#[inline(always)] -pub fn all<A,IA:BaseIter<A>>(this: &IA, blk: &fn(&A) -> bool) -> bool { - for this.each |a| { - if !blk(a) { - return false; - } - } - return true; -} - -#[inline(always)] -pub fn any<A,IA:BaseIter<A>>(this: &IA, blk: &fn(&A) -> bool) -> bool { - for this.each |a| { - if blk(a) { - return true; - } - } - return false; -} - -#[inline(always)] -pub fn filter_to_vec<A:Copy,IA:BaseIter<A>>(this: &IA, - prd: &fn(&A) -> bool) - -> ~[A] { - do vec::build_sized_opt(this.size_hint()) |push| { - for this.each |a| { - if prd(a) { push(*a); } - } - } -} - -#[inline(always)] -pub fn map_to_vec<A,B,IA:BaseIter<A>>(this: &IA, op: &fn(&A) -> B) -> ~[B] { - do vec::build_sized_opt(this.size_hint()) |push| { - for this.each |a| { - push(op(a)); - } - } -} - -#[inline(always)] -pub fn flat_map_to_vec<A,B,IA:BaseIter<A>,IB:BaseIter<B>>(this: &IA, - op: &fn(&A) -> IB) - -> ~[B] { - do vec::build |push| { - for this.each |a| { - for op(a).each |&b| { - push(b); - } - } - } -} - -#[inline(always)] -pub fn foldl<A,B,IA:BaseIter<A>>(this: &IA, b0: B, blk: &fn(&B, &A) -> B) - -> B { - let mut b = b0; - for this.each |a| { - b = blk(&b, a); - } - b -} - -#[inline(always)] -pub fn to_vec<A:Copy,IA:BaseIter<A>>(this: &IA) -> ~[A] { - map_to_vec(this, |&x| x) -} - -#[inline(always)] -pub fn contains<A:Eq,IA:BaseIter<A>>(this: &IA, x: &A) -> bool { - for this.each |a| { - if *a == *x { return true; } - } - return false; -} - -#[inline(always)] -pub fn count<A:Eq,IA:BaseIter<A>>(this: &IA, x: &A) -> uint { - do foldl(this, 0) |count, value| { - if *value == *x { - *count + 1 - } else { - *count - } - } -} - -#[inline(always)] -pub fn position<A,IA:BaseIter<A>>(this: &IA, f: &fn(&A) -> bool) - -> Option<uint> { - let mut i = 0; - for this.each |a| { - if f(a) { return Some(i); } - i += 1; - } - return None; -} - -// note: 'rposition' would only make sense to provide with a bidirectional -// iter interface, such as would provide "reach" in addition to "each". As is, -// it would have to be implemented with foldr, which is too inefficient. - -#[inline(always)] -pub fn min<A:Copy + Ord,IA:BaseIter<A>>(this: &IA) -> A { - match do foldl::<A,Option<A>,IA>(this, None) |a, b| { - match a { - &Some(ref a_) if *a_ < *b => { - *(a) - } - _ => Some(*b) - } - } { - Some(val) => val, - None => fail!("min called on empty iterator") - } -} - -#[inline(always)] -pub fn max<A:Copy + Ord,IA:BaseIter<A>>(this: &IA) -> A { - match do foldl::<A,Option<A>,IA>(this, None) |a, b| { - match a { - &Some(ref a_) if *a_ > *b => { - *(a) - } - _ => Some(*b) - } - } { - Some(val) => val, - None => fail!("max called on empty iterator") - } -} - -#[inline(always)] -pub fn find<A:Copy,IA:BaseIter<A>>(this: &IA, f: &fn(&A) -> bool) - -> Option<A> { - for this.each |i| { - if f(i) { return Some(*i) } - } - return None; -} - -// Some functions for just building - -/** - * Builds a sequence by calling a provided function with an argument - * function that pushes an element to the back of a sequence. - * - * # Arguments - * - * * builder - A function that will construct the sequence. It receives - * as an argument a function that will push an element - * onto the sequence being constructed. - */ -#[inline(always)] -pub fn build<A,B: Buildable<A>>(builder: &fn(push: &fn(A))) -> B { - Buildable::build_sized(4, builder) -} - -/** - * Builds a sequence by calling a provided function with an argument - * function that pushes an element to the back of the sequence. - * This version takes an initial size for the sequence. - * - * # Arguments - * - * * size - An option, maybe containing initial size of the sequence - * to reserve. - * * builder - A function that will construct the sequence. It receives - * as an argument a function that will push an element - * onto the sequence being constructed. - */ -#[inline(always)] -pub fn build_sized_opt<A,B: Buildable<A>>(size: Option<uint>, - builder: &fn(push: &fn(A))) -> B { - Buildable::build_sized(size.get_or_default(4), builder) -} - -// Functions that combine iteration and building - -/// Applies a function to each element of an iterable and returns the results -/// in a sequence built via `BU`. See also `map_to_vec`. -#[inline(always)] -pub fn map<T,IT: BaseIter<T>,U,BU: Buildable<U>>(v: &IT, f: &fn(&T) -> U) - -> BU { - do build_sized_opt(v.size_hint()) |push| { - for v.each() |elem| { - push(f(elem)); - } - } -} - -/** - * Creates and initializes a generic sequence from a function. - * - * Creates a generic sequence of size `n_elts` and initializes the elements - * to the value returned by the function `op`. - */ -#[inline(always)] -pub fn from_fn<T,BT: Buildable<T>>(n_elts: uint, op: InitOp<T>) -> BT { - do Buildable::build_sized(n_elts) |push| { - let mut i: uint = 0u; - while i < n_elts { push(op(i)); i += 1u; } - } -} - -/** - * Creates and initializes a generic sequence with some elements. - * - * Creates an immutable vector of size `n_elts` and initializes the elements - * to the value `t`. - */ -#[inline(always)] -pub fn from_elem<T:Copy,BT:Buildable<T>>(n_elts: uint, t: T) -> BT { - do Buildable::build_sized(n_elts) |push| { - let mut i: uint = 0; - while i < n_elts { push(t); i += 1; } - } -} - -/// Appends two generic sequences. -#[inline(always)] -pub fn append<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(lhs: &IT, rhs: &IT) - -> BT { - let size_opt = lhs.size_hint().chain_ref( - |sz1| rhs.size_hint().map(|sz2| *sz1+*sz2)); - do build_sized_opt(size_opt) |push| { - for lhs.each |x| { push(*x); } - for rhs.each |x| { push(*x); } - } -} - -/// Copies a generic sequence, possibly converting it to a different -/// type of sequence. -#[inline(always)] -pub fn copy_seq<T:Copy,IT:BaseIter<T>,BT:Buildable<T>>(v: &IT) -> BT { - do build_sized_opt(v.size_hint()) |push| { - for v.each |x| { push(*x); } - } -} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs deleted file mode 100644 index 47ff45be687..00000000000 --- a/src/libcore/ops.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Traits for the built-in operators - -#[lang="drop"] -pub trait Drop { - fn finalize(&self); // FIXME(#4332): Rename to "drop"? --pcwalton -} - -#[lang="add"] -pub trait Add<RHS,Result> { - fn add(&self, rhs: &RHS) -> Result; -} - -#[lang="sub"] -pub trait Sub<RHS,Result> { - fn sub(&self, rhs: &RHS) -> Result; -} - -#[lang="mul"] -pub trait Mul<RHS,Result> { - fn mul(&self, rhs: &RHS) -> Result; -} - -#[lang="div"] -pub trait Div<RHS,Result> { - fn div(&self, rhs: &RHS) -> Result; -} - -#[lang="rem"] -pub trait Rem<RHS,Result> { - fn rem(&self, rhs: &RHS) -> Result; -} - -#[lang="neg"] -pub trait Neg<Result> { - fn neg(&self) -> Result; -} - -#[lang="not"] -pub trait Not<Result> { - fn not(&self) -> Result; -} - -#[lang="bitand"] -pub trait BitAnd<RHS,Result> { - fn bitand(&self, rhs: &RHS) -> Result; -} - -#[lang="bitor"] -pub trait BitOr<RHS,Result> { - fn bitor(&self, rhs: &RHS) -> Result; -} - -#[lang="bitxor"] -pub trait BitXor<RHS,Result> { - fn bitxor(&self, rhs: &RHS) -> Result; -} - -#[lang="shl"] -pub trait Shl<RHS,Result> { - fn shl(&self, rhs: &RHS) -> Result; -} - -#[lang="shr"] -pub trait Shr<RHS,Result> { - fn shr(&self, rhs: &RHS) -> Result; -} - -#[lang="index"] -pub trait Index<Index,Result> { - fn index(&self, index: &Index) -> Result; -} diff --git a/src/libcore/option.rs b/src/libcore/option.rs deleted file mode 100644 index bc1ffcdc81a..00000000000 --- a/src/libcore/option.rs +++ /dev/null @@ -1,468 +0,0 @@ -// 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. - -/*! - -Operations on the ubiquitous `Option` type. - -Type `Option` represents an optional value. - -Every `Option<T>` value can either be `Some(T)` or `None`. Where in other -languages you might use a nullable type, in Rust you would use an option -type. - -Options are most commonly used with pattern matching to query the presence -of a value and take action, always accounting for the `None` case. - -# Example - -~~~ -let msg = Some(~"howdy"); - -// Take a reference to the contained string -match msg { - Some(ref m) => io::println(m), - None => () -} - -// Remove the contained string, destroying the Option -let unwrapped_msg = match msg { - Some(m) => m, - None => ~"default message" -}; -~~~ - -*/ - -use cmp::{Eq,Ord}; -use ops::Add; -use kinds::Copy; -use util; -use num::Zero; -use old_iter::{BaseIter, MutableIter, ExtendedIter}; -use old_iter; -use str::StrSlice; -use clone::DeepClone; - -#[cfg(test)] use str; - -/// The option type -#[deriving(Clone, Eq)] -pub enum Option<T> { - None, - Some(T), -} - -impl<T: DeepClone> DeepClone for Option<T> { - fn deep_clone(&self) -> Option<T> { - match *self { - Some(ref x) => Some(x.deep_clone()), - None => None - } - } -} - -impl<T:Ord> Ord for Option<T> { - fn lt(&self, other: &Option<T>) -> bool { - match (self, other) { - (&None, &None) => false, - (&None, &Some(_)) => true, - (&Some(_), &None) => false, - (&Some(ref a), &Some(ref b)) => *a < *b - } - } - - fn le(&self, other: &Option<T>) -> bool { - match (self, other) { - (&None, &None) => true, - (&None, &Some(_)) => true, - (&Some(_), &None) => false, - (&Some(ref a), &Some(ref b)) => *a <= *b - } - } - - fn ge(&self, other: &Option<T>) -> bool { - !(self < other) - } - - fn gt(&self, other: &Option<T>) -> bool { - !(self <= other) - } -} - -impl<T: Copy + Add<T,T>> Add<Option<T>, Option<T>> for Option<T> { - #[inline(always)] - fn add(&self, other: &Option<T>) -> Option<T> { - match (*self, *other) { - (None, None) => None, - (_, None) => *self, - (None, _) => *other, - (Some(ref lhs), Some(ref rhs)) => Some(*lhs + *rhs) - } - } -} - -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<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) - } -} - -pub impl<T> Option<T> { - /// Returns true if the option equals `none` - 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() } - - /// 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> { - - match self { - Some(t) => f(t), - None => None - } - } - - /// Returns the leftmost Some() value, or None if both are None. - #[inline(always)] - fn or(self, optb: Option<T>) -> Option<T> { - match self { - Some(opta) => Some(opta), - _ => optb - } - } - - /// 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 } - } - - /// 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> { - 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> { - 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 { - 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 { - 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) { - 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) { - if self.is_some() { - *self = Some(f(self.swap_unwrap())); - } else { - *self = Some(def); - } - } - - /** - Gets an immutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - fn get_ref<'a>(&'a self) -> &'a T { - match *self { - Some(ref x) => x, - None => fail!("option::get_ref none") - } - } - - /** - Gets a mutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - 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") - } - } - - #[inline(always)] - fn unwrap(self) -> T { - /*! - Moves a value out of an option type and returns it. - - Useful primarily for getting strings, vectors and unique pointers out - of option types without copying them. - - # Failure - - Fails if the value equals `None`. - - # Safety note - - In general, because this function may fail, its use is discouraged. - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - match self { - Some(x) => x, - None => fail!("option::unwrap none") - } - } - - /** - * The option dance. Moves a value out of an option type and returns it, - * replacing the original with `None`. - * - * # Failure - * - * Fails if the value equals `None`. - */ - #[inline(always)] - fn swap_unwrap(&mut self) -> T { - if self.is_none() { fail!("option::swap_unwrap none") } - util::replace(self, None).unwrap() - } - - /** - * Gets the value out of an option, printing a specified message on - * failure - * - * # Failure - * - * Fails if the value equals `none` - */ - #[inline(always)] - fn expect(self, reason: &str) -> T { - match self { - Some(val) => val, - None => fail!(reason.to_owned()), - } - } -} - -pub impl<T:Copy> Option<T> { - /** - Gets the value out of an option - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - fn get(self) -> T { - match self { - Some(copy 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 } - } - - /// Applies a function zero or more times until the result is none. - #[inline(always)] - fn while_some(self, blk: &fn(v: T) -> Option<T>) { - let mut opt = self; - while opt.is_some() { - opt = blk(opt.unwrap()); - } - } -} - -pub 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() } - } -} - -#[test] -fn test_unwrap_ptr() { - unsafe { - let x = ~0; - let addr_x: *int = ::cast::transmute(&*x); - let opt = Some(x); - let y = opt.unwrap(); - let addr_y: *int = ::cast::transmute(&*y); - assert_eq!(addr_x, addr_y); - } -} - -#[test] -fn test_unwrap_str() { - let x = ~"test"; - let addr_x = str::as_buf(x, |buf, _len| buf); - let opt = Some(x); - let y = opt.unwrap(); - let addr_y = str::as_buf(y, |buf, _len| buf); - assert_eq!(addr_x, addr_y); -} - -#[test] -fn test_unwrap_resource() { - struct R { - i: @mut int, - } - - #[unsafe_destructor] - impl ::ops::Drop for R { - fn finalize(&self) { *(self.i) += 1; } - } - - fn R(i: @mut int) -> R { - R { - i: i - } - } - - let i = @mut 0; - { - let x = R(i); - let opt = Some(x); - let _y = opt.unwrap(); - } - assert_eq!(*i, 1); -} - -#[test] -fn test_option_dance() { - let x = Some(()); - let mut y = Some(5); - let mut y2 = 0; - for x.each |_x| { - y2 = y.swap_unwrap(); - } - assert_eq!(y2, 5); - assert!(y.is_none()); -} -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_option_too_much_dance() { - let mut y = Some(util::NonCopyable()); - let _y2 = y.swap_unwrap(); - let _y3 = y.swap_unwrap(); -} - -#[test] -fn test_option_while_some() { - let mut i = 0; - do Some(10).while_some |j| { - i += 1; - if (j > 0) { - Some(j-1) - } else { - None - } - } - assert_eq!(i, 11); -} - -#[test] -fn test_get_or_zero() { - let some_stuff = Some(42); - assert_eq!(some_stuff.get_or_zero(), 42); - let no_stuff: Option<int> = None; - assert_eq!(no_stuff.get_or_zero(), 0); -} diff --git a/src/libcore/os.rs b/src/libcore/os.rs deleted file mode 100644 index b2a30e50992..00000000000 --- a/src/libcore/os.rs +++ /dev/null @@ -1,1670 +0,0 @@ -// 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. - -/*! - * Higher-level interfaces to libc::* functions and operating system services. - * - * In general these take and return rust types, use rust idioms (enums, - * closures, vectors) rather than C idioms, and do more extensive safety - * checks. - * - * This module is not meant to only contain 1:1 mappings to libc entries; any - * os-interface code that is reasonably useful and broadly applicable can go - * here. Including utility routines that merely build on other os code. - * - * We assume the general case is that users do not care, and do not want to - * be made to care, which operating system they are on. While they may want - * to special case various special cases -- and so we will not _hide_ the - * facts of which OS the user is on -- they should be given the opportunity - * to write OS-ignorant code by default. - */ - -use cast; -use io; -use libc; -use libc::{c_char, c_void, c_int, size_t}; -use libc::{mode_t, FILE}; -use option; -use option::{Some, None}; -use prelude::*; -use ptr; -use str; -use uint; -use unstable::finally::Finally; -use vec; - -pub use libc::fclose; -pub use os::consts::*; - -pub fn close(fd: c_int) -> c_int { - unsafe { - libc::close(fd) - } -} - -pub mod rustrt { - use libc::{c_char, c_int}; - use libc; - - pub extern { - unsafe fn rust_get_argc() -> c_int; - unsafe fn rust_get_argv() -> **c_char; - unsafe fn rust_path_is_dir(path: *libc::c_char) -> c_int; - unsafe fn rust_path_exists(path: *libc::c_char) -> c_int; - unsafe fn rust_set_exit_status(code: libc::intptr_t); - } -} - -pub static TMPBUF_SZ : uint = 1000u; -static BUF_BYTES : uint = 2048u; - -pub fn getcwd() -> Path { - let buf = [0 as libc::c_char, ..BUF_BYTES]; - unsafe { - if(0 as *libc::c_char == libc::getcwd( - &buf[0], - BUF_BYTES as libc::size_t)) { - fail!(); - } - Path(str::raw::from_c_str(&buf[0])) - } -} - -// FIXME: move these to str perhaps? #2620 - -pub fn as_c_charp<T>(s: &str, f: &fn(*c_char) -> T) -> T { - str::as_c_str(s, |b| f(b as *c_char)) -} - -pub fn fill_charp_buf(f: &fn(*mut c_char, size_t) -> bool) - -> Option<~str> { - let mut buf = vec::from_elem(TMPBUF_SZ, 0u8 as c_char); - do vec::as_mut_buf(buf) |b, sz| { - if f(b, sz as size_t) { - unsafe { - Some(str::raw::from_buf(b as *u8)) - } - } else { - None - } - } -} - -#[cfg(windows)] -pub mod win32 { - use libc; - use vec; - use str; - use option::{None, Option}; - use option; - use os::TMPBUF_SZ; - use libc::types::os::arch::extra::DWORD; - - pub fn fill_utf16_buf_and_decode(f: &fn(*mut u16, DWORD) -> DWORD) - -> Option<~str> { - unsafe { - let mut n = TMPBUF_SZ as DWORD; - let mut res = None; - let mut done = false; - while !done { - let mut k: DWORD = 0; - let mut buf = vec::from_elem(n as uint, 0u16); - do vec::as_mut_buf(buf) |b, _sz| { - k = f(b, TMPBUF_SZ as DWORD); - if k == (0 as DWORD) { - done = true; - } else if (k == n && - libc::GetLastError() == - libc::ERROR_INSUFFICIENT_BUFFER as DWORD) { - n *= (2 as DWORD); - } else { - done = true; - } - } - if k != 0 && done { - let sub = vec::slice(buf, 0u, k as uint); - res = option::Some(str::from_utf16(sub)); - } - } - return res; - } - } - - 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]; - vec::as_imm_buf(t, |buf, _len| f(buf)) - } -} - -/* -Accessing environment variables is not generally threadsafe. -Serialize access through a global lock. -*/ -fn with_env_lock<T>(f: &fn() -> T) -> T { - use unstable::finally::Finally; - - unsafe { - return do (|| { - rust_take_env_lock(); - f() - }).finally { - rust_drop_env_lock(); - }; - } - - extern { - #[fast_ffi] - fn rust_take_env_lock(); - #[fast_ffi] - fn rust_drop_env_lock(); - } -} - -pub fn env() -> ~[(~str,~str)] { - unsafe { - #[cfg(windows)] - unsafe fn get_env_pairs() -> ~[~str] { - use libc::types::os::arch::extra::LPTCH; - use libc::funcs::extra::kernel32::{ - GetEnvironmentStringsA, - FreeEnvironmentStringsA - }; - let ch = GetEnvironmentStringsA(); - if (ch as uint == 0) { - fail!("os::env() failure getting env string from OS: %s", os::last_os_error()); - } - let mut curr_ptr: uint = ch as uint; - let mut result = ~[]; - while(*(curr_ptr as *libc::c_char) != 0 as libc::c_char) { - let env_pair = str::raw::from_c_str( - curr_ptr as *libc::c_char); - result.push(env_pair); - curr_ptr += - libc::strlen(curr_ptr as *libc::c_char) as uint - + 1; - } - FreeEnvironmentStringsA(ch); - result - } - #[cfg(unix)] - unsafe fn get_env_pairs() -> ~[~str] { - extern { - unsafe fn rust_env_pairs() -> **libc::c_char; - } - let environ = rust_env_pairs(); - if (environ as uint == 0) { - fail!("os::env() failure getting env string from OS: %s", os::last_os_error()); - } - let mut result = ~[]; - ptr::array_each(environ, |e| { - let env_pair = str::raw::from_c_str(e); - debug!("get_env_pairs: %s", - env_pair); - result.push(env_pair); - }); - result - } - - 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()) } - debug!("splitting: len: %u", - vs.len()); - assert_eq!(vs.len(), 2); - pairs.push((copy vs[0], copy vs[1])); - } - pairs - } - do with_env_lock { - let unparsed_environ = get_env_pairs(); - env_convert(unparsed_environ) - } - } -} - -#[cfg(unix)] -pub fn getenv(n: &str) -> Option<~str> { - unsafe { - do with_env_lock { - let s = str::as_c_str(n, |s| libc::getenv(s)); - if ptr::null::<u8>() == cast::transmute(s) { - option::None::<~str> - } else { - let s = cast::transmute(s); - option::Some::<~str>(str::raw::from_buf(s)) - } - } - } -} - -#[cfg(windows)] -pub fn getenv(n: &str) -> Option<~str> { - unsafe { - do with_env_lock { - use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; - do as_utf16_p(n) |u| { - do fill_utf16_buf_and_decode() |buf, sz| { - libc::GetEnvironmentVariableW(u, buf, sz) - } - } - } - } -} - - -#[cfg(unix)] -pub fn setenv(n: &str, v: &str) { - unsafe { - do with_env_lock { - do str::as_c_str(n) |nbuf| { - do str::as_c_str(v) |vbuf| { - libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); - } - } - } - } -} - - -#[cfg(windows)] -pub fn setenv(n: &str, v: &str) { - unsafe { - do with_env_lock { - use os::win32::as_utf16_p; - do as_utf16_p(n) |nbuf| { - do as_utf16_p(v) |vbuf| { - libc::SetEnvironmentVariableW(nbuf, vbuf); - } - } - } - } -} - -/// Remove a variable from the environment entirely -pub fn unsetenv(n: &str) { - #[cfg(unix)] - fn _unsetenv(n: &str) { - unsafe { - do with_env_lock { - do str::as_c_str(n) |nbuf| { - libc::funcs::posix01::unistd::unsetenv(nbuf); - } - } - } - } - #[cfg(windows)] - fn _unsetenv(n: &str) { - unsafe { - do with_env_lock { - use os::win32::as_utf16_p; - do as_utf16_p(n) |nbuf| { - libc::SetEnvironmentVariableW(nbuf, ptr::null()); - } - } - } - } - - _unsetenv(n); -} - -pub fn fdopen(fd: c_int) -> *FILE { - unsafe { - return do as_c_charp("r") |modebuf| { - libc::fdopen(fd, modebuf) - }; - } -} - - -// fsync related - -#[cfg(windows)] -pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int { - unsafe { - use libc::funcs::extra::msvcrt::*; - return commit(fd); - } -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int { - unsafe { - use libc::funcs::posix01::unistd::*; - match level { - io::fsync::FSync - | io::fsync::FullFSync => return fsync(fd), - io::fsync::FDataSync => return fdatasync(fd) - } - } -} - -#[cfg(target_os = "macos")] -pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int { - unsafe { - use libc::consts::os::extra::*; - use libc::funcs::posix88::fcntl::*; - use libc::funcs::posix01::unistd::*; - match level { - io::fsync::FSync => return fsync(fd), - _ => { - // According to man fnctl, the ok retval is only specified to be - // !=-1 - if (fcntl(F_FULLFSYNC as c_int, fd) == -1 as c_int) - { return -1 as c_int; } - else - { return 0 as c_int; } - } - } - } -} - -#[cfg(target_os = "freebsd")] -pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int { - unsafe { - use libc::funcs::posix01::unistd::*; - return fsync(fd); - } -} - -pub struct Pipe { - in: c_int, - out: c_int -} - -#[cfg(unix)] -pub fn pipe() -> Pipe { - unsafe { - let mut fds = Pipe {in: 0 as c_int, - out: 0 as c_int }; - assert_eq!(libc::pipe(&mut fds.in), (0 as c_int)); - return Pipe {in: fds.in, out: fds.out}; - } -} - - - -#[cfg(windows)] -pub fn pipe() -> Pipe { - unsafe { - // Windows pipes work subtly differently than unix pipes, and their - // inheritance has to be handled in a different way that I do not - // fully understand. Here we explicitly make the pipe non-inheritable, - // which means to pass it to a subprocess they need to be duplicated - // first, as in core::run. - let mut fds = Pipe {in: 0 as c_int, - out: 0 as c_int }; - let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint, - (libc::O_BINARY | libc::O_NOINHERIT) as c_int); - assert_eq!(res, 0 as c_int); - assert!((fds.in != -1 as c_int && fds.in != 0 as c_int)); - assert!((fds.out != -1 as c_int && fds.in != 0 as c_int)); - return Pipe {in: fds.in, out: fds.out}; - } -} - -fn dup2(src: c_int, dst: c_int) -> c_int { - unsafe { - libc::dup2(src, dst) - } -} - - -pub fn dll_filename(base: &str) -> ~str { - return str::to_owned(DLL_PREFIX) + str::to_owned(base) + - str::to_owned(DLL_SUFFIX) -} - - -pub fn self_exe_path() -> Option<Path> { - - #[cfg(target_os = "freebsd")] - fn load_self() -> Option<~str> { - unsafe { - use libc::funcs::bsd44::*; - use libc::consts::os::extra::*; - do fill_charp_buf() |buf, sz| { - let mib = ~[CTL_KERN as c_int, - KERN_PROC as c_int, - KERN_PROC_PATHNAME as c_int, -1 as c_int]; - let mut sz = sz; - sysctl(vec::raw::to_ptr(mib), mib.len() as ::libc::c_uint, - buf as *mut c_void, &mut sz, ptr::null(), - 0u as size_t) == (0 as c_int) - } - } - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - fn load_self() -> Option<~str> { - unsafe { - use libc::funcs::posix01::unistd::readlink; - - let mut path_str = str::with_capacity(TMPBUF_SZ); - let len = do str::as_c_str(path_str) |buf| { - let buf = buf as *mut c_char; - do as_c_charp("/proc/self/exe") |proc_self_buf| { - readlink(proc_self_buf, buf, TMPBUF_SZ as size_t) - } - }; - if len == -1 { - None - } else { - str::raw::set_len(&mut path_str, len as uint); - Some(path_str) - } - } - } - - #[cfg(target_os = "macos")] - fn load_self() -> Option<~str> { - unsafe { - do fill_charp_buf() |buf, sz| { - let mut sz = sz as u32; - libc::funcs::extra::_NSGetExecutablePath( - buf, &mut sz) == (0 as c_int) - } - } - } - - #[cfg(windows)] - fn load_self() -> Option<~str> { - unsafe { - use os::win32::fill_utf16_buf_and_decode; - do fill_utf16_buf_and_decode() |buf, sz| { - libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz) - } - } - } - - do load_self().map |pth| { - Path(*pth).dir_path() - } -} - - -/** - * Returns the path to the user's home directory, if known. - * - * On Unix, returns the value of the 'HOME' environment variable if it is set - * and not equal to the empty string. - * - * On Windows, returns the value of the 'HOME' environment variable if it is - * set and not equal to the empty string. Otherwise, returns the value of the - * 'USERPROFILE' environment variable if it is set and not equal to the empty - * string. - * - * Otherwise, homedir returns option::none. - */ -pub fn homedir() -> Option<Path> { - return match getenv("HOME") { - Some(ref p) => if !str::is_empty(*p) { - Some(Path(*p)) - } else { - secondary() - }, - None => secondary() - }; - - #[cfg(unix)] - fn secondary() -> Option<Path> { - None - } - - #[cfg(windows)] - fn secondary() -> Option<Path> { - do getenv(~"USERPROFILE").chain |p| { - if !str::is_empty(p) { - Some(Path(p)) - } else { - None - } - } - } -} - -/** - * Returns the path to a temporary directory. - * - * On Unix, returns the value of the 'TMPDIR' environment variable if it is - * set and non-empty and '/tmp' otherwise. - * - * On Windows, returns the value of, in order, the 'TMP', 'TEMP', - * 'USERPROFILE' environment variable if any are set and not the empty - * string. Otherwise, tmpdir returns the path to the Windows directory. - */ -pub fn tmpdir() -> Path { - return lookup(); - - fn getenv_nonempty(v: &str) -> Option<Path> { - match getenv(v) { - Some(x) => - if str::is_empty(x) { - None - } else { - Some(Path(x)) - }, - _ => None - } - } - - #[cfg(unix)] - #[allow(non_implicitly_copyable_typarams)] - fn lookup() -> Path { - getenv_nonempty("TMPDIR").get_or_default(Path("/tmp")) - } - - #[cfg(windows)] - #[allow(non_implicitly_copyable_typarams)] - fn lookup() -> Path { - getenv_nonempty("TMP").or( - getenv_nonempty("TEMP").or( - getenv_nonempty("USERPROFILE").or( - getenv_nonempty("WINDIR")))).get_or_default(Path("C:\\Windows")) - } -} - -/// Recursively walk a directory structure -pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { - list_dir(p).each(|q| { - let path = &p.push(*q); - f(path) && (!path_is_dir(path) || walk_dir(path, f)) - }) -} - -/// Indicates whether a path represents a directory -pub fn path_is_dir(p: &Path) -> bool { - unsafe { - do str::as_c_str(p.to_str()) |buf| { - rustrt::rust_path_is_dir(buf) != 0 as c_int - } - } -} - -/// Indicates whether a path exists -pub fn path_exists(p: &Path) -> bool { - unsafe { - do str::as_c_str(p.to_str()) |buf| { - rustrt::rust_path_exists(buf) != 0 as c_int - } - } -} - -/** - * Convert a relative path to an absolute path - * - * If the given path is relative, return it prepended with the current working - * directory. If the given path is already an absolute path, return it - * as is. - */ -// NB: this is here rather than in path because it is a form of environment -// querying; what it does depends on the process working directory, not just -// the input paths. -pub fn make_absolute(p: &Path) -> Path { - if p.is_absolute { - copy *p - } else { - getcwd().push_many(p.components) - } -} - - -/// Creates a directory at the specified path -pub fn make_dir(p: &Path, mode: c_int) -> bool { - return mkdir(p, mode); - - #[cfg(windows)] - fn mkdir(p: &Path, _mode: c_int) -> bool { - unsafe { - use os::win32::as_utf16_p; - // FIXME: turn mode into something useful? #2623 - do as_utf16_p(p.to_str()) |buf| { - libc::CreateDirectoryW(buf, unsafe { - cast::transmute(0) - }) - != (0 as libc::BOOL) - } - } - } - - #[cfg(unix)] - fn mkdir(p: &Path, mode: c_int) -> bool { - unsafe { - do as_c_charp(p.to_str()) |c| { - libc::mkdir(c, mode as mode_t) == (0 as c_int) - } - } - } -} - -/// Creates a directory with a given mode. -/// Returns true iff creation -/// succeeded. Also creates all intermediate subdirectories -/// if they don't already exist, giving all of them the same mode. - -// tjc: if directory exists but with different permissions, -// should we return false? -pub fn mkdir_recursive(p: &Path, mode: c_int) -> bool { - if path_is_dir(p) { - return true; - } - else if p.components.is_empty() { - return false; - } - else if p.components.len() == 1 { - // No parent directories to create - path_is_dir(p) || make_dir(p, mode) - } - else { - mkdir_recursive(&p.pop(), mode) && make_dir(p, mode) - } -} - -/// Lists the contents of a directory -#[allow(non_implicitly_copyable_typarams)] -pub fn list_dir(p: &Path) -> ~[~str] { - unsafe { - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - #[cfg(target_os = "freebsd")] - #[cfg(target_os = "macos")] - unsafe fn get_list(p: &Path) -> ~[~str] { - use libc::{dirent_t}; - use libc::{opendir, readdir, closedir}; - extern { - unsafe fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char; - } - let input = p.to_str(); - let mut strings = ~[]; - let input_ptr = ::cast::transmute(&input[0]); - debug!("os::list_dir -- BEFORE OPENDIR"); - let dir_ptr = opendir(input_ptr); - if (dir_ptr as uint != 0) { - debug!("os::list_dir -- opendir() SUCCESS"); - let mut entry_ptr = readdir(dir_ptr); - while (entry_ptr as uint != 0) { - strings.push(str::raw::from_c_str(rust_list_dir_val( - entry_ptr))); - entry_ptr = readdir(dir_ptr); - } - closedir(dir_ptr); - } - else { - debug!("os::list_dir -- opendir() FAILURE"); - } - debug!( - "os::list_dir -- AFTER -- #: %?", - strings.len()); - strings - } - #[cfg(windows)] - unsafe fn get_list(p: &Path) -> ~[~str] { - use libc::types::os::arch::extra::{LPCTSTR, HANDLE, BOOL}; - use libc::consts::os::extra::INVALID_HANDLE_VALUE; - use libc::wcslen; - use libc::funcs::extra::kernel32::{ - FindFirstFileW, - FindNextFileW, - FindClose, - }; - use os::win32::{ - as_utf16_p - }; - use rt::global_heap::{malloc_raw, free_raw}; - #[nolink] - extern { - unsafe fn rust_list_dir_wfd_size() -> libc::size_t; - unsafe fn rust_list_dir_wfd_fp_buf(wfd: *libc::c_void) - -> *u16; - } - fn star(p: &Path) -> Path { p.push("*") } - do as_utf16_p(star(p).to_str()) |path_ptr| { - let mut strings = ~[]; - let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint); - let find_handle = - FindFirstFileW( - path_ptr, - ::cast::transmute(wfd_ptr)); - if find_handle as int != INVALID_HANDLE_VALUE { - let mut more_files = 1 as libc::c_int; - while more_files != 0 { - let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr); - if fp_buf as uint == 0 { - fail!("os::list_dir() failure: got null ptr from wfd"); - } - else { - let fp_vec = vec::from_buf( - fp_buf, wcslen(fp_buf) as uint); - let fp_str = str::from_utf16(fp_vec); - strings.push(fp_str); - } - more_files = FindNextFileW( - find_handle, - ::cast::transmute(wfd_ptr)); - } - FindClose(find_handle); - free_raw(wfd_ptr); - } - strings - } - } - do get_list(p).filtered |filename| { - *filename != ~"." && *filename != ~".." - } - } -} - -/** - * Lists the contents of a directory - * - * This version prepends each entry with the directory. - */ -pub fn list_dir_path(p: &Path) -> ~[~Path] { - list_dir(p).map(|f| ~p.push(*f)) -} - -/// Removes a directory at the specified path, after removing -/// all its contents. Use carefully! -pub fn remove_dir_recursive(p: &Path) -> bool { - let mut error_happened = false; - for walk_dir(p) |inner| { - if !error_happened { - if path_is_dir(inner) { - if !remove_dir_recursive(inner) { - error_happened = true; - } - } - else { - if !remove_file(inner) { - error_happened = true; - } - } - } - }; - // Directory should now be empty - !error_happened && remove_dir(p) -} - -/// Removes a directory at the specified path -pub fn remove_dir(p: &Path) -> bool { - return rmdir(p); - - #[cfg(windows)] - fn rmdir(p: &Path) -> bool { - unsafe { - use os::win32::as_utf16_p; - return do as_utf16_p(p.to_str()) |buf| { - libc::RemoveDirectoryW(buf) != (0 as libc::BOOL) - }; - } - } - - #[cfg(unix)] - fn rmdir(p: &Path) -> bool { - unsafe { - return do as_c_charp(p.to_str()) |buf| { - libc::rmdir(buf) == (0 as c_int) - }; - } - } -} - -pub fn change_dir(p: &Path) -> bool { - return chdir(p); - - #[cfg(windows)] - fn chdir(p: &Path) -> bool { - unsafe { - use os::win32::as_utf16_p; - return do as_utf16_p(p.to_str()) |buf| { - libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL) - }; - } - } - - #[cfg(unix)] - fn chdir(p: &Path) -> bool { - unsafe { - return do as_c_charp(p.to_str()) |buf| { - libc::chdir(buf) == (0 as c_int) - }; - } - } -} - -/// Changes the current working directory to the specified -/// path while acquiring a global lock, then calls `action`. -/// If the change is successful, releases the lock and restores the -/// CWD to what it was before, returning true. -/// Returns false if the directory doesn't exist or if the directory change -/// is otherwise unsuccessful. -pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { - use unstable::global::global_data_clone_create; - use unstable::sync::{Exclusive, exclusive}; - - fn key(_: Exclusive<()>) { } - - let result = unsafe { - 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 - } - } -} - -/// Copies a file from one location to another -pub fn copy_file(from: &Path, to: &Path) -> bool { - return do_copy_file(from, to); - - #[cfg(windows)] - fn do_copy_file(from: &Path, to: &Path) -> bool { - unsafe { - use os::win32::as_utf16_p; - return do as_utf16_p(from.to_str()) |fromp| { - do as_utf16_p(to.to_str()) |top| { - libc::CopyFileW(fromp, top, (0 as libc::BOOL)) != - (0 as libc::BOOL) - } - } - } - } - - #[cfg(unix)] - fn do_copy_file(from: &Path, to: &Path) -> bool { - unsafe { - let istream = do as_c_charp(from.to_str()) |fromp| { - do as_c_charp("rb") |modebuf| { - libc::fopen(fromp, modebuf) - } - }; - if istream as uint == 0u { - return false; - } - // Preserve permissions - let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \ - for source file"); - - let ostream = do as_c_charp(to.to_str()) |top| { - do as_c_charp("w+b") |modebuf| { - libc::fopen(top, modebuf) - } - }; - if ostream as uint == 0u { - fclose(istream); - return false; - } - let bufsize = 8192u; - let mut buf = vec::with_capacity::<u8>(bufsize); - let mut done = false; - let mut ok = true; - while !done { - do vec::as_mut_buf(buf) |b, _sz| { - let nread = libc::fread(b as *mut c_void, 1u as size_t, - bufsize as size_t, - istream); - if nread > 0 as size_t { - if libc::fwrite(b as *c_void, 1u as size_t, nread, - ostream) != nread { - ok = false; - done = true; - } - } else { - done = true; - } - } - } - fclose(istream); - fclose(ostream); - - // Give the new file the old file's permissions - unsafe { - if do str::as_c_str(to.to_str()) |to_buf| { - libc::chmod(to_buf, from_mode as mode_t) - } != 0 { - return false; // should be a condition... - } - } - return ok; - } - } -} - -/// Deletes an existing file -pub fn remove_file(p: &Path) -> bool { - return unlink(p); - - #[cfg(windows)] - fn unlink(p: &Path) -> bool { - unsafe { - use os::win32::as_utf16_p; - return do as_utf16_p(p.to_str()) |buf| { - libc::DeleteFileW(buf) != (0 as libc::BOOL) - }; - } - } - - #[cfg(unix)] - fn unlink(p: &Path) -> bool { - unsafe { - return do as_c_charp(p.to_str()) |buf| { - libc::unlink(buf) == (0 as c_int) - }; - } - } -} - -#[cfg(unix)] -pub fn errno() -> int { - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn errno_location() -> *c_int { - #[nolink] - extern { - unsafe fn __error() -> *c_int; - } - unsafe { - __error() - } - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - fn errno_location() -> *c_int { - #[nolink] - extern { - unsafe fn __errno_location() -> *c_int; - } - unsafe { - __errno_location() - } - } - - unsafe { - (*errno_location()) as int - } -} - -#[cfg(windows)] -pub fn errno() -> uint { - use libc::types::os::arch::extra::DWORD; - - #[link_name = "kernel32"] - #[abi = "stdcall"] - extern "stdcall" { - unsafe fn GetLastError() -> DWORD; - } - - unsafe { - GetLastError() as uint - } -} - -/// Get a string representing the platform-dependent last error -pub fn last_os_error() -> ~str { - #[cfg(unix)] - fn strerror() -> ~str { - #[cfg(target_os = "macos")] - #[cfg(target_os = "android")] - #[cfg(target_os = "freebsd")] - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int { - #[nolink] - extern { - unsafe fn strerror_r(errnum: c_int, buf: *mut c_char, - buflen: size_t) -> c_int; - } - unsafe { - strerror_r(errnum, buf, buflen) - } - } - - // GNU libc provides a non-compliant version of strerror_r by default - // and requires macros to instead use the POSIX compliant variant. - // So we just use __xpg_strerror_r which is always POSIX compliant - #[cfg(target_os = "linux")] - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int { - #[nolink] - extern { - unsafe fn __xpg_strerror_r(errnum: c_int, buf: *mut c_char, - buflen: size_t) -> c_int; - } - unsafe { - __xpg_strerror_r(errnum, buf, buflen) - } - } - - let mut buf = [0 as c_char, ..TMPBUF_SZ]; - unsafe { - let err = strerror_r(errno() as c_int, &mut buf[0], - TMPBUF_SZ as size_t); - if err < 0 { - fail!("strerror_r failure"); - } - - str::raw::from_c_str(&buf[0]) - } - } - - #[cfg(windows)] - fn strerror() -> ~str { - use libc::types::os::arch::extra::DWORD; - use libc::types::os::arch::extra::LPSTR; - use libc::types::os::arch::extra::LPVOID; - - #[link_name = "kernel32"] - #[abi = "stdcall"] - extern "stdcall" { - unsafe fn FormatMessageA(flags: DWORD, lpSrc: LPVOID, - msgId: DWORD, langId: DWORD, - buf: LPSTR, nsize: DWORD, - args: *c_void) -> DWORD; - } - - static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; - static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - - let mut buf = [0 as c_char, ..TMPBUF_SZ]; - - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as DWORD; - let err = errno() as DWORD; - unsafe { - let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::mut_null(), err, langId, - &mut buf[0], TMPBUF_SZ as DWORD, - ptr::null()); - if res == 0 { - fail!("[%?] FormatMessage failure", errno()); - } - - str::raw::from_c_str(&buf[0]) - } - } - - strerror() -} - -/** - * Sets the process exit code - * - * Sets the exit code returned by the process if all supervised tasks - * terminate successfully (without failing). If the current root task fails - * and is supervised by the scheduler then any user-specified exit status is - * ignored and the process exits with the default failure status - */ -pub fn set_exit_status(code: int) { - unsafe { - rustrt::rust_set_exit_status(code as libc::intptr_t); - } -} - -unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] { - let mut args = ~[]; - for uint::range(0, argc as uint) |i| { - vec::push(&mut args, str::raw::from_c_str(*argv.offset(i))); - } - args -} - -/** - * Returns the command line arguments - * - * Returns a list of the command line arguments. - */ -#[cfg(target_os = "macos")] -pub fn real_args() -> ~[~str] { - unsafe { - let (argc, argv) = (*_NSGetArgc() as c_int, - *_NSGetArgv() as **c_char); - load_argc_and_argv(argc, argv) - } -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -#[cfg(target_os = "freebsd")] -pub fn real_args() -> ~[~str] { - unsafe { - let argc = rustrt::rust_get_argc(); - let argv = rustrt::rust_get_argv(); - load_argc_and_argv(argc, argv) - } -} - -#[cfg(windows)] -pub fn real_args() -> ~[~str] { - let mut nArgs: c_int = 0; - let lpArgCount = ptr::to_mut_unsafe_ptr(&mut nArgs); - let lpCmdLine = unsafe { GetCommandLineW() }; - let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) }; - - let mut args = ~[]; - for uint::range(0, nArgs as uint) |i| { - unsafe { - // Determine the length of this argument. - let ptr = *szArgList.offset(i); - let mut len = 0; - while *ptr.offset(len) != 0 { len += 1; } - - // Push it onto the list. - vec::push(&mut args, - vec::raw::buf_as_slice(ptr, len, - str::from_utf16)); - } - } - - unsafe { - LocalFree(cast::transmute(szArgList)); - } - - return args; -} - -type LPCWSTR = *u16; - -#[cfg(windows)] -#[link_name="kernel32"] -#[abi="stdcall"] -extern "stdcall" { - fn GetCommandLineW() -> LPCWSTR; - fn LocalFree(ptr: *c_void); -} - -#[cfg(windows)] -#[link_name="shell32"] -#[abi="stdcall"] -extern "stdcall" { - fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16; -} - -struct OverriddenArgs { - val: ~[~str] -} - -fn overridden_arg_key(_v: @OverriddenArgs) {} - -pub fn args() -> ~[~str] { - unsafe { - match local_data::local_data_get(overridden_arg_key) { - None => real_args(), - Some(args) => copy args.val - } - } -} - -pub fn set_args(new_args: ~[~str]) { - unsafe { - let overridden_args = @OverriddenArgs { val: copy new_args }; - local_data::local_data_set(overridden_arg_key, overridden_args); - } -} - -// FIXME #6100 we should really use an internal implementation of this - using -// the POSIX glob functions isn't portable to windows, probably has slight -// inconsistencies even where it is implemented, and makes extending -// functionality a lot more difficult -// FIXME #6101 also provide a non-allocating version - each_glob or so? -/// Returns a vector of Path objects that match the given glob pattern -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -#[cfg(target_os = "freebsd")] -#[cfg(target_os = "macos")] -pub fn glob(pattern: &str) -> ~[Path] { - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - fn default_glob_t () -> libc::glob_t { - libc::glob_t { - gl_pathc: 0, - gl_pathv: ptr::null(), - gl_offs: 0, - __unused1: ptr::null(), - __unused2: ptr::null(), - __unused3: ptr::null(), - __unused4: ptr::null(), - __unused5: ptr::null(), - } - } - - #[cfg(target_os = "freebsd")] - fn default_glob_t () -> libc::glob_t { - libc::glob_t { - gl_pathc: 0, - __unused1: 0, - gl_offs: 0, - __unused2: 0, - gl_pathv: ptr::null(), - __unused3: ptr::null(), - __unused4: ptr::null(), - __unused5: ptr::null(), - __unused6: ptr::null(), - __unused7: ptr::null(), - __unused8: ptr::null(), - } - } - - #[cfg(target_os = "macos")] - fn default_glob_t () -> libc::glob_t { - libc::glob_t { - gl_pathc: 0, - __unused1: 0, - gl_offs: 0, - __unused2: 0, - gl_pathv: ptr::null(), - __unused3: ptr::null(), - __unused4: ptr::null(), - __unused5: ptr::null(), - __unused6: ptr::null(), - __unused7: ptr::null(), - __unused8: ptr::null(), - } - } - - let mut g = default_glob_t(); - do str::as_c_str(pattern) |c_pattern| { - unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) } - }; - do(|| { - let paths = unsafe { - vec::raw::from_buf_raw(g.gl_pathv, g.gl_pathc as uint) - }; - do paths.map |&c_str| { - Path(unsafe { str::raw::from_c_str(c_str) }) - } - }).finally { - unsafe { libc::globfree(&mut g) }; - } -} - -/// Returns a vector of Path objects that match the given glob pattern -#[cfg(target_os = "win32")] -pub fn glob(pattern: &str) -> ~[Path] { - fail!("glob() is unimplemented on Windows") -} - -#[cfg(target_os = "macos")] -extern { - // These functions are in crt_externs.h. - pub fn _NSGetArgc() -> *c_int; - pub fn _NSGetArgv() -> ***c_char; -} - -pub mod consts { - - #[cfg(unix)] - pub use os::consts::unix::*; - - #[cfg(windows)] - pub use os::consts::windows::*; - - #[cfg(target_os = "macos")] - pub use os::consts::macos::*; - - #[cfg(target_os = "freebsd")] - pub use os::consts::freebsd::*; - - #[cfg(target_os = "linux")] - pub use os::consts::linux::*; - - #[cfg(target_os = "android")] - pub use os::consts::android::*; - - #[cfg(target_os = "win32")] - pub use os::consts::win32::*; - - #[cfg(target_arch = "x86")] - pub use os::consts::x86::*; - - #[cfg(target_arch = "x86_64")] - pub use os::consts::x86_64::*; - - #[cfg(target_arch = "arm")] - pub use os::consts::arm::*; - - #[cfg(target_arch = "mips")] - use os::consts::mips::*; - - pub mod unix { - pub static FAMILY: &'static str = "unix"; - } - - pub mod windows { - pub static FAMILY: &'static str = "windows"; - } - - pub mod macos { - pub static SYSNAME: &'static str = "macos"; - pub static DLL_PREFIX: &'static str = "lib"; - pub static DLL_SUFFIX: &'static str = ".dylib"; - pub static EXE_SUFFIX: &'static str = ""; - } - - pub mod freebsd { - pub static SYSNAME: &'static str = "freebsd"; - pub static DLL_PREFIX: &'static str = "lib"; - pub static DLL_SUFFIX: &'static str = ".so"; - pub static EXE_SUFFIX: &'static str = ""; - } - - pub mod linux { - pub static SYSNAME: &'static str = "linux"; - pub static DLL_PREFIX: &'static str = "lib"; - pub static DLL_SUFFIX: &'static str = ".so"; - pub static EXE_SUFFIX: &'static str = ""; - } - - pub mod android { - pub static SYSNAME: &'static str = "android"; - pub static DLL_PREFIX: &'static str = "lib"; - pub static DLL_SUFFIX: &'static str = ".so"; - pub static EXE_SUFFIX: &'static str = ""; - } - - pub mod win32 { - pub static SYSNAME: &'static str = "win32"; - pub static DLL_PREFIX: &'static str = ""; - pub static DLL_SUFFIX: &'static str = ".dll"; - pub static EXE_SUFFIX: &'static str = ".exe"; - } - - - pub mod x86 { - pub static ARCH: &'static str = "x86"; - } - pub mod x86_64 { - pub static ARCH: &'static str = "x86_64"; - } - pub mod arm { - pub static ARCH: &'static str = "arm"; - } - pub mod mips { - pub static ARCH: &'static str = "mips"; - } -} - -#[cfg(test)] -#[allow(non_implicitly_copyable_typarams)] -mod tests { - use libc::{c_int, c_void, size_t}; - use libc; - use option::Some; - use option; - use os::{as_c_charp, env, getcwd, getenv, make_absolute, real_args}; - use os::{remove_file, setenv, unsetenv}; - use os; - use path::Path; - use rand::RngUtil; - use rand; - use run; - use str; - use vec; - use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - - - #[test] - pub fn last_os_error() { - debug!(os::last_os_error()); - } - - #[test] - pub fn test_args() { - let a = real_args(); - assert!(a.len() >= 1); - } - - fn make_rand_name() -> ~str { - let mut rng = rand::rng(); - let n = ~"TEST" + rng.gen_str(10u); - assert!(getenv(n).is_none()); - n - } - - #[test] - fn test_setenv() { - let n = make_rand_name(); - setenv(n, ~"VALUE"); - assert_eq!(getenv(n), option::Some(~"VALUE")); - } - - #[test] - fn test_unsetenv() { - let n = make_rand_name(); - setenv(n, ~"VALUE"); - unsetenv(n); - assert_eq!(getenv(n), option::None); - } - - #[test] - #[ignore(cfg(windows))] - #[ignore] - fn test_setenv_overwrite() { - let n = make_rand_name(); - setenv(n, ~"1"); - setenv(n, ~"2"); - assert_eq!(getenv(n), option::Some(~"2")); - setenv(n, ~""); - assert_eq!(getenv(n), option::Some(~"")); - } - - // Windows GetEnvironmentVariable requires some extra work to make sure - // the buffer the variable is copied into is the right size - #[test] - #[ignore(cfg(windows))] - #[ignore] - fn test_getenv_big() { - let mut s = ~""; - let mut i = 0; - while i < 100 { s += ~"aaaaaaaaaa"; i += 1; } - let n = make_rand_name(); - setenv(n, s); - debug!(copy s); - assert_eq!(getenv(n), option::Some(s)); - } - - #[test] - fn test_self_exe_path() { - let path = os::self_exe_path(); - assert!(path.is_some()); - let path = path.get(); - debug!(copy path); - - // Hard to test this function - assert!(path.is_absolute); - } - - #[test] - #[ignore] - fn test_env_getenv() { - let e = env(); - assert!(e.len() > 0u); - for e.each |p| { - let (n, v) = copy *p; - debug!(copy n); - let v2 = getenv(n); - // MingW seems to set some funky environment variables like - // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned - // from env() but not visible from getenv(). - assert!(v2.is_none() || v2 == option::Some(v)); - } - } - - #[test] - fn test_env_setenv() { - let n = make_rand_name(); - - let mut e = env(); - setenv(n, ~"VALUE"); - assert!(!vec::contains(e, &(copy n, ~"VALUE"))); - - e = env(); - assert!(vec::contains(e, &(n, ~"VALUE"))); - } - - #[test] - fn test() { - assert!((!Path("test-path").is_absolute)); - - debug!(~"Current working directory: " + getcwd().to_str()); - - debug!(make_absolute(&Path("test-path"))); - debug!(make_absolute(&Path("/usr/bin"))); - } - - #[test] - #[cfg(unix)] - fn homedir() { - let oldhome = getenv(~"HOME"); - - setenv(~"HOME", ~"/home/MountainView"); - assert_eq!(os::homedir(), Some(Path("/home/MountainView"))); - - setenv(~"HOME", ~""); - assert!(os::homedir().is_none()); - - for oldhome.each |s| { setenv(~"HOME", *s) } - } - - #[test] - #[cfg(windows)] - fn homedir() { - - let oldhome = getenv(~"HOME"); - let olduserprofile = getenv(~"USERPROFILE"); - - setenv(~"HOME", ~""); - setenv(~"USERPROFILE", ~""); - - assert!(os::homedir().is_none()); - - setenv(~"HOME", ~"/home/MountainView"); - assert_eq!(os::homedir(), Some(Path("/home/MountainView"))); - - setenv(~"HOME", ~""); - - setenv(~"USERPROFILE", ~"/home/MountainView"); - assert_eq!(os::homedir(), Some(Path("/home/MountainView"))); - - setenv(~"HOME", ~"/home/MountainView"); - setenv(~"USERPROFILE", ~"/home/PaloAlto"); - assert_eq!(os::homedir(), Some(Path("/home/MountainView"))); - - oldhome.each(|s| {setenv(~"HOME", *s);true}); - olduserprofile.each(|s| {setenv(~"USERPROFILE", *s);true}); - } - - #[test] - fn tmpdir() { - assert!(!str::is_empty(os::tmpdir().to_str())); - } - - // Issue #712 - #[test] - fn test_list_dir_no_invalid_memory_access() { - os::list_dir(&Path(".")); - } - - #[test] - fn list_dir() { - let dirs = os::list_dir(&Path(".")); - // Just assuming that we've got some contents in the current directory - assert!(dirs.len() > 0u); - - for dirs.each |dir| { - debug!(copy *dir); - } - } - - #[test] - fn path_is_dir() { - assert!((os::path_is_dir(&Path(".")))); - assert!((!os::path_is_dir(&Path("test/stdtest/fs.rs")))); - } - - #[test] - fn path_exists() { - assert!((os::path_exists(&Path(".")))); - assert!((!os::path_exists(&Path( - "test/nonexistent-bogus-path")))); - } - - #[test] - fn copy_file_does_not_exist() { - assert!(!os::copy_file(&Path("test/nonexistent-bogus-path"), - &Path("test/other-bogus-path"))); - assert!(!os::path_exists(&Path("test/other-bogus-path"))); - } - - #[test] - fn copy_file_ok() { - unsafe { - let tempdir = getcwd(); // would like to use $TMPDIR, - // doesn't seem to work on Linux - assert!((str::len(tempdir.to_str()) > 0u)); - let in = tempdir.push("in.txt"); - let out = tempdir.push("out.txt"); - - /* Write the temp input file */ - let ostream = do as_c_charp(in.to_str()) |fromp| { - do as_c_charp("w+b") |modebuf| { - libc::fopen(fromp, modebuf) - } - }; - assert!((ostream as uint != 0u)); - let s = ~"hello"; - let mut buf = str::to_bytes(s) + ~[0 as u8]; - 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) - == buf.len() as size_t)) - } - assert_eq!(libc::fclose(ostream), (0u as c_int)); - let in_mode = in.get_mode(); - let rs = os::copy_file(&in, &out); - if (!os::path_exists(&in)) { - fail!("%s doesn't exist", in.to_str()); - } - assert!((rs)); - let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]); - assert_eq!(rslt, 0); - assert_eq!(out.get_mode(), in_mode); - assert!((remove_file(&in))); - assert!((remove_file(&out))); - } - } - - #[test] - fn recursive_mkdir_slash() { - let path = Path("/"); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - } - - #[test] - fn recursive_mkdir_empty() { - let path = Path(""); - assert!(!os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - } - - // More recursive_mkdir tests are in std::tempfile -} diff --git a/src/libcore/owned.rs b/src/libcore/owned.rs deleted file mode 100644 index 3262fb4afdc..00000000000 --- a/src/libcore/owned.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations on unique pointer types - -#[cfg(not(test))] use cmp::{Eq, Ord}; - -#[cfg(not(test))] -impl<T:Eq> Eq for ~T { - #[inline(always)] - fn eq(&self, other: &~T) -> bool { *(*self) == *(*other) } - #[inline(always)] - fn ne(&self, other: &~T) -> bool { *(*self) != *(*other) } -} - -#[cfg(not(test))] -impl<T:Ord> Ord for ~T { - #[inline(always)] - fn lt(&self, other: &~T) -> bool { *(*self) < *(*other) } - #[inline(always)] - fn le(&self, other: &~T) -> bool { *(*self) <= *(*other) } - #[inline(always)] - fn ge(&self, other: &~T) -> bool { *(*self) >= *(*other) } - #[inline(always)] - fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) } -} diff --git a/src/libcore/path.rs b/src/libcore/path.rs deleted file mode 100644 index ed9ef864f80..00000000000 --- a/src/libcore/path.rs +++ /dev/null @@ -1,1200 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -Cross-platform file path handling - -*/ - -use container::Container; -use cmp::Eq; -use libc; -use option::{None, Option, Some}; -use str; -use str::StrSlice; -use to_str::ToStr; -use ascii::{AsciiCast, AsciiStr}; -use old_iter::BaseIter; -use vec::OwnedVector; - -#[cfg(windows)] -pub use Path = self::WindowsPath; -#[cfg(unix)] -pub use Path = self::PosixPath; - -#[deriving(Clone, Eq)] -pub struct WindowsPath { - host: Option<~str>, - device: Option<~str>, - is_absolute: bool, - components: ~[~str], -} - -pub fn WindowsPath(s: &str) -> WindowsPath { - GenericPath::from_str(s) -} - -#[deriving(Clone, Eq)] -pub struct PosixPath { - is_absolute: bool, - components: ~[~str], -} - -pub fn PosixPath(s: &str) -> PosixPath { - GenericPath::from_str(s) -} - -pub trait GenericPath { - /// Converts a string to a Path - fn from_str(&str) -> Self; - - /// Returns the directory component of `self`, as a string - fn dirname(&self) -> ~str; - /// Returns the file component of `self`, as a string option. - /// Returns None if `self` names a directory. - fn filename(&self) -> Option<~str>; - /// Returns the stem of the file component of `self`, as a string option. - /// The stem is the slice of a filename starting at 0 and ending just before - /// the last '.' in the name. - /// Returns None if `self` names a directory. - fn filestem(&self) -> Option<~str>; - /// Returns the type of the file component of `self`, as a string option. - /// The file type is the slice of a filename starting just after the last - /// '.' in the name and ending at the last index in the filename. - /// Returns None if `self` names a directory. - fn filetype(&self) -> Option<~str>; - - /// Returns a new path consisting of `self` with the parent directory component replaced - /// with the given string. - fn with_dirname(&self, (&str)) -> Self; - /// Returns a new path consisting of `self` with the file component replaced - /// with the given string. - fn with_filename(&self, (&str)) -> Self; - /// Returns a new path consisting of `self` with the file stem replaced - /// with the given string. - fn with_filestem(&self, (&str)) -> Self; - /// Returns a new path consisting of `self` with the file type replaced - /// with the given string. - fn with_filetype(&self, (&str)) -> Self; - - /// Returns the directory component of `self`, as a new path. - /// If `self` has no parent, returns `self`. - fn dir_path(&self) -> Self; - /// Returns the file component of `self`, as a new path. - /// If `self` names a directory, returns the empty path. - fn file_path(&self) -> Self; - - /// Returns a new Path whose parent directory is `self` and whose - /// file component is the given string. - fn push(&self, (&str)) -> Self; - /// Returns a new Path consisting of the given path, made relative to `self`. - 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; - /// 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; - - /// The same as `push_rel`, except that the directory argument must not - /// contain directory separators in any of its components. - fn unsafe_join(&self, (&Self)) -> Self; - /// On Unix, always returns false. On Windows, returns true iff `self`'s - /// file stem is one of: `con` `aux` `com1` `com2` `com3` `com4` - /// `lpt1` `lpt2` `lpt3` `prn` `nul` - fn is_restricted(&self) -> bool; - - /// Returns a new path that names the same file as `self`, without containing - /// any '.', '..', or empty components. On Windows, uppercases the drive letter - /// as well. - fn normalize(&self) -> Self; - - /// Returns `true` if `self` is an absolute path. - fn is_absolute(&self) -> bool; -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -mod stat { - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - __pad1: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - __pad2: 0, - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - __unused4: 0, - __unused5: 0, - } - } - } - - #[cfg(target_arch = "mips")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_pad1: [0, ..3], - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_pad2: [0, ..2], - st_size: 0, - st_pad3: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_blksize: 0, - st_blocks: 0, - st_pad5: [0, ..14], - } - } - } - - #[cfg(target_arch = "x86_64")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_nlink: 0, - st_mode: 0, - st_uid: 0, - st_gid: 0, - __pad0: 0, - st_rdev: 0, - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - __unused: [0, 0, 0], - } - } - } -} - -#[cfg(target_os = "freebsd")] -mod stat { - #[cfg(target_arch = "x86_64")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_size: 0, - st_blocks: 0, - st_blksize: 0, - st_flags: 0, - st_gen: 0, - st_lspare: 0, - st_birthtime: 0, - st_birthtime_nsec: 0, - __unused: [0, 0], - } - } - } -} - -#[cfg(target_os = "macos")] -mod stat { - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_mode: 0, - st_nlink: 0, - st_ino: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_birthtime: 0, - st_birthtime_nsec: 0, - st_size: 0, - st_blocks: 0, - st_blksize: 0, - st_flags: 0, - st_gen: 0, - st_lspare: 0, - st_qspare: [0, 0], - } - } - } -} - -#[cfg(target_os = "win32")] -mod stat { - pub mod arch { - use libc; - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_size: 0, - st_atime: 0, - st_mtime: 0, - st_ctime: 0, - } - } - } -} - - -pub impl Path { - fn stat(&self) -> Option<libc::stat> { - unsafe { - do str::as_c_str(self.to_str()) |buf| { - let mut st = stat::arch::default_stat(); - match libc::stat(buf, &mut st) { - 0 => Some(st), - _ => None, - } - } - } - } - - #[cfg(unix)] - fn lstat(&self) -> Option<libc::stat> { - unsafe { - do str::as_c_str(self.to_str()) |buf| { - let mut st = stat::arch::default_stat(); - match libc::lstat(buf, &mut st) { - 0 => Some(st), - _ => None, - } - } - } - } - - fn exists(&self) -> bool { - match self.stat() { - None => false, - Some(_) => true, - } - } - - 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> { - match self.stat() { - None => None, - Some(ref st) => Some(st.st_mode as uint), - } - } -} - -#[cfg(target_os = "freebsd")] -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] -pub impl Path { - fn get_atime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_atime as i64, - st.st_atime_nsec as int)) - } - } - } - - fn get_mtime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_mtime as i64, - st.st_mtime_nsec as int)) - } - } - } - - fn get_ctime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_ctime as i64, - st.st_ctime_nsec as int)) - } - } - } -} - -#[cfg(target_os = "freebsd")] -#[cfg(target_os = "macos")] -pub impl Path { - fn get_birthtime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_birthtime as i64, - st.st_birthtime_nsec as int)) - } - } - } -} - -#[cfg(target_os = "win32")] -pub impl Path { - fn get_atime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_atime as i64, 0)) - } - } - } - - fn get_mtime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_mtime as i64, 0)) - } - } - } - - fn get_ctime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_ctime as i64, 0)) - } - } - } -} - -impl ToStr for PosixPath { - fn to_str(&self) -> ~str { - let mut s = ~""; - if self.is_absolute { - s += "/"; - } - s + str::connect(self.components, "/") - } -} - -// FIXME (#3227): when default methods in traits are working, de-duplicate -// 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 is_absolute = (s.len() != 0 && s[0] == '/' as u8); - PosixPath { - is_absolute: is_absolute, - components: components, - } - } - - fn dirname(&self) -> ~str { - let s = self.dir_path().to_str(); - match s.len() { - 0 => ~".", - _ => s, - } - } - - fn filename(&self) -> Option<~str> { - match self.components.len() { - 0 => None, - n => Some(copy self.components[n - 1]), - } - } - - fn filestem(&self) -> Option<~str> { - match self.filename() { - None => None, - Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) => Some(f.slice(0, p).to_owned()), - None => Some(copy *f), - } - } - } - } - - fn filetype(&self) -> Option<~str> { - 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()), - _ => None, - } - } - } - } - - fn with_dirname(&self, d: &str) -> PosixPath { - let dpath = PosixPath(d); - match self.filename() { - Some(ref f) => dpath.push(*f), - None => dpath, - } - } - - fn with_filename(&self, f: &str) -> PosixPath { - assert!(! str::any(f, |c| windows::is_sep(c as u8))); - self.dir_path().push(f) - } - - fn with_filestem(&self, s: &str) -> PosixPath { - match self.filetype() { - None => self.with_filename(s), - Some(ref t) => self.with_filename(str::to_owned(s) + *t), - } - } - - fn with_filetype(&self, t: &str) -> PosixPath { - match (t.len(), self.filestem()) { - (0, None) => copy *self, - (0, Some(ref s)) => self.with_filename(*s), - (_, None) => self.with_filename(fmt!(".%s", t)), - (_, Some(ref s)) => self.with_filename(fmt!("%s.%s", *s, t)), - } - } - - fn dir_path(&self) -> PosixPath { - match self.components.len() { - 0 => copy *self, - _ => self.pop(), - } - } - - fn file_path(&self) -> PosixPath { - let cs = match self.filename() { - None => ~[], - Some(ref f) => ~[copy *f] - }; - PosixPath { - is_absolute: false, - components: cs, - } - } - - fn push_rel(&self, other: &PosixPath) -> PosixPath { - assert!(!other.is_absolute); - self.push_many(other.components) - } - - fn unsafe_join(&self, other: &PosixPath) -> PosixPath { - if other.is_absolute { - PosixPath { - is_absolute: true, - components: copy other.components, - } - } else { - self.push_rel(other) - } - } - - fn is_restricted(&self) -> bool { - false - } - - fn push_many(&self, cs: &[~str]) -> 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()) - } - v.push_all_move(ss); - } - PosixPath { - is_absolute: self.is_absolute, - components: v, - } - } - - 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()) - } - v.push_all_move(ss); - PosixPath { components: v, ..copy *self } - } - - fn pop(&self) -> PosixPath { - let mut cs = copy self.components; - if cs.len() != 0 { - cs.pop(); - } - PosixPath { - is_absolute: self.is_absolute, - components: cs, - } //..self } - } - - fn normalize(&self) -> PosixPath { - PosixPath { - is_absolute: self.is_absolute, - components: normalize(self.components), - } // ..self } - } - - fn is_absolute(&self) -> bool { - self.is_absolute - } -} - - -impl ToStr for WindowsPath { - fn to_str(&self) -> ~str { - let mut s = ~""; - match self.host { - Some(ref h) => { s += "\\\\"; s += *h; } - None => { } - } - match self.device { - Some(ref d) => { s += *d; s += ":"; } - None => { } - } - if self.is_absolute { - s += "\\"; - } - s + str::connect(self.components, "\\") - } -} - - -impl GenericPath for WindowsPath { - fn from_str(s: &str) -> WindowsPath { - let host; - let device; - let rest; - - match ( - windows::extract_drive_prefix(s), - windows::extract_unc_prefix(s), - ) { - (Some((ref d, ref r)), _) => { - host = None; - device = Some(copy *d); - rest = copy *r; - } - (None, Some((ref h, ref r))) => { - host = Some(copy *h); - device = None; - rest = copy *r; - } - (None, None) => { - host = None; - device = None; - rest = str::to_owned(s); - } - } - - 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])); - WindowsPath { - host: host, - device: device, - is_absolute: is_absolute, - components: components, - } - } - - fn dirname(&self) -> ~str { - let s = self.dir_path().to_str(); - match s.len() { - 0 => ~".", - _ => s, - } - } - - fn filename(&self) -> Option<~str> { - match self.components.len() { - 0 => None, - n => Some(copy self.components[n - 1]), - } - } - - fn filestem(&self) -> Option<~str> { - match self.filename() { - None => None, - Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) => Some(f.slice(0, p).to_owned()), - None => Some(copy *f), - } - } - } - } - - fn filetype(&self) -> Option<~str> { - 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()), - _ => None, - } - } - } - } - - fn with_dirname(&self, d: &str) -> WindowsPath { - let dpath = WindowsPath(d); - match self.filename() { - Some(ref f) => dpath.push(*f), - None => dpath, - } - } - - fn with_filename(&self, f: &str) -> WindowsPath { - assert!(! str::any(f, |c| windows::is_sep(c as u8))); - self.dir_path().push(f) - } - - fn with_filestem(&self, s: &str) -> WindowsPath { - match self.filetype() { - None => self.with_filename(s), - Some(ref t) => self.with_filename(str::to_owned(s) + *t), - } - } - - fn with_filetype(&self, t: &str) -> WindowsPath { - match (t.len(), self.filestem()) { - (0, None) => copy *self, - (0, Some(ref s)) => self.with_filename(*s), - (_, None) => self.with_filename(fmt!(".%s", t)), - (_, Some(ref s)) => self.with_filename(fmt!("%s.%s", *s, t)), - } - } - - fn dir_path(&self) -> WindowsPath { - match self.components.len() { - 0 => copy *self, - _ => self.pop(), - } - } - - fn file_path(&self) -> WindowsPath { - WindowsPath { - host: None, - device: None, - is_absolute: false, - components: match self.filename() { - None => ~[], - Some(ref f) => ~[copy *f], - } - } - } - - fn push_rel(&self, other: &WindowsPath) -> WindowsPath { - assert!(!other.is_absolute); - self.push_many(other.components) - } - - fn unsafe_join(&self, other: &WindowsPath) -> WindowsPath { - /* rhs not absolute is simple push */ - if !other.is_absolute { - return self.push_many(other.components); - } - - /* if rhs has a host set, then the whole thing wins */ - match other.host { - Some(copy host) => { - return WindowsPath { - host: Some(host), - device: copy other.device, - is_absolute: true, - components: copy other.components, - }; - } - _ => {} - } - - /* if rhs has a device set, then a part wins */ - match other.device { - Some(copy device) => { - return WindowsPath { - host: None, - device: Some(device), - is_absolute: true, - components: copy other.components, - }; - } - _ => {} - } - - /* fallback: host and device of lhs win, but the - whole path of the right */ - WindowsPath { - host: copy self.host, - device: copy self.device, - is_absolute: self.is_absolute || other.is_absolute, - components: copy other.components, - } - } - - fn is_restricted(&self) -> bool { - match self.filestem() { - Some(stem) => { - // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. - match stem.to_ascii().to_lower().to_str_ascii() { - ~"con" | ~"aux" | ~"com1" | ~"com2" | ~"com3" | ~"com4" | - ~"lpt1" | ~"lpt2" | ~"lpt3" | ~"prn" | ~"nul" => true, - _ => false - } - }, - None => false - } - } - - fn push_many(&self, cs: &[~str]) -> 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()) - } - v.push_all_move(ss); - } - // tedious, but as-is, we can't use ..self - WindowsPath { - host: copy self.host, - device: copy self.device, - is_absolute: self.is_absolute, - components: v - } - } - - 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()) - } - v.push_all_move(ss); - WindowsPath { components: v, ..copy *self } - } - - fn pop(&self) -> WindowsPath { - let mut cs = copy self.components; - if cs.len() != 0 { - cs.pop(); - } - WindowsPath { - host: copy self.host, - device: copy self.device, - is_absolute: self.is_absolute, - components: cs, - } - } - - fn normalize(&self) -> WindowsPath { - WindowsPath { - host: copy self.host, - device: match self.device { - None => None, - - // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. - Some(ref device) => Some(device.to_ascii().to_upper().to_str_ascii()) - }, - is_absolute: self.is_absolute, - components: normalize(self.components) - } - } - - fn is_absolute(&self) -> bool { - self.is_absolute - } -} - - -pub fn normalize(components: &[~str]) -> ~[~str] { - let mut cs = ~[]; - for components.each |c| { - if *c == ~"." && components.len() > 1 { loop; } - if *c == ~"" { loop; } - if *c == ~".." && cs.len() != 0 { - cs.pop(); - loop; - } - cs.push(copy *c); - } - cs -} - -// Various windows helpers, and tests for the impl. -pub mod windows { - use libc; - use option::{None, Option, Some}; - - #[inline(always)] - pub fn is_sep(u: u8) -> bool { - u == '/' as u8 || u == '\\' as u8 - } - - pub fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> { - if (s.len() > 1 && - (s[0] == '\\' as u8 || s[0] == '/' as u8) && - s[0] == s[1]) { - let mut i = 2; - while i < s.len() { - if is_sep(s[i]) { - let pre = s.slice(2, i).to_owned(); - let rest = s.slice(i, s.len()).to_owned(); - return Some((pre, rest)); - } - i += 1; - } - } - None - } - - pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> { - unsafe { - if (s.len() > 1 && - libc::isalpha(s[0] as libc::c_int) != 0 && - s[1] == ':' as u8) { - let rest = if s.len() == 2 { - ~"" - } else { - s.slice(2, s.len()).to_owned() - }; - return Some((s.slice(0,1).to_owned(), rest)); - } - None - } - } -} - -#[cfg(test)] -mod tests { - use option::{None, Some}; - use path::{PosixPath, WindowsPath, windows}; - use str; - - #[test] - fn test_double_slash_collapsing() { - let path = PosixPath("tmp/"); - let path = path.push("/hmm"); - let path = path.normalize(); - assert_eq!(~"tmp/hmm", path.to_str()); - - let path = WindowsPath("tmp/"); - let path = path.push("/hmm"); - let path = path.normalize(); - assert_eq!(~"tmp\\hmm", path.to_str()); - } - - #[test] - fn test_filetype_foo_bar() { - let wp = PosixPath("foo.bar"); - assert_eq!(wp.filetype(), Some(~".bar")); - - let wp = WindowsPath("foo.bar"); - assert_eq!(wp.filetype(), Some(~".bar")); - } - - #[test] - fn test_filetype_foo() { - let wp = PosixPath("foo"); - assert_eq!(wp.filetype(), None); - - let wp = WindowsPath("foo"); - assert_eq!(wp.filetype(), None); - } - - #[test] - fn test_posix_paths() { - fn t(wp: &PosixPath, s: &str) { - let ss = wp.to_str(); - let sss = str::to_owned(s); - if (ss != sss) { - debug!("got %s", ss); - debug!("expected %s", sss); - assert_eq!(ss, sss); - } - } - - t(&(PosixPath("hi")), "hi"); - t(&(PosixPath("/lib")), "/lib"); - t(&(PosixPath("hi/there")), "hi/there"); - t(&(PosixPath("hi/there.txt")), "hi/there.txt"); - - t(&(PosixPath("hi/there.txt")), "hi/there.txt"); - t(&(PosixPath("hi/there.txt") - .with_filetype("")), "hi/there"); - - t(&(PosixPath("/a/b/c/there.txt") - .with_dirname("hi")), "hi/there.txt"); - - t(&(PosixPath("hi/there.txt") - .with_dirname(".")), "./there.txt"); - - t(&(PosixPath("a/b/c") - .push("..")), "a/b/c/.."); - - t(&(PosixPath("there.txt") - .with_filetype("o")), "there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o")), "hi/there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o") - .with_dirname("/usr/lib")), - "/usr/lib/there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o") - .with_dirname("/usr/lib/")), - "/usr/lib/there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o") - .with_dirname("/usr//lib//")), - "/usr/lib/there.o"); - - t(&(PosixPath("/usr/bin/rust") - .push_many([~"lib", ~"thingy.so"]) - .with_filestem("librustc")), - "/usr/bin/rust/lib/librustc.so"); - - } - - #[test] - fn test_normalize() { - fn t(wp: &PosixPath, s: &str) { - let ss = wp.to_str(); - let sss = str::to_owned(s); - if (ss != sss) { - debug!("got %s", ss); - debug!("expected %s", sss); - assert_eq!(ss, sss); - } - } - - t(&(PosixPath("hi/there.txt") - .with_dirname(".").normalize()), "there.txt"); - - t(&(PosixPath("a/b/../c/././/../foo.txt/").normalize()), - "a/foo.txt"); - - t(&(PosixPath("a/b/c") - .push("..").normalize()), "a/b"); - } - - #[test] - fn test_extract_unc_prefixes() { - assert!(windows::extract_unc_prefix("\\\\").is_none()); - assert!(windows::extract_unc_prefix("//").is_none()); - assert!(windows::extract_unc_prefix("\\\\hi").is_none()); - assert!(windows::extract_unc_prefix("//hi").is_none()); - assert!(windows::extract_unc_prefix("\\\\hi\\") == - Some((~"hi", ~"\\"))); - assert!(windows::extract_unc_prefix("//hi\\") == - Some((~"hi", ~"\\"))); - assert!(windows::extract_unc_prefix("\\\\hi\\there") == - Some((~"hi", ~"\\there"))); - assert!(windows::extract_unc_prefix("//hi/there") == - Some((~"hi", ~"/there"))); - assert!(windows::extract_unc_prefix( - "\\\\hi\\there\\friends.txt") == - Some((~"hi", ~"\\there\\friends.txt"))); - assert!(windows::extract_unc_prefix( - "//hi\\there\\friends.txt") == - Some((~"hi", ~"\\there\\friends.txt"))); - } - - #[test] - fn test_extract_drive_prefixes() { - assert!(windows::extract_drive_prefix("c").is_none()); - assert!(windows::extract_drive_prefix("c:") == - Some((~"c", ~""))); - assert!(windows::extract_drive_prefix("d:") == - Some((~"d", ~""))); - assert!(windows::extract_drive_prefix("z:") == - Some((~"z", ~""))); - assert!(windows::extract_drive_prefix("c:\\hi") == - Some((~"c", ~"\\hi"))); - assert!(windows::extract_drive_prefix("d:hi") == - Some((~"d", ~"hi"))); - assert!(windows::extract_drive_prefix("c:hi\\there.txt") == - Some((~"c", ~"hi\\there.txt"))); - assert!(windows::extract_drive_prefix("c:\\hi\\there.txt") == - Some((~"c", ~"\\hi\\there.txt"))); - } - - #[test] - fn test_windows_paths() { - fn t(wp: &WindowsPath, s: &str) { - let ss = wp.to_str(); - let sss = str::to_owned(s); - if (ss != sss) { - debug!("got %s", ss); - debug!("expected %s", sss); - assert_eq!(ss, sss); - } - } - - t(&(WindowsPath("hi")), "hi"); - t(&(WindowsPath("hi/there")), "hi\\there"); - t(&(WindowsPath("hi/there.txt")), "hi\\there.txt"); - - t(&(WindowsPath("there.txt") - .with_filetype("o")), "there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o")), "hi\\there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o") - .with_dirname("c:\\program files A")), - "c:\\program files A\\there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o") - .with_dirname("c:\\program files B\\")), - "c:\\program files B\\there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o") - .with_dirname("c:\\program files C\\/")), - "c:\\program files C\\there.o"); - - t(&(WindowsPath("c:\\program files (x86)\\rust") - .push_many([~"lib", ~"thingy.dll"]) - .with_filename("librustc.dll")), - "c:\\program files (x86)\\rust\\lib\\librustc.dll"); - - t(&(WindowsPath("\\\\computer\\share") - .unsafe_join(&WindowsPath("\\a"))), - "\\\\computer\\a"); - - t(&(WindowsPath("//computer/share") - .unsafe_join(&WindowsPath("\\a"))), - "\\\\computer\\a"); - - t(&(WindowsPath("//computer/share") - .unsafe_join(&WindowsPath("\\\\computer\\share"))), - "\\\\computer\\share"); - - t(&(WindowsPath("C:/whatever") - .unsafe_join(&WindowsPath("//computer/share/a/b"))), - "\\\\computer\\share\\a\\b"); - - t(&(WindowsPath("C:") - .unsafe_join(&WindowsPath("D:/foo"))), - "D:\\foo"); - - t(&(WindowsPath("C:") - .unsafe_join(&WindowsPath("B"))), - "C:B"); - - t(&(WindowsPath("C:") - .unsafe_join(&WindowsPath("/foo"))), - "C:\\foo"); - - t(&(WindowsPath("C:\\") - .unsafe_join(&WindowsPath("\\bar"))), - "C:\\bar"); - - t(&(WindowsPath("") - .unsafe_join(&WindowsPath(""))), - ""); - - t(&(WindowsPath("") - .unsafe_join(&WindowsPath("a"))), - "a"); - - t(&(WindowsPath("") - .unsafe_join(&WindowsPath("C:\\a"))), - "C:\\a"); - - t(&(WindowsPath("c:\\foo") - .normalize()), - "C:\\foo"); - } - - #[test] - fn test_windows_path_restrictions() { - assert_eq!(WindowsPath("hi").is_restricted(), false); - assert_eq!(WindowsPath("C:\\NUL").is_restricted(), true); - assert_eq!(WindowsPath("C:\\COM1.TXT").is_restricted(), true); - assert_eq!(WindowsPath("c:\\prn.exe").is_restricted(), true); - } -} diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs deleted file mode 100644 index 1c2b57bb2df..00000000000 --- a/src/libcore/pipes.rs +++ /dev/null @@ -1,916 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Runtime support for message passing with protocol enforcement. - - -Pipes consist of two endpoints. One endpoint can send messages and -the other can receive messages. The set of legal messages and which -directions they can flow at any given point are determined by a -protocol. Below is an example protocol. - -~~~ -proto! pingpong ( - ping: send { - ping -> pong - } - pong: recv { - pong -> ping - } -) -~~~ - -The `proto!` syntax extension will convert this into a module called -`pingpong`, which includes a set of types and functions that can be -used to write programs that follow the pingpong protocol. - -*/ - -/* IMPLEMENTATION NOTES - -The initial design for this feature is available at: - -https://github.com/eholk/rust/wiki/Proposal-for-channel-contracts - -Much of the design in that document is still accurate. There are -several components for the pipe implementation. First of all is the -syntax extension. To see how that works, it is best see comments in -libsyntax/ext/pipes.rs. - -This module includes two related pieces of the runtime -implementation: support for unbounded and bounded -protocols. The main difference between the two is the type of the -buffer that is carried along in the endpoint data structures. - - -The heart of the implementation is the packet type. It contains a -header and a payload field. Much of the code in this module deals with -the header field. This is where the synchronization information is -stored. In the case of a bounded protocol, the header also includes a -pointer to the buffer the packet is contained in. - -Packets represent a single message in a protocol. The payload field -gets instatiated at the type of the message, which is usually an enum -generated by the pipe compiler. Packets are conceptually single use, -although in bounded protocols they are reused each time around the -loop. - - -Packets are usually handled through a send_packet_buffered or -recv_packet_buffered object. Each packet is referenced by one -send_packet and one recv_packet, and these wrappers enforce that only -one end can send and only one end can receive. The structs also -include a destructor that marks packets are terminated if the sender -or receiver destroys the object before sending or receiving a value. - -The *_packet_buffered structs take two type parameters. The first is -the message type for the current packet (or state). The second -represents the type of the whole buffer. For bounded protocols, the -protocol compiler generates a struct with a field for each protocol -state. This generated struct is used as the buffer type parameter. For -unbounded protocols, the buffer is simply one packet, so there is a -shorthand struct called send_packet and recv_packet, where the buffer -type is just `packet<T>`. Using the same underlying structure for both -bounded and unbounded protocols allows for less code duplication. - -*/ - -use container::Container; -use cast::{forget, transmute, transmute_copy}; -use either::{Either, Left, Right}; -use kinds::Owned; -use libc; -use ops::Drop; -use option::{None, Option, Some}; -use unstable::finally::Finally; -use unstable::intrinsics; -use ptr; -use ptr::Ptr; -use task; -use vec; -use vec::OwnedVector; -use util::replace; - -static SPIN_COUNT: uint = 0; - -macro_rules! move_it ( - { $x:expr } => ( unsafe { let y = *ptr::to_unsafe_ptr(&($x)); y } ) -) - -#[deriving(Eq)] -enum State { - Empty, - Full, - Blocked, - Terminated -} - -pub struct BufferHeader { - // Tracks whether this buffer needs to be freed. We can probably - // get away with restricting it to 0 or 1, if we're careful. - ref_count: int, - - // We may want a drop, and to be careful about stringing this - // thing along. -} - -pub fn BufferHeader() -> BufferHeader { - BufferHeader { - ref_count: 0 - } -} - -// This is for protocols to associate extra data to thread around. -pub struct Buffer<T> { - header: BufferHeader, - data: T, -} - -pub struct PacketHeader { - state: State, - blocked_task: *rust_task, - - // This is a transmute_copy of a ~buffer, that can also be cast - // to a buffer_header if need be. - buffer: *libc::c_void, -} - -pub fn PacketHeader() -> PacketHeader { - PacketHeader { - state: Empty, - blocked_task: ptr::null(), - buffer: ptr::null() - } -} - -pub impl PacketHeader { - // Returns the old state. - 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) { - let old_task = swap_task(&mut self.blocked_task, ptr::null()); - if !old_task.is_null() { - rustrt::rust_task_deref(old_task) - } - match swap_state_acq(&mut self.state, Empty) { - Empty | Blocked => (), - Terminated => self.state = Terminated, - Full => self.state = Full - } - } - - // 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 { - assert!(self.buffer.is_not_null()); - transmute_copy(&self.buffer) - } - - fn set_buffer<T:Owned>(&mut self, b: ~Buffer<T>) { - unsafe { - self.buffer = transmute_copy(&b); - } - } -} - -pub struct Packet<T> { - header: PacketHeader, - payload: Option<T>, -} - -pub trait HasBuffer { - fn set_buffer(&mut self, b: *libc::c_void); -} - -impl<T:Owned> HasBuffer for Packet<T> { - fn set_buffer(&mut self, b: *libc::c_void) { - self.header.buffer = b; - } -} - -pub fn mk_packet<T:Owned>() -> Packet<T> { - Packet { - header: PacketHeader(), - payload: None, - } -} -fn unibuffer<T>() -> ~Buffer<Packet<T>> { - let mut b = ~Buffer { - header: BufferHeader(), - data: Packet { - header: PacketHeader(), - payload: None, - } - }; - - unsafe { - b.data.header.buffer = transmute_copy(&b); - } - b -} - -pub fn packet<T>() -> *mut Packet<T> { - let mut b = unibuffer(); - let p = ptr::to_mut_unsafe_ptr(&mut b.data); - // We'll take over memory management from here. - unsafe { - forget(b); - } - p -} - -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>) { - unsafe { - let p = init(transmute_copy(&buffer), &mut buffer.data); - forget(buffer); - (SendPacketBuffered(p), RecvPacketBuffered(p)) - } -} - -pub fn swap_task(dst: &mut *rust_task, src: *rust_task) -> *rust_task { - // It might be worth making both acquire and release versions of - // this. - unsafe { - transmute(intrinsics::atomic_xchg(transmute(dst), src as int)) - } -} - -#[allow(non_camel_case_types)] -pub type rust_task = libc::c_void; - -pub mod rustrt { - use libc; - use super::rust_task; - - pub extern { - #[rust_stack] - unsafe fn rust_get_task() -> *rust_task; - #[rust_stack] - unsafe fn rust_task_ref(task: *rust_task); - unsafe fn rust_task_deref(task: *rust_task); - - #[rust_stack] - unsafe fn task_clear_event_reject(task: *rust_task); - - unsafe fn task_wait_event(this: *rust_task, - killed: &mut *libc::c_void) - -> bool; - unsafe fn task_signal_event(target: *rust_task, event: *libc::c_void); - } -} - -fn wait_event(this: *rust_task) -> *libc::c_void { - unsafe { - let mut event = ptr::null(); - - let killed = rustrt::task_wait_event(this, &mut event); - if killed && !task::failing() { - fail!("killed") - } - event - } -} - -fn swap_state_acq(dst: &mut State, src: State) -> State { - unsafe { - transmute(intrinsics::atomic_xchg_acq(transmute(dst), src as int)) - } -} - -fn swap_state_rel(dst: &mut State, src: State) -> State { - unsafe { - transmute(intrinsics::atomic_xchg_rel(transmute(dst), src as int)) - } -} - -pub unsafe fn get_buffer<T>(p: *mut PacketHeader) -> ~Buffer<T> { - transmute((*p).buf_header()) -} - -// This could probably be done with SharedMutableState to avoid move_it!(). -struct BufferResource<T> { - buffer: ~Buffer<T>, - -} - -#[unsafe_destructor] -impl<T> Drop for BufferResource<T> { - fn finalize(&self) { - unsafe { - let this: &mut BufferResource<T> = transmute(self); - - let mut b = move_it!(this.buffer); - //let p = ptr::to_unsafe_ptr(*b); - //error!("drop %?", p); - let old_count = intrinsics::atomic_xsub_rel( - &mut b.header.ref_count, - 1); - //let old_count = atomic_xchng_rel(b.header.ref_count, 0); - if old_count == 1 { - // The new count is 0. - - // go go gadget drop glue - } - else { - forget(b) - } - } - } -} - -fn BufferResource<T>(mut b: ~Buffer<T>) -> BufferResource<T> { - //let p = ptr::to_unsafe_ptr(*b); - //error!("take %?", p); - unsafe { - intrinsics::atomic_xadd_acq(&mut b.header.ref_count, 1); - } - - BufferResource { - // tjc: ???? - buffer: b - } -} - -pub fn send<T,Tbuffer>(mut p: SendPacketBuffered<T,Tbuffer>, - payload: T) - -> bool { - let header = p.header(); - let p_ = p.unwrap(); - let p = unsafe { &mut *p_ }; - assert_eq!(ptr::to_unsafe_ptr(&(p.header)), header); - assert!(p.payload.is_none()); - p.payload = Some(payload); - let old_state = swap_state_rel(&mut p.header.state, Full); - match old_state { - Empty => { - // Yay, fastpath. - - // The receiver will eventually clean this up. - //unsafe { forget(p); } - return true; - } - Full => fail!("duplicate send"), - Blocked => { - debug!("waking up task for %?", p_); - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::task_signal_event( - old_task, - ptr::to_unsafe_ptr(&(p.header)) as *libc::c_void); - rustrt::rust_task_deref(old_task); - } - } - - // The receiver will eventually clean this up. - //unsafe { forget(p); } - return true; - } - Terminated => { - // The receiver will never receive this. Rely on drop_glue - // to clean everything up. - return false; - } - } -} - -/** Receives a message from a pipe. - -Fails if the sender closes the connection. - -*/ -pub fn recv<T:Owned,Tbuffer:Owned>( - p: RecvPacketBuffered<T, Tbuffer>) -> T { - try_recv(p).expect("connection closed") -} - -/** Attempts to receive a message from a pipe. - -Returns `None` if the sender has closed the connection without sending -a message, or `Some(T)` if a message was received. - -*/ -pub fn try_recv<T:Owned,Tbuffer:Owned>(mut p: RecvPacketBuffered<T, Tbuffer>) - -> Option<T> { - let p_ = p.unwrap(); - let p = unsafe { &mut *p_ }; - - do (|| { - try_recv_(p) - }).finally { - unsafe { - if task::failing() { - p.header.state = Terminated; - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - rustrt::rust_task_deref(old_task); - } - } - } - } -} - -fn try_recv_<T:Owned>(p: &mut Packet<T>) -> Option<T> { - // optimistic path - match p.header.state { - Full => { - let payload = replace(&mut p.payload, None); - p.header.state = Empty; - return Some(payload.unwrap()) - }, - Terminated => return None, - _ => {} - } - - // regular path - let this = unsafe { rustrt::rust_get_task() }; - unsafe { - rustrt::task_clear_event_reject(this); - rustrt::rust_task_ref(this); - }; - debug!("blocked = %x this = %x", p.header.blocked_task as uint, - this as uint); - let old_task = swap_task(&mut p.header.blocked_task, this); - debug!("blocked = %x this = %x old_task = %x", - p.header.blocked_task as uint, - this as uint, old_task as uint); - assert!(old_task.is_null()); - let mut first = true; - let mut count = SPIN_COUNT; - loop { - unsafe { - rustrt::task_clear_event_reject(this); - } - - let old_state = swap_state_acq(&mut p.header.state, - Blocked); - match old_state { - Empty => { - debug!("no data available on %?, going to sleep.", p); - if count == 0 { - wait_event(this); - } - else { - count -= 1; - // FIXME (#524): Putting the yield here destroys a lot - // of the benefit of spinning, since we still go into - // the scheduler at every iteration. However, without - // this everything spins too much because we end up - // sometimes blocking the thing we are waiting on. - task::yield(); - } - debug!("woke up, p.state = %?", copy p.header.state); - } - Blocked => if first { - fail!("blocking on already blocked packet") - }, - Full => { - let payload = replace(&mut p.payload, None); - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::rust_task_deref(old_task); - } - } - p.header.state = Empty; - return Some(payload.unwrap()) - } - Terminated => { - // This assert detects when we've accidentally unsafely - // casted too big of a number to a state. - assert_eq!(old_state, Terminated); - - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::rust_task_deref(old_task); - } - } - return None; - } - } - first = false; - } -} - -/// Returns true if messages are available. -pub fn peek<T:Owned,Tb:Owned>(p: &mut RecvPacketBuffered<T, Tb>) -> bool { - unsafe { - match (*p.header()).state { - Empty | Terminated => false, - Blocked => fail!("peeking on blocked packet"), - Full => true - } - } -} - -fn sender_terminate<T:Owned>(p: *mut Packet<T>) { - let p = unsafe { - &mut *p - }; - match swap_state_rel(&mut p.header.state, Terminated) { - Empty => { - // The receiver will eventually clean up. - } - Blocked => { - // wake up the target - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::task_signal_event( - old_task, - ptr::to_unsafe_ptr(&(p.header)) as *libc::c_void); - rustrt::rust_task_deref(old_task); - } - } - // The receiver will eventually clean up. - } - Full => { - // This is impossible - fail!("you dun goofed") - } - Terminated => { - assert!(p.header.blocked_task.is_null()); - // I have to clean up, use drop_glue - } - } -} - -fn receiver_terminate<T:Owned>(p: *mut Packet<T>) { - let p = unsafe { - &mut *p - }; - match swap_state_rel(&mut p.header.state, Terminated) { - Empty => { - assert!(p.header.blocked_task.is_null()); - // the sender will clean up - } - Blocked => { - let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); - if !old_task.is_null() { - unsafe { - rustrt::rust_task_deref(old_task); - assert_eq!(old_task, rustrt::rust_get_task()); - } - } - } - Terminated | Full => { - assert!(p.header.blocked_task.is_null()); - // I have to clean up, use drop_glue - } - } -} - -/** Returns when one of the packet headers reports data is available. - -This function is primarily intended for building higher level waiting -functions, such as `select`, `select2`, etc. - -It takes a vector slice of packet_headers and returns an index into -that vector. The index points to an endpoint that has either been -closed by the sender or has a message waiting to be received. - -*/ -pub fn wait_many<T: Selectable>(pkts: &mut [T]) -> uint { - let this = unsafe { - rustrt::rust_get_task() - }; - - unsafe { - rustrt::task_clear_event_reject(this); - } - - let mut data_avail = false; - let mut ready_packet = pkts.len(); - for vec::eachi_mut(pkts) |i, p| { - unsafe { - let p = &mut *p.header(); - let old = p.mark_blocked(this); - match old { - Full | Terminated => { - data_avail = true; - ready_packet = i; - (*p).state = old; - break; - } - Blocked => fail!("blocking on blocked packet"), - Empty => () - } - } - } - - while !data_avail { - debug!("sleeping on %? packets", pkts.len()); - let event = wait_event(this) as *PacketHeader; - - let mut pos = None; - for vec::eachi_mut(pkts) |i, p| { - if p.header() == event { - pos = Some(i); - break; - } - }; - - match pos { - Some(i) => { - ready_packet = i; - data_avail = true; - } - None => debug!("ignoring spurious event, %?", event) - } - } - - debug!("%?", &mut pkts[ready_packet]); - - for vec::each_mut(pkts) |p| { - unsafe { - (*p.header()).unblock() - } - } - - debug!("%?, %?", ready_packet, &mut pkts[ready_packet]); - - unsafe { - assert!((*pkts[ready_packet].header()).state == Full - || (*pkts[ready_packet].header()).state == Terminated); - } - - ready_packet -} - -/** The sending end of a pipe. It can be used to send exactly one -message. - -*/ -pub type SendPacket<T> = SendPacketBuffered<T, Packet<T>>; - -pub fn SendPacket<T>(p: *mut Packet<T>) -> SendPacket<T> { - SendPacketBuffered(p) -} - -pub struct SendPacketBuffered<T, Tbuffer> { - p: Option<*mut Packet<T>>, - buffer: Option<BufferResource<Tbuffer>>, -} - -#[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> Drop for SendPacketBuffered<T,Tbuffer> { - fn finalize(&self) { - unsafe { - let this: &mut SendPacketBuffered<T,Tbuffer> = transmute(self); - if this.p != None { - let p = replace(&mut this.p, None); - sender_terminate(p.unwrap()) - } - } - } -} - -pub fn SendPacketBuffered<T,Tbuffer>(p: *mut Packet<T>) - -> SendPacketBuffered<T,Tbuffer> { - SendPacketBuffered { - p: Some(p), - buffer: unsafe { - Some(BufferResource(get_buffer(&mut (*p).header))) - } - } -} - -pub impl<T,Tbuffer> SendPacketBuffered<T,Tbuffer> { - fn unwrap(&mut self) -> *mut Packet<T> { - replace(&mut self.p, None).unwrap() - } - - fn header(&mut self) -> *mut PacketHeader { - match self.p { - Some(packet) => unsafe { - let packet = &mut *packet; - let header = ptr::to_mut_unsafe_ptr(&mut packet.header); - header - }, - None => fail!("packet already consumed") - } - } - - fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { - //error!("send reuse_buffer"); - replace(&mut self.buffer, None).unwrap() - } -} - -/// Represents the receive end of a pipe. It can receive exactly one -/// message. -pub type RecvPacket<T> = RecvPacketBuffered<T, Packet<T>>; - -pub fn RecvPacket<T>(p: *mut Packet<T>) -> RecvPacket<T> { - RecvPacketBuffered(p) -} - -pub struct RecvPacketBuffered<T, Tbuffer> { - p: Option<*mut Packet<T>>, - buffer: Option<BufferResource<Tbuffer>>, -} - -#[unsafe_destructor] -impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> { - fn finalize(&self) { - unsafe { - let this: &mut RecvPacketBuffered<T,Tbuffer> = transmute(self); - if this.p != None { - let p = replace(&mut this.p, None); - receiver_terminate(p.unwrap()) - } - } - } -} - -pub impl<T:Owned,Tbuffer:Owned> RecvPacketBuffered<T, Tbuffer> { - fn unwrap(&mut self) -> *mut Packet<T> { - replace(&mut self.p, None).unwrap() - } - - fn reuse_buffer(&mut self) -> BufferResource<Tbuffer> { - replace(&mut self.buffer, None).unwrap() - } -} - -impl<T:Owned,Tbuffer:Owned> Selectable for RecvPacketBuffered<T, Tbuffer> { - fn header(&mut self) -> *mut PacketHeader { - match self.p { - Some(packet) => unsafe { - let packet = &mut *packet; - let header = ptr::to_mut_unsafe_ptr(&mut packet.header); - header - }, - None => fail!("packet already consumed") - } - } -} - -pub fn RecvPacketBuffered<T,Tbuffer>(p: *mut Packet<T>) - -> RecvPacketBuffered<T,Tbuffer> { - RecvPacketBuffered { - p: Some(p), - buffer: unsafe { - Some(BufferResource(get_buffer(&mut (*p).header))) - } - } -} - -pub fn entangle<T>() -> (SendPacket<T>, RecvPacket<T>) { - let p = packet(); - (SendPacket(p), RecvPacket(p)) -} - -/** Receives a message from one of two endpoints. - -The return value is `left` if the first endpoint received something, -or `right` if the second endpoint receives something. In each case, -the result includes the other endpoint as well so it can be used -again. Below is an example of using `select2`. - -~~~ -match select2(a, b) { - left((none, b)) { - // endpoint a was closed. - } - right((a, none)) { - // endpoint b was closed. - } - left((Some(_), b)) { - // endpoint a received a message - } - right(a, Some(_)) { - // endpoint b received a message. - } -} -~~~ - -Sometimes messages will be available on both endpoints at once. In -this case, `select2` may return either `left` or `right`. - -*/ -pub fn select2<A:Owned,Ab:Owned,B:Owned,Bb:Owned>( - mut a: RecvPacketBuffered<A, Ab>, - mut b: RecvPacketBuffered<B, Bb>) - -> Either<(Option<A>, RecvPacketBuffered<B, Bb>), - (RecvPacketBuffered<A, Ab>, Option<B>)> { - let mut endpoints = [ a.header(), b.header() ]; - let i = wait_many(endpoints); - match i { - 0 => Left((try_recv(a), b)), - 1 => Right((a, try_recv(b))), - _ => fail!("select2 return an invalid packet") - } -} - -pub trait Selectable { - fn header(&mut self) -> *mut PacketHeader; -} - -impl Selectable for *mut PacketHeader { - fn header(&mut self) -> *mut PacketHeader { *self } -} - -/// Returns the index of an endpoint that is ready to receive. -pub fn selecti<T:Selectable>(endpoints: &mut [T]) -> uint { - wait_many(endpoints) -} - -/// Returns 0 or 1 depending on which endpoint is ready to receive -pub fn select2i<A:Selectable,B:Selectable>(a: &mut A, b: &mut B) - -> Either<(), ()> { - let mut endpoints = [ a.header(), b.header() ]; - match wait_many(endpoints) { - 0 => Left(()), - 1 => Right(()), - _ => fail!("wait returned unexpected index") - } -} - -/// Waits on a set of endpoints. Returns a message, its index, and a -/// list of the remaining endpoints. -pub fn select<T:Owned,Tb:Owned>(mut endpoints: ~[RecvPacketBuffered<T, Tb>]) - -> (uint, - Option<T>, - ~[RecvPacketBuffered<T, Tb>]) { - let mut endpoint_headers = ~[]; - for vec::each_mut(endpoints) |endpoint| { - endpoint_headers.push(endpoint.header()); - } - - let ready = wait_many(endpoint_headers); - let mut remaining = endpoints; - let port = remaining.swap_remove(ready); - let result = try_recv(port); - (ready, result, remaining) -} - -pub mod rt { - use option::{None, Option, Some}; - - // These are used to hide the option constructors from the - // compiler because their names are changing - pub fn make_some<T>(val: T) -> Option<T> { Some(val) } - pub fn make_none<T>() -> Option<T> { None } -} - -#[cfg(test)] -mod test { - use either::Right; - use comm::{Chan, Port, oneshot, recv_one, stream, Select2, - GenericChan, Peekable}; - - #[test] - fn test_select2() { - let (p1, c1) = stream(); - let (p2, c2) = stream(); - - c1.send(~"abc"); - - let mut tuple = (p1, p2); - match tuple.select() { - Right(_) => fail!(), - _ => (), - } - - c2.send(123); - } - - #[test] - fn test_oneshot() { - let (p, c) = oneshot(); - - c.send(()); - - recv_one(p) - } - - #[test] - fn test_peek_terminated() { - let (port, chan): (Port<int>, Chan<int>) = stream(); - - { - // Destroy the channel - let _chan = chan; - } - - assert!(!port.peek()); - } -} diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs deleted file mode 100644 index 58d0c40efa0..00000000000 --- a/src/libcore/prelude.rs +++ /dev/null @@ -1,111 +0,0 @@ -// 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 Rust prelude. Imported into every module by default. - -/* Reexported core operators */ - -pub use either::{Either, Left, Right}; -pub use kinds::{Const, Copy, Owned}; -pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; -pub use ops::{BitAnd, BitOr, BitXor}; -pub use ops::{Drop}; -pub use ops::{Shl, Shr, Index}; -pub use option::{Option, Some, None}; -pub use result::{Result, Ok, Err}; - -/* Reexported functions */ - -pub use io::{print, println}; - -/* 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 num::{Num, NumCast}; -pub use num::{Orderable, Signed, Unsigned, Round}; -pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; -pub use num::{Integer, Fractional, Real, RealExt}; -pub use num::{Bitwise, BitCount, Bounded}; -pub use num::{Primitive, Int, Float}; -pub use path::GenericPath; -pub use path::Path; -pub use path::PosixPath; -pub use path::WindowsPath; -pub use ptr::Ptr; -pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; -pub use str::{StrSlice, OwnedStr}; -pub use from_str::{FromStr}; -pub use to_bytes::IterBytes; -pub use to_str::{ToStr, ToStrConsume}; -pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; -pub use tuple::{CloneableTuple2, CloneableTuple3, CloneableTuple4, CloneableTuple5}; -pub use tuple::{CloneableTuple6, CloneableTuple7, CloneableTuple8, CloneableTuple9}; -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::{ImmutableEqVector, ImmutableCopyableVector}; -pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector}; -pub use io::{Reader, ReaderUtil, Writer, WriterUtil}; - -/* 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/libcore/ptr.rs b/src/libcore/ptr.rs deleted file mode 100644 index f6cc00ccc86..00000000000 --- a/src/libcore/ptr.rs +++ /dev/null @@ -1,561 +0,0 @@ -// 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. - -//! Unsafe pointer utility functions - -use cast; -use libc; -use libc::{c_void, size_t}; -use option::{Option, Some, None}; -use sys; - -#[cfg(not(test))] use cmp::{Eq, Ord}; -use uint; - -pub mod libc_ { - use libc::c_void; - use libc; - - #[nolink] - #[abi = "cdecl"] - pub extern { - #[rust_stack] - unsafe fn memmove(dest: *mut c_void, - src: *const c_void, - n: libc::size_t) - -> *c_void; - - #[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 { - (ptr as uint + count * sys::size_of::<T>()) as *T -} - -/// Calculate the offset from a const pointer -#[inline(always)] -pub fn const_offset<T>(ptr: *const T, count: uint) -> *const T { - (ptr as uint + count * sys::size_of::<T>()) as *T -} - -/// Calculate the offset from a mut pointer -#[inline(always)] -pub fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T { - (ptr as uint + count * sys::size_of::<T>()) as *mut T -} - -/// Return the offset of the first null pointer in `buf`. -#[inline(always)] -pub unsafe fn buf_len<T>(buf: **T) -> uint { - position(buf, |i| *i == null()) -} - -/// Return the first offset `i` such that `f(buf[i]) == true`. -#[inline(always)] -pub unsafe fn position<T>(buf: *T, f: &fn(&T) -> bool) -> uint { - let mut i = 0; - loop { - if f(&(*offset(buf, i))) { return i; } - else { i += 1; } - } -} - -/// Create an unsafe null pointer -#[inline(always)] -pub fn null<T>() -> *T { unsafe { cast::transmute(0u) } } - -/// Create an unsafe mutable null pointer -#[inline(always)] -pub fn mut_null<T>() -> *mut T { unsafe { cast::transmute(0u) } } - -/// Returns true if the pointer is equal to the null pointer. -#[inline(always)] -pub fn is_null<T>(ptr: *const T) -> bool { ptr == null() } - -/// Returns true if the pointer is not equal to the null pointer. -#[inline(always)] -pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) } - -/** - * 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 = "32")] -pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { - use unstable::intrinsics::memmove32; - let n = count * sys::size_of::<T>(); - memmove32(dst as *mut u8, src as *u8, n as u32); -} -#[inline(always)] -#[cfg(target_word_size = "64")] -pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) { - use unstable::intrinsics::memmove64; - let n = count * sys::size_of::<T>(); - memmove64(dst as *mut u8, src as *u8, n as u64); -} - -#[inline(always)] -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); -} - -/** - 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) } -} - -/** - 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. -*/ -#[inline(always)] -pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T { - unsafe { cast::transmute(thing) } -} - -/** - 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. -*/ -#[inline(always)] -pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T { - unsafe { cast::transmute(thing) } -} - -/** - 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.) -*/ -#[inline(always)] -pub fn to_uint<T>(thing: &T) -> uint { - unsafe { - cast::transmute(thing) - } -} - -/// 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) -} - -/** - Given a **T (pointer to an array of pointers), - iterate through each *T, up to the provided `len`, - passing to the provided callback function - - SAFETY NOTE: Pointer-arithmetic. Dragons be here. -*/ -pub unsafe fn array_each_with_len<T>(arr: **T, len: uint, cb: &fn(*T)) { - debug!("array_each_with_len: before iterate"); - if (arr as uint == 0) { - fail!("ptr::array_each_with_len failure: arr input is null pointer"); - } - //let start_ptr = *arr; - uint::iterate(0, len, |e| { - let n = offset(arr, e); - cb(*n); - true - }); - debug!("array_each_with_len: after iterate"); -} - -/** - Given a null-pointer-terminated **T (pointer to - an array of pointers), iterate through each *T, - passing to the provided callback function - - SAFETY NOTE: This will only work with a null-terminated - pointer array. Barely less-dodgey Pointer Arithmetic. - Dragons be here. -*/ -pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) { - if (arr as uint == 0) { - fail!("ptr::array_each_with_len failure: arr input is null pointer"); - } - let len = buf_len(arr); - debug!("array_each inferred len: %u", - len); - array_each_with_len(arr, len, cb); -} - -pub trait Ptr<T> { - fn is_null(&const self) -> bool; - fn is_not_null(&const self) -> bool; - unsafe fn to_option(&const self) -> Option<&T>; - fn offset(&self, count: uint) -> Self; -} - -/// Extension methods for immutable pointers -impl<T> Ptr<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) } - - /// Returns true if the pointer is not equal to the null pointer. - #[inline(always)] - fn is_not_null(&const self) -> bool { is_not_null(*self) } - - /// - /// Returns `None` if the pointer is null, or else returns the value wrapped - /// in `Some`. - /// - /// # Safety Notes - /// - /// While this method is useful for null-safety, it is important to note - /// that this is still an unsafe operation because the returned value could - /// be pointing to invalid memory. - /// - #[inline(always)] - unsafe fn to_option(&const self) -> Option<&T> { - if self.is_null() { None } else { - Some(cast::transmute(*self)) - } - } - - /// Calculates the offset from a pointer. - #[inline(always)] - fn offset(&self, count: uint) -> *T { offset(*self, count) } -} - -/// Extension methods for mutable pointers -impl<T> Ptr<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) } - - /// Returns true if the pointer is not equal to the null pointer. - #[inline(always)] - fn is_not_null(&const self) -> bool { is_not_null(*self) } - - /// - /// Returns `None` if the pointer is null, or else returns the value wrapped - /// in `Some`. - /// - /// # Safety Notes - /// - /// While this method is useful for null-safety, it is important to note - /// that this is still an unsafe operation because the returned value could - /// be pointing to invalid memory. - /// - #[inline(always)] - unsafe fn to_option(&const self) -> Option<&T> { - if self.is_null() { None } else { - Some(cast::transmute(*self)) - } - } - - /// Calculates the offset from a mutable pointer. - #[inline(always)] - fn offset(&self, count: uint) -> *mut T { mut_offset(*self, count) } -} - -// Equality for pointers -#[cfg(not(test))] -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; - } - } - #[inline(always)] - fn ne(&self, other: &*const T) -> bool { !(*self).eq(other) } -} - -// Comparison for pointers -#[cfg(not(test))] -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; - } - } - #[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; - } - } - #[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; - } - } - #[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) - } -} - -#[cfg(test)] -pub mod ptr_tests { - use super::*; - use prelude::*; - - #[test] - fn test() { - unsafe { - struct Pair { - fst: int, - snd: int - }; - let mut p = Pair {fst: 10, snd: 20}; - let pptr: *mut Pair = &mut p; - let iptr: *mut int = cast::transmute(pptr); - assert_eq!(*iptr, 10); - *iptr = 30; - assert_eq!(*iptr, 30); - assert_eq!(p.fst, 30); - - *pptr = Pair {fst: 50, snd: 60}; - assert_eq!(*iptr, 50); - assert_eq!(p.fst, 50); - assert_eq!(p.snd, 60); - - let v0 = ~[32000u16, 32001u16, 32002u16]; - let mut v1 = ~[0u16, 0u16, 0u16]; - - copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 1u), - offset(vec::raw::to_ptr(v0), 1u), 1u); - assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16)); - copy_memory(vec::raw::to_mut_ptr(v1), - offset(vec::raw::to_ptr(v0), 2u), 1u); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && - v1[2] == 0u16)); - copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 2u), - vec::raw::to_ptr(v0), 1u); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && - v1[2] == 32000u16)); - } - } - - #[test] - fn test_position() { - use str::as_c_str; - use libc::c_char; - - let s = ~"hello"; - unsafe { - assert!(2u == as_c_str(s, |p| position(p, - |c| *c == 'l' as c_char))); - assert!(4u == as_c_str(s, |p| position(p, - |c| *c == 'o' as c_char))); - assert!(5u == as_c_str(s, |p| position(p, - |c| *c == 0 as c_char))); - } - } - - #[test] - fn test_buf_len() { - let s0 = ~"hello"; - let s1 = ~"there"; - let s2 = ~"thing"; - do str::as_c_str(s0) |p0| { - do str::as_c_str(s1) |p1| { - do str::as_c_str(s2) |p2| { - let v = ~[p0, p1, p2, null()]; - do vec::as_imm_buf(v) |vp, len| { - assert_eq!(unsafe { buf_len(vp) }, 3u); - assert_eq!(len, 4u); - } - } - } - } - } - - #[test] - fn test_is_null() { - let p: *int = null(); - assert!(p.is_null()); - assert!(!p.is_not_null()); - - let q = offset(p, 1u); - assert!(!q.is_null()); - assert!(q.is_not_null()); - - let mp: *mut int = mut_null(); - assert!(mp.is_null()); - assert!(!mp.is_not_null()); - - let mq = mp.offset(1u); - assert!(!mq.is_null()); - assert!(mq.is_not_null()); - } - - #[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); - - let q: *int = &2; - assert_eq!(q.to_option().unwrap(), &2); // FIXME (#6641) - - let p: *mut int = mut_null(); - assert_eq!(p.to_option(), None); // FIXME (#6641) - - let q: *mut int = &mut 2; - assert_eq!(q.to_option().unwrap(), &2); // FIXME (#6641) - } - - #[test] - fn test_ptr_array_each_with_len() { - unsafe { - let one = ~"oneOne"; - let two = ~"twoTwo"; - let three = ~"threeThree"; - let arr: ~[*i8] = ~[ - ::cast::transmute(&one[0]), - ::cast::transmute(&two[0]), - ::cast::transmute(&three[0]), - ]; - let expected_arr = [ - one, two, three - ]; - let arr_ptr = &arr[0]; - let mut ctr = 0; - let mut iteration_count = 0; - array_each_with_len(arr_ptr, arr.len(), - |e| { - let actual = str::raw::from_c_str(e); - let expected = copy expected_arr[ctr]; - debug!( - "test_ptr_array_each e: %s, a: %s", - expected, actual); - assert_eq!(actual, expected); - ctr += 1; - iteration_count += 1; - }); - assert_eq!(iteration_count, 3u); - } - } - #[test] - fn test_ptr_array_each() { - unsafe { - let one = ~"oneOne"; - let two = ~"twoTwo"; - let three = ~"threeThree"; - let arr: ~[*i8] = ~[ - ::cast::transmute(&one[0]), - ::cast::transmute(&two[0]), - ::cast::transmute(&three[0]), - // fake a null terminator - 0 as *i8 - ]; - let expected_arr = [ - one, two, three - ]; - let arr_ptr = &arr[0]; - let mut ctr = 0; - let mut iteration_count = 0; - array_each(arr_ptr, |e| { - let actual = str::raw::from_c_str(e); - let expected = copy expected_arr[ctr]; - debug!( - "test_ptr_array_each e: %s, a: %s", - expected, actual); - assert_eq!(actual, expected); - ctr += 1; - iteration_count += 1; - }); - assert_eq!(iteration_count, 3); - } - } - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_ptr_array_each_with_len_null_ptr() { - unsafe { - array_each_with_len(0 as **libc::c_char, 1, |e| { - str::raw::from_c_str(e); - }); - } - } - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_ptr_array_each_null_ptr() { - unsafe { - array_each(0 as **libc::c_char, |e| { - str::raw::from_c_str(e); - }); - } - } -} diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs deleted file mode 100644 index 84dd7d187e4..00000000000 --- a/src/libcore/rand.rs +++ /dev/null @@ -1,1092 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -Random number generation. - -The key functions are `random()` and `RngUtil::gen()`. These are polymorphic -and so can be used to generate any type that implements `Rand`. Type inference -means that often a simple call to `rand::random()` or `rng.gen()` will -suffice, but sometimes an annotation is required, e.g. `rand::random::<float>()`. - -See the `distributions` submodule for sampling random numbers from -distributions like normal and exponential. - -# Examples -~~~ -use core::rand::RngUtil; - -fn main() { - let rng = rand::rng(); - if rng.gen() { // bool - println(fmt!("int: %d, uint: %u", rng.gen(), rng.gen())) - } -} -~~~ - -~~~ -fn main () { - let tuple_ptr = rand::random::<~(f64, char)>(); - println(fmt!("%?", tuple_ptr)) -} -~~~ -*/ - - -use int; -use prelude::*; -use str; -use u32; -use uint; -use util; -use vec; -use libc::size_t; - -#[path="rand/distributions.rs"] -pub mod distributions; - -/// A type that can be randomly generated using an Rng -pub trait Rand { - fn rand<R: Rng>(rng: &mut R) -> Self; -} - -impl Rand for int { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> int { - if int::bits == 32 { - rng.next() as int - } else { - rng.gen::<i64>() as int - } - } -} - -impl Rand for i8 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> i8 { - rng.next() as i8 - } -} - -impl Rand for i16 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> i16 { - rng.next() as i16 - } -} - -impl Rand for i32 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> i32 { - rng.next() as i32 - } -} - -impl Rand for i64 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> i64 { - (rng.next() as i64 << 32) | rng.next() as i64 - } -} - -impl Rand for uint { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> uint { - if uint::bits == 32 { - rng.next() as uint - } else { - rng.gen::<u64>() as uint - } - } -} - -impl Rand for u8 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> u8 { - rng.next() as u8 - } -} - -impl Rand for u16 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> u16 { - rng.next() as u16 - } -} - -impl Rand for u32 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> u32 { - rng.next() - } -} - -impl Rand for u64 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> u64 { - (rng.next() as u64 << 32) | rng.next() as u64 - } -} - -impl Rand for float { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> float { - rng.gen::<f64>() as float - } -} - -impl Rand for f32 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> f32 { - rng.gen::<f64>() as f32 - } -} - -static scale : f64 = (u32::max_value as f64) + 1.0f64; -impl Rand for f64 { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> f64 { - let u1 = rng.next() as f64; - let u2 = rng.next() as f64; - let u3 = rng.next() as f64; - - ((u1 / scale + u2) / scale + u3) / scale - } -} - -impl Rand for char { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> char { - rng.next() as char - } -} - -impl Rand for bool { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> bool { - rng.next() & 1u32 == 1u32 - } -} - -macro_rules! tuple_impl { - // use variables to indicate the arity of the tuple - ($($tyvar:ident),* ) => { - // the trailing commas are for the 1 tuple - impl< - $( $tyvar : Rand ),* - > Rand for ( $( $tyvar ),* , ) { - - #[inline] - fn rand<R: Rng>(_rng: &mut R) -> ( $( $tyvar ),* , ) { - ( - // use the $tyvar's to get the appropriate number of - // repeats (they're not actually needed) - $( - _rng.gen::<$tyvar>() - ),* - , - ) - } - } - } -} - -impl Rand for () { - #[inline] - fn rand<R: Rng>(_: &mut R) -> () { () } -} -tuple_impl!{A} -tuple_impl!{A, B} -tuple_impl!{A, B, C} -tuple_impl!{A, B, C, D} -tuple_impl!{A, B, C, D, E} -tuple_impl!{A, B, C, D, E, F} -tuple_impl!{A, B, C, D, E, F, G} -tuple_impl!{A, B, C, D, E, F, G, H} -tuple_impl!{A, B, C, D, E, F, G, H, I} -tuple_impl!{A, B, C, D, E, F, G, H, I, J} - -impl<T:Rand> Rand for Option<T> { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> Option<T> { - if rng.gen() { - Some(rng.gen()) - } else { - None - } - } -} - -impl<T: Rand> Rand for ~T { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> ~T { ~rng.gen() } -} - -impl<T: Rand> Rand for @T { - #[inline] - fn rand<R: Rng>(rng: &mut R) -> @T { @rng.gen() } -} - -#[abi = "cdecl"] -pub mod rustrt { - use libc::size_t; - - pub extern { - unsafe fn rand_seed_size() -> size_t; - unsafe fn rand_gen_seed(buf: *mut u8, sz: size_t); - } -} - -/// A random number generator -pub trait Rng { - /// Return the next random integer - pub fn next(&mut self) -> u32; -} - -/// A value with a particular weight compared to other values -pub struct Weighted<T> { - weight: uint, - item: T, -} - -pub trait RngUtil { - /// Return a random value of a Rand type - fn gen<T:Rand>(&mut self) -> T; - /** - * Return a int randomly chosen from the range [start, end), - * failing if start >= end - */ - fn gen_int_range(&mut self, start: int, end: int) -> int; - /** - * Return a uint randomly chosen from the range [start, end), - * failing if start >= end - */ - fn gen_uint_range(&mut self, start: uint, end: uint) -> uint; - /** - * Return a char randomly chosen from chars, failing if chars is empty - */ - fn gen_char_from(&mut self, chars: &str) -> char; - /** - * Return a bool with a 1 in n chance of true - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * println(fmt!("%b",rng.gen_weighted_bool(3))); - * } - * ~~~ - */ - fn gen_weighted_bool(&mut self, n: uint) -> bool; - /** - * Return a random string of the specified length composed of A-Z,a-z,0-9 - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * println(rng.gen_str(8)); - * } - * ~~~ - */ - fn gen_str(&mut self, len: uint) -> ~str; - /** - * Return a random byte string of the specified length - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * println(fmt!("%?",rng.gen_bytes(8))); - * } - * ~~~ - */ - fn gen_bytes(&mut self, len: uint) -> ~[u8]; - /** - * Choose an item randomly, failing if values is empty - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * println(fmt!("%d",rng.choose([1,2,4,8,16,32]))); - * } - * ~~~ - */ - fn choose<T:Copy>(&mut self, values: &[T]) -> T; - /// Choose Some(item) randomly, returning None if values is empty - fn choose_option<T:Copy>(&mut self, values: &[T]) -> Option<T>; - /** - * Choose an item respecting the relative weights, failing if the sum of - * the weights is 0 - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * let x = [rand::Weighted {weight: 4, item: 'a'}, - * rand::Weighted {weight: 2, item: 'b'}, - * rand::Weighted {weight: 2, item: 'c'}]; - * println(fmt!("%c",rng.choose_weighted(x))); - * } - * ~~~ - */ - fn choose_weighted<T:Copy>(&mut self, v : &[Weighted<T>]) -> T; - /** - * Choose Some(item) respecting the relative weights, returning none if - * the sum of the weights is 0 - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * let x = [rand::Weighted {weight: 4, item: 'a'}, - * rand::Weighted {weight: 2, item: 'b'}, - * rand::Weighted {weight: 2, item: 'c'}]; - * println(fmt!("%?",rng.choose_weighted_option(x))); - * } - * ~~~ - */ - fn choose_weighted_option<T:Copy>(&mut self, v: &[Weighted<T>]) - -> Option<T>; - /** - * Return a vec containing copies of the items, in order, where - * the weight of the item determines how many copies there are - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * let x = [rand::Weighted {weight: 4, item: 'a'}, - * rand::Weighted {weight: 2, item: 'b'}, - * rand::Weighted {weight: 2, item: 'c'}]; - * println(fmt!("%?",rng.weighted_vec(x))); - * } - * ~~~ - */ - fn weighted_vec<T:Copy>(&mut self, v: &[Weighted<T>]) -> ~[T]; - /** - * Shuffle a vec - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * println(fmt!("%?",rng.shuffle([1,2,3]))); - * } - * ~~~ - */ - fn shuffle<T:Copy>(&mut self, values: &[T]) -> ~[T]; - /** - * Shuffle a mutable vec in place - * - * *Example* - * - * ~~~ - * - * use core::rand::RngUtil; - * - * fn main() { - * rng = rand::rng(); - * let mut y = [1,2,3]; - * rng.shuffle_mut(y); - * println(fmt!("%?",y)); - * rng.shuffle_mut(y); - * println(fmt!("%?",y)); - * } - * ~~~ - */ - fn shuffle_mut<T>(&mut self, values: &mut [T]); -} - -/// Extension methods for random number generators -impl<R: Rng> RngUtil for R { - /// Return a random value for a Rand type - #[inline(always)] - fn gen<T: Rand>(&mut self) -> T { - Rand::rand(self) - } - - /** - * Return an int randomly chosen from the range [start, end), - * failing if start >= end - */ - fn gen_int_range(&mut self, start: int, end: int) -> int { - assert!(start < end); - start + int::abs(self.gen::<int>() % (end - start)) - } - - /** - * Return a uint randomly chosen from the range [start, end), - * failing if start >= end - */ - fn gen_uint_range(&mut self, start: uint, end: uint) -> uint { - assert!(start < end); - start + (self.gen::<uint>() % (end - start)) - } - - /** - * Return a char randomly chosen from chars, failing if chars is empty - */ - 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) } - self.choose(cs) - } - - /// Return a bool with a 1-in-n chance of true - fn gen_weighted_bool(&mut self, n: uint) -> bool { - if n == 0u { - true - } else { - self.gen_uint_range(1u, n + 1u) == 1u - } - } - - /** - * Return a random string of the specified length composed of A-Z,a-z,0-9 - */ - fn gen_str(&mut self, len: uint) -> ~str { - let charset = ~"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - abcdefghijklmnopqrstuvwxyz\ - 0123456789"; - let mut s = ~""; - let mut i = 0u; - while (i < len) { - s = s + str::from_char(self.gen_char_from(charset)); - i += 1u; - } - s - } - - /// Return a random byte string of the specified length - fn gen_bytes(&mut self, len: uint) -> ~[u8] { - do vec::from_fn(len) |_i| { - self.gen() - } - } - - /// Choose an item randomly, failing if values is empty - fn choose<T:Copy>(&mut self, values: &[T]) -> T { - self.choose_option(values).get() - } - - /// Choose Some(item) randomly, returning None if values is empty - fn choose_option<T:Copy>(&mut self, values: &[T]) -> Option<T> { - if values.is_empty() { - None - } else { - Some(values[self.gen_uint_range(0u, values.len())]) - } - } - /** - * Choose an item respecting the relative weights, failing if the sum of - * the weights is 0 - */ - fn choose_weighted<T:Copy>(&mut self, v: &[Weighted<T>]) -> T { - self.choose_weighted_option(v).get() - } - - /** - * Choose Some(item) respecting the relative weights, returning none if - * the sum of the weights is 0 - */ - fn choose_weighted_option<T:Copy>(&mut self, v: &[Weighted<T>]) - -> Option<T> { - let mut total = 0u; - for v.each |item| { - total += item.weight; - } - if total == 0u { - return None; - } - let chosen = self.gen_uint_range(0u, total); - let mut so_far = 0u; - for v.each |item| { - so_far += item.weight; - if so_far > chosen { - return Some(item.item); - } - } - util::unreachable(); - } - - /** - * Return a vec containing copies of the items, in order, where - * the weight of the item determines how many copies there are - */ - fn weighted_vec<T:Copy>(&mut self, v: &[Weighted<T>]) -> ~[T] { - let mut r = ~[]; - for v.each |item| { - for uint::range(0u, item.weight) |_i| { - r.push(item.item); - } - } - r - } - - /// Shuffle a vec - fn shuffle<T:Copy>(&mut self, values: &[T]) -> ~[T] { - let mut m = vec::to_owned(values); - self.shuffle_mut(m); - m - } - - /// Shuffle a mutable vec in place - fn shuffle_mut<T>(&mut self, values: &mut [T]) { - let mut i = values.len(); - while i >= 2u { - // invariant: elements with index >= i have been locked in place. - i -= 1u; - // lock element i in place. - vec::swap(values, i, self.gen_uint_range(0u, i + 1u)); - } - } -} - -/// Create a random number generator with a default algorithm and seed. -pub fn rng() -> IsaacRng { - IsaacRng::new() -} - -static RAND_SIZE_LEN: u32 = 8; -static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; - -/// A random number generator that uses the [ISAAC -/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29). -pub struct IsaacRng { - priv cnt: u32, - priv rsl: [u32, .. RAND_SIZE], - priv mem: [u32, .. RAND_SIZE], - priv a: u32, - priv b: u32, - priv c: u32 -} - -pub impl IsaacRng { - /// Create an ISAAC random number generator with a random seed. - fn new() -> IsaacRng { - IsaacRng::new_seeded(seed()) - } - - /// Create an ISAAC random number generator with a seed. This can be any - /// length, although the maximum number of bytes used is 1024 and any more - /// 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 { - let mut rng = IsaacRng { - cnt: 0, - rsl: [0, .. RAND_SIZE], - mem: [0, .. RAND_SIZE], - a: 0, b: 0, c: 0 - }; - - let array_size = sys::size_of_val(&rng.rsl); - let copy_length = cmp::min(array_size, seed.len()); - - // manually create a &mut [u8] slice of randrsl to copy into. - let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) }; - vec::bytes::copy_memory(dest, seed, copy_length); - rng.init(true); - rng - } - - /// Create an ISAAC random number generator using the default - /// fixed seed. - fn new_unseeded() -> IsaacRng { - let mut rng = IsaacRng { - cnt: 0, - rsl: [0, .. RAND_SIZE], - mem: [0, .. RAND_SIZE], - a: 0, b: 0, c: 0 - }; - rng.init(false); - rng - } - - /// 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); - - - macro_rules! mix( - () => {{ - a^=b<<11; d+=a; b+=c; - b^=c>>2; e+=b; c+=d; - c^=d<<8; f+=c; d+=e; - d^=e>>16; g+=d; e+=f; - e^=f<<10; h+=e; f+=g; - f^=g>>4; a+=f; g+=h; - g^=h<<8; b+=g; h+=a; - h^=a>>9; c+=h; a+=b; - }} - ); - - for 4.times { mix!(); } - - if use_rsl { - macro_rules! memloop ( - ($arr:expr) => {{ - for u32::range_step(0, RAND_SIZE, 8) |i| { - a+=$arr[i ]; b+=$arr[i+1]; - c+=$arr[i+2]; d+=$arr[i+3]; - e+=$arr[i+4]; f+=$arr[i+5]; - g+=$arr[i+6]; h+=$arr[i+7]; - mix!(); - self.mem[i ]=a; self.mem[i+1]=b; - self.mem[i+2]=c; self.mem[i+3]=d; - self.mem[i+4]=e; self.mem[i+5]=f; - self.mem[i+6]=g; self.mem[i+7]=h; - } - }} - ); - - memloop!(self.rsl); - memloop!(self.mem); - } else { - for u32::range_step(0, RAND_SIZE, 8) |i| { - mix!(); - self.mem[i ]=a; self.mem[i+1]=b; - self.mem[i+2]=c; self.mem[i+3]=d; - self.mem[i+4]=e; self.mem[i+5]=f; - self.mem[i+6]=g; self.mem[i+7]=h; - } - } - - self.isaac(); - } - - /// Refills the output buffer (`self.rsl`) - #[inline] - priv fn isaac(&mut self) { - self.c += 1; - // abbreviations - let mut a = self.a, b = self.b + self.c; - - static midpoint: uint = RAND_SIZE as uint / 2; - - macro_rules! ind (($x:expr) => { - self.mem[($x >> 2) & (RAND_SIZE - 1)] - }); - macro_rules! rngstep( - ($j:expr, $shift:expr) => {{ - let base = base + $j; - let mix = if $shift < 0 { - a >> -$shift as uint - } else { - a << $shift as uint - }; - - let x = self.mem[base + mr_offset]; - a = (a ^ mix) + self.mem[base + m2_offset]; - let y = ind!(x) + a + b; - self.mem[base + mr_offset] = y; - - b = ind!(y >> RAND_SIZE_LEN) + x; - self.rsl[base + mr_offset] = b; - }} - ); - - for [(0, midpoint), (midpoint, 0)].each |&(mr_offset, m2_offset)| { - for uint::range_step(0, midpoint, 4) |base| { - rngstep!(0, 13); - rngstep!(1, -6); - rngstep!(2, 2); - rngstep!(3, -16); - } - } - - self.a = a; - self.b = b; - self.cnt = RAND_SIZE; - } -} - -impl Rng for IsaacRng { - #[inline(always)] - fn next(&mut self) -> u32 { - if self.cnt == 0 { - // make some more numbers - self.isaac(); - } - self.cnt -= 1; - self.rsl[self.cnt] - } -} - -/// An [Xorshift random number -/// generator](http://en.wikipedia.org/wiki/Xorshift). Not suitable for -/// cryptographic purposes. -pub struct XorShiftRng { - priv x: u32, - priv y: u32, - priv z: u32, - priv w: u32, -} - -impl Rng for XorShiftRng { - #[inline] - pub fn next(&mut self) -> u32 { - let x = self.x; - let t = x ^ (x << 11); - self.x = self.y; - self.y = self.z; - self.z = self.w; - let w = self.w; - self.w = w ^ (w >> 19) ^ (t ^ (t >> 8)); - self.w - } -} - -pub impl XorShiftRng { - /// Create an xor shift random number generator with a default seed. - fn new() -> XorShiftRng { - // constants taken from http://en.wikipedia.org/wiki/Xorshift - XorShiftRng::new_seeded(123456789u32, - 362436069u32, - 521288629u32, - 88675123u32) - } - - /** - * 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. - */ - fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng { - XorShiftRng { - x: x, - y: y, - z: z, - w: w, - } - } -} - -/// Create a new random seed. -pub fn seed() -> ~[u8] { - unsafe { - let n = rustrt::rand_seed_size() as uint; - let mut s = vec::from_elem(n, 0_u8); - do vec::as_mut_buf(s) |p, sz| { - rustrt::rand_gen_seed(p, sz as size_t) - } - s - } -} - -// used to make space in TLS for a random number generator -fn tls_rng_state(_v: @@mut IsaacRng) {} - -/** - * Gives back a lazily initialized task-local random number generator, - * seeded by the system. Intended to be used in method chaining style, ie - * `task_rng().gen::<int>()`. - */ -#[inline] -pub fn task_rng() -> @@mut IsaacRng { - let r : Option<@@mut IsaacRng>; - unsafe { - r = local_data::local_data_get(tls_rng_state); - } - match r { - None => { - unsafe { - let rng = @@mut IsaacRng::new_seeded(seed()); - local_data::local_data_set(tls_rng_state, rng); - rng - } - } - Some(rng) => rng - } -} - -// Allow direct chaining with `task_rng` -impl<R: Rng> Rng for @@mut R { - #[inline(always)] - fn next(&mut self) -> u32 { - match *self { - @@ref mut r => r.next() - } - } -} - -/** - * Returns a random value of a Rand type, using the task's random number - * generator. - */ -#[inline] -pub fn random<T: Rand>() -> T { - match *task_rng() { - @ref mut r => r.gen() - } -} - -#[cfg(test)] -mod tests { - use option::{Option, Some}; - use super::*; - - #[test] - fn test_rng_seeded() { - let seed = seed(); - let mut ra = IsaacRng::new_seeded(seed); - let mut rb = IsaacRng::new_seeded(seed); - assert_eq!(ra.gen_str(100u), rb.gen_str(100u)); - } - - #[test] - fn test_rng_seeded_custom_seed() { - // much shorter than generated seeds which are 1024 bytes - let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let mut ra = IsaacRng::new_seeded(seed); - let mut rb = IsaacRng::new_seeded(seed); - assert_eq!(ra.gen_str(100u), rb.gen_str(100u)); - } - - #[test] - fn test_rng_seeded_custom_seed2() { - let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let mut ra = IsaacRng::new_seeded(seed); - // Regression test that isaac is actually using the above vector - let r = ra.next(); - error!("%?", r); - assert!(r == 890007737u32 // on x86_64 - || r == 2935188040u32); // on x86 - } - - #[test] - fn test_gen_int_range() { - let mut r = rng(); - let a = r.gen_int_range(-3, 42); - assert!(a >= -3 && a < 42); - assert_eq!(r.gen_int_range(0, 1), 0); - assert_eq!(r.gen_int_range(-12, -11), -12); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_gen_int_from_fail() { - let mut r = rng(); - r.gen_int_range(5, -2); - } - - #[test] - fn test_gen_uint_range() { - let mut r = rng(); - let a = r.gen_uint_range(3u, 42u); - assert!(a >= 3u && a < 42u); - assert_eq!(r.gen_uint_range(0u, 1u), 0u); - assert_eq!(r.gen_uint_range(12u, 13u), 12u); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_gen_uint_range_fail() { - let mut r = rng(); - r.gen_uint_range(5u, 2u); - } - - #[test] - fn test_gen_float() { - let mut r = rng(); - let a = r.gen::<float>(); - let b = r.gen::<float>(); - debug!((a, b)); - } - - #[test] - fn test_gen_weighted_bool() { - let mut r = rng(); - assert_eq!(r.gen_weighted_bool(0u), true); - assert_eq!(r.gen_weighted_bool(1u), true); - } - - #[test] - fn test_gen_str() { - let mut r = rng(); - debug!(r.gen_str(10u)); - debug!(r.gen_str(10u)); - debug!(r.gen_str(10u)); - assert_eq!(r.gen_str(0u).len(), 0u); - assert_eq!(r.gen_str(10u).len(), 10u); - assert_eq!(r.gen_str(16u).len(), 16u); - } - - #[test] - fn test_gen_bytes() { - let mut r = rng(); - assert_eq!(r.gen_bytes(0u).len(), 0u); - assert_eq!(r.gen_bytes(10u).len(), 10u); - assert_eq!(r.gen_bytes(16u).len(), 16u); - } - - #[test] - fn test_choose() { - let mut r = rng(); - assert_eq!(r.choose([1, 1, 1]), 1); - } - - #[test] - fn test_choose_option() { - let mut r = rng(); - let x: Option<int> = r.choose_option([]); - assert!(x.is_none()); - assert_eq!(r.choose_option([1, 1, 1]), Some(1)); - } - - #[test] - fn test_choose_weighted() { - let mut r = rng(); - assert!(r.choose_weighted(~[ - Weighted { weight: 1u, item: 42 }, - ]) == 42); - assert!(r.choose_weighted(~[ - Weighted { weight: 0u, item: 42 }, - Weighted { weight: 1u, item: 43 }, - ]) == 43); - } - - #[test] - fn test_choose_weighted_option() { - let mut r = rng(); - assert!(r.choose_weighted_option(~[ - Weighted { weight: 1u, item: 42 }, - ]) == Some(42)); - assert!(r.choose_weighted_option(~[ - Weighted { weight: 0u, item: 42 }, - Weighted { weight: 1u, item: 43 }, - ]) == Some(43)); - let v: Option<int> = r.choose_weighted_option([]); - assert!(v.is_none()); - } - - #[test] - fn test_weighted_vec() { - let mut r = rng(); - let empty: ~[int] = ~[]; - assert_eq!(r.weighted_vec(~[]), empty); - assert!(r.weighted_vec(~[ - Weighted { weight: 0u, item: 3u }, - Weighted { weight: 1u, item: 2u }, - Weighted { weight: 2u, item: 1u }, - ]) == ~[2u, 1u, 1u]); - } - - #[test] - fn test_shuffle() { - let mut r = rng(); - let empty: ~[int] = ~[]; - assert_eq!(r.shuffle(~[]), empty); - assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]); - } - - #[test] - fn test_task_rng() { - let mut r = task_rng(); - r.gen::<int>(); - assert_eq!(r.shuffle(~[1, 1, 1]), ~[1, 1, 1]); - assert_eq!(r.gen_uint_range(0u, 1u), 0u); - } - - #[test] - fn test_random() { - // not sure how to test this aside from just getting some values - let _n : uint = random(); - let _f : f32 = random(); - let _o : Option<Option<i8>> = random(); - let _many : ((), - (~uint, @int, ~Option<~(@char, ~(@bool,))>), - (u8, i8, u16, i16, u32, i32, u64, i64), - (f32, (f64, (float,)))) = random(); - } - - #[test] - fn compare_isaac_implementation() { - // This is to verify that the implementation of the ISAAC rng is - // correct (i.e. matches the output of the upstream implementation, - // which is in the runtime) - use vec; - use libc::size_t; - - #[abi = "cdecl"] - mod rustrt { - use libc::size_t; - - #[allow(non_camel_case_types)] // runtime type - pub enum rust_rng {} - - pub extern { - unsafe fn rand_new_seeded(buf: *u8, sz: size_t) -> *rust_rng; - unsafe fn rand_next(rng: *rust_rng) -> u32; - unsafe fn rand_free(rng: *rust_rng); - } - } - - // run against several seeds - for 10.times { - unsafe { - let seed = super::seed(); - let rt_rng = do vec::as_imm_buf(seed) |p, sz| { - rustrt::rand_new_seeded(p, sz as size_t) - }; - let mut rng = IsaacRng::new_seeded(seed); - - for 10000.times { - assert_eq!(rng.next(), rustrt::rand_next(rt_rng)); - } - rustrt::rand_free(rt_rng); - } - } - } -} diff --git a/src/libcore/rand/distributions.rs b/src/libcore/rand/distributions.rs deleted file mode 100644 index 72cff5111e7..00000000000 --- a/src/libcore/rand/distributions.rs +++ /dev/null @@ -1,148 +0,0 @@ -// 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. - -//! Sampling from random distributions - -// Some implementations use the Ziggurat method -// https://en.wikipedia.org/wiki/Ziggurat_algorithm -// -// The version used here is ZIGNOR [Doornik 2005, "An Improved -// Ziggurat Method to Generate Normal Random Samples"] which is slower -// (about double, it generates an extra random number) than the -// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for -// Generating Random Variables"], but more robust. If one wanted, one -// could implement VIZIGNOR the ZIGNOR paper for more speed. - -use prelude::*; -use rand::{Rng,Rand}; - -mod ziggurat_tables; - -// inlining should mean there is no performance penalty for this -#[inline(always)] -fn ziggurat<R:Rng>(rng: &mut R, - center_u: bool, - X: ziggurat_tables::ZigTable, - F: ziggurat_tables::ZigTable, - F_DIFF: ziggurat_tables::ZigTable, - pdf: &'static fn(f64) -> f64, // probability density function - zero_case: &'static fn(&mut R, f64) -> f64) -> f64 { - loop { - let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()}; - let i: uint = rng.gen::<uint>() & 0xff; - let x = u * X[i]; - - let test_x = if center_u {f64::abs(x)} else {x}; - - // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i]) - if test_x < X[i + 1] { - return x; - } - if i == 0 { - return zero_case(rng, u); - } - // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 - if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) { - return x; - } - } -} - -/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a -/// standard normal, or Gaussian). Multiplying the generated values by the -/// desired standard deviation `sigma` then adding the desired mean `mu` will -/// give N(mu, sigma^2) distributed random numbers. -/// -/// Note that this has to be unwrapped before use as an `f64` (using either -/// `*` or `cast::transmute` is safe). -/// -/// # Example -/// -/// ~~~ -/// use core::rand::distributions::StandardNormal; -/// -/// fn main() { -/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0; -/// println(fmt!("%f is from a N(2, 9) distribution", normal)) -/// } -/// ~~~ -pub struct StandardNormal(f64); - -impl Rand for StandardNormal { - fn rand<R:Rng>(rng: &mut R) -> StandardNormal { - #[inline(always)] - fn pdf(x: f64) -> f64 { - f64::exp((-x*x/2.0) as f64) as f64 - } - #[inline(always)] - fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 { - // compute a random number in the tail by hand - - // strange initial conditions, because the loop is not - // 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; - - // XXX infinities? - while -2.0*y < x * x { - x = f64::ln(rng.gen()) / ziggurat_tables::ZIG_NORM_R; - y = f64::ln(rng.gen()); - } - if u < 0.0 {x-ziggurat_tables::ZIG_NORM_R} else {ziggurat_tables::ZIG_NORM_R-x} - } - - StandardNormal(ziggurat( - rng, - true, // this is symmetric - &ziggurat_tables::ZIG_NORM_X, - &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF, - pdf, zero_case)) - } -} - -/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by -/// the desired rate `lambda` will give Exp(lambda) distributed random -/// numbers. -/// -/// Note that this has to be unwrapped before use as an `f64` (using either -/// `*` or `cast::transmute` is safe). -/// -/// # Example -/// -/// ~~~ -/// use core::rand::distributions::Exp1; -/// -/// fn main() { -/// let exp2 = (*rand::random::<Exp1>()) * 0.5; -/// println(fmt!("%f is from a Exp(2) distribution", exp2)); -/// } -/// ~~~ -pub struct Exp1(f64); - -// This could be done via `-f64::ln(rng.gen::<f64>())` but that is slower. -impl Rand for Exp1 { - #[inline] - fn rand<R:Rng>(rng: &mut R) -> Exp1 { - #[inline(always)] - fn pdf(x: f64) -> f64 { - f64::exp(-x) - } - #[inline(always)] - fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 { - ziggurat_tables::ZIG_EXP_R - f64::ln(rng.gen()) - } - - Exp1(ziggurat(rng, false, - &ziggurat_tables::ZIG_EXP_X, - &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF, - pdf, zero_case)) - } -} diff --git a/src/libcore/rand/ziggurat_tables.rs b/src/libcore/rand/ziggurat_tables.rs deleted file mode 100644 index aca2457cac4..00000000000 --- a/src/libcore/rand/ziggurat_tables.rs +++ /dev/null @@ -1,412 +0,0 @@ -// 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. - -// Tables for distributions which are sampled using the ziggurat -// algorithm. Autogenerated by `ziggurat_tables.py`. - -pub type ZigTable = &'static [f64, .. 257]; -pub static ZIG_NORM_R: f64 = 3.654152885361008796; -pub static ZIG_NORM_X: [f64, .. 257] = - [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, - 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, - 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548, - 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056, - 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570, - 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761, - 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318, - 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520, - 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952, - 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565, - 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760, - 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995, - 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268, - 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957, - 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778, - 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715, - 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244, - 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896, - 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257, - 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081, - 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281, - 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566, - 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199, - 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933, - 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012, - 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086, - 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338, - 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526, - 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427, - 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339, - 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456, - 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553, - 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404, - 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369, - 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830, - 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425, - 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534, - 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964, - 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606, - 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679, - 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728, - 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732, - 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903, - 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552, - 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650, - 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240, - 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975, - 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151, - 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714, - 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538, - 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441, - 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750, - 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130, - 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997, - 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550, - 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752, - 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785, - 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653, - 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448, - 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928, - 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262, - 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393, - 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, - 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, - 0.000000000000000000]; -pub static ZIG_NORM_F: [f64, .. 257] = - [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, - 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, - 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839, - 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237, - 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690, - 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918, - 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664, - 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916, - 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854, - 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965, - 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509, - 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229, - 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627, - 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880, - 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014, - 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349, - 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352, - 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926, - 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563, - 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071, - 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654, - 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926, - 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112, - 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651, - 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589, - 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525, - 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988, - 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150, - 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837, - 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316, - 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984, - 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274, - 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396, - 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099, - 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340, - 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515, - 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344, - 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958, - 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668, - 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784, - 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519, - 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750, - 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481, - 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788, - 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658, - 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142, - 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700, - 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941, - 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916, - 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473, - 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719, - 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205, - 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991, - 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357, - 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376, - 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409, - 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437, - 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500, - 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902, - 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935, - 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077, - 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839, - 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247, - 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, - 1.000000000000000000]; -pub static ZIG_NORM_F_DIFF: [f64, .. 257] = - [0.000000000000000000, 0.000782818165911943, 0.001348786815607765, 0.001428899847265509, - 0.001484430705892882, 0.001528472172127356, 0.001565707298030807, 0.001598388670308183, - 0.001627786418212004, 0.001654692743837703, 0.001679637706201265, 0.001702994844613767, - 0.001725038123187510, 0.001745974954326004, 0.001765966477270568, 0.001785140598493315, - 0.001803600702759419, 0.001821431661060659, 0.001838704088536796, 0.001855477433793579, - 0.001871802266665008, 0.001887722003144375, 0.001903274226858077, 0.001918491715965767, - 0.001933403251421835, 0.001948034260540625, 0.001962407334827158, 0.001976542650643127, - 0.001990458313945481, 0.002004170645086643, 0.002017694415851860, 0.002031043048104267, - 0.002044228781321551, 0.002057262814738517, 0.002070155428613822, 0.002082916088226049, - 0.002095553533492583, 0.002108075856553551, 0.002120490569226280, 0.002132804661891696, - 0.002145024655099026, 0.002157156644953973, 0.002169206343177243, 0.002181179112575302, - 0.002193079998548175, 0.002204913757158977, 0.002216684880213121, 0.002228397617726446, - 0.002240055998106505, 0.002251663846325885, 0.002263224800326716, 0.002274742325862292, - 0.002286219729956393, 0.002297660173134250, 0.002309066680560787, 0.002320442152205823, - 0.002331789372137141, 0.002343111017035562, 0.002354409664009627, 0.002365687797781804, - 0.002376947817308683, 0.002388192041889739, 0.002399422716815966, 0.002410642018598946, - 0.002421852059823287, 0.002433054893654529, 0.002444252518034679, 0.002455446879594508, - 0.002466639877306970, 0.002477833365903986, 0.002489029159078809, 0.002500229032490808, - 0.002511434726590794, 0.002522647949281448, 0.002533870378427505, 0.002545103664226889, - 0.002556349431455662, 0.002567609281597438, 0.002578884794865288, 0.002590177532127119, - 0.002601489036740262, 0.002612820836305291, 0.002624174444343735, 0.002635551361907296, - 0.002646953079123743, 0.002658381076686089, 0.002669836827288052, 0.002681321797012387, - 0.002692837446676144, 0.002704385233135737, 0.002715966610556786, 0.002727583031652520, - 0.002739235948893221, 0.002750926815690169, 0.002762657087557796, 0.002774428223256353, - 0.002786241685917290, 0.002798098944155558, 0.002810001473169871, 0.002821950755833219, - 0.002833948283778004, 0.002845995558475284, 0.002858094092312607, 0.002870245409671041, - 0.002882451048004164, 0.002894712558920987, 0.002907031509275432, 0.002919409482262880, - 0.002931848078526783, 0.002944348917277934, 0.002956913637427061, 0.002969543898733384, - 0.002982241382970874, 0.002995007795115689, 0.003007844864553855, 0.003020754346314269, - 0.003033738022328147, 0.003046797702715820, 0.003059935227105459, 0.003073152465984053, - 0.003086451322084072, 0.003099833731808721, 0.003113301666695822, 0.003126857134927052, - 0.003140502182881588, 0.003154238896738770, 0.003168069404132778, 0.003181995875862154, - 0.003196020527657495, 0.003210145622009941, 0.003224373470066433, 0.003238706433592253, - 0.003253146927007733, 0.003267697419501892, 0.003282360437226572, 0.003297138565578506, - 0.003312034451571411, 0.003327050806304299, 0.003342190407532641, 0.003357456102345890, - 0.003372850809960137, 0.003388377524629727, 0.003404039318688046, 0.003419839345721265, - 0.003435780843885239, 0.003451867139373843, 0.003468101650046629, 0.003484487889225119, - 0.003501029469670069, 0.003517730107746697, 0.003534593627793237, 0.003551623966702611, - 0.003568825178730639, 0.003586201440546166, 0.003603757056536316, 0.003621496464384588, - 0.003639424240937217, 0.003657545108379068, 0.003675863940735269, 0.003694385770723563, - 0.003713115796977806, 0.003732059391668707, 0.003751222108547281, 0.003770609691440940, - 0.003790228083232539, 0.003810083435355216, 0.003830182117840641, 0.003850530729957835, - 0.003871136111486317, 0.003892005354668437, 0.003913145816891062, 0.003934565134149914, - 0.003956271235355358, 0.003978272357543333, 0.004000577062061084, 0.004023194251800533, - 0.004046133189565926, 0.004069403517661885, 0.004093015278800460, 0.004116978938436600, - 0.004141305408647655, 0.004166006073685835, 0.004191092817346642, 0.004216578052307351, - 0.004242474751606884, 0.004268796482457593, 0.004295557442594244, 0.004322772499391836, - 0.004350457232007221, 0.004378627976825644, 0.004407301876525049, 0.004436496933105327, - 0.004466232065271192, 0.004496527170598785, 0.004527403192966406, 0.004558882195791591, - 0.004590987441673855, 0.004623743479123199, 0.004657176237135574, 0.004691313128472929, - 0.004726183162616859, 0.004761817069491636, 0.004798247435199299, 0.004835508851176451, - 0.004873638078381815, 0.004912674228345848, 0.004952658963181422, 0.004993636716962402, - 0.005035654941235035, 0.005078764377854039, 0.005123019362831771, 0.005168478165478940, - 0.005215203367812893, 0.005263262290042703, 0.005312727468930079, 0.005363677197016692, - 0.005416196132139284, 0.005470375988385734, 0.005526316321746716, 0.005584125426278286, - 0.005643921359735682, 0.005705833121505521, 0.005770002010457520, 0.005836583196307310, - 0.005905747545561058, 0.005977683752542928, 0.006052600837980204, 0.006130731092920838, - 0.006212333565464245, 0.006297698213369562, 0.006387150879090475, 0.006481059288027780, - 0.006579840329791975, 0.006683968961788356, 0.006793989182803495, 0.006910527673723577, - 0.007034310911336661, 0.007166186857056056, 0.007307152748134871, 0.007458391141830445, - 0.007621317291194862, 0.007797642342679434, 0.007989459040836144, 0.008199360125510702, - 0.008430605346682607, 0.008687362737884952, 0.008975066840784529, 0.009300967772353674, - 0.009675004947253041, 0.010111261142904171, 0.010630518154258861, 0.011265064987797335, - 0.012068570920629962, 0.013138877484087819, 0.014680138359337902, 0.017222609470315398, - 0.022898298717268672]; -pub static ZIG_EXP_R: f64 = 7.697117470131050077; -pub static ZIG_EXP_X: [f64, .. 257] = - [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, - 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, - 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530, - 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380, - 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857, - 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762, - 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744, - 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770, - 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608, - 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405, - 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160, - 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481, - 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601, - 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825, - 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780, - 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752, - 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489, - 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970, - 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815, - 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886, - 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372, - 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213, - 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027, - 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289, - 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526, - 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563, - 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943, - 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242, - 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954, - 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014, - 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566, - 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896, - 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334, - 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892, - 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092, - 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058, - 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504, - 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137, - 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189, - 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117, - 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330, - 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124, - 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677, - 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511, - 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813, - 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209, - 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735, - 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509, - 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311, - 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066, - 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206, - 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430, - 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102, - 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959, - 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947, - 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030, - 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626, - 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398, - 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235, - 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765, - 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122, - 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703, - 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, - 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, - 0.000000000000000000]; -pub static ZIG_EXP_F: [f64, .. 257] = - [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, - 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, - 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991, - 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981, - 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943, - 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355, - 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581, - 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221, - 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622, - 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431, - 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139, - 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289, - 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379, - 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030, - 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660, - 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816, - 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752, - 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435, - 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146, - 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197, - 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213, - 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145, - 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283, - 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641, - 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671, - 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602, - 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146, - 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839, - 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129, - 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081, - 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829, - 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083, - 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189, - 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654, - 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628, - 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956, - 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560, - 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543, - 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173, - 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967, - 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746, - 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252, - 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185, - 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223, - 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717, - 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449, - 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379, - 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056, - 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350, - 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209, - 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907, - 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836, - 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708, - 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881, - 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931, - 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056, - 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150, - 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560, - 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398, - 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177, - 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456, - 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838, - 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101, - 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477, - 1.000000000000000000]; -pub static ZIG_EXP_F_DIFF: [f64, .. 257] = - [0.000000000000000000, 0.000287067661533533, 0.000513134928485678, 0.000569030497974398, - 0.000609667963417335, 0.000642831049855169, 0.000671465984262828, 0.000697030342996893, - 0.000720360862708599, 0.000741986223663093, 0.000762263730113694, 0.000781447246315807, - 0.000799724254382053, 0.000817237547791934, 0.000834098656693235, 0.000850396538527769, - 0.000866203416804620, 0.000881578828420777, 0.000896572504999613, 0.000911226471926952, - 0.000925576608509206, 0.000939653828282008, 0.000953484986066785, 0.000967093584871414, - 0.000980500333784669, 0.000993723593313716, 0.001006779734568374, 0.001019683431705467, - 0.001032447902101660, 0.001045085105172934, 0.001057605908173612, 0.001070020225402434, - 0.001082337135821582, 0.001094564983022843, 0.001106711460658764, 0.001118783685829211, - 0.001130788262427001, 0.001142731336065933, 0.001154618641914802, 0.001166455546523074, - 0.001178247084534012, 0.001189997991027938, 0.001201712730115490, 0.001213395520299268, - 0.001225050357040701, 0.001236681032901414, 0.001248291155571943, 0.001259884164055092, - 0.001271463343231895, 0.001283031837006378, 0.001294592660197942, 0.001306148709326875, - 0.001317702772419903, 0.001329257537945404, 0.001340815602974395, 0.001352379480650950, - 0.001363951607045839, 0.001375534347457789, 0.001387130002219621, 0.001398740812059381, - 0.001410368963061376, 0.001422016591266340, 0.001433685786946429, 0.001445378598586011, - 0.001457097036596827, 0.001468843076792140, 0.001480618663643060, 0.001492425713336909, - 0.001504266116655995, 0.001516141741693663, 0.001528054436422108, 0.001540006031125918, - 0.001551998340713470, 0.001564033166917514, 0.001576112300394977, 0.001588237522735750, - 0.001600410608388780, 0.001612633326513305, 0.001624907442762655, 0.001637234721007311, - 0.001649616925003372, 0.001662055820012304, 0.001674553174376953, 0.001687110761059388, - 0.001699730359144919, 0.001712413755316500, 0.001725162745304071, 0.001737979135312442, - 0.001750864743431488, 0.001763821401032123, 0.001776850954151601, 0.001789955264870927, - 0.001803136212688003, 0.001816395695889220, 0.001829735632922019, 0.001843157963772116, - 0.001856664651347151, 0.001870257682870316, 0.001883939071285826, 0.001897710856679738, - 0.001911575107717528, 0.001925533923102574, 0.001939589433056721, 0.001953743800826108, - 0.001967999224215228, 0.001982357937151347, 0.001996822211282223, 0.002011394357609747, - 0.002026076728162574, 0.002040871717710169, 0.002055781765521847, 0.002070809357173103, - 0.002085957026402963, 0.002101227357025226, 0.002116622984897121, 0.002132146599948981, - 0.002147800948277823, 0.002163588834309782, 0.002179513123034188, 0.002195576742314159, - 0.002211782685277469, 0.002228134012792427, 0.002244633856033434, 0.002261285419141418, - 0.002278091981983449, 0.002295056903017983, 0.002312183622271174, 0.002329475664429648, - 0.002346936642057179, 0.002364570258941101, 0.002382380313575932, 0.002400370702791893, - 0.002418545425535629, 0.002436908586812392, 0.002455464401797752, 0.002474217200128692, - 0.002493171430384328, 0.002512331664766249, 0.002531702603989994, 0.002551289082400404, - 0.002571096073321844, 0.002591128694658967, 0.002611392214760672, 0.002631892058563845, - 0.002652633814032662, 0.002673623238910738, 0.002694866267805934, 0.002716369019626269, - 0.002738137805389534, 0.002760179136428037, 0.002782499733014893, 0.002805106533435520, - 0.002828006703534697, 0.002851207646767162, 0.002874717014785921, 0.002898542718600849, - 0.002922692940346749, 0.002947176145699226, 0.002972001096982591, 0.002997176867015228, - 0.003022712853742948, 0.003048618795714386, 0.003074904788455568, 0.003101581301807876, - 0.003128659198296080, 0.003156149752600867, 0.003184064672214937, 0.003212416119368622, - 0.003241216734320596, 0.003270479660111680, 0.003300218568896729, 0.003330447689969929, - 0.003361181839619420, 0.003392436452949343, 0.003424227617828290, 0.003456572111131984, - 0.003489487437467131, 0.003522991870580083, 0.003557104497672658, 0.003591845266868621, - 0.003627235038102472, 0.003663295637722386, 0.003700049917134574, 0.003737521815846301, - 0.003775736429304177, 0.003814720081962375, 0.003854500406067995, 0.003895106426696382, - 0.003936568653631844, 0.003978919180756157, 0.004022191793678687, 0.004066422086428989, - 0.004111647588127876, 0.004157907900659452, 0.004205244848493050, 0.004253702641940915, - 0.004303328055299205, 0.004354170621502118, 0.004406282845128784, 0.004459720435841752, - 0.004514542564613699, 0.004570812145417769, 0.004628596145424491, 0.004687965927177740, - 0.004748997626717266, 0.004811772572194672, 0.004876377748206484, 0.004942906311860507, - 0.005011458167522187, 0.005082140608288488, 0.005155069033533799, 0.005230367753417398, - 0.005308170893076836, 0.005388623411430704, 0.005471882252147620, 0.005558117647517014, - 0.005647514599798176, 0.005740274569295156, 0.005836617404105682, 0.005936783553485037, - 0.006041036615386131, 0.006149666279423593, 0.006262991739818591, 0.006381365669577810, - 0.006505178868201678, 0.006634865721946159, 0.006770910649812723, 0.006913855752425535, - 0.007064309938019209, 0.007222959874423007, 0.007390583214465396, 0.007568064673498798, - 0.007756415714389786, 0.007956798835585532, 0.008170557788458321, 0.008399255510700199, - 0.008644722212900025, 0.008909116987305010, 0.009195007664428712, 0.009505475652925033, - 0.009844255532840629, 0.010215923852312625, 0.010626158965710175, 0.011082105722287849, - 0.011592898788496009, 0.012170432837851575, 0.012830529553771619, 0.013594766864701180, - 0.014493463190219380, 0.015570784932380066, 0.016894014550512759, 0.018571645120042057, - 0.020792203980939394, 0.023918831757214210, 0.028765597544542998, 0.037673750936428774, - 0.061856319137823523]; diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs deleted file mode 100644 index 30f60dce041..00000000000 --- a/src/libcore/reflect.rs +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -Runtime type reflection - -*/ - -use intrinsic::{TyDesc, TyVisitor}; -use intrinsic::Opaque; -use libc::c_void; -use sys; -use vec; - -/** - * Trait for visitor that wishes to reflect on data. To use this, create a - * struct that encapsulates the set of pointers you wish to walk through a - * data structure, and implement both `MovePtr` for it as well as `TyVisitor`; - * then build a MovePtrAdaptor wrapped around your struct. - */ -pub trait MovePtr { - fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void); - fn push_ptr(&self); - fn pop_ptr(&self); -} - -/// Helper function for alignment calculation. -#[inline(always)] -pub fn align(size: uint, align: uint) -> uint { - ((size + align) - 1u) & !(align - 1u) -} - -/// Adaptor to wrap around visitors implementing MovePtr. -pub struct MovePtrAdaptor<V> { - inner: V -} -pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> { - MovePtrAdaptor { inner: v } -} - -pub impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> { - #[inline(always)] - 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| { - align(p as uint, a) as *c_void - }; - } - - #[inline(always)] - fn align_to<T>(&self) { - self.align(sys::min_align_of::<T>()); - } - - #[inline(always)] - fn bump_past<T>(&self) { - self.bump(sys::size_of::<T>()); - } -} - -/// Abstract type-directed pointer-movement using the MovePtr trait -impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> { - fn visit_bot(&self) -> bool { - self.align_to::<()>(); - if ! self.inner.visit_bot() { return false; } - self.bump_past::<()>(); - true - } - - fn visit_nil(&self) -> bool { - self.align_to::<()>(); - if ! self.inner.visit_nil() { return false; } - self.bump_past::<()>(); - true - } - - fn visit_bool(&self) -> bool { - self.align_to::<bool>(); - if ! self.inner.visit_bool() { return false; } - self.bump_past::<bool>(); - true - } - - fn visit_int(&self) -> bool { - self.align_to::<int>(); - if ! self.inner.visit_int() { return false; } - self.bump_past::<int>(); - true - } - - fn visit_i8(&self) -> bool { - self.align_to::<i8>(); - if ! self.inner.visit_i8() { return false; } - self.bump_past::<i8>(); - true - } - - fn visit_i16(&self) -> bool { - self.align_to::<i16>(); - if ! self.inner.visit_i16() { return false; } - self.bump_past::<i16>(); - true - } - - fn visit_i32(&self) -> bool { - self.align_to::<i32>(); - if ! self.inner.visit_i32() { return false; } - self.bump_past::<i32>(); - true - } - - fn visit_i64(&self) -> bool { - self.align_to::<i64>(); - if ! self.inner.visit_i64() { return false; } - self.bump_past::<i64>(); - true - } - - fn visit_uint(&self) -> bool { - self.align_to::<uint>(); - if ! self.inner.visit_uint() { return false; } - self.bump_past::<uint>(); - true - } - - fn visit_u8(&self) -> bool { - self.align_to::<u8>(); - if ! self.inner.visit_u8() { return false; } - self.bump_past::<u8>(); - true - } - - fn visit_u16(&self) -> bool { - self.align_to::<u16>(); - if ! self.inner.visit_u16() { return false; } - self.bump_past::<u16>(); - true - } - - fn visit_u32(&self) -> bool { - self.align_to::<u32>(); - if ! self.inner.visit_u32() { return false; } - self.bump_past::<u32>(); - true - } - - fn visit_u64(&self) -> bool { - self.align_to::<u64>(); - if ! self.inner.visit_u64() { return false; } - self.bump_past::<u64>(); - true - } - - fn visit_float(&self) -> bool { - self.align_to::<float>(); - if ! self.inner.visit_float() { return false; } - self.bump_past::<float>(); - true - } - - fn visit_f32(&self) -> bool { - self.align_to::<f32>(); - if ! self.inner.visit_f32() { return false; } - self.bump_past::<f32>(); - true - } - - fn visit_f64(&self) -> bool { - self.align_to::<f64>(); - if ! self.inner.visit_f64() { return false; } - self.bump_past::<f64>(); - true - } - - fn visit_char(&self) -> bool { - self.align_to::<char>(); - if ! self.inner.visit_char() { return false; } - self.bump_past::<char>(); - true - } - - fn visit_str(&self) -> bool { - self.align_to::<~str>(); - if ! self.inner.visit_str() { return false; } - self.bump_past::<~str>(); - true - } - - fn visit_estr_box(&self) -> bool { - self.align_to::<@str>(); - if ! self.inner.visit_estr_box() { return false; } - self.bump_past::<@str>(); - true - } - - fn visit_estr_uniq(&self) -> bool { - self.align_to::<~str>(); - if ! self.inner.visit_estr_uniq() { return false; } - self.bump_past::<~str>(); - true - } - - fn visit_estr_slice(&self) -> bool { - self.align_to::<&'static str>(); - if ! self.inner.visit_estr_slice() { return false; } - self.bump_past::<&'static str>(); - true - } - - fn visit_estr_fixed(&self, n: uint, - sz: uint, - align: uint) -> bool { - self.align(align); - if ! self.inner.visit_estr_fixed(n, sz, align) { return false; } - self.bump(sz); - true - } - - fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<@u8>(); - if ! self.inner.visit_box(mtbl, inner) { return false; } - self.bump_past::<@u8>(); - true - } - - fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<~u8>(); - if ! self.inner.visit_uniq(mtbl, inner) { return false; } - self.bump_past::<~u8>(); - true - } - - fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<*u8>(); - if ! self.inner.visit_ptr(mtbl, inner) { return false; } - self.bump_past::<*u8>(); - true - } - - fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<&'static u8>(); - if ! self.inner.visit_rptr(mtbl, inner) { return false; } - self.bump_past::<&'static u8>(); - true - } - - fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<vec::UnboxedVecRepr>(); - if ! self.inner.visit_vec(mtbl, inner) { return false; } - true - } - - fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<~[u8]>(); - if ! self.inner.visit_vec(mtbl, inner) { return false; } - self.bump_past::<~[u8]>(); - true - } - - fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<@[u8]>(); - if ! self.inner.visit_evec_box(mtbl, inner) { return false; } - self.bump_past::<@[u8]>(); - true - } - - fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<~[u8]>(); - if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; } - self.bump_past::<~[u8]>(); - true - } - - fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.align_to::<&'static [u8]>(); - if ! self.inner.visit_evec_slice(mtbl, inner) { return false; } - self.bump_past::<&'static [u8]>(); - true - } - - fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, - mtbl: uint, inner: *TyDesc) -> bool { - self.align(align); - if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) { - return false; - } - self.bump(sz); - true - } - - fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { - self.align(align); - if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; } - true - } - - fn visit_rec_field(&self, i: uint, name: &str, - mtbl: uint, inner: *TyDesc) -> bool { - unsafe { self.align((*inner).align); } - if ! self.inner.visit_rec_field(i, name, mtbl, inner) { - return false; - } - unsafe { self.bump((*inner).size); } - true - } - - fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { - if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; } - true - } - - fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint) - -> bool { - self.align(align); - if ! self.inner.visit_enter_class(n_fields, sz, align) { - return false; - } - true - } - - fn visit_class_field(&self, i: uint, name: &str, - mtbl: uint, inner: *TyDesc) -> bool { - unsafe { self.align((*inner).align); } - if ! self.inner.visit_class_field(i, name, mtbl, inner) { - return false; - } - unsafe { self.bump((*inner).size); } - true - } - - fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint) - -> bool { - if ! self.inner.visit_leave_class(n_fields, sz, align) { - return false; - } - true - } - - fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { - self.align(align); - if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; } - true - } - - fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { - unsafe { self.align((*inner).align); } - if ! self.inner.visit_tup_field(i, inner) { return false; } - unsafe { self.bump((*inner).size); } - true - } - - fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { - if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; } - true - } - - fn visit_enter_fn(&self, purity: uint, proto: uint, - n_inputs: uint, retstyle: uint) -> bool { - if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) { - return false - } - true - } - - fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool { - if ! self.inner.visit_fn_input(i, mode, inner) { return false; } - true - } - - fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool { - if ! self.inner.visit_fn_output(retstyle, inner) { return false; } - true - } - - fn visit_leave_fn(&self, purity: uint, proto: uint, - n_inputs: uint, retstyle: uint) -> bool { - if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) { - return false; - } - true - } - - fn visit_enter_enum(&self, n_variants: uint, - get_disr: extern unsafe fn(ptr: *Opaque) -> int, - sz: uint, align: uint) - -> bool { - self.align(align); - if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) { - return false; - } - true - } - - fn visit_enter_enum_variant(&self, variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool { - if ! self.inner.visit_enter_enum_variant(variant, disr_val, - n_fields, name) { - return false; - } - true - } - - fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool { - self.inner.push_ptr(); - self.bump(offset); - if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; } - self.inner.pop_ptr(); - true - } - - fn visit_leave_enum_variant(&self, variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool { - if ! self.inner.visit_leave_enum_variant(variant, disr_val, - n_fields, name) { - return false; - } - true - } - - fn visit_leave_enum(&self, n_variants: uint, - get_disr: extern unsafe fn(ptr: *Opaque) -> int, - sz: uint, align: uint) -> bool { - if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) { - return false; - } - self.bump(sz); - true - } - - fn visit_trait(&self) -> bool { - self.align_to::<@TyVisitor>(); - if ! self.inner.visit_trait() { return false; } - self.bump_past::<@TyVisitor>(); - true - } - - fn visit_var(&self) -> bool { - if ! self.inner.visit_var() { return false; } - true - } - - fn visit_var_integral(&self) -> bool { - if ! self.inner.visit_var_integral() { return false; } - true - } - - fn visit_param(&self, i: uint) -> bool { - if ! self.inner.visit_param(i) { return false; } - true - } - - fn visit_self(&self) -> bool { - self.align_to::<&'static u8>(); - if ! self.inner.visit_self() { return false; } - self.align_to::<&'static u8>(); - true - } - - fn visit_type(&self) -> bool { - if ! self.inner.visit_type() { return false; } - true - } - - fn visit_opaque_box(&self) -> bool { - self.align_to::<@u8>(); - if ! self.inner.visit_opaque_box() { return false; } - self.bump_past::<@u8>(); - true - } - - fn visit_constr(&self, inner: *TyDesc) -> bool { - if ! self.inner.visit_constr(inner) { return false; } - true - } - - fn visit_closure_ptr(&self, ck: uint) -> bool { - self.align_to::<@fn()>(); - if ! self.inner.visit_closure_ptr(ck) { return false; } - self.bump_past::<@fn()>(); - true - } -} diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs deleted file mode 100644 index a05009e375c..00000000000 --- a/src/libcore/repr.rs +++ /dev/null @@ -1,639 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -More runtime type reflection - -*/ - -use cast::transmute; -use char; -use intrinsic; -use intrinsic::{TyDesc, TyVisitor, visit_tydesc}; -use intrinsic::Opaque; -use io::{Writer, WriterUtil}; -use libc::c_void; -use managed; -use ptr; -use reflect; -use reflect::{MovePtr, align}; -use str::StrSlice; -use to_str::ToStr; -use vec::raw::{VecRepr, SliceRepr}; -use vec; -use vec::{OwnedVector, UnboxedVecRepr}; - -#[cfg(test)] use io; - -pub use managed::raw::BoxRepr; - -/// Helpers - -trait EscapedCharWriter { - fn write_escaped_char(&self, ch: char); -} - -impl EscapedCharWriter for @Writer { - fn write_escaped_char(&self, ch: char) { - match ch { - '\t' => self.write_str("\\t"), - '\r' => self.write_str("\\r"), - '\n' => self.write_str("\\n"), - '\\' => self.write_str("\\\\"), - '\'' => self.write_str("\\'"), - '"' => self.write_str("\\\""), - '\x20'..'\x7e' => self.write_char(ch), - _ => { - // FIXME #4423: This is inefficient because it requires a - // malloc. - self.write_str(char::escape_unicode(ch)) - } - } - } -} - -/// Representations - -trait Repr { - fn write_repr(&self, writer: @Writer); -} - -impl Repr for () { - fn write_repr(&self, writer: @Writer) { writer.write_str("()"); } -} - -impl Repr for bool { - fn write_repr(&self, writer: @Writer) { - writer.write_str(if *self { "true" } else { "false" }) - } -} - -impl Repr for int { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self); } -} -impl Repr for i8 { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} -impl Repr for i16 { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} -impl Repr for i32 { - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} -impl Repr for i64 { - // FIXME #4424: This can lose precision. - fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); } -} - -impl Repr for uint { - fn write_repr(&self, writer: @Writer) { writer.write_uint(*self); } -} -impl Repr for u8 { - fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); - } -} -impl Repr for u16 { - fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); - } -} -impl Repr for u32 { - fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); - } -} -impl Repr for u64 { - // FIXME #4424: This can lose precision. - fn write_repr(&self, writer: @Writer) { - writer.write_uint(*self as uint); - } -} - -impl Repr for float { - // FIXME #4423: This mallocs. - fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); } -} -impl Repr for f32 { - // FIXME #4423 This mallocs. - fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); } -} -impl Repr for f64 { - // FIXME #4423: This mallocs. - fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); } -} - -impl Repr for char { - fn write_repr(&self, writer: @Writer) { writer.write_char(*self); } -} - - -// New implementation using reflect::MovePtr - -enum VariantState { - SearchingFor(int), - Matched, - AlreadyFound -} - -pub struct ReprVisitor { - ptr: @mut *c_void, - ptr_stk: @mut ~[*c_void], - var_stk: @mut ~[VariantState], - writer: @Writer -} -pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor { - ReprVisitor { - ptr: @mut ptr, - ptr_stk: @mut ~[], - var_stk: @mut ~[], - writer: writer, - } -} - -impl MovePtr for ReprVisitor { - #[inline(always)] - fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) { - *self.ptr = adjustment(*self.ptr); - } - fn push_ptr(&self) { - self.ptr_stk.push(*self.ptr); - } - fn pop_ptr(&self) { - *self.ptr = self.ptr_stk.pop(); - } -} - -pub impl ReprVisitor { - - // Various helpers for the TyVisitor impl - - #[inline(always)] - fn get<T>(&self, f: &fn(&T)) -> bool { - unsafe { - f(transmute::<*c_void,&T>(*self.ptr)); - } - true - } - - #[inline(always)] - 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 { - unsafe { - let u = ReprVisitor(ptr, self.writer); - let v = reflect::MovePtrAdaptor(u); - visit_tydesc(inner, @v as @TyVisitor); - true - } - } - - #[inline(always)] - fn write<T:Repr>(&self) -> bool { - do self.get |v:&T| { - v.write_repr(self.writer); - } - } - - fn write_escaped_slice(&self, slice: &str) { - self.writer.write_char('"'); - for slice.each_char |ch| { - self.writer.write_escaped_char(ch); - } - self.writer.write_char('"'); - } - - fn write_mut_qualifier(&self, mtbl: uint) { - if mtbl == 0 { - self.writer.write_str("mut "); - } else if mtbl == 1 { - // skip, this is ast::m_imm - } else { - assert_eq!(mtbl, 2); - self.writer.write_str("const "); - } - } - - 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) }; - self.writer.write_char('['); - let mut first = true; - while (p as uint) < (end as uint) { - if first { - first = false; - } else { - self.writer.write_str(", "); - } - self.write_mut_qualifier(mtbl); - self.visit_ptr_inner(p as *c_void, inner); - p = align(ptr::offset(p, sz) as uint, al) as *u8; - } - self.writer.write_char(']'); - true - } - - 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 { - fn visit_bot(&self) -> bool { - self.writer.write_str("!"); - true - } - fn visit_nil(&self) -> bool { self.write::<()>() } - fn visit_bool(&self) -> bool { self.write::<bool>() } - fn visit_int(&self) -> bool { self.write::<int>() } - fn visit_i8(&self) -> bool { self.write::<i8>() } - fn visit_i16(&self) -> bool { self.write::<i16>() } - fn visit_i32(&self) -> bool { self.write::<i32>() } - fn visit_i64(&self) -> bool { self.write::<i64>() } - - fn visit_uint(&self) -> bool { self.write::<uint>() } - fn visit_u8(&self) -> bool { self.write::<u8>() } - fn visit_u16(&self) -> bool { self.write::<u16>() } - fn visit_u32(&self) -> bool { self.write::<u32>() } - fn visit_u64(&self) -> bool { self.write::<u64>() } - - fn visit_float(&self) -> bool { self.write::<float>() } - fn visit_f32(&self) -> bool { self.write::<f32>() } - fn visit_f64(&self) -> bool { self.write::<f64>() } - - fn visit_char(&self) -> bool { - do self.get::<char> |&ch| { - self.writer.write_char('\''); - self.writer.write_escaped_char(ch); - self.writer.write_char('\''); - } - } - - // Type no longer exists, vestigial function. - fn visit_str(&self) -> bool { fail!(); } - - fn visit_estr_box(&self) -> bool { - do self.get::<@str> |s| { - self.writer.write_char('@'); - self.write_escaped_slice(*s); - } - } - fn visit_estr_uniq(&self) -> bool { - do self.get::<~str> |s| { - self.writer.write_char('~'); - self.write_escaped_slice(*s); - } - } - fn visit_estr_slice(&self) -> bool { - do self.get::<&str> |s| { - self.write_escaped_slice(*s); - } - } - - // Type no longer exists, vestigial function. - fn visit_estr_fixed(&self, _n: uint, _sz: uint, - _align: uint) -> bool { fail!(); } - - fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write_char('@'); - self.write_mut_qualifier(mtbl); - do self.get::<&managed::raw::BoxRepr> |b| { - let p = ptr::to_unsafe_ptr(&b.data) as *c_void; - self.visit_ptr_inner(p, inner); - } - } - - fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write_char('~'); - self.write_mut_qualifier(mtbl); - do self.get::<&managed::raw::BoxRepr> |b| { - let p = ptr::to_unsafe_ptr(&b.data) as *c_void; - self.visit_ptr_inner(p, inner); - } - } - - fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { - do self.get::<*c_void> |p| { - self.writer.write_str(fmt!("(0x%x as *())", - *p as uint)); - } - } - - fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write_char('&'); - self.write_mut_qualifier(mtbl); - do self.get::<*c_void> |p| { - self.visit_ptr_inner(*p, inner); - } - } - - // Type no longer exists, vestigial function. - fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); } - - - fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<vec::UnboxedVecRepr> |b| { - self.write_unboxed_vec_repr(mtbl, b, inner); - } - } - - fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&VecRepr> |b| { - self.writer.write_char('@'); - self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); - } - } - - fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<&VecRepr> |b| { - self.writer.write_char('~'); - self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); - } - } - - fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<SliceRepr> |s| { - self.writer.write_char('&'); - self.write_vec_range(mtbl, s.data, s.len, inner); - } - } - - fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint, - mtbl: uint, inner: *TyDesc) -> bool { - do self.get::<u8> |b| { - self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner); - } - } - - fn visit_enter_rec(&self, _n_fields: uint, - _sz: uint, _align: uint) -> bool { - self.writer.write_char('{'); - true - } - - fn visit_rec_field(&self, i: uint, name: &str, - mtbl: uint, inner: *TyDesc) -> bool { - if i != 0 { - self.writer.write_str(", "); - } - self.write_mut_qualifier(mtbl); - self.writer.write_str(name); - self.writer.write_str(": "); - self.visit_inner(inner); - true - } - - fn visit_leave_rec(&self, _n_fields: uint, - _sz: uint, _align: uint) -> bool { - self.writer.write_char('}'); - true - } - - fn visit_enter_class(&self, _n_fields: uint, - _sz: uint, _align: uint) -> bool { - self.writer.write_char('{'); - true - } - fn visit_class_field(&self, i: uint, name: &str, - mtbl: uint, inner: *TyDesc) -> bool { - if i != 0 { - self.writer.write_str(", "); - } - self.write_mut_qualifier(mtbl); - self.writer.write_str(name); - self.writer.write_str(": "); - self.visit_inner(inner); - true - } - fn visit_leave_class(&self, _n_fields: uint, - _sz: uint, _align: uint) -> bool { - self.writer.write_char('}'); - true - } - - fn visit_enter_tup(&self, _n_fields: uint, - _sz: uint, _align: uint) -> bool { - self.writer.write_char('('); - true - } - fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { - if i != 0 { - self.writer.write_str(", "); - } - self.visit_inner(inner); - true - } - fn visit_leave_tup(&self, _n_fields: uint, - _sz: uint, _align: uint) -> bool { - if _n_fields == 1 { - self.writer.write_char(','); - } - self.writer.write_char(')'); - true - } - - fn visit_enter_enum(&self, - _n_variants: uint, - get_disr: extern unsafe fn(ptr: *Opaque) -> int, - _sz: uint, - _align: uint) -> bool { - let var_stk: &mut ~[VariantState] = self.var_stk; - let disr = unsafe { - get_disr(transmute(*self.ptr)) - }; - var_stk.push(SearchingFor(disr)); - true - } - - fn visit_enter_enum_variant(&self, _variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool { - let mut write = false; - match self.var_stk.pop() { - SearchingFor(sought) => { - if disr_val == sought { - self.var_stk.push(Matched); - write = true; - } else { - self.var_stk.push(SearchingFor(sought)); - } - } - Matched | AlreadyFound => { - self.var_stk.push(AlreadyFound); - } - } - - if write { - self.writer.write_str(name); - if n_fields > 0 { - self.writer.write_char('('); - } - } - true - } - - fn visit_enum_variant_field(&self, - i: uint, - _offset: uint, - inner: *TyDesc) - -> bool { - match self.var_stk[vec::uniq_len(&const *self.var_stk) - 1] { - Matched => { - if i != 0 { - self.writer.write_str(", "); - } - if ! self.visit_inner(inner) { - return false; - } - } - _ => () - } - true - } - - fn visit_leave_enum_variant(&self, _variant: uint, - _disr_val: int, - n_fields: uint, - _name: &str) -> bool { - match self.var_stk[vec::uniq_len(&const *self.var_stk) - 1] { - Matched => { - if n_fields > 0 { - self.writer.write_char(')'); - } - } - _ => () - } - true - } - - fn visit_leave_enum(&self, - _n_variants: uint, - _get_disr: extern unsafe fn(ptr: *Opaque) -> int, - _sz: uint, - _align: uint) - -> bool { - let var_stk: &mut ~[VariantState] = self.var_stk; - match var_stk.pop() { - SearchingFor(*) => fail!("enum value matched no variant"), - _ => true - } - } - - fn visit_enter_fn(&self, _purity: uint, _proto: uint, - _n_inputs: uint, _retstyle: uint) -> bool { true } - fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { - true - } - fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool { - true - } - fn visit_leave_fn(&self, _purity: uint, _proto: uint, - _n_inputs: uint, _retstyle: uint) -> bool { true } - - - fn visit_trait(&self) -> bool { true } - fn visit_var(&self) -> bool { true } - fn visit_var_integral(&self) -> bool { true } - fn visit_param(&self, _i: uint) -> bool { true } - fn visit_self(&self) -> bool { true } - fn visit_type(&self) -> bool { true } - - fn visit_opaque_box(&self) -> bool { - self.writer.write_char('@'); - do self.get::<&managed::raw::BoxRepr> |b| { - let p = ptr::to_unsafe_ptr(&b.data) as *c_void; - self.visit_ptr_inner(p, b.header.type_desc); - } - } - - // Type no longer exists, vestigial function. - fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); } - - fn visit_closure_ptr(&self, _ck: uint) -> bool { true } -} - -pub fn write_repr<T>(writer: @Writer, object: &T) { - unsafe { - let ptr = ptr::to_unsafe_ptr(object) as *c_void; - let tydesc = intrinsic::get_tydesc::<T>(); - let u = ReprVisitor(ptr, writer); - let v = reflect::MovePtrAdaptor(u); - visit_tydesc(tydesc, @v as @TyVisitor) - } -} - -#[cfg(test)] -struct P {a: int, b: float} - -#[test] -fn test_repr() { - - fn exact_test<T>(t: &T, e:&str) { - let s : &str = io::with_str_writer(|w| write_repr(w, t)); - if s != e { - error!("expected '%s', got '%s'", - e, s); - } - assert_eq!(s, e); - } - - exact_test(&10, "10"); - exact_test(&true, "true"); - exact_test(&false, "false"); - exact_test(&1.234, "1.234"); - exact_test(&(&"hello"), "\"hello\""); - exact_test(&(@"hello"), "@\"hello\""); - exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\""); - - // FIXME #4210: the mut fields are a bit off here. - exact_test(&(@10), "@10"); - exact_test(&(@mut 10), "@10"); - exact_test(&(~10), "~10"); - exact_test(&(&10), "&10"); - let mut x = 10; - exact_test(&(&mut x), "&mut 10"); - - exact_test(&(1,), "(1,)"); - exact_test(&(@[1,2,3,4,5,6,7,8]), - "@[1, 2, 3, 4, 5, 6, 7, 8]"); - exact_test(&(@[1u8,2u8,3u8,4u8]), - "@[1, 2, 3, 4]"); - exact_test(&(@["hi", "there"]), - "@[\"hi\", \"there\"]"); - exact_test(&(~["hi", "there"]), - "~[\"hi\", \"there\"]"); - exact_test(&(&["hi", "there"]), - "&[\"hi\", \"there\"]"); - exact_test(&(P{a:10, b:1.234}), - "{a: 10, b: 1.234}"); - exact_test(&(@P{a:10, b:1.234}), - "@{a: 10, b: 1.234}"); - exact_test(&(~P{a:10, b:1.234}), - "~{a: 10, b: 1.234}"); - exact_test(&(10_u8, ~"hello"), - "(10, ~\"hello\")"); - exact_test(&(10_u16, ~"hello"), - "(10, ~\"hello\")"); - exact_test(&(10_u32, ~"hello"), - "(10, ~\"hello\")"); - exact_test(&(10_u64, ~"hello"), - "(10, ~\"hello\")"); -} diff --git a/src/libcore/result.rs b/src/libcore/result.rs deleted file mode 100644 index cda2fe13e37..00000000000 --- a/src/libcore/result.rs +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A type representing either success or failure - -// NB: transitionary, de-mode-ing. - -use cmp::Eq; -use either; -use either::Either; -use kinds::Copy; -use option::{None, Option, Some}; -use old_iter::BaseIter; -use vec; -use vec::OwnedVector; - -/// The result type -#[deriving(Clone, Eq)] -pub enum Result<T, U> { - /// Contains the successful result value - Ok(T), - /// Contains the error value - Err(U) -} - -/** - * Get the value out of a successful result - * - * # Failure - * - * If the result is an error - */ -#[inline(always)] -pub fn get<T:Copy,U>(res: &Result<T, U>) -> T { - match *res { - Ok(copy t) => t, - Err(ref the_err) => - fail!("get called on error result: %?", *the_err) - } -} - -/** - * Get a reference to the value out of a successful result - * - * # Failure - * - * If the result is an error - */ -#[inline(always)] -pub fn get_ref<'a, T, U>(res: &'a Result<T, U>) -> &'a T { - match *res { - Ok(ref t) => t, - Err(ref the_err) => - fail!("get_ref called on error result: %?", *the_err) - } -} - -/** - * Get the value out of an error result - * - * # Failure - * - * If the result is not an error - */ -#[inline(always)] -pub fn get_err<T, U: Copy>(res: &Result<T, U>) -> U { - match *res { - Err(copy u) => u, - Ok(_) => fail!("get_err called on ok result") - } -} - -/// Returns true if the result is `ok` -#[inline(always)] -pub fn is_ok<T, U>(res: &Result<T, U>) -> bool { - match *res { - Ok(_) => true, - Err(_) => false - } -} - -/// Returns true if the result is `err` -#[inline(always)] -pub fn is_err<T, U>(res: &Result<T, U>) -> bool { - !is_ok(res) -} - -/** - * Convert to the `either` type - * - * `ok` result variants are converted to `either::right` variants, `err` - * result variants are converted to `either::left`. - */ -#[inline(always)] -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_) - } -} - -/** - * Call a function based on a previous result - * - * If `res` is `ok` then the value is extracted and passed to `op` whereupon - * `op`s result is returned. if `res` is `err` then it is immediately - * returned. This function can be used to compose the results of two - * functions. - * - * Example: - * - * let res = chain(read_file(file)) { |buf| - * ok(parse_bytes(buf)) - * } - */ -#[inline(always)] -pub fn chain<T, U, V>(res: Result<T, V>, op: &fn(T) - -> Result<U, V>) -> Result<U, V> { - match res { - Ok(t) => op(t), - Err(e) => Err(e) - } -} - -/** - * Call a function based on a previous result - * - * If `res` is `err` then the value is extracted and passed to `op` - * whereupon `op`s result is returned. if `res` is `ok` then it is - * immediately returned. This function can be used to pass through a - * successful result while handling an error. - */ -#[inline(always)] -pub fn chain_err<T, U, V>( - res: Result<T, V>, - op: &fn(t: V) -> Result<T, U>) - -> Result<T, U> { - match res { - Ok(t) => Ok(t), - Err(v) => op(v) - } -} - -/** - * Call a function based on a previous result - * - * If `res` is `ok` then the value is extracted and passed to `op` whereupon - * `op`s result is returned. if `res` is `err` then it is immediately - * returned. This function can be used to compose the results of two - * functions. - * - * Example: - * - * iter(read_file(file)) { |buf| - * print_buf(buf) - * } - */ -#[inline(always)] -pub fn iter<T, E>(res: &Result<T, E>, f: &fn(&T)) { - match *res { - Ok(ref t) => f(t), - Err(_) => () - } -} - -/** - * Call a function based on a previous result - * - * If `res` is `err` then the value is extracted and passed to `op` whereupon - * `op`s result is returned. if `res` is `ok` then it is immediately returned. - * This function can be used to pass through a successful result while - * handling an error. - */ -#[inline(always)] -pub fn iter_err<T, E>(res: &Result<T, E>, f: &fn(&E)) { - match *res { - Ok(_) => (), - Err(ref e) => f(e) - } -} - -/** - * Call a function based on a previous result - * - * If `res` is `ok` then the value is extracted and passed to `op` whereupon - * `op`s result is wrapped in `ok` and returned. if `res` is `err` then it is - * immediately returned. This function can be used to compose the results of - * two functions. - * - * Example: - * - * let res = map(read_file(file)) { |buf| - * parse_bytes(buf) - * } - */ -#[inline(always)] -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) - } -} - -/** - * Call a function based on a previous result - * - * If `res` is `err` then the value is extracted and passed to `op` whereupon - * `op`s result is wrapped in an `err` and returned. if `res` is `ok` then it - * is immediately returned. This function can be used to pass through a - * successful result while handling an error. - */ -#[inline(always)] -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), - Err(ref e) => Err(op(e)) - } -} - -pub impl<T, E> Result<T, E> { - #[inline(always)] - fn get_ref<'a>(&'a self) -> &'a T { get_ref(self) } - - #[inline(always)] - fn is_ok(&self) -> bool { is_ok(self) } - - #[inline(always)] - fn is_err(&self) -> bool { is_err(self) } - - #[inline(always)] - fn iter(&self, f: &fn(&T)) { iter(self, f) } - - #[inline(always)] - fn iter_err(&self, f: &fn(&E)) { iter_err(self, f) } - - #[inline(always)] - fn unwrap(self) -> T { unwrap(self) } - - #[inline(always)] - fn unwrap_err(self) -> E { unwrap_err(self) } - - #[inline(always)] - 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> { - chain_err(self, op) - } -} - -pub impl<T:Copy,E> Result<T, E> { - #[inline(always)] - fn get(&self) -> T { get(self) } - - #[inline(always)] - 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> { - #[inline(always)] - fn get_err(&self) -> E { get_err(self) } - - #[inline(always)] - fn map<U:Copy>(&self, op: &fn(&T) -> U) -> Result<U,E> { - map(self, op) - } -} - -/** - * Maps each element in the vector `ts` using the operation `op`. Should an - * error occur, no further mappings are performed and the error is returned. - * Should no error occur, a vector containing the result of each map is - * returned. - * - * Here is an example which increments every integer in a vector, - * checking for overflow: - * - * fn inc_conditionally(x: uint) -> result<uint,str> { - * if x == uint::max_value { return err("overflow"); } - * else { return ok(x+1u); } - * } - * map(~[1u, 2u, 3u], inc_conditionally).chain {|incd| - * assert!(incd == ~[2u, 3u, 4u]); - * } - */ -#[inline(always)] -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)); - for ts.each |t| { - match op(t) { - Ok(copy v) => vs.push(v), - Err(copy u) => return Err(u) - } - } - return Ok(vs); -} - -#[inline(always)] -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) - } - } -} - -/** - * Same as map, but it operates over two parallel vectors. - * - * A precondition is used here to ensure that the vectors are the same - * length. While we do not often use preconditions in the standard - * library, a precondition is used here because result::t is generally - * used in 'careful' code contexts where it is both appropriate and easy - * to accommodate an error like the vectors being of different lengths. - */ -#[inline(always)] -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 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) - } - i += 1u; - } - return Ok(vs); -} - -/** - * Applies op to the pairwise elements from `ss` and `ts`, aborting on - * error. This could be implemented using `map_zip()` but it is more efficient - * on its own as no result vector is built. - */ -#[inline(always)] -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 mut i = 0u; - while i < n { - match op(&ss[i],&ts[i]) { - Ok(()) => (), - Err(copy u) => return Err(u) - } - i += 1u; - } - return Ok(()); -} - -/// Unwraps a result, assuming it is an `ok(T)` -#[inline(always)] -pub fn unwrap<T, U>(res: Result<T, U>) -> T { - match res { - Ok(t) => t, - Err(_) => fail!("unwrap called on an err result") - } -} - -/// Unwraps a result, assuming it is an `err(U)` -#[inline(always)] -pub fn unwrap_err<T, U>(res: Result<T, U>) -> U { - match res { - Err(u) => u, - Ok(_) => fail!("unwrap called on an ok result") - } -} - -#[cfg(test)] -#[allow(non_implicitly_copyable_typarams)] -mod tests { - use result::{Err, Ok, Result, chain, get, get_err}; - use result; - - pub fn op1() -> result::Result<int, ~str> { result::Ok(666) } - - pub fn op2(i: int) -> result::Result<uint, ~str> { - result::Ok(i as uint + 1u) - } - - pub fn op3() -> result::Result<int, ~str> { result::Err(~"sadface") } - - #[test] - pub fn chain_success() { - assert_eq!(get(&chain(op1(), op2)), 667u); - } - - #[test] - pub fn chain_failure() { - assert_eq!(get_err(&chain(op3(), op2)), ~"sadface"); - } - - #[test] - pub fn test_impl_iter() { - let mut valid = false; - Ok::<~str, ~str>(~"a").iter(|_x| valid = true); - assert!(valid); - - Err::<~str, ~str>(~"b").iter(|_x| valid = false); - assert!(valid); - } - - #[test] - pub fn test_impl_iter_err() { - let mut valid = true; - Ok::<~str, ~str>(~"a").iter_err(|_x| valid = false); - assert!(valid); - - valid = false; - Err::<~str, ~str>(~"b").iter_err(|_x| valid = true); - assert!(valid); - } - - #[test] - pub fn test_impl_map() { - assert_eq!(Ok::<~str, ~str>(~"a").map(|_x| ~"b"), Ok(~"b")); - assert_eq!(Err::<~str, ~str>(~"a").map(|_x| ~"b"), Err(~"a")); - } - - #[test] - pub fn test_impl_map_err() { - assert_eq!(Ok::<~str, ~str>(~"a").map_err(|_x| ~"b"), Ok(~"a")); - assert_eq!(Err::<~str, ~str>(~"a").map_err(|_x| ~"b"), Err(~"b")); - } - - #[test] - pub fn test_get_ref_method() { - let foo: Result<int, ()> = Ok(100); - assert_eq!(*foo.get_ref(), 100); - } -} diff --git a/src/libcore/rt/context.rs b/src/libcore/rt/context.rs deleted file mode 100644 index 0d011ce42ba..00000000000 --- a/src/libcore/rt/context.rs +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::*; -use super::stack::StackSegment; -use libc::c_void; -use cast::{transmute, transmute_mut_unsafe, - transmute_region, transmute_mut_region}; - -// XXX: Registers is boxed so that it is 16-byte aligned, for storing -// SSE regs. It would be marginally better not to do this. In C++ we -// use an attribute on a struct. -// XXX: It would be nice to define regs as `~Option<Registers>` since -// the registers are sometimes empty, but the discriminant would -// then misalign the regs again. -pub struct Context { - /// The context entry point, saved here for later destruction - start: Option<~~fn()>, - /// Hold the registers while the task or scheduler is suspended - regs: ~Registers -} - -pub impl Context { - fn empty() -> Context { - Context { - start: None, - regs: new_regs() - } - } - - /// Create a new context that will resume execution by running ~fn() - 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 - let start = ~start; - - // The C-ABI function that is the task entry point - extern fn task_start_wrapper(f: &~fn()) { (*f)() } - - let fp: *c_void = task_start_wrapper as *c_void; - let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) }; - let sp: *uint = stack.end(); - let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) }; - - // Save and then immediately load the current context, - // which we will then modify to call the given function when restored - let mut regs = new_regs(); - unsafe { - swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs)) - }; - - initialize_call_frame(&mut *regs, fp, argp, sp); - - return Context { - start: Some(start), - regs: regs - } - } - - /* Switch contexts - - Suspend the current execution context and resume another by - 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) { - let out_regs: &mut Registers = match out_context { - &Context { regs: ~ref mut r, _ } => r - }; - let in_regs: &Registers = match in_context { - &Context { regs: ~ref r, _ } => r - }; - - unsafe { swap_registers(out_regs, in_regs) }; - } -} - -extern { - #[rust_stack] - fn swap_registers(out_regs: *mut Registers, in_regs: *Registers); -} - -#[cfg(target_arch = "x86")] -struct Registers { - eax: u32, ebx: u32, ecx: u32, edx: u32, - ebp: u32, esi: u32, edi: u32, esp: u32, - cs: u16, ds: u16, ss: u16, es: u16, fs: u16, gs: u16, - eflags: u32, eip: u32 -} - -#[cfg(target_arch = "x86")] -fn new_regs() -> ~Registers { - ~Registers { - eax: 0, ebx: 0, ecx: 0, edx: 0, - ebp: 0, esi: 0, edi: 0, esp: 0, - cs: 0, ds: 0, ss: 0, es: 0, fs: 0, gs: 0, - eflags: 0, eip: 0 - } -} - -#[cfg(target_arch = "x86")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - - let sp = align_down(sp); - let sp = mut_offset(sp, -4); - - unsafe { *sp = arg as uint }; - let sp = mut_offset(sp, -1); - unsafe { *sp = 0 }; // The final return address - - regs.esp = sp as u32; - regs.eip = fptr as u32; - - // Last base pointer on the stack is 0 - regs.ebp = 0; -} - -#[cfg(target_arch = "x86_64")] -type Registers = [uint, ..22]; - -#[cfg(target_arch = "x86_64")] -fn new_regs() -> ~Registers { ~([0, .. 22]) } - -#[cfg(target_arch = "x86_64")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - - // Redefinitions from regs.h - static RUSTRT_ARG0: uint = 3; - static RUSTRT_RSP: uint = 1; - static RUSTRT_IP: uint = 8; - static RUSTRT_RBP: uint = 2; - - let sp = align_down(sp); - let sp = mut_offset(sp, -1); - - // The final return address. 0 indicates the bottom of the stack - unsafe { *sp = 0; } - - rtdebug!("creating call frame"); - rtdebug!("fptr %x", fptr as uint); - rtdebug!("arg %x", arg as uint); - rtdebug!("sp %x", sp as uint); - - regs[RUSTRT_ARG0] = arg as uint; - regs[RUSTRT_RSP] = sp as uint; - regs[RUSTRT_IP] = fptr as uint; - - // Last base pointer on the stack should be 0 - regs[RUSTRT_RBP] = 0; -} - -#[cfg(target_arch = "arm")] -type Registers = [uint, ..32]; - -#[cfg(target_arch = "arm")] -fn new_regs() -> ~Registers { ~([0, .. 32]) } - -#[cfg(target_arch = "arm")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - let sp = align_down(sp); - // sp of arm eabi is 8-byte aligned - let sp = mut_offset(sp, -2); - - // The final return address. 0 indicates the bottom of the stack - unsafe { *sp = 0; } - - regs[0] = arg as uint; // r0 - regs[13] = sp as uint; // #53 sp, r13 - regs[14] = fptr as uint; // #60 pc, r15 --> lr -} - -#[cfg(target_arch = "mips")] -type Registers = [uint, ..32]; - -#[cfg(target_arch = "mips")] -fn new_regs() -> ~Registers { ~([0, .. 32]) } - -#[cfg(target_arch = "mips")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - let sp = align_down(sp); - // sp of mips o32 is 8-byte aligned - let sp = mut_offset(sp, -2); - - // The final return address. 0 indicates the bottom of the stack - unsafe { *sp = 0; } - - regs[4] = arg as uint; - regs[29] = sp as uint; - regs[25] = fptr as uint; - regs[31] = fptr as uint; -} - -fn align_down(sp: *mut uint) -> *mut uint { - unsafe { - let sp: uint = transmute(sp); - let sp = sp & !(16 - 1); - transmute::<uint, *mut uint>(sp) - } -} - -// XXX: ptr::offset is positive ints only -#[inline(always)] -pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T { - use core::sys::size_of; - (ptr as int + count * (size_of::<T>() as int)) as *mut T -} diff --git a/src/libcore/rt/env.rs b/src/libcore/rt/env.rs deleted file mode 100644 index 1d7ff173149..00000000000 --- a/src/libcore/rt/env.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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. - -//! Runtime environment settings - -use libc::{size_t, c_char, c_int}; - -pub struct Environment { - /// The number of threads to use by default - num_sched_threads: size_t, - /// The minimum size of a stack segment - min_stack_size: size_t, - /// The maximum amount of total stack per task before aborting - max_stack_size: size_t, - /// The default logging configuration - logspec: *c_char, - /// Record and report detailed information about memory leaks - detailed_leaks: bool, - /// Seed the random number generator - rust_seed: *c_char, - /// Poison allocations on free - poison_on_free: bool, - /// The argc value passed to main - argc: c_int, - /// The argv value passed to main - argv: **c_char, - /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) - debug_mem: bool, - /// Print GC debugging info (true if env var RUST_DEBUG_BORROW is set) - debug_borrow: bool, -} - -/// Get the global environment settings -/// # Safety Note -/// This will abort the process if run outside of task context -pub fn get() -> &Environment { - unsafe { rust_get_rt_env() } -} - -extern { - fn rust_get_rt_env() -> &Environment; -} diff --git a/src/libcore/rt/global_heap.rs b/src/libcore/rt/global_heap.rs deleted file mode 100644 index ce7ff87b445..00000000000 --- a/src/libcore/rt/global_heap.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys::{TypeDesc, size_of}; -use libc::{c_void, size_t, uintptr_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; -use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub}; -use ptr::null; -use intrinsic::TyDesc; - -pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - // FIXME #3475: Converting between our two different tydesc types - let td: *TyDesc = transmute(td); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); -} - -fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::<BoxHeaderRepr>(); - // FIXME (#2699): This alignment calculation is suspicious. Is it right? - let total_size = align_to(header_size, body_align) + body_size; - return total_size; -} - -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -fn align_to(size: uint, align: uint) -> uint { - assert!(align != 0); - (size + align - 1) & !(align - 1) -} - -fn exchange_count_ptr() -> *mut int { - // XXX: Need mutable globals - unsafe { transmute(&rust_exchange_count) } -} - -extern { - static rust_exchange_count: uintptr_t; -} diff --git a/src/libcore/rt/io/comm_adapters.rs b/src/libcore/rt/io/comm_adapters.rs deleted file mode 100644 index 7e891f1718e..00000000000 --- a/src/libcore/rt/io/comm_adapters.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::{Reader, Writer}; - -struct PortReader<P>; - -impl<P: GenericPort<~[u8]>> PortReader<P> { - pub fn new(_port: P) -> PortReader<P> { fail!() } -} - -impl<P: GenericPort<~[u8]>> Reader for PortReader<P> { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -struct ChanWriter<C>; - -impl<C: GenericChan<~[u8]>> ChanWriter<C> { - pub fn new(_chan: C) -> ChanWriter<C> { fail!() } -} - -impl<C: GenericChan<~[u8]>> Writer for ChanWriter<C> { - pub fn write(&mut self, _buf: &[u8]) { fail!() } - - pub fn flush(&mut self) { fail!() } -} - -struct ReaderPort<R>; - -impl<R: Reader> ReaderPort<R> { - pub fn new(_reader: R) -> ReaderPort<R> { fail!() } -} - -impl<R: Reader> GenericPort<~[u8]> for ReaderPort<R> { - fn recv(&self) -> ~[u8] { fail!() } - - fn try_recv(&self) -> Option<~[u8]> { fail!() } -} - -struct WriterChan<W>; - -impl<W: Writer> WriterChan<W> { - pub fn new(_writer: W) -> WriterChan<W> { fail!() } -} - -impl<W: Writer> GenericChan<~[u8]> for WriterChan<W> { - fn send(&self, _x: ~[u8]) { fail!() } -} diff --git a/src/libcore/rt/io/extensions.rs b/src/libcore/rt/io/extensions.rs deleted file mode 100644 index ceff2ecd77d..00000000000 --- a/src/libcore/rt/io/extensions.rs +++ /dev/null @@ -1,903 +0,0 @@ -// 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. - -//! Utility mixins that apply to all Readers and Writers - -// XXX: Not sure how this should be structured -// XXX: Iteration should probably be considered separately - -use uint; -use int; -use vec; -use rt::io::{Reader, Writer}; -use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; -use option::{Option, Some, None}; -use unstable::finally::Finally; -use util; -use cast; -use io::{u64_to_le_bytes, u64_to_be_bytes}; - -pub trait ReaderUtil { - - /// Reads a single byte. Returns `None` on EOF. - /// - /// # Failure - /// - /// Raises the same conditions as the `read` method. Returns - /// `None` if the condition is handled. - fn read_byte(&mut self) -> Option<u8>; - - /// Reads `len` bytes and appends them to a vector. - /// - /// May push fewer than the requested number of bytes on error - /// or EOF. Returns true on success, false on EOF or error. - /// - /// # Failure - /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then `push_bytes` may push less - /// than the requested number of bytes. - fn push_bytes(&mut self, buf: &mut ~[u8], len: uint); - - /// Reads `len` bytes and gives you back a new vector of length `len` - /// - /// # Failure - /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then the returned vector may - /// contain less than the requested number of bytes. - fn read_bytes(&mut self, len: uint) -> ~[u8]; - - /// Reads all remaining bytes from the stream. - /// - /// # Failure - /// - /// Raises the same conditions as the `read` method. - fn read_to_end(&mut self) -> ~[u8]; - -} - -pub trait ReaderByteConversions { - /// Reads `n` little-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_uint_n(&mut self, nbytes: uint) -> u64; - - /// Reads `n` little-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_int_n(&mut self, nbytes: uint) -> i64; - - /// Reads `n` big-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_uint_n(&mut self, nbytes: uint) -> u64; - - /// Reads `n` big-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_int_n(&mut self, nbytes: uint) -> i64; - - /// Reads a little-endian unsigned integer. - /// - /// The number of bytes returned is system-dependant. - fn read_le_uint(&mut self) -> uint; - - /// Reads a little-endian integer. - /// - /// The number of bytes returned is system-dependant. - fn read_le_int(&mut self) -> int; - - /// Reads a big-endian unsigned integer. - /// - /// The number of bytes returned is system-dependant. - fn read_be_uint(&mut self) -> uint; - - /// Reads a big-endian integer. - /// - /// The number of bytes returned is system-dependant. - fn read_be_int(&mut self) -> int; - - /// Reads a big-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_be_u64(&mut self) -> u64; - - /// Reads a big-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_be_u32(&mut self) -> u32; - - /// Reads a big-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_be_u16(&mut self) -> u16; - - /// Reads a big-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_be_i64(&mut self) -> i64; - - /// Reads a big-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_be_i32(&mut self) -> i32; - - /// Reads a big-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_be_i16(&mut self) -> i16; - - /// Reads a big-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_be_f64(&mut self) -> f64; - - /// Reads a big-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_be_f32(&mut self) -> f32; - - /// Reads a little-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_le_u64(&mut self) -> u64; - - /// Reads a little-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_le_u32(&mut self) -> u32; - - /// Reads a little-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_le_u16(&mut self) -> u16; - - /// Reads a little-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_le_i64(&mut self) -> i64; - - /// Reads a little-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_le_i32(&mut self) -> i32; - - /// Reads a little-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_le_i16(&mut self) -> i16; - - /// Reads a little-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_le_f64(&mut self) -> f64; - - /// Reads a little-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_le_f32(&mut self) -> f32; - - /// Read a u8. - /// - /// `u8`s are 1 byte. - fn read_u8(&mut self) -> u8; - - /// Read an i8. - /// - /// `i8`s are 1 byte. - fn read_i8(&mut self) -> i8; - -} - -pub trait WriterByteConversions { - /// Write the result of passing n through `int::to_str_bytes`. - fn write_int(&mut self, n: int); - - /// Write the result of passing n through `uint::to_str_bytes`. - fn write_uint(&mut self, n: uint); - - /// Write a little-endian uint (number of bytes depends on system). - fn write_le_uint(&mut self, n: uint); - - /// Write a little-endian int (number of bytes depends on system). - fn write_le_int(&mut self, n: int); - - /// Write a big-endian uint (number of bytes depends on system). - fn write_be_uint(&mut self, n: uint); - - /// Write a big-endian int (number of bytes depends on system). - fn write_be_int(&mut self, n: int); - - /// Write a big-endian u64 (8 bytes). - fn write_be_u64_(&mut self, n: u64); - - /// Write a big-endian u32 (4 bytes). - fn write_be_u32(&mut self, n: u32); - - /// Write a big-endian u16 (2 bytes). - fn write_be_u16(&mut self, n: u16); - - /// Write a big-endian i64 (8 bytes). - fn write_be_i64(&mut self, n: i64); - - /// Write a big-endian i32 (4 bytes). - fn write_be_i32(&mut self, n: i32); - - /// Write a big-endian i16 (2 bytes). - fn write_be_i16(&mut self, n: i16); - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - fn write_be_f64(&mut self, f: f64); - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - fn write_be_f32(&mut self, f: f32); - - /// Write a little-endian u64 (8 bytes). - fn write_le_u64_(&mut self, n: u64); - - /// Write a little-endian u32 (4 bytes). - fn write_le_u32(&mut self, n: u32); - - /// Write a little-endian u16 (2 bytes). - fn write_le_u16(&mut self, n: u16); - - /// Write a little-endian i64 (8 bytes). - fn write_le_i64(&mut self, n: i64); - - /// Write a little-endian i32 (4 bytes). - fn write_le_i32(&mut self, n: i32); - - /// Write a little-endian i16 (2 bytes). - fn write_le_i16(&mut self, n: i16); - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - fn write_le_f64(&mut self, f: f64); - - /// Write a litten-endian IEEE754 single-precision floating-point - /// (4 bytes). - fn write_le_f32(&mut self, f: f32); - - /// Write a u8 (1 byte). - fn write_u8(&mut self, n: u8); - - /// Write a i8 (1 byte). - fn write_i8(&mut self, n: i8); -} - -impl<T: Reader> ReaderUtil for T { - fn read_byte(&mut self) -> Option<u8> { - let mut buf = [0]; - match self.read(buf) { - Some(0) => { - debug!("read 0 bytes. trying again"); - self.read_byte() - } - Some(1) => Some(buf[0]), - Some(_) => util::unreachable(), - None => None - } - } - - fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) { - unsafe { - let start_len = buf.len(); - let mut total_read = 0; - - vec::reserve_at_least(buf, start_len + len); - vec::raw::set_len(buf, start_len + len); - - do (|| { - while total_read < len { - let slice = vec::mut_slice(*buf, start_len + total_read, buf.len()); - match self.read(slice) { - Some(nread) => { - total_read += nread; - } - None => { - read_error::cond.raise(standard_error(EndOfFile)); - break; - } - } - } - }).finally { - vec::raw::set_len(buf, start_len + total_read); - } - } - } - - fn read_bytes(&mut self, len: uint) -> ~[u8] { - let mut buf = vec::with_capacity(len); - self.push_bytes(&mut buf, len); - return buf; - } - - fn read_to_end(&mut self) -> ~[u8] { - let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE); - let mut keep_reading = true; - do read_error::cond.trap(|e| { - if e.kind == EndOfFile { - keep_reading = false; - } else { - read_error::cond.raise(e) - } - }).in { - while keep_reading { - self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) - } - } - return buf; - } -} - -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; - while i > 0 { - val += (self.read_u8() as u64) << pos; - pos += 8; - i -= 1; - } - val - } - - fn read_le_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_le_uint_n(nbytes), nbytes) - } - - fn read_be_uint_n(&mut self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64, i = nbytes; - while i > 0 { - i -= 1; - val += (self.read_u8() as u64) << i * 8; - } - val - } - - fn read_be_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_be_uint_n(nbytes), nbytes) - } - - fn read_le_uint(&mut self) -> uint { - self.read_le_uint_n(uint::bytes) as uint - } - - fn read_le_int(&mut self) -> int { - self.read_le_int_n(int::bytes) as int - } - - fn read_be_uint(&mut self) -> uint { - self.read_be_uint_n(uint::bytes) as uint - } - - fn read_be_int(&mut self) -> int { - self.read_be_int_n(int::bytes) as int - } - - fn read_be_u64(&mut self) -> u64 { - self.read_be_uint_n(8) as u64 - } - - fn read_be_u32(&mut self) -> u32 { - self.read_be_uint_n(4) as u32 - } - - fn read_be_u16(&mut self) -> u16 { - self.read_be_uint_n(2) as u16 - } - - fn read_be_i64(&mut self) -> i64 { - self.read_be_int_n(8) as i64 - } - - fn read_be_i32(&mut self) -> i32 { - self.read_be_int_n(4) as i32 - } - - fn read_be_i16(&mut self) -> i16 { - self.read_be_int_n(2) as i16 - } - - fn read_be_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_be_u64()) - } - } - - fn read_be_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_be_u32()) - } - } - - fn read_le_u64(&mut self) -> u64 { - self.read_le_uint_n(8) as u64 - } - - fn read_le_u32(&mut self) -> u32 { - self.read_le_uint_n(4) as u32 - } - - fn read_le_u16(&mut self) -> u16 { - self.read_le_uint_n(2) as u16 - } - - fn read_le_i64(&mut self) -> i64 { - self.read_le_int_n(8) as i64 - } - - fn read_le_i32(&mut self) -> i32 { - self.read_le_int_n(4) as i32 - } - - fn read_le_i16(&mut self) -> i16 { - self.read_le_int_n(2) as i16 - } - - fn read_le_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_le_u64()) - } - } - - fn read_le_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_le_u32()) - } - } - - fn read_u8(&mut self) -> u8 { - match self.read_byte() { - Some(b) => b as u8, - None => 0 - } - } - - fn read_i8(&mut self) -> i8 { - match self.read_byte() { - Some(b) => b as i8, - None => 0 - } - } - -} - -impl<T: Writer> WriterByteConversions for T { - fn write_int(&mut self, n: int) { - int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - - fn write_uint(&mut self, n: uint) { - uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - - fn write_le_uint(&mut self, n: uint) { - u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - - fn write_le_int(&mut self, n: int) { - u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v)) - } - - fn write_be_uint(&mut self, n: uint) { - u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - - fn write_be_int(&mut self, n: int) { - u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v)) - } - - fn write_be_u64_(&mut self, n: u64) { - u64_to_be_bytes(n, 8u, |v| self.write(v)) - } - - fn write_be_u32(&mut self, n: u32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_be_u16(&mut self, n: u16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_be_i64(&mut self, n: i64) { - u64_to_be_bytes(n as u64, 8u, |v| self.write(v)) - } - - fn write_be_i32(&mut self, n: i32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_be_i16(&mut self, n: i16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_be_f64(&mut self, f: f64) { - unsafe { - self.write_be_u64_(cast::transmute(f)) - } - } - - fn write_be_f32(&mut self, f: f32) { - unsafe { - self.write_be_u32(cast::transmute(f)) - } - } - - fn write_le_u64_(&mut self, n: u64) { - u64_to_le_bytes(n, 8u, |v| self.write(v)) - } - - fn write_le_u32(&mut self, n: u32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_le_u16(&mut self, n: u16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_le_i64(&mut self, n: i64) { - u64_to_le_bytes(n as u64, 8u, |v| self.write(v)) - } - - fn write_le_i32(&mut self, n: i32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_le_i16(&mut self, n: i16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_le_f64(&mut self, f: f64) { - unsafe { - self.write_le_u64_(cast::transmute(f)) - } - } - - fn write_le_f32(&mut self, f: f32) { - unsafe { - self.write_le_u32(cast::transmute(f)) - } - } - - fn write_u8(&mut self, n: u8) { - self.write([n]) - } - - fn write_i8(&mut self, n: i8) { - self.write([n as u8]) - } -} - -fn extend_sign(val: u64, nbytes: uint) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -#[cfg(test)] -mod test { - use super::{ReaderUtil, ReaderByteConversions, WriterByteConversions}; - use u64; - use i32; - use option::{Some, None}; - use cell::Cell; - use rt::io::mem::{MemReader, MemWriter}; - use rt::io::mock::MockReader; - use rt::io::{read_error, placeholder_error}; - - #[test] - fn read_byte() { - let mut reader = MemReader::new(~[10]); - let byte = reader.read_byte(); - assert!(byte == Some(10)); - } - - #[test] - fn read_byte_0_bytes() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - Some(0) - } else { - buf[0] = 10; - Some(1) - } - } - }; - let byte = reader.read_byte(); - assert!(byte == Some(10)); - } - - #[test] - fn read_byte_eof() { - let mut reader = MockReader::new(); - reader.read = |_| None; - let byte = reader.read_byte(); - assert!(byte == None); - } - - #[test] - fn read_byte_error() { - let mut reader = MockReader::new(); - reader.read = |_| { - read_error::cond.raise(placeholder_error()); - None - }; - do read_error::cond.trap(|_| { - }).in { - let byte = reader.read_byte(); - assert!(byte == None); - } - } - - #[test] - fn read_bytes() { - let mut reader = MemReader::new(~[10, 11, 12, 13]); - let bytes = reader.read_bytes(4); - assert!(bytes == ~[10, 11, 12, 13]); - } - - #[test] - fn read_bytes_partial() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else { - buf[0] = 12; - buf[1] = 13; - Some(2) - } - } - }; - let bytes = reader.read_bytes(4); - assert!(bytes == ~[10, 11, 12, 13]); - } - - #[test] - fn read_bytes_eof() { - let mut reader = MemReader::new(~[10, 11]); - do read_error::cond.trap(|_| { - }).in { - assert!(reader.read_bytes(4) == ~[10, 11]); - } - } - - #[test] - fn push_bytes() { - let mut reader = MemReader::new(~[10, 11, 12, 13]); - let mut buf = ~[8, 9]; - reader.push_bytes(&mut buf, 4); - assert!(buf == ~[8, 9, 10, 11, 12, 13]); - } - - #[test] - fn push_bytes_partial() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else { - buf[0] = 12; - buf[1] = 13; - Some(2) - } - } - }; - let mut buf = ~[8, 9]; - reader.push_bytes(&mut buf, 4); - assert!(buf == ~[8, 9, 10, 11, 12, 13]); - } - - #[test] - fn push_bytes_eof() { - let mut reader = MemReader::new(~[10, 11]); - let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { - }).in { - reader.push_bytes(&mut buf, 4); - assert!(buf == ~[8, 9, 10, 11]); - } - } - - #[test] - fn push_bytes_error() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - Some(1) - } else { - read_error::cond.raise(placeholder_error()); - None - } - } - }; - let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { } ).in { - reader.push_bytes(&mut buf, 4); - } - assert!(buf == ~[8, 9, 10]); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn push_bytes_fail_reset_len() { - use unstable::finally::Finally; - - // 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); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - Some(1) - } else { - read_error::cond.raise(placeholder_error()); - None - } - } - }; - let buf = @mut ~[8, 9]; - do (|| { - reader.push_bytes(&mut *buf, 4); - }).finally { - // NB: Using rtassert here to trigger abort on failure since this is a should_fail test - rtassert!(*buf == ~[8, 9, 10]); - } - } - - #[test] - fn read_to_end() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else if *count == 1 { - *count = 2; - buf[0] = 12; - buf[1] = 13; - Some(2) - } else { - None - } - } - }; - let buf = reader.read_to_end(); - assert!(buf == ~[10, 11, 12, 13]); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn read_to_end_error() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else { - read_error::cond.raise(placeholder_error()); - None - } - } - }; - let buf = reader.read_to_end(); - assert!(buf == ~[10, 11]); - } - - // XXX: Some problem with resolve here - /*#[test] - fn test_read_write_le() { - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - let mut writer = MemWriter::new(); - for uints.each |i| { - writer.write_le_u64(*i); - } - - let mut reader = MemReader::new(writer.inner()); - for uints.each |i| { - assert!(reader.read_le_u64() == *i); - } - } - - #[test] - fn test_read_write_be() { - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - let mut writer = MemWriter::new(); - for uints.each |i| { - writer.write_be_u64(*i); - } - - let mut reader = MemReader::new(writer.inner()); - for uints.each |i| { - assert!(reader.read_be_u64() == *i); - } - } - - #[test] - fn test_read_be_int_n() { - let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value]; - - let mut writer = MemWriter::new(); - for ints.each |i| { - writer.write_be_i32(*i); - } - - let mut reader = MemReader::new(writer.inner()); - for ints.each |i| { - // this tests that the sign extension is working - // (comparing the values as i32 would not test this) - assert!(reader.read_be_int_n(4) == *i as i64); - } - } - - #[test] - fn test_read_f32() { - //big-endian floating-point 8.1250 - let buf = ~[0x41, 0x02, 0x00, 0x00]; - - let mut writer = MemWriter::new(); - writer.write(buf); - - let mut reader = MemReader::new(writer.inner()); - let f = reader.read_be_f32(); - assert!(f == 8.1250); - } - - #[test] - fn test_read_write_f32() { - let f:f32 = 8.1250; - - let mut writer = MemWriter::new(); - writer.write_be_f32(f); - writer.write_le_f32(f); - - let mut reader = MemReader::new(writer.inner()); - assert!(reader.read_be_f32() == 8.1250); - assert!(reader.read_le_f32() == 8.1250); - }*/ - -} diff --git a/src/libcore/rt/io/file.rs b/src/libcore/rt/io/file.rs deleted file mode 100644 index 1f61cf25fbd..00000000000 --- a/src/libcore/rt/io/file.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::support::PathLike; -use super::{Reader, Writer, Seek}; -use super::SeekStyle; - -/// # XXX -/// * Ugh, this is ridiculous. What is the best way to represent these options? -enum FileMode { - /// Opens an existing file. IoError if file does not exist. - Open, - /// Creates a file. IoError if file exists. - Create, - /// Opens an existing file or creates a new one. - OpenOrCreate, - /// Opens an existing file or creates a new one, positioned at EOF. - Append, - /// Opens an existing file, truncating it to 0 bytes. - Truncate, - /// Opens an existing file or creates a new one, truncating it to 0 bytes. - CreateOrTruncate, -} - -enum FileAccess { - Read, - Write, - ReadWrite -} - -pub struct FileStream; - -impl FileStream { - pub fn open<P: PathLike>(_path: &P, - _mode: FileMode, - _access: FileAccess - ) -> Option<FileStream> { - fail!() - } -} - -impl Reader for FileStream { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { - fail!() - } - - fn eof(&mut self) -> bool { - fail!() - } -} - -impl Writer for FileStream { - fn write(&mut self, _v: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl Seek for FileStream { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -#[test] -#[ignore] -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()); -} diff --git a/src/libcore/rt/io/flate.rs b/src/libcore/rt/io/flate.rs deleted file mode 100644 index db2683dc85d..00000000000 --- a/src/libcore/rt/io/flate.rs +++ /dev/null @@ -1,121 +0,0 @@ -// 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. - -//! Some various other I/O types - -// NOTE: These ultimately belong somewhere else - -use prelude::*; -use super::*; - -/// A Writer decorator that compresses using the 'deflate' scheme -pub struct DeflateWriter<W> { - inner_writer: W -} - -impl<W: Writer> DeflateWriter<W> { - pub fn new(inner_writer: W) -> DeflateWriter<W> { - DeflateWriter { - inner_writer: inner_writer - } - } -} - -impl<W: Writer> Writer for DeflateWriter<W> { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl<W: Writer> Decorator<W> for DeflateWriter<W> { - fn inner(self) -> W { - match self { - DeflateWriter { inner_writer: w } => w - } - } - - fn inner_ref<'a>(&'a self) -> &'a W { - match *self { - DeflateWriter { inner_writer: ref w } => w - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut W { - match *self { - DeflateWriter { inner_writer: ref mut w } => w - } - } -} - -/// A Reader decorator that decompresses using the 'deflate' scheme -pub struct InflateReader<R> { - inner_reader: R -} - -impl<R: Reader> InflateReader<R> { - pub fn new(inner_reader: R) -> InflateReader<R> { - InflateReader { - inner_reader: inner_reader - } - } -} - -impl<R: Reader> Reader for InflateReader<R> { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl<R: Reader> Decorator<R> for InflateReader<R> { - fn inner(self) -> R { - match self { - InflateReader { inner_reader: r } => r - } - } - - fn inner_ref<'a>(&'a self) -> &'a R { - match *self { - InflateReader { inner_reader: ref r } => r - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R { - match *self { - InflateReader { inner_reader: ref mut r } => r - } - } -} - -#[cfg(test)] -mod test { - use prelude::*; - use super::*; - use super::super::mem::*; - use super::super::Decorator; - - #[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(); - deflate_writer.write(in_bytes); - deflate_writer.flush(); - let buf = deflate_writer.inner().inner(); - let mem_reader = MemReader::new(buf); - let mut inflate_reader = InflateReader::new(mem_reader); - let mut out_bytes = [0, .. 100]; - let bytes_read = inflate_reader.read(out_bytes).get(); - assert_eq!(bytes_read, in_bytes.len()); - let out_msg = str::from_bytes(out_bytes); - assert!(in_msg == out_msg); - } -} diff --git a/src/libcore/rt/io/mem.rs b/src/libcore/rt/io/mem.rs deleted file mode 100644 index b2701c1fdc3..00000000000 --- a/src/libcore/rt/io/mem.rs +++ /dev/null @@ -1,221 +0,0 @@ -// 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. - -//! Readers and Writers for in-memory buffers -//! -//! # XXX -//! -//! * Should probably have something like this for strings. -//! * Should they implement Closable? Would take extra state. - -use prelude::*; -use super::*; -use cmp::min; - -/// Writes to an owned, growable byte vector -pub struct MemWriter { - buf: ~[u8] -} - -impl MemWriter { - pub fn new() -> MemWriter { MemWriter { buf: ~[] } } -} - -impl Writer for MemWriter { - fn write(&mut self, buf: &[u8]) { - self.buf.push_all(buf) - } - - fn flush(&mut self) { /* no-op */ } -} - -impl Seek for MemWriter { - fn tell(&self) -> u64 { self.buf.len() as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -impl Decorator<~[u8]> for MemWriter { - - fn inner(self) -> ~[u8] { - match self { - MemWriter { buf: buf } => buf - } - } - - fn inner_ref<'a>(&'a self) -> &'a ~[u8] { - match *self { - MemWriter { buf: ref buf } => buf - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { - match *self { - MemWriter { buf: ref mut buf } => buf - } - } -} - -/// Reads from an owned byte vector -pub struct MemReader { - buf: ~[u8], - pos: uint -} - -impl MemReader { - pub fn new(buf: ~[u8]) -> MemReader { - MemReader { - buf: buf, - pos: 0 - } - } -} - -impl Reader for MemReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - { if self.eof() { return None; } } - - let write_len = min(buf.len(), self.buf.len() - self.pos); - { - let input = self.buf.slice(self.pos, self.pos + write_len); - let output = vec::mut_slice(buf, 0, write_len); - assert_eq!(input.len(), output.len()); - vec::bytes::copy_memory(output, input, write_len); - } - self.pos += write_len; - assert!(self.pos <= self.buf.len()); - - return Some(write_len); - } - - fn eof(&mut self) -> bool { self.pos == self.buf.len() } -} - -impl Seek for MemReader { - fn tell(&self) -> u64 { self.pos as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -impl Decorator<~[u8]> for MemReader { - - fn inner(self) -> ~[u8] { - match self { - MemReader { buf: buf, _ } => buf - } - } - - fn inner_ref<'a>(&'a self) -> &'a ~[u8] { - match *self { - MemReader { buf: ref buf, _ } => buf - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { - match *self { - MemReader { buf: ref mut buf, _ } => buf - } - } -} - - -/// Writes to a fixed-size byte slice -struct BufWriter<'self> { - buf: &'self mut [u8], - pos: uint -} - -impl<'self> BufWriter<'self> { - pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> { - BufWriter { - buf: buf, - pos: 0 - } - } -} - -impl<'self> Writer for BufWriter<'self> { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl<'self> Seek for BufWriter<'self> { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - - -/// Reads from a fixed-size byte slice -struct BufReader<'self> { - buf: &'self [u8], - pos: uint -} - -impl<'self> BufReader<'self> { - pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> { - BufReader { - buf: buf, - pos: 0 - } - } -} - -impl<'self> Reader for BufReader<'self> { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl<'self> Seek for BufReader<'self> { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -#[cfg(test)] -mod test { - use prelude::*; - use super::*; - - #[test] - fn test_mem_writer() { - let mut writer = MemWriter::new(); - assert_eq!(writer.tell(), 0); - writer.write([0]); - assert_eq!(writer.tell(), 1); - writer.write([1, 2, 3]); - writer.write([4, 5, 6, 7]); - assert_eq!(writer.tell(), 8); - assert_eq!(writer.inner(), ~[0, 1, 2, 3, 4, 5 , 6, 7]); - } - - #[test] - fn test_mem_reader() { - let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]); - let mut buf = []; - assert_eq!(reader.read(buf), Some(0)); - assert_eq!(reader.tell(), 0); - let mut buf = [0]; - assert_eq!(reader.read(buf), Some(1)); - assert_eq!(reader.tell(), 1); - assert_eq!(buf, [0]); - let mut buf = [0, ..4]; - assert_eq!(reader.read(buf), Some(4)); - assert_eq!(reader.tell(), 5); - assert_eq!(buf, [1, 2, 3, 4]); - assert_eq!(reader.read(buf), Some(3)); - assert_eq!(buf.slice(0, 3), [5, 6, 7]); - assert!(reader.eof()); - assert_eq!(reader.read(buf), None); - assert!(reader.eof()); - } -} diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs deleted file mode 100644 index 0ec51a3aa94..00000000000 --- a/src/libcore/rt/io/mod.rs +++ /dev/null @@ -1,504 +0,0 @@ -// 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. - -/*! Synchronous I/O - -This module defines the Rust interface for synchronous I/O. -It models byte-oriented input and output with the Reader and Writer traits. -Types that implement both `Reader` and `Writer` and called 'streams', -and automatically implement trait `Stream`. -Implementations are provided for common I/O streams like -file, TCP, UDP, Unix domain sockets. -Readers and Writers may be composed to add capabilities like string -parsing, encoding, and compression. - -This will likely live in core::io, not core::rt::io. - -# Examples - -Some examples of obvious things you might want to do - -* Read lines from stdin - - for stdin().each_line |line| { - println(line) - } - -* Read a complete file to a string, (converting newlines?) - - let contents = File::open("message.txt").read_to_str(); // read_to_str?? - -* Write a line to a file - - let file = File::open("message.txt", Create, Write); - file.write_line("hello, file!"); - -* Iterate over the lines of a file - - do File::open("message.txt").each_line |line| { - println(line) - } - -* Pull the lines of a file into a vector of strings - - let lines = File::open("message.txt").line_iter().to_vec(); - -* Make an simple HTTP request - - let socket = TcpStream::open("localhost:8080"); - socket.write_line("GET / HTTP/1.0"); - socket.write_line(""); - let response = socket.read_to_end(); - -* Connect based on URL? Requires thinking about where the URL type lives - and how to make protocol handlers extensible, e.g. the "tcp" protocol - yields a `TcpStream`. - - connect("tcp://localhost:8080"); - -# Terms - -* Reader - An I/O source, reads bytes into a buffer -* Writer - An I/O sink, writes bytes from a buffer -* Stream - Typical I/O sources like files and sockets are both Readers and Writers, - and are collectively referred to a `streams`. -* Decorator - A Reader or Writer that composes with others to add additional capabilities - such as encoding or decoding - -# Blocking and synchrony - -When discussing I/O you often hear the terms 'synchronous' and -'asynchronous', along with 'blocking' and 'non-blocking' compared and -contrasted. A synchronous I/O interface performs each I/O operation to -completion before proceeding to the next. Synchronous interfaces are -usually used in imperative style as a sequence of commands. An -asynchronous interface allows multiple I/O requests to be issued -simultaneously, without waiting for each to complete before proceeding -to the next. - -Asynchronous interfaces are used to achieve 'non-blocking' I/O. In -traditional single-threaded systems, performing a synchronous I/O -operation means that the program stops all activity (it 'blocks') -until the I/O is complete. Blocking is bad for performance when -there are other computations that could be done. - -Asynchronous interfaces are most often associated with the callback -(continuation-passing) style popularised by node.js. Such systems rely -on all computations being run inside an event loop which maintains a -list of all pending I/O events; when one completes the registered -callback is run and the code that made the I/O request continiues. -Such interfaces achieve non-blocking at the expense of being more -difficult to reason about. - -Rust's I/O interface is synchronous - easy to read - and non-blocking by default. - -Remember that Rust tasks are 'green threads', lightweight threads that -are multiplexed onto a single operating system thread. If that system -thread blocks then no other task may proceed. Rust tasks are -relatively cheap to create, so as long as other tasks are free to -execute then non-blocking code may be written by simply creating a new -task. - -When discussing blocking in regards to Rust's I/O model, we are -concerned with whether performing I/O blocks other Rust tasks from -proceeding. In other words, when a task calls `read`, it must then -wait (or 'sleep', or 'block') until the call to `read` is complete. -During this time, other tasks may or may not be executed, depending on -how `read` is implemented. - - -Rust's default I/O implementation is non-blocking; by cooperating -directly with the task scheduler it arranges to never block progress -of *other* tasks. Under the hood, Rust uses asynchronous I/O via a -per-scheduler (and hence per-thread) event loop. Synchronous I/O -requests are implemented by descheduling the running task and -performing an asynchronous request; the task is only resumed once the -asynchronous request completes. - -For blocking (but possibly more efficient) implementations, look -in the `io::native` module. - -# Error Handling - -I/O is an area where nearly every operation can result in unexpected -errors. It should allow errors to be handled efficiently. -It needs to be convenient to use I/O when you don't care -about dealing with specific errors. - -Rust's I/O employs a combination of techniques to reduce boilerplate -while still providing feedback about errors. The basic strategy: - -* Errors are fatal by default, resulting in task failure -* Errors raise the `io_error` conditon which provides an opportunity to inspect - an IoError object containing details. -* Return values must have a sensible null or zero value which is returned - if a condition is handled successfully. This may be an `Option`, an empty - vector, or other designated error value. -* Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`, - so that nullable values do not have to be 'unwrapped' before use. - -These features combine in the API to allow for expressions like -`File::new("diary.txt").write_line("met a girl")` without having to -worry about whether "diary.txt" exists or whether the write -succeeds. As written, if either `new` or `write_line` encounters -an error the task will fail. - -If you wanted to handle the error though you might write - - let mut error = None; - do io_error::cond(|e: IoError| { - error = Some(e); - }).in { - File::new("diary.txt").write_line("met a girl"); - } - - if error.is_some() { - println("failed to write my diary"); - } - -XXX: Need better condition handling syntax - -In this case the condition handler will have the opportunity to -inspect the IoError raised by either the call to `new` or the call to -`write_line`, but then execution will continue. - -So what actually happens if `new` encounters an error? To understand -that it's important to know that what `new` returns is not a `File` -but an `Option<File>`. If the file does not open, and the condition -is handled, then `new` will simply return `None`. Because there is an -implementation of `Writer` (the trait required ultimately required for -types to implement `write_line`) there is no need to inspect or unwrap -the `Option<File>` and we simply call `write_line` on it. If `new` -returned a `None` then the followup call to `write_line` will also -raise an error. - -## Concerns about this strategy - -This structure will encourage a programming style that is prone -to errors similar to null pointer dereferences. -In particular code written to ignore errors and expect conditions to be unhandled -will start passing around null or zero objects when wrapped in a condition handler. - -* XXX: How should we use condition handlers that return values? -* XXX: Should EOF raise default conditions when EOF is not an error? - -# Issues withi/o scheduler affinity, work stealing, task pinning - -# Resource management - -* `close` vs. RAII - -# Paths, URLs and overloaded constructors - - - -# Scope - -In scope for core - -* Url? - -Some I/O things don't belong in core - - - url - - net - `fn connect` - - http - - flate - -Out of scope - -* Async I/O. We'll probably want it eventually - - -# XXX Questions and issues - -* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose. - Overloading would be nice. -* Add overloading for Path and &str and Url &str -* stdin/err/out -* print, println, etc. -* fsync -* relationship with filesystem querying, Directory, File types etc. -* Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic? -* Can Port and Chan be implementations of a generic Reader<T>/Writer<T>? -* Trait for things that are both readers and writers, Stream? -* How to handle newline conversion -* String conversion -* File vs. FileStream? File is shorter but could also be used for getting file info - - maybe File is for general file querying and *also* has a static `open` method -* open vs. connect for generic stream opening -* Do we need `close` at all? dtors might be good enough -* How does I/O relate to the Iterator trait? -* std::base64 filters -* Using conditions is a big unknown since we don't have much experience with them -* Too many uses of OtherIoError - -*/ - -use prelude::*; - -// Reexports -pub use self::stdio::stdin; -pub use self::stdio::stdout; -pub use self::stdio::stderr; -pub use self::stdio::print; -pub use self::stdio::println; - -pub use self::file::FileStream; -pub use self::net::ip::IpAddr; -pub use self::net::tcp::TcpListener; -pub use self::net::tcp::TcpStream; -pub use self::net::udp::UdpStream; - -// Some extension traits that all Readers and Writers get. -pub use self::extensions::ReaderUtil; -pub use self::extensions::ReaderByteConversions; -pub use self::extensions::WriterByteConversions; - -/// Synchronous, non-blocking file I/O. -pub mod file; - -/// Synchronous, non-blocking network I/O. -pub mod net { - pub mod tcp; - pub mod udp; - pub mod ip; - #[cfg(unix)] - pub mod unix; - pub mod http; -} - -/// Readers and Writers for memory buffers and strings. -pub mod mem; - -/// Non-blocking access to stdin, stdout, stderr -pub mod stdio; - -/// Implementations for Option -mod option; - -/// Basic stream compression. XXX: Belongs with other flate code -pub mod flate; - -/// Interop between byte streams and pipes. Not sure where it belongs -pub mod comm_adapters; - -/// Extension traits -mod extensions; - -/// Non-I/O things needed by the I/O module -mod support; - -/// Thread-blocking implementations -pub mod native { - /// Posix file I/O - pub mod file; - /// # XXX - implement this - pub mod stdio { } - /// Sockets - /// # XXX - implement this - pub mod net { - pub mod tcp { } - pub mod udp { } - #[cfg(unix)] - pub mod unix { } - } -} - -/// Mock implementations for testing -mod mock; - -/// The default buffer size for various I/O operations -/// XXX: Not pub -pub static DEFAULT_BUF_SIZE: uint = 1024 * 64; - -/// The type passed to I/O condition handlers to indicate error -/// -/// # XXX -/// -/// Is something like this sufficient? It's kind of archaic -pub struct IoError { - kind: IoErrorKind, - desc: &'static str, - detail: Option<~str> -} - -#[deriving(Eq)] -pub enum IoErrorKind { - PreviousIoError, - OtherIoError, - EndOfFile, - FileNotFound, - PermissionDenied, - ConnectionFailed, - Closed, - ConnectionRefused, - ConnectionReset, - BrokenPipe -} - -// XXX: Can't put doc comments on macros -// Raised by `I/O` operations on error. -condition! { - // FIXME (#6009): uncomment `pub` after expansion support lands. - /*pub*/ io_error: super::IoError -> (); -} - -// XXX: Can't put doc comments on macros -// Raised by `read` on error -condition! { - // FIXME (#6009): uncomment `pub` after expansion support lands. - /*pub*/ read_error: super::IoError -> (); -} - -pub trait Reader { - /// Read bytes, up to the length of `buf` and place them in `buf`. - /// Returns the number of bytes read. The number of bytes read my - /// be less than the number requested, even 0. Returns `None` on EOF. - /// - /// # Failure - /// - /// Raises the `read_error` condition on error. If the condition - /// is handled then no guarantee is made about the number of bytes - /// read and the contents of `buf`. If the condition is handled - /// returns `None` (XXX see below). - /// - /// # XXX - /// - /// * Should raise_default error on eof? - /// * If the condition is handled it should still return the bytes read, - /// in which case there's no need to return Option - but then you *have* - /// to install a handler to detect eof. - /// - /// This doesn't take a `len` argument like the old `read`. - /// Will people often need to slice their vectors to call this - /// and will that be annoying? - /// Is it actually possible for 0 bytes to be read successfully? - fn read(&mut self, buf: &mut [u8]) -> Option<uint>; - - /// Return whether the Reader has reached the end of the stream. - /// - /// # Example - /// - /// let reader = FileStream::new() - /// while !reader.eof() { - /// println(reader.read_line()); - /// } - /// - /// # Failue - /// - /// Returns `true` on failure. - fn eof(&mut self) -> bool; -} - -pub trait Writer { - /// Write the given buffer - /// - /// # Failure - /// - /// Raises the `io_error` condition on error - fn write(&mut self, buf: &[u8]); - - /// Flush output - fn flush(&mut self); -} - -pub trait Stream: Reader + Writer { } - -pub enum SeekStyle { - /// Seek from the beginning of the stream - SeekSet, - /// Seek from the end of the stream - SeekEnd, - /// Seek from the current position - SeekCur, -} - -/// # XXX -/// * Are `u64` and `i64` the right choices? -pub trait Seek { - fn tell(&self) -> u64; - - /// Seek to an offset in a stream - /// - /// A successful seek clears the EOF indicator. - /// - /// # XXX - /// - /// * What is the behavior when seeking past the end of a stream? - fn seek(&mut self, pos: i64, style: SeekStyle); -} - -/// A listener is a value that listens for connections -pub trait Listener<S> { - /// Wait for and accept an incoming connection - /// - /// Returns `None` on timeout. - /// - /// # Failure - /// - /// Raises `io_error` condition. If the condition is handled, - /// then `accept` returns `None`. - fn accept(&mut self) -> Option<S>; -} - -/// Common trait for decorator types. -/// -/// Provides accessors to get the inner, 'decorated' values. The I/O library -/// uses decorators to add functionality like compression and encryption to I/O -/// streams. -/// -/// # XXX -/// -/// Is this worth having a trait for? May be overkill -pub trait Decorator<T> { - /// Destroy the decorator and extract the decorated value - /// - /// # XXX - /// - /// Because this takes `self' one could never 'undecorate' a Reader/Writer - /// that has been boxed. Is that ok? This feature is mostly useful for - /// extracting the buffer from MemWriter - fn inner(self) -> T; - - /// Take an immutable reference to the decorated value - fn inner_ref<'a>(&'a self) -> &'a T; - - /// Take a mutable reference to the decorated value - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T; -} - -pub fn standard_error(kind: IoErrorKind) -> IoError { - match kind { - PreviousIoError => { - IoError { - kind: PreviousIoError, - desc: "Failing due to a previous I/O error", - detail: None - } - } - EndOfFile => { - IoError { - kind: EndOfFile, - desc: "End of file", - detail: None - } - } - _ => fail!() - } -} - -pub fn placeholder_error() -> IoError { - IoError { - kind: OtherIoError, - desc: "Placeholder error. You shouldn't be seeing this", - detail: None - } -} \ No newline at end of file diff --git a/src/libcore/rt/io/native/file.rs b/src/libcore/rt/io/native/file.rs deleted file mode 100644 index 31c90336a24..00000000000 --- a/src/libcore/rt/io/native/file.rs +++ /dev/null @@ -1,74 +0,0 @@ -// 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. - -//! Blocking posix-based file I/O - -use prelude::*; -use super::super::*; -use libc::{c_int, FILE}; - -#[allow(non_camel_case_types)] -pub type fd_t = c_int; - -// Make this a newtype so we can't do I/O on arbitrary integers -pub struct FileDesc(fd_t); - -impl FileDesc { - /// Create a `FileDesc` from an open C file descriptor. - /// - /// The `FileDesc` takes ownership of the file descriptor - /// and will close it upon destruction. - pub fn new(_fd: fd_t) -> FileDesc { fail!() } -} - -impl Reader for FileDesc { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for FileDesc { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl Seek for FileDesc { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -pub struct CFile(*FILE); - -impl CFile { - /// Create a `CFile` from an open `FILE` pointer. - /// - /// The `CFile` takes ownership of the file descriptor - /// and will close it upon destruction. - pub fn new(_file: *FILE) -> CFile { fail!() } -} - -impl Reader for CFile { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for CFile { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl Seek for CFile { - fn tell(&self) -> u64 { fail!() } - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} diff --git a/src/libcore/rt/io/net/http.rs b/src/libcore/rt/io/net/http.rs deleted file mode 100644 index c693cfaab67..00000000000 --- a/src/libcore/rt/io/net/http.rs +++ /dev/null @@ -1,29 +0,0 @@ -// 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. - -//! Simple HTTP client and server - -// XXX This should not be in core - -struct HttpServer; - -#[cfg(test)] -mod test { - use unstable::run_in_bare_thread; - - #[test] #[ignore] - fn smoke_test() { - do run_in_bare_thread { - } - - do run_in_bare_thread { - } - } -} diff --git a/src/libcore/rt/io/net/ip.rs b/src/libcore/rt/io/net/ip.rs deleted file mode 100644 index df1dfe4d38a..00000000000 --- a/src/libcore/rt/io/net/ip.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -pub enum IpAddr { - Ipv4(u8, u8, u8, u8, u16), - Ipv6 -} diff --git a/src/libcore/rt/io/net/tcp.rs b/src/libcore/rt/io/net/tcp.rs deleted file mode 100644 index f7c03c13a58..00000000000 --- a/src/libcore/rt/io/net/tcp.rs +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::{Option, Some, None}; -use result::{Ok, Err}; -use rt::io::net::ip::IpAddr; -use rt::io::{Reader, Writer, Listener}; -use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{IoFactory, IoFactoryObject, - RtioTcpListener, RtioTcpListenerObject, - RtioTcpStream, RtioTcpStreamObject}; -use rt::local::Local; - -pub struct TcpStream { - rtstream: ~RtioTcpStreamObject -} - -impl TcpStream { - fn new(s: ~RtioTcpStreamObject) -> TcpStream { - TcpStream { - rtstream: s - } - } - - pub fn connect(addr: IpAddr) -> Option<TcpStream> { - let stream = unsafe { - rtdebug!("borrowing io to connect"); - let io = Local::unsafe_borrow::<IoFactoryObject>(); - rtdebug!("about to connect"); - (*io).tcp_connect(addr) - }; - - match stream { - Ok(s) => { - Some(TcpStream::new(s)) - } - Err(ioerr) => { - rtdebug!("failed to connect: %?", ioerr); - io_error::cond.raise(ioerr); - return None; - } - } - } -} - -impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - let bytes_read = self.rtstream.read(buf); - match bytes_read { - Ok(read) => Some(read), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); - } - return None; - } - } - } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for TcpStream { - fn write(&mut self, buf: &[u8]) { - let res = self.rtstream.write(buf); - match res { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } - - fn flush(&mut self) { fail!() } -} - -pub struct TcpListener { - rtlistener: ~RtioTcpListenerObject, -} - -impl TcpListener { - pub fn bind(addr: IpAddr) -> Option<TcpListener> { - let listener = unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - (*io).tcp_bind(addr) - }; - match listener { - Ok(l) => { - Some(TcpListener { - rtlistener: l - }) - } - Err(ioerr) => { - io_error::cond.raise(ioerr); - return None; - } - } - } -} - -impl Listener<TcpStream> for TcpListener { - fn accept(&mut self) -> Option<TcpStream> { - let rtstream = self.rtlistener.accept(); - match rtstream { - Ok(s) => { - Some(TcpStream::new(s)) - } - Err(ioerr) => { - io_error::cond.raise(ioerr); - return None; - } - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use int; - use cell::Cell; - use rt::test::*; - use rt::io::net::ip::Ipv4; - use rt::io::*; - - #[test] #[ignore] - fn bind_error() { - do run_in_newsched_task { - let mut called = false; - do io_error::cond.trap(|e| { - assert!(e.kind == PermissionDenied); - called = true; - }).in { - let addr = Ipv4(0, 0, 0, 0, 1); - let listener = TcpListener::bind(addr); - assert!(listener.is_none()); - } - assert!(called); - } - } - - #[test] - fn connect_error() { - do run_in_newsched_task { - let mut called = false; - do io_error::cond.trap(|e| { - assert!(e.kind == ConnectionRefused); - called = true; - }).in { - let addr = Ipv4(0, 0, 0, 0, 1); - let stream = TcpStream::connect(addr); - assert!(stream.is_none()); - } - assert!(called); - } - } - - #[test] - fn smoke_test() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let mut buf = [0]; - stream.read(buf); - assert!(buf[0] == 99); - } - - do spawntask_immediately { - let mut stream = TcpStream::connect(addr); - stream.write([99]); - } - } - } - - #[test] - fn read_eof() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let mut buf = [0]; - let nread = stream.read(buf); - assert!(nread.is_none()); - } - - do spawntask_immediately { - let _stream = TcpStream::connect(addr); - // Close - } - } - } - - #[test] - fn read_eof_twice() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let mut buf = [0]; - let nread = stream.read(buf); - assert!(nread.is_none()); - let nread = stream.read(buf); - assert!(nread.is_none()); - } - - do spawntask_immediately { - let _stream = TcpStream::connect(addr); - // Close - } - } - } - - #[test] - fn write_close() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let buf = [0]; - loop { - let mut stop = false; - do io_error::cond.trap(|e| { - // NB: ECONNRESET on linux, EPIPE on mac - assert!(e.kind == ConnectionReset || e.kind == BrokenPipe); - stop = true; - }).in { - stream.write(buf); - } - if stop { break } - } - } - - do spawntask_immediately { - let _stream = TcpStream::connect(addr); - // Close - } - } - } - - #[test] - fn multiple_connect_serial() { - do run_in_newsched_task { - let addr = next_test_ip4(); - let max = 10; - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - for max.times { - let mut stream = listener.accept(); - let mut buf = [0]; - stream.read(buf); - assert_eq!(buf[0], 99); - } - } - - do spawntask_immediately { - for max.times { - let mut stream = TcpStream::connect(addr); - stream.write([99]); - } - } - } - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule() { - do run_in_newsched_task { - let addr = next_test_ip4(); - static MAX: int = 10; - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - for int::range(0, MAX) |i| { - let stream = Cell(listener.accept()); - rtdebug!("accepted"); - // Start another task to handle the connection - do spawntask_immediately { - let mut stream = stream.take(); - let mut buf = [0]; - stream.read(buf); - assert!(buf[0] == i as u8); - rtdebug!("read"); - } - } - } - - connect(0, addr); - - fn connect(i: int, addr: IpAddr) { - if i == MAX { return } - - do spawntask_immediately { - rtdebug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - rtdebug!("writing"); - stream.write([i as u8]); - } - } - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule() { - do run_in_newsched_task { - let addr = next_test_ip4(); - static MAX: int = 10; - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - for int::range(0, MAX) |_| { - let stream = Cell(listener.accept()); - rtdebug!("accepted"); - // Start another task to handle the connection - do spawntask_later { - let mut stream = stream.take(); - let mut buf = [0]; - stream.read(buf); - assert!(buf[0] == 99); - rtdebug!("read"); - } - } - } - - connect(0, addr); - - fn connect(i: int, addr: IpAddr) { - if i == MAX { return } - - do spawntask_later { - rtdebug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - rtdebug!("writing"); - stream.write([99]); - } - } - } - } - -} diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs deleted file mode 100644 index bb5457e334d..00000000000 --- a/src/libcore/rt/io/net/udp.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::super::*; -use super::ip::IpAddr; - -pub struct UdpStream; - -impl UdpStream { - pub fn connect(_addr: IpAddr) -> Option<UdpStream> { - fail!() - } -} - -impl Reader for UdpStream { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for UdpStream { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -pub struct UdpListener; - -impl UdpListener { - pub fn bind(_addr: IpAddr) -> Option<UdpListener> { - fail!() - } -} - -impl Listener<UdpStream> for UdpListener { - fn accept(&mut self) -> Option<UdpStream> { fail!() } -} diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs deleted file mode 100644 index b85b7dd059d..00000000000 --- a/src/libcore/rt/io/net/unix.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::super::*; -use super::super::support::PathLike; - -pub struct UnixStream; - -impl UnixStream { - pub fn connect<P: PathLike>(_path: &P) -> Option<UnixStream> { - fail!() - } -} - -impl Reader for UnixStream { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for UnixStream { - fn write(&mut self, _v: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -pub struct UnixListener; - -impl UnixListener { - pub fn bind<P: PathLike>(_path: &P) -> Option<UnixListener> { - fail!() - } -} - -impl Listener<UnixStream> for UnixListener { - fn accept(&mut self) -> Option<UnixStream> { fail!() } -} diff --git a/src/libcore/rt/io/option.rs b/src/libcore/rt/io/option.rs deleted file mode 100644 index d71ef55d3ad..00000000000 --- a/src/libcore/rt/io/option.rs +++ /dev/null @@ -1,153 +0,0 @@ -// 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. - -//! Implementations of I/O traits for the Option type -//! -//! I/O constructors return option types to allow errors to be handled. -//! These implementations allow e.g. `Option<FileStream>` to be used -//! as a `Reader` without unwrapping the option first. -//! -//! # XXX Seek and Close - -use option::*; -use super::{Reader, Writer, Listener}; -use super::{standard_error, PreviousIoError, io_error, read_error, IoError}; - -fn prev_io_error() -> IoError { - standard_error(PreviousIoError) -} - -impl<W: Writer> Writer for Option<W> { - fn write(&mut self, buf: &[u8]) { - match *self { - Some(ref mut writer) => writer.write(buf), - None => io_error::cond.raise(prev_io_error()) - } - } - - fn flush(&mut self) { - match *self { - Some(ref mut writer) => writer.flush(), - None => io_error::cond.raise(prev_io_error()) - } - } -} - -impl<R: Reader> Reader for Option<R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - match *self { - Some(ref mut reader) => reader.read(buf), - None => { - read_error::cond.raise(prev_io_error()); - None - } - } - } - - fn eof(&mut self) -> bool { - match *self { - Some(ref mut reader) => reader.eof(), - None => { - io_error::cond.raise(prev_io_error()); - true - } - } - } -} - -impl<L: Listener<S>, S> Listener<S> for Option<L> { - fn accept(&mut self) -> Option<S> { - match *self { - Some(ref mut listener) => listener.accept(), - None => { - io_error::cond.raise(prev_io_error()); - None - } - } - } -} - -#[cfg(test)] -mod test { - use option::*; - use super::super::mem::*; - use rt::test::*; - use super::super::{PreviousIoError, io_error, read_error}; - - #[test] - fn test_option_writer() { - do run_in_newsched_task { - let mut writer: Option<MemWriter> = Some(MemWriter::new()); - writer.write([0, 1, 2]); - writer.flush(); - assert_eq!(writer.unwrap().inner(), ~[0, 1, 2]); - } - } - - #[test] - fn test_option_writer_error() { - do run_in_newsched_task { - let mut writer: Option<MemWriter> = None; - - let mut called = false; - do io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - writer.write([0, 0, 0]); - } - assert!(called); - - let mut called = false; - do io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - writer.flush(); - } - assert!(called); - } - } - - #[test] - fn test_option_reader() { - do run_in_newsched_task { - let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3])); - let mut buf = [0, 0]; - reader.read(buf); - assert_eq!(buf, [0, 1]); - assert!(!reader.eof()); - } - } - - #[test] - fn test_option_reader_error() { - let mut reader: Option<MemReader> = None; - let mut buf = []; - - let mut called = false; - do read_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - reader.read(buf); - } - assert!(called); - - let mut called = false; - do io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - assert!(reader.eof()); - } - assert!(called); - } -} diff --git a/src/libcore/rt/io/stdio.rs b/src/libcore/rt/io/stdio.rs deleted file mode 100644 index 247fe954408..00000000000 --- a/src/libcore/rt/io/stdio.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::{Reader, Writer}; - -pub fn stdin() -> StdReader { fail!() } - -pub fn stdout() -> StdWriter { fail!() } - -pub fn stderr() -> StdReader { fail!() } - -pub fn print(_s: &str) { fail!() } - -pub fn println(_s: &str) { fail!() } - -pub enum StdStream { - StdIn, - StdOut, - StdErr -} - -pub struct StdReader; - -impl StdReader { - pub fn new(_stream: StdStream) -> StdReader { fail!() } -} - -impl Reader for StdReader { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -pub struct StdWriter; - -impl StdWriter { - pub fn new(_stream: StdStream) -> StdWriter { fail!() } -} - -impl Writer for StdWriter { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - diff --git a/src/libcore/rt/io/support.rs b/src/libcore/rt/io/support.rs deleted file mode 100644 index 7bace5d6df2..00000000000 --- a/src/libcore/rt/io/support.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::*; - -pub trait PathLike { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T; -} - -impl<'self> PathLike for &'self str { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T { - f(*self) - } -} - -impl PathLike for Path { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T { - let s = self.to_str(); - f(s) - } -} - -#[cfg(test)] -mod test { - use path::*; - use super::PathLike; - - #[test] - fn path_like_smoke_test() { - let expected = "/home"; - let path = Path(expected); - path.path_as_str(|p| assert!(p == expected)); - path.path_as_str(|p| assert!(p == expected)); - } -} diff --git a/src/libcore/rt/local_heap.rs b/src/libcore/rt/local_heap.rs deleted file mode 100644 index 6bf228a1b22..00000000000 --- a/src/libcore/rt/local_heap.rs +++ /dev/null @@ -1,80 +0,0 @@ -// 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 local, garbage collected heap - -use libc::{c_void, uintptr_t, size_t}; -use ops::Drop; - -type MemoryRegion = c_void; -type BoxedRegion = c_void; - -pub type OpaqueBox = c_void; -pub type TypeDesc = c_void; - -pub struct LocalHeap { - memory_region: *MemoryRegion, - boxed_region: *BoxedRegion -} - -impl LocalHeap { - pub fn new() -> LocalHeap { - unsafe { - // Don't need synchronization for the single-threaded local heap - let synchronized = false as uintptr_t; - // XXX: These usually come from the environment - let detailed_leaks = false as uintptr_t; - let poison_on_free = false as uintptr_t; - let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free); - assert!(region.is_not_null()); - let boxed = rust_new_boxed_region(region, poison_on_free); - assert!(boxed.is_not_null()); - LocalHeap { - memory_region: region, - boxed_region: boxed - } - } - } - - pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox { - unsafe { - return rust_boxed_region_malloc(self.boxed_region, td, size as size_t); - } - } - - pub fn free(&mut self, box: *OpaqueBox) { - unsafe { - return rust_boxed_region_free(self.boxed_region, box); - } - } -} - -impl Drop for LocalHeap { - fn finalize(&self) { - unsafe { - rust_delete_boxed_region(self.boxed_region); - rust_delete_memory_region(self.memory_region); - } - } -} - -extern { - fn rust_new_memory_region(synchronized: uintptr_t, - detailed_leaks: uintptr_t, - poison_on_free: uintptr_t) -> *MemoryRegion; - fn rust_delete_memory_region(region: *MemoryRegion); - fn rust_new_boxed_region(region: *MemoryRegion, - poison_on_free: uintptr_t) -> *BoxedRegion; - fn rust_delete_boxed_region(region: *BoxedRegion); - fn rust_boxed_region_malloc(region: *BoxedRegion, - td: *TypeDesc, - size: size_t) -> *OpaqueBox; - fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); -} diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs deleted file mode 100644 index 2fac1df01a4..00000000000 --- a/src/libcore/rt/mod.rs +++ /dev/null @@ -1,243 +0,0 @@ -// 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 Rust Runtime, including the task scheduler and I/O - -The `rt` module provides the private runtime infrastructure necessary -to support core language features like the exchange and local heap, -the garbage collector, logging, local data and unwinding. It also -implements the default task scheduler and task model. Initialization -routines are provided for setting up runtime resources in common -configurations, including that used by `rustc` when generating -executables. - -It is intended that the features provided by `rt` can be factored in a -way such that the core library can be built with different 'profiles' -for different use cases, e.g. excluding the task scheduler. A number -of runtime features though are critical to the functioning of the -language and an implementation must be provided regardless of the -execution environment. - -Of foremost importance is the global exchange heap, in the module -`global_heap`. Very little practical Rust code can be written without -access to the global heap. Unlike most of `rt` the global heap is -truly a global resource and generally operates independently of the -rest of the runtime. - -All other runtime features are task-local, including the local heap, -the garbage collector, local storage, logging and the stack unwinder. - -The relationship between `rt` and the rest of the core library is -not entirely clear yet and some modules will be moving into or -out of `rt` as development proceeds. - -Several modules in `core` are clients of `rt`: - -* `core::task` - The user-facing interface to the Rust task model. -* `core::task::local_data` - The interface to local data. -* `core::gc` - The garbage collector. -* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`. -* `core::condition` - Uses local data. -* `core::cleanup` - Local heap destruction. -* `core::io` - In the future `core::io` will use an `rt` implementation. -* `core::logging` -* `core::pipes` -* `core::comm` -* `core::stackwalk` - -*/ - -#[doc(hidden)]; - -use ptr::Ptr; - -/// The global (exchange) heap. -pub mod global_heap; - -/// Implementations of language-critical runtime features like @. -pub mod task; - -/// The coroutine task scheduler, built on the `io` event loop. -mod sched; - -/// Synchronous I/O. -#[path = "io/mod.rs"] -pub mod io; - -/// The EventLoop and internal synchronous I/O interface. -mod rtio; - -/// libuv and default rtio implementation. -#[path = "uv/mod.rs"] -pub mod uv; - -/// The Local trait for types that are accessible via thread-local -/// or task-local storage. -pub mod local; - -/// A parallel work-stealing deque. -mod work_queue; - -/// A parallel queue. -mod message_queue; - -/// Stack segments and caching. -mod stack; - -/// CPU context swapping. -mod context; - -/// Bindings to system threading libraries. -mod thread; - -/// The runtime configuration, read from environment variables -pub mod env; - -/// The local, managed heap -mod local_heap; - -/// The Logger trait and implementations -pub mod logging; - -/// Tools for testing the runtime -pub mod test; - -/// Reference counting -pub mod rc; - -/// A simple single-threaded channel type for passing buffered data between -/// scheduler and task context -pub mod tube; - -/// Simple reimplementation of core::comm -pub mod comm; - -// FIXME #5248 shouldn't be pub -/// The runtime needs to be able to put a pointer into thread-local storage. -pub mod local_ptr; - -// FIXME #5248: The import in `sched` doesn't resolve unless this is pub! -/// Bindings to pthread/windows thread-local storage. -pub mod thread_local_storage; - - -/// Set up a default runtime configuration, given compiler-supplied arguments. -/// -/// This is invoked by the `start` _language item_ (unstable::lang) to -/// run a Rust executable. -/// -/// # Arguments -/// -/// * `argc` & `argv` - The argument vector. On Unix this information is used -/// by os::args. -/// * `crate_map` - Runtime information about the executing crate, mostly for logging -/// -/// # Return value -/// -/// The return value is used as the process return code. 0 on success, 101 on error. -pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int { - - use self::sched::{Scheduler, Coroutine}; - use self::uv::uvio::UvEventLoop; - - init(crate_map); - - let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_); - let main_task = ~Coroutine::new(&mut sched.stack_pool, main); - - sched.enqueue_task(main_task); - sched.run(); - - return 0; -} - -/// One-time runtime initialization. Currently all this does is set up logging -/// based on the RUST_LOG environment variable. -pub fn init(crate_map: *u8) { - logging::init(crate_map); -} - -/// Possible contexts in which Rust code may be executing. -/// Different runtime services are available depending on context. -/// Mostly used for determining if we're using the new scheduler -/// or the old scheduler. -#[deriving(Eq)] -pub enum RuntimeContext { - // Only the exchange heap is available - GlobalContext, - // The scheduler may be accessed - SchedulerContext, - // Full task services, e.g. local heap, unwinding - TaskContext, - // Running in an old-style task - OldTaskContext -} - -/// Determine the current RuntimeContext -pub fn context() -> RuntimeContext { - - use task::rt::rust_task; - use self::local::Local; - use self::sched::Scheduler; - - // XXX: Hitting TLS twice to check if the scheduler exists - // then to check for the task is not good for perf - if unsafe { rust_try_get_task().is_not_null() } { - return OldTaskContext; - } else { - if Local::exists::<Scheduler>() { - let context = ::cell::empty_cell(); - do Local::borrow::<Scheduler> |sched| { - if sched.in_task_context() { - context.put_back(TaskContext); - } else { - context.put_back(SchedulerContext); - } - } - return context.take(); - } else { - return GlobalContext; - } - } - - pub extern { - #[rust_stack] - fn rust_try_get_task() -> *rust_task; - } -} - -#[test] -fn test_context() { - use unstable::run_in_bare_thread; - use self::sched::{Scheduler, Coroutine}; - use rt::uv::uvio::UvEventLoop; - use cell::Cell; - use rt::local::Local; - - assert_eq!(context(), OldTaskContext); - do run_in_bare_thread { - assert_eq!(context(), GlobalContext); - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~do Coroutine::new(&mut sched.stack_pool) { - assert_eq!(context(), TaskContext); - let sched = Local::take::<Scheduler>(); - do sched.deschedule_running_task_and_then() |task| { - assert_eq!(context(), SchedulerContext); - let task = Cell(task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(task.take()); - } - } - }; - sched.enqueue_task(task); - sched.run(); - } -} diff --git a/src/libcore/rt/rtio.rs b/src/libcore/rt/rtio.rs deleted file mode 100644 index 4b5eda22ff5..00000000000 --- a/src/libcore/rt/rtio.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::*; -use result::*; - -use rt::io::IoError; -use super::io::net::ip::IpAddr; -use rt::uv::uvio; - -// XXX: ~object doesn't work currently so these are some placeholder -// types to use instead -pub type EventLoopObject = uvio::UvEventLoop; -pub type IoFactoryObject = uvio::UvIoFactory; -pub type RtioTcpStreamObject = uvio::UvTcpStream; -pub type RtioTcpListenerObject = uvio::UvTcpListener; - -pub trait EventLoop { - fn run(&mut self); - fn callback(&mut self, ~fn()); - fn callback_ms(&mut self, ms: u64, ~fn()); - /// The asynchronous I/O services. Not all event loops may provide one - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; -} - -pub trait IoFactory { - fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError>; - fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError>; -} - -pub trait RtioTcpListener { - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError>; -} - -pub trait RtioTcpStream { - fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>; - fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; -} diff --git a/src/libcore/rt/stack.rs b/src/libcore/rt/stack.rs deleted file mode 100644 index ec56e65931c..00000000000 --- a/src/libcore/rt/stack.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use container::Container; -use ptr::Ptr; -use vec; -use ops::Drop; -use libc::{c_uint, uintptr_t}; - -pub struct StackSegment { - buf: ~[u8], - valgrind_id: c_uint -} - -pub impl StackSegment { - fn new(size: uint) -> StackSegment { - unsafe { - // Crate a block of uninitialized values - let mut stack = vec::with_capacity(size); - vec::raw::set_len(&mut stack, size); - - let mut stk = StackSegment { - buf: stack, - valgrind_id: 0 - }; - - // XXX: Using the FFI to call a C macro. Slow - stk.valgrind_id = rust_valgrind_stack_register(stk.start(), stk.end()); - return stk; - } - } - - /// Point to the low end of the allocated stack - 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 { - vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint - } -} - -impl Drop for StackSegment { - fn finalize(&self) { - unsafe { - // XXX: Using the FFI to call a C macro. Slow - rust_valgrind_stack_deregister(self.valgrind_id); - } - } -} - -pub struct StackPool(()); - -impl StackPool { - pub fn new() -> StackPool { StackPool(()) } - - fn take_segment(&self, min_size: uint) -> StackSegment { - StackSegment::new(min_size) - } - - fn give_segment(&self, _stack: StackSegment) { - } -} - -extern { - fn rust_valgrind_stack_register(start: *uintptr_t, end: *uintptr_t) -> c_uint; - fn rust_valgrind_stack_deregister(id: c_uint); -} diff --git a/src/libcore/rt/task.rs b/src/libcore/rt/task.rs deleted file mode 100644 index 0314137fc7f..00000000000 --- a/src/libcore/rt/task.rs +++ /dev/null @@ -1,230 +0,0 @@ -// 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. - -//! Language-level runtime services that should reasonably expected -//! to be available 'everywhere'. Local heaps, GC, unwinding, -//! local storage, and logging. Even a 'freestanding' Rust would likely want -//! to implement this. - -use prelude::*; -use libc::{c_void, uintptr_t}; -use cast::transmute; -use super::sched::Scheduler; -use rt::local::Local; -use super::local_heap::LocalHeap; -use rt::logging::StdErrLogger; - -pub struct Task { - heap: LocalHeap, - gc: GarbageCollector, - storage: LocalStorage, - logger: StdErrLogger, - unwinder: Option<Unwinder>, - destroyed: bool -} - -pub struct GarbageCollector; -pub struct LocalStorage(*c_void, Option<~fn(*c_void)>); - -pub struct Unwinder { - unwinding: bool, -} - -impl Task { - pub fn new() -> Task { - Task { - heap: LocalHeap::new(), - gc: GarbageCollector, - storage: LocalStorage(ptr::null(), None), - logger: StdErrLogger, - unwinder: Some(Unwinder { unwinding: false }), - destroyed: false - } - } - - pub fn without_unwinding() -> Task { - Task { - heap: LocalHeap::new(), - gc: GarbageCollector, - storage: LocalStorage(ptr::null(), None), - logger: StdErrLogger, - unwinder: None, - destroyed: false - } - } - - 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)); - } - - match self.unwinder { - Some(ref mut unwinder) => { - // If there's an unwinder then set up the catch block - unwinder.try(f); - } - None => { - // Otherwise, just run the body - f() - } - } - self.destroy(); - } - - /// 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 - /// thread-local-storage. - 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)); - } - match self.storage { - LocalStorage(ptr, Some(ref dtor)) => { - (*dtor)(ptr) - } - _ => () - } - self.destroyed = true; - } -} - -impl Drop for Task { - fn finalize(&self) { assert!(self.destroyed) } -} - -// Just a sanity check to make sure we are catching a Rust-thrown exception -static UNWIND_TOKEN: uintptr_t = 839147; - -impl Unwinder { - pub fn try(&mut self, f: &fn()) { - use sys::Closure; - - unsafe { - let closure: Closure = transmute(f); - let code = transmute(closure.code); - let env = transmute(closure.env); - - let token = rust_try(try_fn, code, env); - assert!(token == 0 || token == UNWIND_TOKEN); - } - - extern fn try_fn(code: *c_void, env: *c_void) { - unsafe { - let closure: Closure = Closure { - code: transmute(code), - env: transmute(env), - }; - let closure: &fn() = transmute(closure); - closure(); - } - } - - extern { - #[rust_stack] - fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t; - } - } - - pub fn begin_unwind(&mut self) -> ! { - self.unwinding = true; - unsafe { - rust_begin_unwind(UNWIND_TOKEN); - return transmute(()); - } - extern { - fn rust_begin_unwind(token: uintptr_t); - } - } -} - -#[cfg(test)] -mod test { - use rt::test::*; - - #[test] - fn local_heap() { - do run_in_newsched_task() { - let a = @5; - let b = a; - assert!(*a == 5); - assert!(*b == 5); - } - } - - #[test] - fn tls() { - use local_data::*; - do run_in_newsched_task() { - unsafe { - fn key(_x: @~str) { } - local_data_set(key, @~"data"); - assert!(*local_data_get(key).get() == ~"data"); - fn key2(_x: @~str) { } - local_data_set(key2, @~"data"); - assert!(*local_data_get(key2).get() == ~"data"); - } - } - } - - #[test] - fn unwind() { - do run_in_newsched_task() { - let result = spawntask_try(||()); - assert!(result.is_ok()); - let result = spawntask_try(|| fail!()); - assert!(result.is_err()); - } - } - - #[test] - fn rng() { - do run_in_newsched_task() { - use rand::{rng, Rng}; - let mut r = rng(); - let _ = r.next(); - } - } - - #[test] - fn logging() { - do run_in_newsched_task() { - info!("here i am. logging in a newsched task"); - } - } - - #[test] - fn comm_oneshot() { - use comm::*; - - do run_in_newsched_task { - let (port, chan) = oneshot(); - send_one(chan, 10); - assert!(recv_one(port) == 10); - } - } - - #[test] - fn comm_stream() { - use comm::*; - - do run_in_newsched_task() { - let (port, chan) = stream(); - chan.send(10); - assert!(port.recv() == 10); - } - } -} - diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs deleted file mode 100644 index c60ae2bfeff..00000000000 --- a/src/libcore/rt/test.rs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use uint; -use option::*; -use cell::Cell; -use result::{Result, Ok, Err}; -use super::io::net::ip::{IpAddr, Ipv4}; -use rt::task::Task; -use rt::thread::Thread; -use rt::local::Local; - -/// Creates a new scheduler in a new thread and runs a task in it, -/// then waits for the scheduler to exit. Failure of the task -/// will abort the process. -pub fn run_in_newsched_task(f: ~fn()) { - use super::sched::*; - use unstable::run_in_bare_thread; - use rt::uv::uvio::UvEventLoop; - - let f = Cell(f); - - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f.take()); - sched.enqueue_task(task); - sched.run(); - } -} - -/// Test tasks will abort on failure instead of unwinding -pub fn spawntask(f: ~fn()) { - use super::sched::*; - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - do sched.switch_running_tasks_and_then(task) |task| { - let task = Cell(task); - let sched = Local::take::<Scheduler>(); - sched.schedule_new_task(task.take()); - } -} - -/// Create a new task and run it right now. Aborts on failure -pub fn spawntask_immediately(f: ~fn()) { - use super::sched::*; - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - do sched.switch_running_tasks_and_then(task) |task| { - let task = Cell(task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(task.take()); - } - } -} - -/// Create a new task and run it right now. Aborts on failure -pub fn spawntask_later(f: ~fn()) { - use super::sched::*; - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - - sched.enqueue_task(task); - Local::put(sched); -} - -/// Spawn a task and either run it immediately or run it later -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 mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - - if run_now { - do sched.switch_running_tasks_and_then(task) |task| { - let task = Cell(task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(task.take()); - } - } - } else { - sched.enqueue_task(task); - Local::put(sched); - } -} - - -/// 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() |old_task| { - let old_task = Cell(old_task); - let f = f.take(); - let mut sched = Local::take::<Scheduler>(); - 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()) |new_task| { - let new_task = Cell(new_task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(new_task.take()); - } - } - } - }; - - sched.resume_task_immediately(new_task); - } - - if !failed { 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::*; - use rt::uv::uvio::UvEventLoop; - - let f = Cell(f); - let thread = do Thread::start { - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f.take()); - sched.enqueue_task(task); - sched.run(); - }; - return thread; -} - -/// Get a port number, starting at 9600, for use in tests -pub fn next_test_port() -> u16 { - unsafe { - return rust_dbg_next_port() as u16; - } - extern { - fn rust_dbg_next_port() -> ::libc::uintptr_t; - } -} - -/// Get a unique localhost:port pair starting at 9600 -pub fn next_test_ip4() -> IpAddr { - Ipv4(127, 0, 0, 1, next_test_port()) -} - -/// Get a constant that represents the number of times to repeat stress tests. Default 1. -pub fn stress_factor() -> uint { - use os::getenv; - - match getenv("RUST_RT_STRESS") { - Some(val) => uint::from_str(val).get(), - None => 1 - } -} - diff --git a/src/libcore/rt/thread.rs b/src/libcore/rt/thread.rs deleted file mode 100644 index 0f1ae09bd94..00000000000 --- a/src/libcore/rt/thread.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc; -use ops::Drop; - -#[allow(non_camel_case_types)] // runtime type -type raw_thread = libc::c_void; - -pub struct Thread { - main: ~fn(), - raw_thread: *raw_thread -} - -pub impl Thread { - fn start(main: ~fn()) -> Thread { - fn substart(main: &~fn()) -> *raw_thread { - unsafe { rust_raw_thread_start(main) } - } - let raw = substart(&main); - Thread { - main: main, - raw_thread: raw - } - } -} - -impl Drop for Thread { - fn finalize(&self) { - unsafe { rust_raw_thread_join_delete(self.raw_thread) } - } -} - -extern { - pub unsafe fn rust_raw_thread_start(f: &(~fn())) -> *raw_thread; - pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); -} diff --git a/src/libcore/rt/thread_local_storage.rs b/src/libcore/rt/thread_local_storage.rs deleted file mode 100644 index 7187d2db41c..00000000000 --- a/src/libcore/rt/thread_local_storage.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc::c_void; -#[cfg(unix)] -use libc::c_int; -#[cfg(unix)] -use ptr::null; -#[cfg(windows)] -use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL}; - -#[cfg(unix)] -pub type Key = pthread_key_t; - -#[cfg(unix)] -pub unsafe fn create(key: &mut Key) { - assert_eq!(0, pthread_key_create(key, null())); -} - -#[cfg(unix)] -pub unsafe fn set(key: Key, value: *mut c_void) { - assert_eq!(0, pthread_setspecific(key, value)); -} - -#[cfg(unix)] -pub unsafe fn get(key: Key) -> *mut c_void { - pthread_getspecific(key) -} - -#[cfg(target_os="macos")] -#[allow(non_camel_case_types)] // foreign type -type pthread_key_t = ::libc::c_ulong; - -#[cfg(target_os="linux")] -#[cfg(target_os="freebsd")] -#[cfg(target_os="android")] -#[allow(non_camel_case_types)] // foreign type -type pthread_key_t = ::libc::c_uint; - -#[cfg(unix)] -extern { - #[fast_ffi] - fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int; - #[fast_ffi] - fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> c_int; - #[fast_ffi] - fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; -} - -#[cfg(windows)] -pub type Key = DWORD; - -#[cfg(windows)] -pub unsafe fn create(key: &mut Key) { - static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; - *key = unsafe { TlsAlloc() }; - assert!(*key != TLS_OUT_OF_INDEXES); -} - -#[cfg(windows)] -pub unsafe fn set(key: Key, value: *mut c_void) { - unsafe { assert!(0 != TlsSetValue(key, value)) } -} - -#[cfg(windows)] -pub unsafe fn get(key: Key) -> *mut c_void { - TlsGetValue(key) -} - -#[cfg(windows)] -#[abi = "stdcall"] -extern "stdcall" { - fn TlsAlloc() -> DWORD; - fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; - fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; -} - -#[test] -fn tls_smoke_test() { - use cast::transmute; - unsafe { - let mut key = 0; - let value = ~20; - create(&mut key); - set(key, transmute(value)); - let value: ~int = transmute(get(key)); - assert_eq!(value, ~20); - let value = ~30; - set(key, transmute(value)); - let value: ~int = transmute(get(key)); - assert_eq!(value, ~30); - } -} diff --git a/src/libcore/rt/uv/file.rs b/src/libcore/rt/uv/file.rs deleted file mode 100644 index 2d145055097..00000000000 --- a/src/libcore/rt/uv/file.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use ptr::null; -use libc::c_void; -use rt::uv::{Request, NativeHandle, Loop, FsCallback}; -use rt::uv::uvll; -use rt::uv::uvll::*; - -pub struct FsRequest(*uvll::uv_fs_t); -impl Request for FsRequest; - -impl FsRequest { - fn new() -> FsRequest { - let fs_req = unsafe { malloc_req(UV_FS) }; - assert!(fs_req.is_not_null()); - let fs_req = fs_req as *uvll::uv_write_t; - unsafe { uvll::set_data_for_req(fs_req, null::<()>()); } - NativeHandle::from_native_handle(fs_req) - } - - fn delete(self) { - unsafe { free_req(self.native_handle() as *c_void) } - } - - fn open(&mut self, _loop_: &Loop, _cb: FsCallback) { - } - - fn close(&mut self, _loop_: &Loop, _cb: FsCallback) { - } -} - -impl NativeHandle<*uvll::uv_fs_t> for FsRequest { - fn from_native_handle(handle: *uvll:: uv_fs_t) -> FsRequest { - FsRequest(handle) - } - fn native_handle(&self) -> *uvll::uv_fs_t { - match self { &FsRequest(ptr) => ptr } - } -} diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs deleted file mode 100644 index 2bd657fd864..00000000000 --- a/src/libcore/rt/uv/mod.rs +++ /dev/null @@ -1,420 +0,0 @@ -// 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. - -/*! - -Bindings to libuv, along with the default implementation of `core::rt::rtio`. - -UV types consist of the event loop (Loop), Watchers, Requests and -Callbacks. - -Watchers and Requests encapsulate pointers to uv *handles*, which have -subtyping relationships with each other. This subtyping is reflected -in the bindings with explicit or implicit coercions. For example, an -upcast from TcpWatcher to StreamWatcher is done with -`tcp_watcher.as_stream()`. In other cases a callback on a specific -type of watcher will be passed a watcher of a supertype. - -Currently all use of Request types (connect/write requests) are -encapsulated in the bindings and don't need to be dealt with by the -caller. - -# Safety note - -Due to the complex lifecycle of uv handles, as well as compiler bugs, -this module is not memory safe and requires explicit memory management, -via `close` and `delete` methods. - -*/ - -use container::Container; -use option::*; -use str::raw::from_c_str; -use to_str::ToStr; -use ptr::Ptr; -use libc; -use vec; -use ptr; -use cast; -use str; -use libc::{c_void, c_int, size_t, malloc, free}; -use cast::transmute; -use ptr::null; -use unstable::finally::Finally; - -use rt::io::IoError; - -#[cfg(test)] use unstable::run_in_bare_thread; - -pub use self::file::FsRequest; -pub use self::net::{StreamWatcher, TcpWatcher}; -pub use self::idle::IdleWatcher; -pub use self::timer::TimerWatcher; - -/// The implementation of `rtio` for libuv -pub mod uvio; - -/// C bindings to libuv -pub mod uvll; - -pub mod file; -pub mod net; -pub mod idle; -pub mod timer; - -/// XXX: Loop(*handle) is buggy with destructors. Normal structs -/// with dtors may not be destructured, but tuple structs can, -/// but the results are not correct. -pub struct Loop { - handle: *uvll::uv_loop_t -} - -/// The trait implemented by uv 'watchers' (handles). Watchers are -/// non-owning wrappers around the uv handles and are not completely -/// safe - there may be multiple instances for a single underlying -/// handle. Watchers are generally created, then `start`ed, `stop`ed -/// and `close`ed, but due to their complex life cycle may not be -/// entirely memory safe if used in unanticipated patterns. -pub trait Watcher { } - -pub trait Request { } - -/// A type that wraps a native handle -pub trait NativeHandle<T> { - pub fn from_native_handle(T) -> Self; - pub fn native_handle(&self) -> T; -} - -pub impl Loop { - fn new() -> Loop { - let handle = unsafe { uvll::loop_new() }; - assert!(handle.is_not_null()); - NativeHandle::from_native_handle(handle) - } - - fn run(&mut self) { - unsafe { uvll::run(self.native_handle()) }; - } - - fn close(&mut self) { - unsafe { uvll::loop_delete(self.native_handle()) }; - } -} - -impl NativeHandle<*uvll::uv_loop_t> for Loop { - fn from_native_handle(handle: *uvll::uv_loop_t) -> Loop { - Loop { handle: handle } - } - fn native_handle(&self) -> *uvll::uv_loop_t { - self.handle - } -} - -// XXX: The uv alloc callback also has a *uv_handle_t arg -pub type AllocCallback = ~fn(uint) -> Buf; -pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option<UvError>); -pub type NullCallback = ~fn(); -pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>); -pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>); -pub type FsCallback = ~fn(FsRequest, Option<UvError>); -pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>); - - -/// Callbacks used by StreamWatchers, set as custom data on the foreign handle -struct WatcherData { - read_cb: Option<ReadCallback>, - write_cb: Option<ConnectionCallback>, - connect_cb: Option<ConnectionCallback>, - close_cb: Option<NullCallback>, - alloc_cb: Option<AllocCallback>, - idle_cb: Option<IdleCallback>, - timer_cb: Option<TimerCallback> -} - -pub trait WatcherInterop { - fn event_loop(&self) -> Loop; - fn install_watcher_data(&mut self); - fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData; - fn drop_watcher_data(&mut self); -} - -impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W { - /// Get the uv event loop from a Watcher - pub fn event_loop(&self) -> Loop { - unsafe { - let handle = self.native_handle(); - let loop_ = uvll::get_loop_for_uv_handle(handle); - NativeHandle::from_native_handle(loop_) - } - } - - pub fn install_watcher_data(&mut self) { - unsafe { - let data = ~WatcherData { - read_cb: None, - write_cb: None, - connect_cb: None, - close_cb: None, - alloc_cb: None, - idle_cb: None, - timer_cb: None - }; - let data = transmute::<~WatcherData, *c_void>(data); - uvll::set_data_for_uv_handle(self.native_handle(), data); - } - } - - pub fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData { - unsafe { - let data = uvll::get_data_for_uv_handle(self.native_handle()); - let data = transmute::<&*c_void, &mut ~WatcherData>(&data); - return &mut **data; - } - } - - pub fn drop_watcher_data(&mut self) { - unsafe { - let data = uvll::get_data_for_uv_handle(self.native_handle()); - let _data = transmute::<*c_void, ~WatcherData>(data); - uvll::set_data_for_uv_handle(self.native_handle(), null::<()>()); - } - } -} - -// XXX: Need to define the error constants like EOF so they can be -// compared to the UvError type - -pub struct UvError(uvll::uv_err_t); - -pub impl UvError { - - fn name(&self) -> ~str { - unsafe { - let inner = match self { &UvError(ref a) => a }; - let name_str = uvll::err_name(inner); - assert!(name_str.is_not_null()); - from_c_str(name_str) - } - } - - fn desc(&self) -> ~str { - unsafe { - let inner = match self { &UvError(ref a) => a }; - let desc_str = uvll::strerror(inner); - assert!(desc_str.is_not_null()); - from_c_str(desc_str) - } - } - - fn is_eof(&self) -> bool { - self.code == uvll::EOF - } -} - -impl ToStr for UvError { - fn to_str(&self) -> ~str { - fmt!("%s: %s", self.name(), self.desc()) - } -} - -#[test] -fn error_smoke_test() { - let err = uvll::uv_err_t { code: 1, sys_errno_: 1 }; - let err: UvError = UvError(err); - assert_eq!(err.to_str(), ~"EOF: end of file"); -} - -pub fn last_uv_error<H, W: Watcher + NativeHandle<*H>>(watcher: &W) -> UvError { - unsafe { - let loop_ = watcher.event_loop(); - UvError(uvll::last_error(loop_.native_handle())) - } -} - -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::*; - use rt::io::*; - - // uv error descriptions are static - let c_desc = uvll::strerror(&*uverr); - let desc = c_str_to_static_slice(c_desc); - - let kind = match uverr.code { - UNKNOWN => OtherIoError, - OK => OtherIoError, - EOF => EndOfFile, - EACCES => PermissionDenied, - ECONNREFUSED => ConnectionRefused, - ECONNRESET => ConnectionReset, - EPIPE => BrokenPipe, - _ => { - rtdebug!("uverr.code %u", uverr.code as uint); - // XXX: Need to map remaining uv error types - OtherIoError - } - }; - - IoError { - kind: kind, - desc: desc, - detail: None - } - } -} - -/// Given a uv handle, convert a callback status to a UvError -// XXX: Follow the pattern below by parameterizing over T: Watcher, not T -pub fn status_to_maybe_uv_error<T>(handle: *T, status: c_int) -> Option<UvError> { - if status != -1 { - None - } else { - unsafe { - rtdebug!("handle: %x", handle as uint); - let loop_ = uvll::get_loop_for_uv_handle(handle); - rtdebug!("loop: %x", loop_ as uint); - let err = uvll::last_error(loop_); - Some(UvError(err)) - } - } -} - -/// The uv buffer type -pub type Buf = uvll::uv_buf_t; - -/// Borrow a slice to a Buf -pub fn slice_to_uv_buf(v: &[u8]) -> Buf { - let data = vec::raw::to_ptr(v); - unsafe { uvll::buf_init(data, v.len()) } -} - -// XXX: Do these conversions without copying - -/// Transmute an owned vector to a Buf -pub fn vec_to_uv_buf(v: ~[u8]) -> Buf { - unsafe { - let data = malloc(v.len() as size_t) as *u8; - assert!(data.is_not_null()); - do vec::as_imm_buf(v) |b, l| { - let data = data as *mut u8; - ptr::copy_memory(data, b, l) - } - uvll::buf_init(data, v.len()) - } -} - -/// Transmute a Buf that was once a ~[u8] back to ~[u8] -pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> { - if !(buf.len == 0 && buf.base.is_null()) { - let v = unsafe { vec::from_buf(buf.base, buf.len as uint) }; - unsafe { free(buf.base as *c_void) }; - return Some(v); - } else { - // No buffer - rtdebug!("No buffer!"); - return None; - } -} - -#[test] -fn test_slice_to_uv_buf() { - let slice = [0, .. 20]; - let buf = slice_to_uv_buf(slice); - - assert!(buf.len == 20); - - unsafe { - let base = transmute::<*u8, *mut u8>(buf.base); - (*base) = 1; - (*ptr::mut_offset(base, 1)) = 2; - } - - assert!(slice[0] == 1); - assert!(slice[1] == 2); -} - - -#[test] -fn loop_smoke_test() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - loop_.run(); - loop_.close(); - } -} - -#[test] -#[ignore(reason = "valgrind - loop destroyed before watcher?")] -fn idle_new_then_close() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let idle_watcher = { IdleWatcher::new(&mut loop_) }; - idle_watcher.close(||()); - } -} - -#[test] -fn idle_smoke_test() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let mut idle_watcher = { IdleWatcher::new(&mut loop_) }; - let mut count = 10; - let count_ptr: *mut int = &mut count; - do idle_watcher.start |idle_watcher, status| { - let mut idle_watcher = idle_watcher; - assert!(status.is_none()); - if unsafe { *count_ptr == 10 } { - idle_watcher.stop(); - idle_watcher.close(||()); - } else { - unsafe { *count_ptr = *count_ptr + 1; } - } - } - loop_.run(); - loop_.close(); - assert_eq!(count, 10); - } -} - -#[test] -fn idle_start_stop_start() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let mut idle_watcher = { IdleWatcher::new(&mut loop_) }; - do idle_watcher.start |idle_watcher, status| { - let mut idle_watcher = idle_watcher; - assert!(status.is_none()); - idle_watcher.stop(); - do idle_watcher.start |idle_watcher, status| { - assert!(status.is_none()); - let mut idle_watcher = idle_watcher; - idle_watcher.stop(); - idle_watcher.close(||()); - } - } - loop_.run(); - loop_.close(); - } -} diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs deleted file mode 100644 index 68b871e6b31..00000000000 --- a/src/libcore/rt/uv/net.rs +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use libc::{size_t, ssize_t, c_int, c_void}; -use rt::uv::uvll; -use rt::uv::uvll::*; -use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback}; -use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, - status_to_maybe_uv_error}; -use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; -use rt::uv::last_uv_error; - -fn ip4_as_uv_ip4<T>(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { - match addr { - Ipv4(a, b, c, d, p) => { - unsafe { - let addr = malloc_ip4_addr(fmt!("%u.%u.%u.%u", - a as uint, - b as uint, - c as uint, - d as uint), p as int); - do (|| { - f(addr) - }).finally { - free_ip4_addr(addr); - } - } - } - Ipv6 => fail!() - } -} - -// uv_stream t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t -// and uv_file_t -pub struct StreamWatcher(*uvll::uv_stream_t); -impl Watcher for StreamWatcher { } - -pub impl StreamWatcher { - - fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) { - { - let data = self.get_watcher_data(); - data.alloc_cb = Some(alloc); - data.read_cb = Some(cb); - } - - let handle = self.native_handle(); - unsafe { uvll::read_start(handle, alloc_cb, read_cb); } - - extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf { - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream); - let data = stream_watcher.get_watcher_data(); - let alloc_cb = data.alloc_cb.get_ref(); - return (*alloc_cb)(suggested_size as uint); - } - - extern fn read_cb(stream: *uvll::uv_stream_t, nread: ssize_t, buf: Buf) { - rtdebug!("buf addr: %x", buf.base as uint); - rtdebug!("buf len: %d", buf.len as int); - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream); - let data = stream_watcher.get_watcher_data(); - let cb = data.read_cb.get_ref(); - let status = status_to_maybe_uv_error(stream, nread as c_int); - (*cb)(stream_watcher, nread as int, buf, status); - } - } - - 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 - let handle = self.native_handle(); - unsafe { uvll::read_stop(handle); } - } - - fn write(&mut self, buf: Buf, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.write_cb.is_none()); - data.write_cb = Some(cb); - } - - let req = WriteRequest::new(); - let bufs = [buf]; - unsafe { - assert!(0 == uvll::write(req.native_handle(), - self.native_handle(), - bufs, write_cb)); - } - - extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { - let write_request: WriteRequest = NativeHandle::from_native_handle(req); - let mut stream_watcher = write_request.stream(); - write_request.delete(); - let cb = { - let data = stream_watcher.get_watcher_data(); - let cb = data.write_cb.swap_unwrap(); - cb - }; - let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); - cb(stream_watcher, status); - } - } - - 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 { - assert_eq!(0, uvll::accept(self_handle, stream_handle)); - } - } - - fn close(self, cb: NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern fn close_cb(handle: *uvll::uv_stream_t) { - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - { - let data = stream_watcher.get_watcher_data(); - data.close_cb.swap_unwrap()(); - } - stream_watcher.drop_watcher_data(); - unsafe { free_handle(handle as *c_void) } - } - } -} - -impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher { - fn from_native_handle( - handle: *uvll::uv_stream_t) -> StreamWatcher { - StreamWatcher(handle) - } - fn native_handle(&self) -> *uvll::uv_stream_t { - match self { &StreamWatcher(ptr) => ptr } - } -} - -pub struct TcpWatcher(*uvll::uv_tcp_t); -impl Watcher for TcpWatcher { } - -pub impl TcpWatcher { - fn new(loop_: &mut Loop) -> TcpWatcher { - unsafe { - let handle = malloc_handle(UV_TCP); - assert!(handle.is_not_null()); - assert_eq!(0, uvll::tcp_init(loop_.native_handle(), handle)); - let mut watcher: TcpWatcher = NativeHandle::from_native_handle(handle); - watcher.install_watcher_data(); - return watcher; - } - } - - fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - let result = unsafe { - uvll::tcp_bind(self.native_handle(), addr) - }; - if result == 0 { - Ok(()) - } else { - Err(last_uv_error(self)) - } - } - } - _ => fail!() - } - } - - 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); - - let connect_handle = ConnectRequest::new().native_handle(); - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - rtdebug!("connect_t: %x", connect_handle as uint); - assert!(0 == uvll::tcp_connect(connect_handle, - self.native_handle(), - addr, connect_cb)); - } - } - _ => fail!() - } - - extern fn connect_cb(req: *uvll::uv_connect_t, status: c_int) { - rtdebug!("connect_t: %x", req as uint); - let connect_request: ConnectRequest = NativeHandle::from_native_handle(req); - let mut stream_watcher = connect_request.stream(); - connect_request.delete(); - let cb: ConnectionCallback = { - let data = stream_watcher.get_watcher_data(); - data.connect_cb.swap_unwrap() - }; - let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); - cb(stream_watcher, status); - } - } - } - - fn listen(&mut self, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.connect_cb.is_none()); - data.connect_cb = Some(cb); - } - - unsafe { - static BACKLOG: c_int = 128; // XXX should be configurable - // XXX: This can probably fail - assert!(0 == uvll::listen(self.native_handle(), - BACKLOG, connection_cb)); - } - - extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { - rtdebug!("connection_cb"); - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - let data = stream_watcher.get_watcher_data(); - let cb = data.connect_cb.get_ref(); - let status = status_to_maybe_uv_error(handle, status); - (*cb)(stream_watcher, status); - } - } - - fn as_stream(&self) -> StreamWatcher { - NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t) - } -} - -impl NativeHandle<*uvll::uv_tcp_t> for TcpWatcher { - fn from_native_handle(handle: *uvll::uv_tcp_t) -> TcpWatcher { - TcpWatcher(handle) - } - fn native_handle(&self) -> *uvll::uv_tcp_t { - match self { &TcpWatcher(ptr) => ptr } - } -} - -// uv_connect_t is a subclass of uv_req_t -struct ConnectRequest(*uvll::uv_connect_t); -impl Request for ConnectRequest { } - -impl ConnectRequest { - - fn new() -> ConnectRequest { - let connect_handle = unsafe { - malloc_req(UV_CONNECT) - }; - assert!(connect_handle.is_not_null()); - let connect_handle = connect_handle as *uvll::uv_connect_t; - ConnectRequest(connect_handle) - } - - fn stream(&self) -> StreamWatcher { - unsafe { - let stream_handle = uvll::get_stream_handle_from_connect_req(self.native_handle()); - NativeHandle::from_native_handle(stream_handle) - } - } - - fn delete(self) { - unsafe { free_req(self.native_handle() as *c_void) } - } -} - -impl NativeHandle<*uvll::uv_connect_t> for ConnectRequest { - fn from_native_handle( - handle: *uvll:: uv_connect_t) -> ConnectRequest { - ConnectRequest(handle) - } - fn native_handle(&self) -> *uvll::uv_connect_t { - match self { &ConnectRequest(ptr) => ptr } - } -} - -pub struct WriteRequest(*uvll::uv_write_t); - -impl Request for WriteRequest { } - -pub impl WriteRequest { - - fn new() -> WriteRequest { - let write_handle = unsafe { - malloc_req(UV_WRITE) - }; - assert!(write_handle.is_not_null()); - let write_handle = write_handle as *uvll::uv_write_t; - WriteRequest(write_handle) - } - - 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) { - unsafe { free_req(self.native_handle() as *c_void) } - } -} - -impl NativeHandle<*uvll::uv_write_t> for WriteRequest { - fn from_native_handle(handle: *uvll:: uv_write_t) -> WriteRequest { - WriteRequest(handle) - } - fn native_handle(&self) -> *uvll::uv_write_t { - match self { &WriteRequest(ptr) => ptr } - } -} - - -#[cfg(test)] -mod test { - use super::*; - use util::ignore; - use cell::Cell; - use vec; - use unstable::run_in_bare_thread; - use rt::thread::Thread; - use rt::test::*; - use rt::uv::{Loop, AllocCallback}; - use rt::uv::{vec_from_uv_buf, vec_to_uv_buf, slice_to_uv_buf}; - - #[test] - fn connect_close() { - do run_in_bare_thread() { - let mut loop_ = Loop::new(); - let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - // Connect to a port where nobody is listening - let addr = next_test_ip4(); - do tcp_watcher.connect(addr) |stream_watcher, status| { - rtdebug!("tcp_watcher.connect!"); - assert!(status.is_some()); - assert_eq!(status.get().name(), ~"ECONNREFUSED"); - stream_watcher.close(||()); - } - loop_.run(); - loop_.close(); - } - } - - #[test] - fn listen() { - do run_in_bare_thread() { - static MAX: int = 10; - let mut loop_ = Loop::new(); - let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = next_test_ip4(); - server_tcp_watcher.bind(addr); - let loop_ = loop_; - rtdebug!("listening"); - do server_tcp_watcher.listen |server_stream_watcher, status| { - rtdebug!("listened!"); - assert!(status.is_none()); - let mut server_stream_watcher = server_stream_watcher; - let mut loop_ = loop_; - 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 server_stream_watcher = server_stream_watcher; - rtdebug!("starting read"); - let alloc: AllocCallback = |size| { - vec_to_uv_buf(vec::from_elem(size, 0)) - }; - do client_tcp_watcher.read_start(alloc) - |stream_watcher, nread, buf, status| { - - rtdebug!("i'm reading!"); - let buf = vec_from_uv_buf(buf); - let mut count = count_cell.take(); - if status.is_none() { - rtdebug!("got %d bytes", nread); - let buf = buf.unwrap(); - for buf.slice(0, nread as uint).each |byte| { - assert!(*byte == count as u8); - rtdebug!("%u", *byte as uint); - count += 1; - } - } else { - assert_eq!(count, MAX); - do stream_watcher.close { - server_stream_watcher.close(||()); - } - } - count_cell.put_back(count); - } - } - - let _client_thread = do Thread::start { - rtdebug!("starting client thread"); - let mut loop_ = Loop::new(); - let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - do tcp_watcher.connect(addr) |stream_watcher, status| { - rtdebug!("connecting"); - assert!(status.is_none()); - 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); - do stream_watcher.write(buf) |stream_watcher, status| { - rtdebug!("writing"); - assert!(status.is_none()); - let msg_cell = Cell(msg_cell.take()); - stream_watcher.close(||ignore(msg_cell.take())); - } - } - loop_.run(); - loop_.close(); - }; - - let mut loop_ = loop_; - loop_.run(); - loop_.close(); - } - } -} diff --git a/src/libcore/rt/uv/uvio.rs b/src/libcore/rt/uv/uvio.rs deleted file mode 100644 index cacd67314eb..00000000000 --- a/src/libcore/rt/uv/uvio.rs +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::*; -use result::*; -use ops::Drop; -use cell::{Cell, empty_cell}; -use cast::transmute; -use clone::Clone; -use rt::io::IoError; -use rt::io::net::ip::IpAddr; -use rt::uv::*; -use rt::uv::idle::IdleWatcher; -use rt::rtio::*; -use rt::sched::Scheduler; -use rt::io::{standard_error, OtherIoError}; -use rt::tube::Tube; -use rt::local::Local; - -#[cfg(test)] use container::Container; -#[cfg(test)] use uint; -#[cfg(test)] use unstable::run_in_bare_thread; -#[cfg(test)] use rt::test::*; - -pub struct UvEventLoop { - uvio: UvIoFactory -} - -pub impl UvEventLoop { - fn new() -> UvEventLoop { - UvEventLoop { - uvio: UvIoFactory(Loop::new()) - } - } - - /// A convenience constructor - fn new_scheduler() -> Scheduler { - Scheduler::new(~UvEventLoop::new()) - } -} - -impl Drop for UvEventLoop { - fn finalize(&self) { - // XXX: Need mutable finalizer - let this = unsafe { - transmute::<&UvEventLoop, &mut UvEventLoop>(self) - }; - this.uvio.uv_loop().close(); - } -} - -impl EventLoop for UvEventLoop { - - fn run(&mut self) { - self.uvio.uv_loop().run(); - } - - fn callback(&mut self, f: ~fn()) { - let mut idle_watcher = IdleWatcher::new(self.uvio.uv_loop()); - do idle_watcher.start |idle_watcher, status| { - assert!(status.is_none()); - let mut idle_watcher = idle_watcher; - idle_watcher.stop(); - idle_watcher.close(||()); - f(); - } - } - - fn callback_ms(&mut self, ms: u64, f: ~fn()) { - let mut timer = TimerWatcher::new(self.uvio.uv_loop()); - do timer.start(ms, 0) |timer, status| { - assert!(status.is_none()); - timer.close(||()); - f(); - } - } - - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { - Some(&mut self.uvio) - } -} - -#[test] -fn test_callback_run_once() { - do run_in_bare_thread { - let mut event_loop = UvEventLoop::new(); - let mut count = 0; - let count_ptr: *mut int = &mut count; - do event_loop.callback { - unsafe { *count_ptr += 1 } - } - event_loop.run(); - assert_eq!(count, 1); - } -} - -pub struct UvIoFactory(Loop); - -pub impl UvIoFactory { - fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { - match self { &UvIoFactory(ref mut ptr) => ptr } - } -} - -impl IoFactory for UvIoFactory { - // Connect to an address and return a new stream - // NB: This blocks the task waiting on the connection. - // It would probably be better to return a future - 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_ptr: *Cell<Result<~RtioTcpStreamObject, IoError>> = &result_cell; - - let scheduler = Local::take::<Scheduler>(); - assert!(scheduler.in_task_context()); - - // Block this task and take ownership, switch to scheduler context - do scheduler.deschedule_running_task_and_then |task| { - - rtdebug!("connect: entered scheduler context"); - do Local::borrow::<Scheduler> |scheduler| { - assert!(!scheduler.in_task_context()); - } - let mut tcp_watcher = TcpWatcher::new(self.uv_loop()); - let task_cell = Cell(task); - - // Wait for a connection - do tcp_watcher.connect(addr) |stream_watcher, status| { - rtdebug!("connect: in connect callback"); - if status.is_none() { - rtdebug!("status is none"); - let res = Ok(~UvTcpStream { watcher: stream_watcher }); - - // Store the stream in the task's stack - unsafe { (*result_cell_ptr).put_back(res); } - - // Context switch - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } else { - rtdebug!("status is some"); - let task_cell = Cell(task_cell.take()); - do stream_watcher.close { - let res = Err(uv_error_to_io_error(status.get())); - unsafe { (*result_cell_ptr).put_back(res); } - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - }; - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } - - fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError> { - let mut watcher = TcpWatcher::new(self.uv_loop()); - match watcher.bind(addr) { - Ok(_) => Ok(~UvTcpListener::new(watcher)), - Err(uverr) => { - let scheduler = Local::take::<Scheduler>(); - do scheduler.deschedule_running_task_and_then |task| { - let task_cell = Cell(task); - do watcher.as_stream().close { - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - Err(uv_error_to_io_error(uverr)) - } - } - } -} - -// FIXME #6090: Prefer newtype structs but Drop doesn't work -pub struct UvTcpListener { - watcher: TcpWatcher, - listening: bool, - incoming_streams: Tube<Result<~RtioTcpStreamObject, IoError>> -} - -impl UvTcpListener { - fn new(watcher: TcpWatcher) -> UvTcpListener { - UvTcpListener { - watcher: watcher, - listening: false, - incoming_streams: Tube::new() - } - } - - fn watcher(&self) -> TcpWatcher { self.watcher } -} - -impl Drop for UvTcpListener { - fn finalize(&self) { - let watcher = self.watcher(); - let scheduler = Local::take::<Scheduler>(); - do scheduler.deschedule_running_task_and_then |task| { - let task_cell = Cell(task); - do watcher.as_stream().close { - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - } -} - -impl RtioTcpListener for UvTcpListener { - - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> { - rtdebug!("entering listen"); - - if self.listening { - return self.incoming_streams.recv(); - } - - self.listening = true; - - let server_tcp_watcher = self.watcher(); - let incoming_streams_cell = Cell(self.incoming_streams.clone()); - - let incoming_streams_cell = Cell(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() { - let mut server_stream_watcher = server_stream_watcher; - let mut loop_ = server_stream_watcher.event_loop(); - let client_tcp_watcher = TcpWatcher::new(&mut loop_); - let client_tcp_watcher = client_tcp_watcher.as_stream(); - // XXX: Need's to be surfaced in interface - server_stream_watcher.accept(client_tcp_watcher); - Ok(~UvTcpStream { watcher: client_tcp_watcher }) - } else { - Err(standard_error(OtherIoError)) - }; - - let mut incoming_streams = incoming_streams_cell.take(); - incoming_streams.send(maybe_stream); - incoming_streams_cell.put_back(incoming_streams); - } - - return self.incoming_streams.recv(); - } -} - -// FIXME #6090: Prefer newtype structs but Drop doesn't work -pub struct UvTcpStream { - watcher: StreamWatcher -} - -impl UvTcpStream { - fn watcher(&self) -> StreamWatcher { self.watcher } -} - -impl Drop for UvTcpStream { - fn finalize(&self) { - rtdebug!("closing tcp stream"); - let watcher = self.watcher(); - let scheduler = Local::take::<Scheduler>(); - do scheduler.deschedule_running_task_and_then |task| { - let task_cell = Cell(task); - do watcher.close { - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - } -} - -impl RtioTcpStream for UvTcpStream { - fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> { - let result_cell = empty_cell(); - let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell; - - let scheduler = Local::take::<Scheduler>(); - assert!(scheduler.in_task_context()); - let watcher = self.watcher(); - let buf_ptr: *&mut [u8] = &buf; - do scheduler.deschedule_running_task_and_then |task| { - rtdebug!("read: entered scheduler context"); - do Local::borrow::<Scheduler> |scheduler| { - assert!(!scheduler.in_task_context()); - } - let mut watcher = watcher; - let task_cell = Cell(task); - // XXX: We shouldn't reallocate these callbacks every - // call to read - let alloc: AllocCallback = |_| unsafe { - slice_to_uv_buf(*buf_ptr) - }; - do watcher.read_start(alloc) |watcher, nread, _buf, status| { - - // Stop reading so that no read callbacks are - // triggered before the user calls `read` again. - // XXX: Is there a performance impact to calling - // stop here? - let mut watcher = watcher; - watcher.read_stop(); - - let result = if status.is_none() { - assert!(nread >= 0); - Ok(nread as uint) - } else { - Err(uv_error_to_io_error(status.unwrap())) - }; - - unsafe { (*result_cell_ptr).put_back(result); } - - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } - - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { - let result_cell = empty_cell(); - let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell; - let scheduler = Local::take::<Scheduler>(); - assert!(scheduler.in_task_context()); - let watcher = self.watcher(); - let buf_ptr: *&[u8] = &buf; - do scheduler.deschedule_running_task_and_then |task| { - let mut watcher = watcher; - let task_cell = Cell(task); - let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - do watcher.write(buf) |_watcher, status| { - let result = if status.is_none() { - Ok(()) - } else { - Err(uv_error_to_io_error(status.unwrap())) - }; - - unsafe { (*result_cell_ptr).put_back(result); } - - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } -} - -#[test] -fn test_simple_io_no_connect() { - do run_in_newsched_task { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let addr = next_test_ip4(); - let maybe_chan = (*io).tcp_connect(addr); - assert!(maybe_chan.is_err()); - } - } -} - -#[test] -fn test_simple_tcp_server_and_client() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - // Start the server first so it's listening when we connect - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut listener = (*io).tcp_bind(addr).unwrap(); - let mut stream = listener.accept().unwrap(); - let mut buf = [0, .. 2048]; - let nread = stream.read(buf).unwrap(); - assert_eq!(nread, 8); - for uint::range(0, nread) |i| { - rtdebug!("%u", buf[i] as uint); - assert_eq!(buf[i], i as u8); - } - } - } - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut stream = (*io).tcp_connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - } - } - } -} - -#[test] #[ignore(reason = "busted")] -fn test_read_and_block() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() }; - let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() }; - let mut stream = listener.accept().unwrap(); - let mut buf = [0, .. 2048]; - - let expected = 32; - let mut current = 0; - let mut reads = 0; - - while current < expected { - let nread = stream.read(buf).unwrap(); - for uint::range(0, nread) |i| { - let val = buf[i] as uint; - assert_eq!(val, current % 8); - current += 1; - } - reads += 1; - - let scheduler = Local::take::<Scheduler>(); - // Yield to the other task in hopes that it - // will trigger a read callback while we are - // not ready for it - do scheduler.deschedule_running_task_and_then |task| { - let task = Cell(task); - do Local::borrow::<Scheduler> |scheduler| { - scheduler.enqueue_task(task.take()); - } - } - } - - // Make sure we had multiple reads - assert!(reads > 1); - } - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut stream = (*io).tcp_connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - } - } - - } -} - -#[test] -fn test_read_read_read() { - do run_in_newsched_task { - let addr = next_test_ip4(); - static MAX: uint = 500000; - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut listener = (*io).tcp_bind(addr).unwrap(); - let mut stream = listener.accept().unwrap(); - let buf = [1, .. 2048]; - let mut total_bytes_written = 0; - while total_bytes_written < MAX { - stream.write(buf); - total_bytes_written += buf.len(); - } - } - } - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut stream = (*io).tcp_connect(addr).unwrap(); - let mut buf = [0, .. 2048]; - let mut total_bytes_read = 0; - while total_bytes_read < MAX { - let nread = stream.read(buf).unwrap(); - rtdebug!("read %u bytes", nread as uint); - total_bytes_read += nread; - for uint::range(0, nread) |i| { - assert_eq!(buf[i], 1); - } - } - rtdebug!("read %u bytes total", total_bytes_read as uint); - } - } - } -} diff --git a/src/libcore/rt/uv/uvll.rs b/src/libcore/rt/uv/uvll.rs deleted file mode 100644 index ddc9040d730..00000000000 --- a/src/libcore/rt/uv/uvll.rs +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * Low-level bindings to the libuv library. - * - * This module contains a set of direct, 'bare-metal' wrappers around - * the libuv C-API. - * - * We're not bothering yet to redefine uv's structs as Rust structs - * because they are quite large and change often between versions. - * The maintenance burden is just too high. Instead we use the uv's - * `uv_handle_size` and `uv_req_size` to find the correct size of the - * structs and allocate them on the heap. This can be revisited later. - * - * There are also a collection of helper functions to ease interacting - * with the low-level API. - * - * As new functionality, existant in uv.h, is added to the rust stdlib, - * the mappings should be added in this module. - */ - -#[allow(non_camel_case_types)]; // C types - -use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t}; -use libc::{malloc, free}; -use prelude::*; - -pub static UNKNOWN: c_int = -1; -pub static OK: c_int = 0; -pub static EOF: c_int = 1; -pub static EADDRINFO: c_int = 2; -pub static EACCES: c_int = 3; -pub static ECONNREFUSED: c_int = 12; -pub static ECONNRESET: c_int = 13; -pub static EPIPE: c_int = 36; - -pub struct uv_err_t { - code: c_int, - sys_errno_: c_int -} - -pub struct uv_buf_t { - base: *u8, - len: libc::size_t, -} - -pub type uv_handle_t = c_void; -pub type uv_loop_t = c_void; -pub type uv_idle_t = c_void; -pub type uv_tcp_t = c_void; -pub type uv_connect_t = c_void; -pub type uv_write_t = c_void; -pub type uv_async_t = c_void; -pub type uv_timer_t = c_void; -pub type uv_stream_t = c_void; -pub type uv_fs_t = c_void; - -pub type uv_idle_cb = *u8; - -pub type sockaddr_in = c_void; -pub type sockaddr_in6 = c_void; - -#[deriving(Eq)] -pub enum uv_handle_type { - UV_UNKNOWN_HANDLE, - UV_ASYNC, - UV_CHECK, - UV_FS_EVENT, - UV_FS_POLL, - UV_HANDLE, - UV_IDLE, - UV_NAMED_PIPE, - UV_POLL, - UV_PREPARE, - UV_PROCESS, - UV_STREAM, - UV_TCP, - UV_TIMER, - UV_TTY, - UV_UDP, - UV_SIGNAL, - UV_FILE, - UV_HANDLE_TYPE_MAX -} - -#[deriving(Eq)] -pub enum uv_req_type { - UV_UNKNOWN_REQ, - UV_REQ, - UV_CONNECT, - UV_WRITE, - UV_SHUTDOWN, - UV_UDP_SEND, - UV_FS, - UV_WORK, - UV_GETADDRINFO, - UV_REQ_TYPE_MAX -} - -pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void { - assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX); - let size = rust_uv_handle_size(handle as uint); - let p = malloc(size); - assert!(p.is_not_null()); - return p; -} - -pub unsafe fn free_handle(v: *c_void) { - free(v) -} - -pub unsafe fn malloc_req(req: uv_req_type) -> *c_void { - assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX); - let size = rust_uv_req_size(req as uint); - let p = malloc(size); - assert!(p.is_not_null()); - return p; -} - -pub unsafe fn free_req(v: *c_void) { - free(v) -} - -#[test] -fn handle_sanity_check() { - unsafe { - assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max()); - } -} - -#[test] -fn request_sanity_check() { - unsafe { - assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max()); - } -} - -pub unsafe fn loop_new() -> *c_void { - return rust_uv_loop_new(); -} - -pub unsafe fn loop_delete(loop_handle: *c_void) { - rust_uv_loop_delete(loop_handle); -} - -pub unsafe fn run(loop_handle: *c_void) { - rust_uv_run(loop_handle); -} - -pub unsafe fn close<T>(handle: *T, cb: *u8) { - rust_uv_close(handle as *c_void, cb); -} - -pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) { - rust_uv_walk(loop_handle, cb, arg); -} - -pub unsafe fn idle_new() -> *uv_idle_t { - rust_uv_idle_new() -} - -pub unsafe fn idle_delete(handle: *uv_idle_t) { - rust_uv_idle_delete(handle) -} - -pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int { - rust_uv_idle_init(loop_handle, handle) -} - -pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int { - rust_uv_idle_start(handle, cb) -} - -pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int { - rust_uv_idle_stop(handle) -} - -pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int { - return rust_uv_tcp_init(loop_handle, handle); -} - -// FIXME ref #2064 -pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in6, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int { - return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int { - return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr); -} - -pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in) -> c_int { - return rust_uv_tcp_getpeername(tcp_handle_ptr, name); -} - -pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in6) ->c_int { - return rust_uv_tcp_getpeername6(tcp_handle_ptr, name); -} - -pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int { - return rust_uv_listen(stream as *c_void, backlog, cb); -} - -pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { - return rust_uv_accept(server as *c_void, client as *c_void); -} - -pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { - let buf_ptr = vec::raw::to_ptr(buf_in); - let buf_cnt = buf_in.len() as i32; - return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); -} -pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { - return rust_uv_read_start(stream as *c_void, on_alloc, on_read); -} - -pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int { - return rust_uv_read_stop(stream as *c_void); -} - -pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t { - return rust_uv_last_error(loop_handle); -} - -pub unsafe fn strerror(err: *uv_err_t) -> *c_char { - return rust_uv_strerror(err); -} -pub unsafe fn err_name(err: *uv_err_t) -> *c_char { - return rust_uv_err_name(err); -} - -pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int { - return rust_uv_async_init(loop_handle, async_handle, cb); -} - -pub unsafe fn async_send(async_handle: *uv_async_t) { - return rust_uv_async_send(async_handle); -} -pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t { - let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t }; - let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf); - rust_uv_buf_init(out_buf_ptr, input, len as size_t); - return out_buf; -} - -pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int { - return rust_uv_timer_init(loop_ptr, timer_ptr); -} -pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64, - repeat: u64) -> c_int { - return rust_uv_timer_start(timer_ptr, cb, timeout, repeat); -} -pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int { - return rust_uv_timer_stop(timer_ptr); -} - -pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int) - } -} -pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int) - } -} - -pub unsafe fn free_ip4_addr(addr: *sockaddr_in) { - rust_uv_free_ip4_addr(addr); -} - -pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) { - rust_uv_free_ip6_addr(addr); -} - -// data access helpers -pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void { - return rust_uv_get_loop_for_uv_handle(handle as *c_void); -} -pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t { - return rust_uv_get_stream_handle_from_connect_req(connect); -} -pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t { - return rust_uv_get_stream_handle_from_write_req(write_req); -} -pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void { - rust_uv_get_data_for_uv_loop(loop_ptr) -} -pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) { - rust_uv_set_data_for_uv_loop(loop_ptr, data); -} -pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void { - return rust_uv_get_data_for_uv_handle(handle as *c_void); -} -pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) { - rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void); -} -pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void { - return rust_uv_get_data_for_req(req as *c_void); -} -pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) { - rust_uv_set_data_for_req(req as *c_void, data as *c_void); -} -pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 { - return rust_uv_get_base_from_buf(buf); -} -pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t { - return rust_uv_get_len_from_buf(buf); -} -pub unsafe fn malloc_buf_base_of(suggested_size: size_t) -> *u8 { - return rust_uv_malloc_buf_base_of(suggested_size); -} -pub unsafe fn free_base_of_buf(buf: uv_buf_t) { - rust_uv_free_base_of_buf(buf); -} - -pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str { - let err = last_error(uv_loop); - let err_ptr = ptr::to_unsafe_ptr(&err); - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - return fmt!("LIBUV ERROR: name: %s msg: %s", - err_name, err_msg); -} - -pub unsafe fn get_last_err_data(uv_loop: *c_void) -> uv_err_data { - let err = last_error(uv_loop); - let err_ptr = ptr::to_unsafe_ptr(&err); - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - uv_err_data { err_name: err_name, err_msg: err_msg } -} - -pub struct uv_err_data { - err_name: ~str, - err_msg: ~str, -} - -extern { - - fn rust_uv_handle_size(type_: uintptr_t) -> size_t; - fn rust_uv_req_size(type_: uintptr_t) -> size_t; - fn rust_uv_handle_type_max() -> uintptr_t; - fn rust_uv_req_type_max() -> uintptr_t; - - // libuv public API - fn rust_uv_loop_new() -> *c_void; - fn rust_uv_loop_delete(lp: *c_void); - fn rust_uv_run(loop_handle: *c_void); - fn rust_uv_close(handle: *c_void, cb: *u8); - fn rust_uv_walk(loop_handle: *c_void, cb: *u8, arg: *c_void); - - fn rust_uv_idle_new() -> *uv_idle_t; - fn rust_uv_idle_delete(handle: *uv_idle_t); - fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int; - fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int; - fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; - - fn rust_uv_async_send(handle: *uv_async_t); - fn rust_uv_async_init(loop_handle: *c_void, - async_handle: *uv_async_t, - cb: *u8) -> c_int; - fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int; - // FIXME ref #2604 .. ? - fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t); - fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t; - // FIXME ref #2064 - fn rust_uv_strerror(err: *uv_err_t) -> *c_char; - // FIXME ref #2064 - fn rust_uv_err_name(err: *uv_err_t) -> *c_char; - fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in; - fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6; - fn rust_uv_free_ip4_addr(addr: *sockaddr_in); - fn rust_uv_free_ip6_addr(addr: *sockaddr_in6); - fn rust_uv_ip4_name(src: *sockaddr_in, dst: *u8, size: size_t) -> c_int; - fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int; - fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint; - fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint; - // FIXME ref #2064 - fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in6) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, addr: *sockaddr_in6) -> c_int; - fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in) -> c_int; - fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in6) ->c_int; - fn rust_uv_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; - fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; - fn rust_uv_write(req: *c_void, - stream: *c_void, - buf_in: *uv_buf_t, - buf_cnt: c_int, - cb: *u8) -> c_int; - fn rust_uv_read_start(stream: *c_void, - on_alloc: *u8, - on_read: *u8) -> c_int; - fn rust_uv_read_stop(stream: *c_void) -> c_int; - fn rust_uv_timer_init(loop_handle: *c_void, - timer_handle: *uv_timer_t) -> c_int; - fn rust_uv_timer_start(timer_handle: *uv_timer_t, - cb: *u8, - timeout: libc::uint64_t, - repeat: libc::uint64_t) -> c_int; - fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; - - fn rust_uv_malloc_buf_base_of(sug_size: size_t) -> *u8; - fn rust_uv_free_base_of_buf(buf: uv_buf_t); - fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t; - fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t; - fn rust_uv_get_loop_for_uv_handle(handle: *c_void) -> *c_void; - fn rust_uv_get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void; - fn rust_uv_set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void); - fn rust_uv_get_data_for_uv_handle(handle: *c_void) -> *c_void; - fn rust_uv_set_data_for_uv_handle(handle: *c_void, data: *c_void); - fn rust_uv_get_data_for_req(req: *c_void) -> *c_void; - fn rust_uv_set_data_for_req(req: *c_void, data: *c_void); - fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; - fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t; -} diff --git a/src/libcore/rt/work_queue.rs b/src/libcore/rt/work_queue.rs deleted file mode 100644 index e9eb663392b..00000000000 --- a/src/libcore/rt/work_queue.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use container::Container; -use option::*; -use vec::OwnedVector; -use unstable::sync::{Exclusive, exclusive}; -use cell::Cell; -use kinds::Owned; -use clone::Clone; - -pub struct WorkQueue<T> { - // XXX: Another mystery bug fixed by boxing this lock - priv queue: ~Exclusive<~[T]> -} - -pub impl<T: Owned> WorkQueue<T> { - 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()) ); - } - - fn pop(&mut self) -> Option<T> { - 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 - } - } - } - - fn is_empty(&self) -> bool { - self.queue.with_imm(|q| q.is_empty() ) - } -} - -impl<T> Clone for WorkQueue<T> { - fn clone(&self) -> WorkQueue<T> { - WorkQueue { - queue: self.queue.clone() - } - } -} diff --git a/src/libcore/run.rs b/src/libcore/run.rs deleted file mode 100644 index 02757ab4899..00000000000 --- a/src/libcore/run.rs +++ /dev/null @@ -1,856 +0,0 @@ -// 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. - -//! Process spawning -use cast; -use io; -use libc; -use libc::{pid_t, c_void, c_int}; -use comm::{stream, SharedChan, GenericChan, GenericPort}; -use option::{Some, None}; -use os; -use prelude::*; -use ptr; -use str; -use task; -use vec; - -/// A value representing a child process -pub struct Program { - priv pid: pid_t, - priv handle: *(), - priv in_fd: c_int, - priv out_file: *libc::FILE, - priv err_file: *libc::FILE, - priv finished: bool, -} - -impl Drop for Program { - fn finalize(&self) { - // FIXME #4943: transmute is bad. - let mut_self: &mut Program = unsafe { cast::transmute(self) }; - - mut_self.finish(); - mut_self.close_outputs(); - free_handle(self.handle); - } -} - -pub impl Program { - - /// Returns the process id of the program - fn get_id(&mut self) -> pid_t { self.pid } - - /// Returns an io::Writer that can be used to write to stdin - fn input(&mut self) -> @io::Writer { - io::fd_writer(self.in_fd, false) - } - - /// Returns an io::Reader that can be used to read from stdout - fn output(&mut self) -> @io::Reader { - io::FILE_reader(self.out_file, false) - } - - /// Returns an io::Reader that can be used to read from stderr - fn err(&mut self) -> @io::Reader { - io::FILE_reader(self.err_file, false) - } - - /// Closes the handle to the child processes standard input - fn close_input(&mut self) { - let invalid_fd = -1i32; - if self.in_fd != invalid_fd { - unsafe { - libc::close(self.in_fd); - } - self.in_fd = invalid_fd; - } - } - - priv fn close_outputs(&mut self) { - unsafe { - fclose_and_null(&mut self.out_file); - fclose_and_null(&mut self.err_file); - } - } - - /** - * Waits for the child process to terminate. Closes the handle - * to stdin if necessary. - */ - fn finish(&mut self) -> int { - if self.finished { return 0; } - self.finished = true; - self.close_input(); - return waitpid(self.pid); - } - - priv fn destroy_internal(&mut self, force: bool) { - killpid(self.pid, force); - self.finish(); - self.close_outputs(); - - #[cfg(windows)] - fn killpid(pid: pid_t, _force: bool) { - unsafe { - libc::funcs::extra::kernel32::TerminateProcess( - cast::transmute(pid), 1); - } - } - - #[cfg(unix)] - fn killpid(pid: pid_t, force: bool) { - let signal = if force { - libc::consts::os::posix88::SIGKILL - } else { - libc::consts::os::posix88::SIGTERM - }; - - unsafe { - libc::funcs::posix88::signal::kill(pid, signal as c_int); - } - } - } - - /** - * Terminate the program, giving it a chance to clean itself up if - * this is supported by the operating system. - * - * On Posix OSs SIGTERM will be sent to the process. On Win32 - * TerminateProcess(..) will be called. - */ - fn destroy(&mut self) { self.destroy_internal(false); } - - /** - * Terminate the program as soon as possible without giving it a - * chance to clean itself up. - * - * 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); } -} - - -/** - * Run a program, providing stdin, stdout and stderr handles - * - * # Arguments - * - * * prog - The path to an executable - * * args - Vector of arguments to pass to the child process - * * env - optional env-modification for child - * * dir - optional dir to run child in (default current dir) - * * in_fd - A file descriptor for the child to use as std input - * * out_fd - A file descriptor for the child to use as std output - * * err_fd - A file descriptor for the child to use as std error - * - * # Return value - * - * The process id of the spawned process - */ -pub fn spawn_process(prog: &str, args: &[~str], - env: &Option<~[(~str,~str)]>, - dir: &Option<~str>, - in_fd: c_int, out_fd: c_int, err_fd: c_int) -> pid_t { - - let res = spawn_process_internal(prog, args, env, dir, in_fd, out_fd, err_fd); - free_handle(res.handle); - return res.pid; -} - -struct RunProgramResult { - // the process id of the program (this should never be negative) - pid: pid_t, - // a handle to the process - on unix this will always be NULL, but on windows it will be a - // HANDLE to the process, which will prevent the pid being re-used until the handle is closed. - handle: *(), -} - -#[cfg(windows)] -fn spawn_process_internal(prog: &str, args: &[~str], - env: &Option<~[(~str,~str)]>, - dir: &Option<~str>, - in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { - - use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; - use libc::consts::os::extra::{ - TRUE, FALSE, - STARTF_USESTDHANDLES, - INVALID_HANDLE_VALUE, - DUPLICATE_SAME_ACCESS - }; - use libc::funcs::extra::kernel32::{ - GetCurrentProcess, - DuplicateHandle, - CloseHandle, - CreateProcessA - }; - use libc::funcs::extra::msvcrt::get_osfhandle; - - unsafe { - - let mut si = zeroed_startupinfo(); - si.cb = sys::size_of::<STARTUPINFO>() as DWORD; - si.dwFlags = STARTF_USESTDHANDLES; - - let cur_proc = GetCurrentProcess(); - - let orig_std_in = get_osfhandle(if in_fd > 0 { in_fd } else { 0 }) as HANDLE; - if orig_std_in == INVALID_HANDLE_VALUE as HANDLE { - fail!("failure in get_osfhandle: %s", os::last_os_error()); - } - if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput, - 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { - fail!("failure in DuplicateHandle: %s", os::last_os_error()); - } - - let orig_std_out = get_osfhandle(if out_fd > 0 { out_fd } else { 1 }) as HANDLE; - if orig_std_out == INVALID_HANDLE_VALUE as HANDLE { - fail!("failure in get_osfhandle: %s", os::last_os_error()); - } - if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput, - 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { - fail!("failure in DuplicateHandle: %s", os::last_os_error()); - } - - let orig_std_err = get_osfhandle(if err_fd > 0 { err_fd } else { 2 }) as HANDLE; - if orig_std_err as HANDLE == INVALID_HANDLE_VALUE as HANDLE { - fail!("failure in get_osfhandle: %s", os::last_os_error()); - } - if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { - fail!("failure in DuplicateHandle: %s", os::last_os_error()); - } - - let cmd = make_command_line(prog, args); - let mut pi = zeroed_process_information(); - let mut create_err = None; - - do with_envp(env) |envp| { - do with_dirp(dir) |dirp| { - do str::as_c_str(cmd) |cmdp| { - let created = CreateProcessA(ptr::null(), cast::transmute(cmdp), - ptr::mut_null(), ptr::mut_null(), TRUE, - 0, envp, dirp, &mut si, &mut pi); - if created == FALSE { - create_err = Some(os::last_os_error()); - } - } - } - } - - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - for create_err.each |msg| { - fail!("failure in CreateProcess: %s", *msg); - } - - // We close the thread handle because we don't care about keeping the thread id valid, - // and we aren't keeping the thread handle around to be able to close it later. We don't - // close the process handle however because we want the process id to stay valid at least - // until the calling code closes the process handle. - CloseHandle(pi.hThread); - - RunProgramResult { - pid: pi.dwProcessId as pid_t, - handle: pi.hProcess as *() - } - } -} - -#[cfg(windows)] -fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { - libc::types::os::arch::extra::STARTUPINFO { - cb: 0, - lpReserved: ptr::mut_null(), - lpDesktop: ptr::mut_null(), - lpTitle: ptr::mut_null(), - dwX: 0, - dwY: 0, - dwXSize: 0, - dwYSize: 0, - dwXCountChars: 0, - dwYCountCharts: 0, - dwFillAttribute: 0, - dwFlags: 0, - wShowWindow: 0, - cbReserved2: 0, - lpReserved2: ptr::mut_null(), - hStdInput: ptr::mut_null(), - hStdOutput: ptr::mut_null(), - hStdError: ptr::mut_null() - } -} - -#[cfg(windows)] -fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { - libc::types::os::arch::extra::PROCESS_INFORMATION { - hProcess: ptr::mut_null(), - hThread: ptr::mut_null(), - dwProcessId: 0, - dwThreadId: 0 - } -} - -// FIXME: this is only pub so it can be tested (see issue #4536) -#[cfg(windows)] -pub fn make_command_line(prog: &str, args: &[~str]) -> ~str { - - let mut cmd = ~""; - append_arg(&mut cmd, prog); - for args.each |arg| { - cmd.push_char(' '); - append_arg(&mut cmd, *arg); - } - return cmd; - - fn append_arg(cmd: &mut ~str, arg: &str) { - let quote = arg.any(|c| c == ' ' || c == '\t'); - if quote { - cmd.push_char('"'); - } - for uint::range(0, arg.len()) |i| { - append_char_at(cmd, arg, i); - } - if quote { - cmd.push_char('"'); - } - } - - fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) { - match arg[i] as char { - '"' => { - // Escape quotes. - cmd.push_str("\\\""); - } - '\\' => { - if backslash_run_ends_in_quote(arg, i) { - // Double all backslashes that are in runs before quotes. - cmd.push_str("\\\\"); - } else { - // Pass other backslashes through unescaped. - cmd.push_char('\\'); - } - } - c => { - cmd.push_char(c); - } - } - } - - fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool { - while i < s.len() && s[i] as char == '\\' { - i += 1; - } - return i < s.len() && s[i] as char == '"'; - } -} - -#[cfg(unix)] -fn spawn_process_internal(prog: &str, args: &[~str], - env: &Option<~[(~str,~str)]>, - dir: &Option<~str>, - in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { - - use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; - use libc::funcs::bsd44::getdtablesize; - - mod rustrt { - use libc::c_void; - - #[abi = "cdecl"] - pub extern { - unsafe fn rust_unset_sigprocmask(); - unsafe fn rust_set_environ(envp: *c_void); - } - } - - unsafe { - - let pid = fork(); - if pid < 0 { - fail!("failure in fork: %s", os::last_os_error()); - } else if pid > 0 { - return RunProgramResult {pid: pid, handle: ptr::null()}; - } - - rustrt::rust_unset_sigprocmask(); - - if in_fd > 0 && dup2(in_fd, 0) == -1 { - fail!("failure in dup2(in_fd, 0): %s", os::last_os_error()); - } - if out_fd > 0 && dup2(out_fd, 1) == -1 { - fail!("failure in dup2(out_fd, 1): %s", os::last_os_error()); - } - if err_fd > 0 && dup2(err_fd, 2) == -1 { - fail!("failure in dup3(err_fd, 2): %s", os::last_os_error()); - } - // close all other fds - for int::range_rev(getdtablesize() as int - 1, 2) |fd| { - close(fd as c_int); - } - - for dir.each |dir| { - do str::as_c_str(*dir) |dirp| { - if chdir(dirp) == -1 { - fail!("failure in chdir: %s", os::last_os_error()); - } - } - } - - do with_envp(env) |envp| { - if !envp.is_null() { - rustrt::rust_set_environ(envp); - } - do with_argv(prog, args) |argv| { - execvp(*argv, argv); - // execvp only returns if an error occurred - fail!("failure in execvp: %s", os::last_os_error()); - } - } - } -} - -#[cfg(unix)] -fn with_argv<T>(prog: &str, args: &[~str], - cb: &fn(**libc::c_char) -> T) -> T { - let mut argptrs = str::as_c_str(prog, |b| ~[b]); - let mut tmps = ~[]; - for args.each |arg| { - let t = @copy *arg; - tmps.push(t); - argptrs.push_all(str::as_c_str(*t, |b| ~[b])); - } - argptrs.push(ptr::null()); - vec::as_imm_buf(argptrs, |buf, _len| cb(buf)) -} - -#[cfg(unix)] -fn with_envp<T>(env: &Option<~[(~str,~str)]>, - cb: &fn(*c_void) -> T) -> T { - // On posixy systems we can pass a char** for envp, which is - // a null-terminated array of "k=v\n" strings. - match *env { - Some(ref es) if !vec::is_empty(*es) => { - let mut tmps = ~[]; - let mut ptrs = ~[]; - - for (*es).each |e| { - let (k,v) = copy *e; - let t = @(fmt!("%s=%s", k, v)); - tmps.push(t); - ptrs.push_all(str::as_c_str(*t, |b| ~[b])); - } - ptrs.push(ptr::null()); - vec::as_imm_buf(ptrs, |p, _len| - unsafe { cb(::cast::transmute(p)) } - ) - } - _ => cb(ptr::null()) - } -} - -#[cfg(windows)] -fn with_envp<T>(env: &Option<~[(~str,~str)]>, - cb: &fn(*mut c_void) -> T) -> T { - // On win32 we pass an "environment block" which is not a char**, but - // rather a concatenation of null-terminated k=v\0 sequences, with a final - // \0 to terminate. - unsafe { - match *env { - Some(ref es) if !vec::is_empty(*es) => { - let mut blk : ~[u8] = ~[]; - for (*es).each |e| { - let (k,v) = copy *e; - let t = fmt!("%s=%s", k, v); - let mut v : ~[u8] = ::cast::transmute(t); - blk += v; - ::cast::forget(v); - } - blk += ~[0_u8]; - vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p))) - } - _ => cb(ptr::mut_null()) - } - } -} - -#[cfg(windows)] -fn with_dirp<T>(d: &Option<~str>, - cb: &fn(*libc::c_char) -> T) -> T { - match *d { - Some(ref dir) => str::as_c_str(*dir, cb), - None => cb(ptr::null()) - } -} - -/// helper function that closes non-NULL files and then makes them NULL -priv unsafe fn fclose_and_null(f: &mut *libc::FILE) { - if *f != 0 as *libc::FILE { - libc::fclose(*f); - *f = 0 as *libc::FILE; - } -} - -#[cfg(windows)] -priv fn free_handle(handle: *()) { - unsafe { - libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle)); - } -} - -#[cfg(unix)] -priv fn free_handle(_handle: *()) { - // unix has no process handle object, just a pid -} - -/** - * Spawns a process and waits for it to terminate - * - * # Arguments - * - * * prog - The path to an executable - * * args - Vector of arguments to pass to the child process - * - * # Return value - * - * The process's exit code - */ -pub fn run_program(prog: &str, args: &[~str]) -> int { - let res = spawn_process_internal(prog, args, &None, &None, - 0i32, 0i32, 0i32); - let code = waitpid(res.pid); - free_handle(res.handle); - return code; -} - -/** - * Spawns a process and returns a Program - * - * The returned value is a <Program> object that can be used for sending and - * receiving data over the standard file descriptors. The class will ensure - * that file descriptors are closed properly. - * - * # Arguments - * - * * prog - The path to an executable - * * args - Vector of arguments to pass to the child process - * - * # Return value - * - * A <Program> object - */ -pub fn start_program(prog: &str, args: &[~str]) -> Program { - let pipe_input = os::pipe(); - let pipe_output = os::pipe(); - let pipe_err = os::pipe(); - let res = - spawn_process_internal(prog, args, &None, &None, - pipe_input.in, pipe_output.out, - pipe_err.out); - - unsafe { - libc::close(pipe_input.in); - libc::close(pipe_output.out); - libc::close(pipe_err.out); - } - - Program { - pid: res.pid, - handle: res.handle, - in_fd: pipe_input.out, - out_file: os::fdopen(pipe_output.in), - err_file: os::fdopen(pipe_err.in), - finished: false, - } -} - -fn read_all(rd: @io::Reader) -> ~str { - let buf = io::with_bytes_writer(|wr| { - let mut bytes = [0, ..4096]; - while !rd.eof() { - let nread = rd.read(bytes, bytes.len()); - wr.write(bytes.slice(0, nread)); - } - }); - str::from_bytes(buf) -} - -pub struct ProgramOutput {status: int, out: ~str, err: ~str} - -/** - * Spawns a process, waits for it to exit, and returns the exit code, and - * contents of stdout and stderr. - * - * # Arguments - * - * * prog - The path to an executable - * * args - Vector of arguments to pass to the child process - * - * # Return value - * - * A record, {status: int, out: str, err: str} containing the exit code, - * the contents of stdout and the contents of stderr. - */ -pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput { - let pipe_in = os::pipe(); - let pipe_out = os::pipe(); - let pipe_err = os::pipe(); - let res = spawn_process_internal(prog, args, &None, &None, - pipe_in.in, pipe_out.out, pipe_err.out); - - os::close(pipe_in.in); - os::close(pipe_out.out); - os::close(pipe_err.out); - os::close(pipe_in.out); - - // Spawn two entire schedulers to read both stdout and sterr - // in parallel so we don't deadlock while blocking on one - // or the other. FIXME (#2625): Surely there's a much more - // clever way to do this. - let (p, ch) = stream(); - let ch = SharedChan::new(ch); - let ch_clone = ch.clone(); - do task::spawn_sched(task::SingleThreaded) { - let errput = readclose(pipe_err.in); - ch.send((2, errput)); - }; - do task::spawn_sched(task::SingleThreaded) { - let output = readclose(pipe_out.in); - ch_clone.send((1, output)); - }; - - let status = waitpid(res.pid); - free_handle(res.handle); - - let mut errs = ~""; - let mut outs = ~""; - let mut count = 2; - while count > 0 { - let stream = p.recv(); - match stream { - (1, copy s) => { - outs = s; - } - (2, copy s) => { - errs = s; - } - (n, _) => { - fail!("program_output received an unexpected file number: %u", n); - } - }; - count -= 1; - }; - return ProgramOutput {status: status, - out: outs, - err: errs}; -} - -pub fn writeclose(fd: c_int, s: ~str) { - use io::WriterUtil; - - error!("writeclose %d, %s", fd as int, s); - let writer = io::fd_writer(fd, false); - writer.write_str(s); - - os::close(fd); -} - -pub fn readclose(fd: c_int) -> ~str { - unsafe { - let file = os::fdopen(fd); - let reader = io::FILE_reader(file, false); - let buf = io::with_bytes_writer(|writer| { - let mut bytes = [0, ..4096]; - while !reader.eof() { - let nread = reader.read(bytes, bytes.len()); - writer.write(bytes.slice(0, nread)); - } - }); - os::fclose(file); - str::from_bytes(buf) - } -} - -/** - * Waits for a process to exit and returns the exit code, failing - * if there is no process with the specified id. - */ -pub fn waitpid(pid: pid_t) -> int { - return waitpid_os(pid); - - #[cfg(windows)] - fn waitpid_os(pid: pid_t) -> int { - - use libc::types::os::arch::extra::DWORD; - use libc::consts::os::extra::{ - SYNCHRONIZE, - PROCESS_QUERY_INFORMATION, - FALSE, - STILL_ACTIVE, - INFINITE, - WAIT_FAILED - }; - use libc::funcs::extra::kernel32::{ - OpenProcess, - GetExitCodeProcess, - CloseHandle, - WaitForSingleObject - }; - - unsafe { - - let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); - if proc.is_null() { - fail!("failure in OpenProcess: %s", os::last_os_error()); - } - - loop { - let mut status = 0; - if GetExitCodeProcess(proc, &mut status) == FALSE { - CloseHandle(proc); - fail!("failure in GetExitCodeProcess: %s", os::last_os_error()); - } - if status != STILL_ACTIVE { - CloseHandle(proc); - return status as int; - } - if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED { - CloseHandle(proc); - fail!("failure in WaitForSingleObject: %s", os::last_os_error()); - } - } - } - } - - #[cfg(unix)] - fn waitpid_os(pid: pid_t) -> int { - - use libc::funcs::posix01::wait::*; - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - fn WIFEXITED(status: i32) -> bool { - (status & 0xffi32) == 0i32 - } - - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn WIFEXITED(status: i32) -> bool { - (status & 0x7fi32) == 0i32 - } - - #[cfg(target_os = "linux")] - #[cfg(target_os = "android")] - fn WEXITSTATUS(status: i32) -> i32 { - (status >> 8i32) & 0xffi32 - } - - #[cfg(target_os = "macos")] - #[cfg(target_os = "freebsd")] - fn WEXITSTATUS(status: i32) -> i32 { - status >> 8i32 - } - - let mut status = 0 as c_int; - if unsafe { waitpid(pid, &mut status, 0) } == -1 { - fail!("failure in waitpid: %s", os::last_os_error()); - } - - return if WIFEXITED(status) { - WEXITSTATUS(status) as int - } else { - 1 - }; - } -} - -#[cfg(test)] -mod tests { - use option::None; - use os; - use run::{readclose, writeclose}; - use run; - - #[test] - #[cfg(windows)] - fn test_make_command_line() { - assert_eq!( - run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]), - ~"prog aaa bbb ccc" - ); - assert_eq!( - run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]), - ~"\"C:\\Program Files\\blah\\blah.exe\" aaa" - ); - assert_eq!( - run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]), - ~"\"C:\\Program Files\\test\" aa\\\"bb" - ); - assert_eq!( - run::make_command_line("echo", [~"a b c"]), - ~"echo \"a b c\"" - ); - } - - // Regression test for memory leaks - #[test] - fn test_leaks() { - run::run_program("echo", []); - run::start_program("echo", []); - run::program_output("echo", []); - } - - #[test] - #[allow(non_implicitly_copyable_typarams)] - fn test_pipes() { - let pipe_in = os::pipe(); - let pipe_out = os::pipe(); - let pipe_err = os::pipe(); - - let pid = - run::spawn_process( - "cat", [], &None, &None, - pipe_in.in, pipe_out.out, pipe_err.out); - os::close(pipe_in.in); - os::close(pipe_out.out); - os::close(pipe_err.out); - - if pid == -1i32 { fail!(); } - let expected = ~"test"; - writeclose(pipe_in.out, copy expected); - let actual = readclose(pipe_out.in); - readclose(pipe_err.in); - run::waitpid(pid); - - debug!(copy expected); - debug!(copy actual); - assert_eq!(expected, actual); - } - - #[test] - fn waitpid() { - let pid = run::spawn_process("false", [], - &None, &None, - 0i32, 0i32, 0i32); - let status = run::waitpid(pid); - assert_eq!(status, 1); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn waitpid_non_existant_pid() { - run::waitpid(123456789); // assume that this pid doesn't exist - } -} diff --git a/src/libcore/stackwalk.rs b/src/libcore/stackwalk.rs deleted file mode 100644 index 784656718d0..00000000000 --- a/src/libcore/stackwalk.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; // FIXME #3538 - -use cast::transmute; -use unstable::intrinsics; - -pub type Word = uint; - -pub struct Frame { - fp: *Word -} - -pub fn Frame(fp: *Word) -> Frame { - Frame { - fp: fp - } -} - -pub fn walk_stack(visit: &fn(Frame) -> bool) -> bool { - - debug!("beginning stack walk"); - - do frame_address |frame_pointer| { - let mut frame_address: *Word = unsafe { - transmute(frame_pointer) - }; - loop { - let fr = Frame(frame_address); - - debug!("frame: %x", unsafe { transmute(fr.fp) }); - visit(fr); - - unsafe { - let next_fp: **Word = transmute(frame_address); - frame_address = *next_fp; - if *frame_address == 0u { - debug!("encountered task_start_wrapper. ending walk"); - // This is the task_start_wrapper_frame. There is - // no stack beneath it and it is a foreign frame. - break; - } - } - } - } - return true; -} - -#[test] -fn test_simple() { - for walk_stack |_frame| { - } -} - -#[test] -fn test_simple_deep() { - fn run(i: int) { - if i == 0 { return } - - for walk_stack |_frame| { - // Would be nice to test something here... - } - run(i - 1); - } - - run(10); -} - -fn frame_address(f: &fn(x: *u8)) { - unsafe { - intrinsics::frame_address(f) - } -} diff --git a/src/libcore/str.rs b/src/libcore/str.rs deleted file mode 100644 index 53169554ec5..00000000000 --- a/src/libcore/str.rs +++ /dev/null @@ -1,4036 +0,0 @@ -// 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. - -/*! - * String manipulation - * - * Strings are a packed UTF-8 representation of text, stored as null - * terminated buffers of u8 bytes. Strings should be indexed in bytes, - * for efficiency, but UTF-8 unsafe operations should be avoided. For - * some heavy-duty uses, try std::rope. - */ - -use at_vec; -use cast::transmute; -use cast; -use char; -use clone::Clone; -use cmp::{TotalOrd, Ordering, Less, Equal, Greater}; -use container::Container; -use iter::Times; -use iterator::Iterator; -use libc; -use option::{None, Option, Some}; -use old_iter::{BaseIter, EqIter}; -use ptr; -use ptr::Ptr; -use str; -use to_str::ToStr; -use uint; -use vec; -use vec::{OwnedVector, OwnedCopyableVector}; - -#[cfg(not(test))] use cmp::{Eq, Ord, Equiv, TotalEq}; - -/* -Section: Creating a string -*/ - -/** - * Convert a vector of bytes to a new UTF-8 string - * - * # Failure - * - * Fails if invalid UTF-8 - */ -pub fn from_bytes(vv: &const [u8]) -> ~str { - assert!(is_utf8(vv)); - return unsafe { raw::from_bytes(vv) }; -} - -/** - * Convert a vector of bytes to a UTF-8 string. - * The vector needs to be one byte longer than the string, and end with a 0 byte. - * - * Compared to `from_bytes()`, this fn doesn't need to allocate a new owned str. - * - * # Failure - * - * Fails if invalid UTF-8 - * Fails if not null terminated - */ -pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str { - assert_eq!(vv[vv.len() - 1], 0); - assert!(is_utf8(vv)); - return unsafe { raw::from_bytes_with_null(vv) }; -} - -pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { - unsafe { - assert!(is_utf8(vector)); - let (ptr, len): (*u8, uint) = ::cast::transmute(vector); - let string: &'a str = ::cast::transmute((ptr, len + 1)); - string - } -} - -/// 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)) } -} - -impl ToStr for ~str { - #[inline(always)] - fn to_str(&self) -> ~str { to_owned(*self) } -} -impl<'self> ToStr for &'self str { - #[inline(always)] - fn to_str(&self) -> ~str { to_owned(*self) } -} -impl ToStr for @str { - #[inline(always)] - fn to_str(&self) -> ~str { to_owned(*self) } -} - -/** - * Convert a byte to a UTF-8 string - * - * # Failure - * - * Fails if invalid UTF-8 - */ -pub fn from_byte(b: u8) -> ~str { - assert!(b < 128u8); - 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 -} - -/// Convert a vector of chars to a string -pub fn from_chars(chs: &[char]) -> ~str { - let mut buf = ~""; - reserve(&mut buf, chs.len()); - for chs.each |ch| { - push_char(&mut buf, *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)] -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); - } -} - -/// 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 -} - -/// Concatenate a vector of strings -pub fn concat(v: &[~str]) -> ~str { - if v.is_empty() { return ~""; } - - let mut len = 0; - for v.each |ss| { - len += ss.len(); - } - let mut s = ~""; - - reserve(&mut s, len); - - 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; - - reserve(&mut s, len); - - 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 { - 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); - } - 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 ~""; } - - // 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; - - reserve(&mut s, len); - - 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); - } - ptr::copy_memory(buf, ssbuf, sslen); - buf = buf.offset(sslen); - } - } - } - } - raw::set_len(&mut s, len); - } - 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) -} - -/// 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)) } - } -} - -/// 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) } - } - } -} - -/// 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 - } -} - -/// 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) } - } -} - -/// 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) - } -} - -/// 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; - } - } - start = i + 1u; - done += 1u; - } - 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; } - } - 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) -} - -/// 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) -} - -/** - * 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; - } - } - start = next; - done += 1u; - } - i = next; - } - 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; - } - i += 1u; - } else { - // Failed match, backtrack - if match_i > 0u { - match_i = 0u; - i = match_start + 1u; - } else { - i += 1u; - } - } - } - 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 - * - * ~~~ - * 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 -pub fn levdistance(s: &str, t: &str) -> uint { - - let slen = s.len(); - let tlen = t.len(); - - if slen == 0 { return tlen; } - if tlen == 0 { return slen; } - - let mut dcol = vec::from_fn(tlen + 1, |x| x); - - for s.each_chari |i, sc| { - - let mut current = i; - dcol[0] = current + 1; - - for t.each_chari |j, tc| { - - let next = dcol[j + 1]; - - if sc == tc { - dcol[j + 1] = current; - } else { - dcol[j + 1] = ::cmp::min(current, next); - dcol[j + 1] = ::cmp::min(dcol[j + 1], dcol[j]) + 1; - } - - current = next; - } - } - - return dcol[tlen]; -} - -/** - * 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| { - 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; } - } else { - if !it( s ) { return false; } - } - } - 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. - * - * #Failure: - * - * Fails during iteration if the string contains a non-whitespace - * sequence longer than the limit. - */ -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: - - enum SplitWithinState { - A, // leading whitespace, initial state - B, // words - C, // internal and trailing whitespace - } - enum Whitespace { - Ws, // current char is whitespace - Cr // current char is not whitespace - } - enum LengthLimit { - UnderLim, // current char makes current substring still fit in limit - OverLim // current char makes current substring no longer fit in limit - } - - let mut slice_start = 0; - let mut last_start = 0; - let mut last_end = 0; - let mut state = A; - - let mut cont = true; - let slice: &fn() = || { cont = it(slice(ss, slice_start, last_end)) }; - - 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 }; - - state = match (state, whitespace, limit) { - (A, Ws, _) => { A } - (A, Cr, _) => { slice_start = i; last_start = i; B } - - (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)), - (B, Cr, OverLim) => { slice(); slice_start = last_start; B } - (B, Ws, UnderLim) => { last_end = i; C } - (B, Ws, OverLim) => { last_end = i; slice(); A } - - (C, Cr, UnderLim) => { last_start = i; B } - (C, Cr, OverLim) => { slice(); slice_start = i; last_start = i; last_end = i; B } - (C, Ws, OverLim) => { slice(); A } - (C, Ws, UnderLim) => { C } - }; - - cont - }; - - str::each_chari(ss, 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, ' '); - 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 -*/ - -/// Bytewise slice equality -#[cfg(not(test))] -#[lang="str_eq"] -#[inline] -pub fn eq_slice(a: &str, b: &str) -> bool { - do as_buf(a) |ap, alen| { - do as_buf(b) |bp, blen| { - if (alen != blen) { false } - else { - unsafe { - libc::memcmp(ap as *libc::c_void, - bp as *libc::c_void, - (alen - 1) as libc::size_t) == 0 - } - } - } - } -} - -#[cfg(test)] -#[inline] -pub fn eq_slice(a: &str, b: &str) -> bool { - do as_buf(a) |ap, alen| { - do as_buf(b) |bp, blen| { - if (alen != blen) { false } - else { - unsafe { - libc::memcmp(ap as *libc::c_void, - bp as *libc::c_void, - (alen - 1) as libc::size_t) == 0 - } - } - } - } -} - -/// Bytewise string equality -#[cfg(not(test))] -#[lang="uniq_str_eq"] -#[inline] -pub fn eq(a: &~str, b: &~str) -> bool { - eq_slice(*a, *b) -} - -#[cfg(test)] -#[inline] -pub fn eq(a: &~str, b: &~str) -> bool { - eq_slice(*a, *b) -} - -#[inline] -fn cmp(a: &str, b: &str) -> Ordering { - let low = uint::min(a.len(), b.len()); - - for uint::range(0, low) |idx| { - match a[idx].cmp(&b[idx]) { - Greater => return Greater, - Less => return Less, - Equal => () - } - } - - a.len().cmp(&b.len()) -} - -#[cfg(not(test))] -impl<'self> TotalOrd for &'self str { - #[inline] - fn cmp(&self, other: & &'self str) -> Ordering { cmp(*self, *other) } -} - -#[cfg(not(test))] -impl TotalOrd for ~str { - #[inline] - fn cmp(&self, other: &~str) -> Ordering { cmp(*self, *other) } -} - -#[cfg(not(test))] -impl TotalOrd for @str { - #[inline] - fn cmp(&self, other: &@str) -> Ordering { cmp(*self, *other) } -} - -/// Bytewise slice less than -#[inline] -fn lt(a: &str, b: &str) -> bool { - let (a_len, b_len) = (a.len(), b.len()); - let end = uint::min(a_len, b_len); - - let mut i = 0; - while i < end { - let (c_a, c_b) = (a[i], b[i]); - if c_a < c_b { return true; } - if c_a > c_b { return false; } - i += 1; - } - - return a_len < b_len; -} - -/// Bytewise less than or equal -#[inline] -pub fn le(a: &str, b: &str) -> bool { - !lt(b, a) -} - -/// Bytewise greater than or equal -#[inline] -fn ge(a: &str, b: &str) -> bool { - !lt(a, b) -} - -/// Bytewise greater than -#[inline] -fn gt(a: &str, b: &str) -> bool { - !le(a, b) -} - -#[cfg(not(test))] -impl<'self> Eq for &'self str { - #[inline(always)] - fn eq(&self, other: & &'self str) -> bool { - eq_slice((*self), (*other)) - } - #[inline(always)] - fn ne(&self, other: & &'self str) -> bool { !(*self).eq(other) } -} - -#[cfg(not(test))] -impl Eq for ~str { - #[inline(always)] - fn eq(&self, other: &~str) -> bool { - eq_slice((*self), (*other)) - } - #[inline(always)] - fn ne(&self, other: &~str) -> bool { !(*self).eq(other) } -} - -#[cfg(not(test))] -impl Eq for @str { - #[inline(always)] - fn eq(&self, other: &@str) -> bool { - eq_slice((*self), (*other)) - } - #[inline(always)] - fn ne(&self, other: &@str) -> bool { !(*self).eq(other) } -} - -#[cfg(not(test))] -impl<'self> TotalEq for &'self str { - #[inline(always)] - fn equals(&self, other: & &'self str) -> bool { - eq_slice((*self), (*other)) - } -} - -#[cfg(not(test))] -impl TotalEq for ~str { - #[inline(always)] - fn equals(&self, other: &~str) -> bool { - eq_slice((*self), (*other)) - } -} - -#[cfg(not(test))] -impl TotalEq for @str { - #[inline(always)] - fn equals(&self, other: &@str) -> bool { - eq_slice((*self), (*other)) - } -} - -#[cfg(not(test))] -impl Ord for ~str { - #[inline(always)] - fn lt(&self, other: &~str) -> bool { lt((*self), (*other)) } - #[inline(always)] - fn le(&self, other: &~str) -> bool { le((*self), (*other)) } - #[inline(always)] - fn ge(&self, other: &~str) -> bool { ge((*self), (*other)) } - #[inline(always)] - fn gt(&self, other: &~str) -> bool { gt((*self), (*other)) } -} - -#[cfg(not(test))] -impl<'self> Ord for &'self str { - #[inline(always)] - fn lt(&self, other: & &'self str) -> bool { lt((*self), (*other)) } - #[inline(always)] - fn le(&self, other: & &'self str) -> bool { le((*self), (*other)) } - #[inline(always)] - fn ge(&self, other: & &'self str) -> bool { ge((*self), (*other)) } - #[inline(always)] - fn gt(&self, other: & &'self str) -> bool { gt((*self), (*other)) } -} - -#[cfg(not(test))] -impl Ord for @str { - #[inline(always)] - fn lt(&self, other: &@str) -> bool { lt((*self), (*other)) } - #[inline(always)] - fn le(&self, other: &@str) -> bool { le((*self), (*other)) } - #[inline(always)] - fn ge(&self, other: &@str) -> bool { ge((*self), (*other)) } - #[inline(always)] - fn gt(&self, other: &@str) -> bool { gt((*self), (*other)) } -} - -#[cfg(not(test))] -impl<'self> Equiv<~str> for &'self str { - #[inline(always)] - fn equiv(&self, other: &~str) -> bool { eq_slice(*self, *other) } -} - -/* -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 -} - -/// 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; } - 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 -*/ - -/// 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); - while i < total { - let mut chsize = utf8_char_width(v[i]); - if chsize == 0u { return false; } - if i + chsize > total { return false; } - i += 1u; - while chsize > 1u { - if v[i] & 192u8 != tag_cont_u8 { return false; } - i += 1u; - chsize -= 1u; - } - } - return true; -} - -/// Determines if a vector of `u16` contains valid UTF-16 -pub fn is_utf16(v: &[u16]) -> bool { - let len = v.len(); - let mut i = 0u; - while (i < len) { - let u = v[i]; - - if u <= 0xD7FF_u16 || u >= 0xE000_u16 { - i += 1u; - - } else { - if i+1u < len { return false; } - let u2 = v[i+1u]; - if u < 0xD7FF_u16 || u > 0xDBFF_u16 { return false; } - if u2 < 0xDC00_u16 || u2 > 0xDFFF_u16 { return false; } - i += 2u; - } - } - return true; -} - -/// 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| { - // Arithmetic with u32 literals is easier on the eyes than chars. - let mut ch = ch as u32; - - if (ch & 0xFFFF_u32) == ch { - // The BMP falls through (assuming non-surrogate, as it - // should) - assert!(ch <= 0xD7FF_u32 || ch >= 0xE000_u32); - u.push(ch as u16) - } else { - // Supplementary planes break into surrogates. - assert!(ch >= 0x1_0000_u32 && ch <= 0x10_FFFF_u32); - ch -= 0x1_0000_u32; - let w1 = 0xD800_u16 | ((ch >> 10) as u16); - let w2 = 0xDC00_u16 | ((ch as u16) & 0x3FF_u16); - u.push_all([w1, w2]) - } - } - u -} - -pub fn utf16_chars(v: &[u16], f: &fn(char)) { - let len = v.len(); - let mut i = 0u; - while (i < len && v[i] != 0u16) { - let u = v[i]; - - if u <= 0xD7FF_u16 || u >= 0xE000_u16 { - f(u as char); - i += 1u; - - } else { - let u2 = v[i+1u]; - assert!(u >= 0xD800_u16 && u <= 0xDBFF_u16); - assert!(u2 >= 0xDC00_u16 && u2 <= 0xDFFF_u16); - let mut c = (u - 0xD800_u16) as char; - c = c << 10; - c |= (u2 - 0xDC00_u16) as char; - c |= 0x1_0000_u32 as char; - f(c); - i += 2u; - } - } -} - -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 -} - -pub fn with_capacity(capacity: uint) -> ~str { - let mut buf = ~""; - reserve(&mut buf, 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; - if byte < 128u { return 1u; } - // Not a valid start byte - if byte < 192u { return 0u; } - if byte < 224u { return 2u; } - if byte < 240u { return 3u; } - if byte < 248u { return 4u; } - if byte < 252u { return 5u; } - 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 - * - * ~~~ - * 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; -} - -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; -static max_one_b: uint = 128u; -static tag_two_b: uint = 192u; -static max_two_b: uint = 2048u; -static tag_three_b: uint = 224u; -static max_three_b: uint = 65536u; -static tag_four_b: uint = 240u; -static max_four_b: uint = 2097152u; -static tag_five_b: uint = 248u; -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 - * - * ~~~ - * let i = str::as_bytes("Hello World") { |bytes| bytes.len() }; - * ~~~ - */ -#[inline] -pub fn as_bytes<T>(s: &const ~str, f: &fn(&~[u8]) -> T) -> T { - unsafe { - let v: *~[u8] = cast::transmute(copy s); - f(&*v) - } -} - -/** - * 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); - } -} - -/** - * 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 - * - * ~~~ - * let s = str::as_c_str("PATH", { |path| libc::getenv(path) }); - * ~~~ - */ -#[inline] -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) - } - } -} - -/** - * Work with the byte buffer and length of a slice. - * - * The given length is one byte longer than the 'official' indexable - * length of the string. This is to permit probing the byte past the - * indexable area for a null byte, as is the case in slices pointing - * to full strings, or suffixes of them. - */ -#[inline(always)] -pub fn as_buf<T>(s: &str, f: &fn(*u8, uint) -> T) -> T { - unsafe { - let v : *(*u8,uint) = transmute(&s); - let (buf,len) = *v; - f(buf, len) - } -} - -/** - * Returns the byte offset of an inner slice relative to an enclosing outer slice - * - * # Example - * - * ~~~ - * let string = "a\nb\nc"; - * let mut lines = ~[]; - * for each_line(string) |line| { lines.push(line) } - * - * assert!(subslice_offset(string, lines[0]) == 0); // &"a" - * assert!(subslice_offset(string, lines[1]) == 2); // &"b" - * assert!(subslice_offset(string, lines[2]) == 4); // &"c" - * ~~~ - */ -#[inline(always)] -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; - 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); - } - assert!(a_start <= b_start); - assert!(b_end <= a_end); - b_start - a_start - } - } -} - -/** - * 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 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; - while *curr != 0u8 { - i += 1u; - curr = ptr::offset(buf, i); - } - return from_buf_len(buf, i); - } - - /// Create a Rust string from a *u8 buffer of the given length - pub unsafe fn from_buf_len(buf: *const u8, len: uint) -> ~str { - let mut v: ~[u8] = vec::with_capacity(len + 1); - vec::as_mut_buf(v, |vbuf, _len| { - ptr::copy_memory(vbuf, buf as *u8, len) - }); - vec::raw::set_len(&mut v, len); - v.push(0u8); - - assert!(is_utf8(v)); - return ::cast::transmute(v); - } - - /// Create a Rust string from a null-terminated C string - pub unsafe fn from_c_str(c_str: *libc::c_char) -> ~str { - from_buf(::cast::transmute(c_str)) - } - - /// Create a Rust string from a `*c_char` buffer of the given length - pub unsafe fn from_c_str_len(c_str: *libc::c_char, len: uint) -> ~str { - from_buf_len(::cast::transmute(c_str), len) - } - - /// Converts a vector of bytes to a new owned string. - pub unsafe fn from_bytes(v: &const [u8]) -> ~str { - do vec::as_const_buf(v) |buf, len| { - from_buf_len(buf, len) - } - } - - /// Converts a vector of bytes to a string. - /// The byte slice needs to contain valid utf8 and needs to be one byte longer than - /// the string, if possible ending in a 0 byte. - pub unsafe fn from_bytes_with_null<'a>(v: &'a [u8]) -> &'a str { - cast::transmute(v) - } - - /// 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); - assert!(is_utf8(::cast::transmute(v))); - f(::cast::transmute(v)) - } - - /** - * Takes a bytewise (not UTF-8) slice from a string. - * - * Returns the substring from [`begin`..`end`). - * - * # Failure - * - * If begin is greater than end. - * If end is greater than the length of the string. - */ - pub unsafe fn slice_bytes_owned(s: &str, begin: uint, end: uint) -> ~str { - do as_buf(s) |sbuf, n| { - assert!((begin <= end)); - assert!((end <= n)); - - let mut v = vec::with_capacity(end - begin + 1u); - do vec::as_imm_buf(v) |vbuf, _vlen| { - let vbuf = ::cast::transmute_mut_unsafe(vbuf); - let src = ptr::offset(sbuf, begin); - ptr::copy_memory(vbuf, src, end - begin); - } - vec::raw::set_len(&mut v, end - begin); - v.push(0u8); - ::cast::transmute(v) - } - } - - /** - * Takes a bytewise (not UTF-8) slice from a string. - * - * Returns the substring from [`begin`..`end`). - * - * # Failure - * - * If begin is greater than end. - * If end is greater than the length of the string. - */ - #[inline] - pub unsafe fn slice_bytes(s: &str, begin: uint, end: uint) -> &str { - do as_buf(s) |sbuf, n| { - assert!((begin <= end)); - assert!((end <= n)); - - let tuple = (ptr::offset(sbuf, begin), end - begin + 1); - ::cast::transmute(tuple) - } - } - - /// 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); - do as_buf(*s) |buf, len| { - let buf: *mut u8 = ::cast::transmute(buf); - *ptr::mut_offset(buf, len) = b; - } - set_len(&mut *s, new_len); - } - - /// 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); - 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); - assert!((len > 0u)); - let b = s[len - 1u]; - set_len(s, len - 1u); - return b; - } - - /// 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); - assert!((len > 0u)); - let b = s[0]; - *s = raw::slice_bytes_owned(*s, 1u, len); - return b; - } - - /// Sets the length of the string and adds the null terminator - #[inline] - pub unsafe fn set_len(v: &mut ~str, new_len: uint) { - let v: **mut vec::raw::VecRepr = cast::transmute(v); - let repr: *mut vec::raw::VecRepr = *v; - (*repr).unboxed.fill = new_len + 1u; - let null = ptr::mut_offset(cast::transmute(&((*repr).unboxed.data)), - new_len); - *null = 0u8; - } - - #[test] - fn test_from_buf_len() { - unsafe { - let a = ~[65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; - let b = vec::raw::to_ptr(a); - let c = from_buf_len(b, 3u); - assert_eq!(c, ~"AAA"); - } - } - -} - -#[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)) - } - } -} - -#[cfg(test)] -pub mod traits {} - -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 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 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 to_owned(&self) -> ~str; - fn to_managed(&self) -> @str; - fn char_at(&self, i: uint) -> char; - fn char_at_reverse(&self, i: uint) -> char; - fn to_bytes(&self) -> ~[u8]; -} - -/// 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) - */ - #[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) - } - /// Returns true if a string contains a char - #[inline] - fn contains_char(&self, needle: char) -> bool { - contains_char(*self, needle) - } - - #[inline] - fn char_iter(&self) -> StrCharIterator<'self> { - StrCharIterator { - index: 0, - string: *self - } - } - - /// Iterate over the bytes in a string - #[inline] - fn each(&self, it: &fn(u8) -> bool) -> bool { each(*self, it) } - /// Iterate over the bytes in a string, with indices - #[inline] - fn eachi(&self, it: &fn(uint, u8) -> bool) -> bool { eachi(*self, it) } - /// Iterate over the bytes in a string - #[inline] - fn each_reverse(&self, it: &fn(u8) -> bool) -> bool { each_reverse(*self, it) } - /// Iterate over the bytes in a string, with indices - #[inline] - fn eachi_reverse(&self, it: &fn(uint, u8) -> bool) -> bool { - eachi_reverse(*self, it) - } - /// Iterate over the chars in a string - #[inline] - fn each_char(&self, it: &fn(char) -> bool) -> bool { each_char(*self, it) } - /// Iterate over the chars in a string, with indices - #[inline] - fn each_chari(&self, it: &fn(uint, char) -> bool) -> bool { - each_chari(*self, it) - } - /// Iterate over the chars in a string in reverse - #[inline] - fn each_char_reverse(&self, it: &fn(char) -> bool) -> bool { - each_char_reverse(*self, it) - } - /// Iterate over the chars in a string in reverse, with indices from the - /// end - #[inline] - fn each_chari_reverse(&self, it: &fn(uint, char) -> bool) -> bool { - each_chari_reverse(*self, it) - } - /// Returns true if one string ends with another - #[inline] - fn ends_with(&self, needle: &str) -> bool { - ends_with(*self, needle) - } - /// Returns true if the string has length 0 - #[inline] - fn is_empty(&self) -> bool { is_empty(*self) } - /** - * 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) } - /** - * 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) } - /// Returns the size in bytes not counting the null terminator - #[inline(always)] - fn len(&self) -> uint { len(*self) } - /// Returns the number of characters that a string holds - #[inline] - fn char_len(&self) -> uint { char_len(*self) } - /** - * Returns a slice of the given string from the byte range - * [`begin`..`end`) - * - * Fails when `begin` and `end` do not point to valid characters or - * beyond the last character of the string - */ - #[inline] - fn slice(&self, begin: uint, end: uint) -> &'self str { - slice(*self, begin, end) - } - /// Splits a string into substrings using a character function - #[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 - */ - #[inline] - fn each_split_char(&self, sep: char, it: &fn(&'self str) -> bool) -> bool { - each_split_char(*self, sep, it) - } - /** - * 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 true if one string starts with another - #[inline] - fn starts_with<'a>(&self, needle: &'a str) -> bool { - starts_with(*self, needle) - } - /** - * 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) - } - /// Escape each char in `s` with char::escape_default. - #[inline] - fn escape_default(&self) -> ~str { escape_default(*self) } - /// Escape each char in `s` with char::escape_unicode. - #[inline] - fn escape_unicode(&self) -> ~str { escape_unicode(*self) } - - /// Returns a string with leading and trailing whitespace removed - #[inline] - fn trim(&self) -> &'self str { trim(*self) } - /// Returns a string with leading whitespace removed - #[inline] - fn trim_left(&self) -> &'self str { trim_left(*self) } - /// Returns a string with trailing whitespace removed - #[inline] - fn trim_right(&self) -> &'self str { trim_right(*self) } - - #[inline] - fn trim_chars(&self, chars_to_trim: &[char]) -> &'self str { - trim_chars(*self, chars_to_trim) - } - #[inline] - fn trim_left_chars(&self, chars_to_trim: &[char]) -> &'self str { - trim_left_chars(*self, chars_to_trim) - } - #[inline] - fn trim_right_chars(&self, chars_to_trim: &[char]) -> &'self str { - trim_right_chars(*self, chars_to_trim) - } - - - #[inline] - fn to_owned(&self) -> ~str { to_owned(*self) } - - #[inline] - fn to_managed(&self) -> @str { - let v = at_vec::from_fn(self.len() + 1, |i| { - if i == self.len() { 0 } else { self[i] } - }); - unsafe { ::cast::transmute(v) } - } - - #[inline] - fn char_at(&self, i: uint) -> char { char_at(*self, i) } - - #[inline] - fn char_at_reverse(&self, i: uint) -> char { - char_at_reverse(*self, i) - } - - fn to_bytes(&self) -> ~[u8] { to_bytes(*self) } -} - -pub trait OwnedStr { - fn push_str(&mut self, v: &str); - fn push_char(&mut self, c: char); -} - -impl OwnedStr for ~str { - #[inline] - fn push_str(&mut self, v: &str) { - push_str(self, v); - } - #[inline] - fn push_char(&mut self, c: char) { - push_char(self, c); - } -} - -impl Clone for ~str { - #[inline(always)] - fn clone(&self) -> ~str { - to_owned(*self) - } -} - -pub struct StrCharIterator<'self> { - priv index: uint, - priv string: &'self str, -} - -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); - self.index = next; - Some(ch) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use container::Container; - use char; - use option::Some; - use libc::c_char; - use libc; - use old_iter::BaseIter; - use ptr; - use str::*; - use vec; - use vec::ImmutableVector; - use cmp::{TotalOrd, Less, Equal, Greater}; - - #[test] - fn test_eq() { - assert!((eq(&~"", &~""))); - assert!((eq(&~"foo", &~"foo"))); - assert!((!eq(&~"foo", &~"bar"))); - } - - #[test] - fn test_eq_slice() { - assert!((eq_slice(slice("foobar", 0, 3), "foo"))); - assert!((eq_slice(slice("barfoo", 3, 6), "foo"))); - assert!((!eq_slice("foo1", "foo2"))); - } - - #[test] - fn test_le() { - assert!((le(&"", &""))); - assert!((le(&"", &"foo"))); - assert!((le(&"foo", &"foo"))); - assert!((!eq(&~"foo", &~"bar"))); - } - - #[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!(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_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)); - } - - #[test] - fn test_pop_char() { - let mut data = ~"ประเทศไทย中华"; - let cc = pop_char(&mut data); - assert_eq!(~"ประเทศไทย中", data); - assert_eq!('华', cc); - } - - #[test] - fn test_pop_char_2() { - let mut data2 = ~"华"; - let cc2 = pop_char(&mut data2); - assert_eq!(~"", data2); - assert_eq!('华', cc2); - } - - #[test] - #[should_fail] - #[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"]); - } - - #[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"]); - } - - - #[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"]); - } - - #[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, ~[]); - } - - #[test] - fn test_split_within() { - 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)); - } - t(~"", 0, ~[]); - t(~"", 15, ~[]); - t(~"hello", 15, ~[~"hello"]); - t(~"\nMary had a little lamb\nLittle lamb\n", 15, - ~[~"Mary had a", ~"little lamb", ~"Little lamb"]); - } - - #[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)); - - 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()); - - 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_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!(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)); - } - - #[test] - fn test_substr() { - fn t(a: &str, b: &str, start: int) { - assert_eq!(substr(a, start as uint, len(b)), b); - } - t("hello", "llo", 2); - t("hello", "el", 1); - assert_eq!("ะเทศไท", substr("ประเทศไทย中华Việt Nam", 6u, 6u)); - } - - #[test] - fn test_concat() { - fn t(v: &[~str], s: &str) { - assert_eq!(concat(v), s.to_str()); - } - t(~[~"you", ~"know", ~"I'm", ~"no", ~"good"], ~"youknowI'mnogood"); - let v: ~[~str] = ~[]; - t(v, ~""); - t(~[~"hi"], ~"hi"); - } - - #[test] - fn test_connect() { - fn t(v: &[~str], sep: &str, s: &str) { - assert_eq!(connect(v, sep), s.to_str()); - } - t(~[~"you", ~"know", ~"I'm", ~"no", ~"good"], - ~" ", ~"you know I'm no good"); - 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()); - } - t(["you", "know", "I'm", "no", "good"], - " ", "you know I'm no good"); - t([], " ", ""); - t(["hi"], " ", "hi"); - } - - #[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), ~""); - } - - #[test] - fn test_unsafe_slice() { - assert_eq!("ab", unsafe {raw::slice_bytes("abc", 0, 2)}); - assert_eq!("bc", unsafe {raw::slice_bytes("abc", 1, 3)}); - assert_eq!("", unsafe {raw::slice_bytes("abc", 1, 1)}); - fn a_million_letter_a() -> ~str { - let mut i = 0; - let mut rs = ~""; - while i < 100000 { push_str(&mut rs, "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; } - rs - } - let letters = a_million_letter_a(); - assert!(half_a_million_letter_a() == - unsafe {raw::slice_bytes(letters, 0u, 500000)}.to_owned()); - } - - #[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"))); - } - - #[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"))); - } - - #[test] - fn test_is_empty() { - assert!((is_empty(~""))); - assert!((!is_empty(~"a"))); - } - - #[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"); - let test = ~"test"; - assert!(replace(~" test test ", test, ~"toast") == - ~" toast toast "); - assert_eq!(replace(~" test test ", test, ~""), ~" "); - } - - #[test] - fn test_replace_2a() { - let data = ~"ประเทศไทย中华"; - let repl = ~"دولة الكويت"; - - let a = ~"ประเ"; - let A = ~"دولة الكويتทศไทย中华"; - assert_eq!(replace(data, a, repl), A); - } - - #[test] - fn test_replace_2b() { - let data = ~"ประเทศไทย中华"; - let repl = ~"دولة الكويت"; - - let b = ~"ะเ"; - let B = ~"ปรدولة الكويتทศไทย中华"; - assert_eq!(replace(data, b, repl), B); - } - - #[test] - fn test_replace_2c() { - let data = ~"ประเทศไทย中华"; - let repl = ~"دولة الكويت"; - - let c = ~"中华"; - let C = ~"ประเทศไทยدولة الكويت"; - assert_eq!(replace(data, c, repl), C); - } - - #[test] - fn test_replace_2d() { - let data = ~"ประเทศไทย中华"; - let repl = ~"دولة الكويت"; - - let d = ~"ไท华"; - assert_eq!(replace(data, 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)); - - 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)); - - fn a_million_letter_X() -> ~str { - let mut i = 0; - let mut rs = ~""; - while i < 100000 { - push_str(&mut rs, "华华华华华华华华华华"); - i += 1; - } - rs - } - fn half_a_million_letter_X() -> ~str { - let mut i = 0; - let mut rs = ~""; - while i < 100000 { push_str(&mut rs, "华华华华华"); i += 1; } - rs - } - let letters = a_million_letter_X(); - assert!(half_a_million_letter_X() == - slice(letters, 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!("ab", slice("abc", 0u, 2u)); - assert_eq!("bc", slice("abc", 1u, 3u)); - assert_eq!("", slice("abc", 1u, 1u)); - - assert_eq!("中", slice(ss, 0u, 3u)); - assert_eq!("华V", slice(ss, 3u, 7u)); - assert_eq!("", slice(ss, 3u, 3u)); - /*0: 中 - 3: 华 - 6: V - 7: i - 8: ệ - 11: t - 12: - 13: N - 14: a - 15: m */ - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_slice_fail() { - slice("中华Việt Nam", 0u, 2u); - } - - #[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 *** "); - } - - #[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"); - } - - #[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"); - } - - #[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 "); - } - - #[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"); - } - - #[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"); - } - - #[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(~" _ "))); - } - - #[test] - fn test_shift_byte() { - let mut s = ~"ABC"; - let b = unsafe{raw::shift_byte(&mut s)}; - assert_eq!(s, ~"BC"); - assert_eq!(b, 65u8); - } - - #[test] - fn test_pop_byte() { - let mut s = ~"ABC"; - let b = unsafe{raw::pop_byte(&mut s)}; - assert_eq!(s, ~"AB"); - assert_eq!(b, 67u8); - } - - #[test] - fn test_unsafe_from_bytes() { - let a = ~[65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8]; - let b = unsafe { raw::from_bytes(a) }; - assert_eq!(b, ~"AAAAAAA"); - } - - #[test] - fn test_from_bytes() { - let ss = ~"ศไทย中华Việt Nam"; - let bb = ~[0xe0_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8]; - - assert_eq!(ss, from_bytes(bb)); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_from_bytes_fail() { - let bb = ~[0xff_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8]; - - let _x = from_bytes(bb); - } - - #[test] - fn test_unsafe_from_bytes_with_null() { - let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; - let b = unsafe { raw::from_bytes_with_null(a) }; - assert_eq!(b, "AAAAAAA"); - } - - #[test] - fn test_from_bytes_with_null() { - let ss = "ศไทย中华Việt Nam"; - let bb = [0xe0_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8, 0x0_u8]; - - assert_eq!(ss, from_bytes_with_null(bb)); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_from_bytes_with_null_fail() { - let bb = [0xff_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8, 0x0_u8]; - - let _x = from_bytes_with_null(bb); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_from_bytes_with_null_fail_2() { - let bb = [0xff_u8, 0xb8_u8, 0xa8_u8, - 0xe0_u8, 0xb9_u8, 0x84_u8, - 0xe0_u8, 0xb8_u8, 0x97_u8, - 0xe0_u8, 0xb8_u8, 0xa2_u8, - 0xe4_u8, 0xb8_u8, 0xad_u8, - 0xe5_u8, 0x8d_u8, 0x8e_u8, - 0x56_u8, 0x69_u8, 0xe1_u8, - 0xbb_u8, 0x87_u8, 0x74_u8, - 0x20_u8, 0x4e_u8, 0x61_u8, - 0x6d_u8, 0x60_u8]; - - let _x = from_bytes_with_null(bb); - } - - #[test] - fn test_from_buf() { - unsafe { - let a = ~[65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; - let b = vec::raw::to_ptr(a); - let c = raw::from_buf(b); - assert_eq!(c, ~"AAAAAAA"); - } - } - - #[test] - #[ignore(cfg(windows))] - #[should_fail] - fn test_as_bytes_fail() { - // Don't double free - as_bytes::<()>(&~"", |_bytes| fail!() ); - } - - #[test] - fn test_as_buf() { - let a = ~"Abcdefg"; - let b = as_buf(a, |buf, _l| { - assert_eq!(unsafe { *buf }, 65u8); - 100 - }); - assert_eq!(b, 100); - } - - #[test] - fn test_as_buf_small() { - let a = ~"A"; - let b = as_buf(a, |buf, _l| { - assert_eq!(unsafe { *buf }, 65u8); - 100 - }); - assert_eq!(b, 100); - } - - #[test] - fn test_as_buf2() { - unsafe { - let s = ~"hello"; - let sb = as_buf(s, |b, _l| b); - let s_cstr = raw::from_buf(sb); - assert_eq!(s_cstr, s); - } - } - - #[test] - fn test_as_buf_3() { - let a = ~"hello"; - do as_buf(a) |buf, len| { - unsafe { - assert_eq!(a[0], 'h' as u8); - assert_eq!(*buf, 'h' as u8); - assert_eq!(len, 6u); - assert_eq!(*ptr::offset(buf,4u), 'o' as u8); - assert_eq!(*ptr::offset(buf,5u), 0u8); - } - } - } - - #[test] - fn test_subslice_offset() { - let a = "kernelsprite"; - let b = slice(a, 7, len(a)); - let c = slice(a, 0, len(a) - 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) } - assert_eq!(subslice_offset(string, lines[0]), 0); - assert_eq!(subslice_offset(string, lines[1]), 2); - assert_eq!(subslice_offset(string, lines[2]), 4); - } - - #[test] - #[should_fail] - fn test_subslice_offset_2() { - let a = "alchemiter"; - let b = "cruxtruder"; - subslice_offset(a, b); - } - - #[test] - fn vec_str_conversions() { - let s1: ~str = ~"All mimsy were the borogoves"; - - let v: ~[u8] = to_bytes(s1); - let s2: ~str = from_bytes(v); - let mut i: uint = 0u; - let n1: uint = len(s1); - let n2: uint = vec::len::<u8>(v); - assert_eq!(n1, n2); - while i < n1 { - let a: u8 = s1[i]; - let b: u8 = s2[i]; - debug!(a); - debug!(b); - assert_eq!(a, b); - i += 1u; - } - } - - #[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")); - - let data = ~"ประเทศไทย中华Việt Nam"; - assert!(contains(data, ~"ประเ")); - assert!(contains(data, ~"ะเ")); - assert!(contains(data, ~"中华")); - assert!(!contains(data, ~"ไท华")); - } - - #[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; - } - } - - #[test] - fn test_map() { - assert_eq!(~"", map(~"", |c| unsafe {libc::toupper(c as c_char)} as char)); - assert_eq!(~"YMCA", map(~"ymca", |c| unsafe {libc::toupper(c as c_char)} as char)); - } - - #[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", - ~[0xd800_u16, 0xdf45_u16, 0xd800_u16, 0xdf3f_u16, - 0xd800_u16, 0xdf3b_u16, 0xd800_u16, 0xdf46_u16, - 0xd800_u16, 0xdf39_u16, 0xd800_u16, 0xdf3b_u16, - 0xd800_u16, 0xdf30_u16, 0x000a_u16]), - - (~"𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n", - ~[0xd801_u16, 0xdc12_u16, 0xd801_u16, - 0xdc49_u16, 0xd801_u16, 0xdc2e_u16, 0xd801_u16, - 0xdc40_u16, 0xd801_u16, 0xdc32_u16, 0xd801_u16, - 0xdc4b_u16, 0x0020_u16, 0xd801_u16, 0xdc0f_u16, - 0xd801_u16, 0xdc32_u16, 0xd801_u16, 0xdc4d_u16, - 0x000a_u16]), - - (~"𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n", - ~[0xd800_u16, 0xdf00_u16, 0xd800_u16, 0xdf16_u16, - 0xd800_u16, 0xdf0b_u16, 0xd800_u16, 0xdf04_u16, - 0xd800_u16, 0xdf11_u16, 0xd800_u16, 0xdf09_u16, - 0x00b7_u16, 0xd800_u16, 0xdf0c_u16, 0xd800_u16, - 0xdf04_u16, 0xd800_u16, 0xdf15_u16, 0xd800_u16, - 0xdf04_u16, 0xd800_u16, 0xdf0b_u16, 0xd800_u16, - 0xdf09_u16, 0xd800_u16, 0xdf11_u16, 0x000a_u16 ]), - - (~"𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n", - ~[0xd801_u16, 0xdc8b_u16, 0xd801_u16, 0xdc98_u16, - 0xd801_u16, 0xdc88_u16, 0xd801_u16, 0xdc91_u16, - 0xd801_u16, 0xdc9b_u16, 0xd801_u16, 0xdc92_u16, - 0x0020_u16, 0xd801_u16, 0xdc95_u16, 0xd801_u16, - 0xdc93_u16, 0x0020_u16, 0xd801_u16, 0xdc88_u16, - 0xd801_u16, 0xdc9a_u16, 0xd801_u16, 0xdc8d_u16, - 0x0020_u16, 0xd801_u16, 0xdc8f_u16, 0xd801_u16, - 0xdc9c_u16, 0xd801_u16, 0xdc92_u16, 0xd801_u16, - 0xdc96_u16, 0xd801_u16, 0xdc86_u16, 0x0020_u16, - 0xd801_u16, 0xdc95_u16, 0xd801_u16, 0xdc86_u16, - 0x000a_u16 ]) ]; - - for pairs.each |p| { - let (s, u) = copy *p; - assert!(to_utf16(s) == u); - assert!(from_utf16(u) == s); - assert!(from_utf16(to_utf16(s)) == s); - assert!(to_utf16(from_utf16(u)) == u); - } - } - - #[test] - fn test_char_at() { - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; - let mut pos = 0; - for v.each |ch| { - assert!(s.char_at(pos) == *ch); - pos += from_char(*ch).len(); - } - } - - #[test] - fn test_char_at_reverse() { - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; - let mut pos = s.len(); - for v.each_reverse |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; - - for s.each |b| { - assert_eq!(b, v[pos]); - pos += 1; - } - } - - #[test] - fn test_each_empty() { - for "".each |b| { - assert_eq!(b, 0u8); - } - } - - #[test] - fn test_eachi() { - 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; - - for s.eachi |i, b| { - assert_eq!(pos, i); - assert_eq!(b, v[pos]); - pos += 1; - } - } - - #[test] - fn test_eachi_empty() { - for "".eachi |i, b| { - assert_eq!(i, 0); - assert_eq!(b, 0); - } - } - - #[test] - fn test_each_reverse() { - 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(); - - for s.each_reverse |b| { - pos -= 1; - assert_eq!(b, v[pos]); - } - } - - #[test] - fn test_each_empty_reverse() { - for "".each_reverse |b| { - assert_eq!(b, 0u8); - } - } - - #[test] - fn test_eachi_reverse() { - 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(); - - for s.eachi_reverse |i, 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); - } - } - - #[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; - } - } - - #[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; - } - } - - #[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]); - } - } - - #[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]); - } - } - - #[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"); - } - - #[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"); - } - - #[test] - fn test_to_managed() { - assert_eq!((~"abc").to_managed(), @"abc"); - assert_eq!(slice("abcdef", 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!(char_range_at_reverse("abc", 0).next, 0); - } - - #[test] - fn test_iterator() { - use iterator::*; - let s = ~"ศไทย中华Việt Nam"; - let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; - - let mut pos = 0; - let mut it = s.char_iter(); - - for it.advance |c| { - assert_eq!(c, v[pos]); - pos += 1; - } - assert_eq!(pos, v.len()); - } -} diff --git a/src/libcore/str/ascii.rs b/src/libcore/str/ascii.rs deleted file mode 100644 index 4e239c4c82c..00000000000 --- a/src/libcore/str/ascii.rs +++ /dev/null @@ -1,287 +0,0 @@ -// 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. - -//! Operations on ASCII strings and characters. - -use to_str::{ToStr,ToStrConsume}; -use str; -use str::StrSlice; -use cast; -use old_iter::BaseIter; -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 { - /// Converts a ascii character into a `u8`. - #[inline(always)] - fn to_byte(self) -> u8 { - self.chr - } - - /// Converts a ascii character into a `char`. - #[inline(always)] - fn to_char(self) -> char { - self.chr as char - } - - /// Convert to lowercase. - #[inline(always)] - fn to_lower(self) -> Ascii { - if self.chr >= 65 && self.chr <= 90 { - Ascii{chr: self.chr | 0x20 } - } else { - self - } - } - - /// Convert to uppercase. - #[inline(always)] - fn to_upper(self) -> Ascii { - if self.chr >= 97 && self.chr <= 122 { - Ascii{chr: self.chr & !0x20 } - } else { - self - } - } - - // Compares two ascii characters of equality, ignoring case. - #[inline(always)] - fn eq_ignore_case(self, other: Ascii) -> bool { - self.to_lower().chr == other.to_lower().chr - } -} - -impl ToStr for Ascii { - #[inline(always)] - fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) } -} - -/// Trait for converting into an ascii type. -pub trait AsciiCast<T> { - /// Convert to an ascii type - fn to_ascii(&self) -> T; - - /// Check if convertible to ascii - fn is_ascii(&self) -> bool; -} - -impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] { - #[inline(always)] - fn to_ascii(&self) -> &'self[Ascii] { - assert!(self.is_ascii()); - unsafe{ cast::transmute(*self) } - } - - #[inline(always)] - fn is_ascii(&self) -> bool { - for self.each |b| { - if !b.is_ascii() { return false; } - } - true - } -} - -impl<'self> AsciiCast<&'self[Ascii]> for &'self str { - #[inline(always)] - fn to_ascii(&self) -> &'self[Ascii] { - assert!(self.is_ascii()); - let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) }; - unsafe{ cast::transmute((p, len - 1))} - } - - #[inline(always)] - fn is_ascii(&self) -> bool { - for self.each |b| { - if !b.is_ascii() { return false; } - } - true - } -} - -impl AsciiCast<Ascii> for u8 { - #[inline(always)] - fn to_ascii(&self) -> Ascii { - assert!(self.is_ascii()); - Ascii{ chr: *self } - } - - #[inline(always)] - fn is_ascii(&self) -> bool { - *self & 128 == 0u8 - } -} - -impl AsciiCast<Ascii> for char { - #[inline(always)] - fn to_ascii(&self) -> Ascii { - assert!(self.is_ascii()); - Ascii{ chr: *self as u8 } - } - - #[inline(always)] - fn is_ascii(&self) -> bool { - *self - ('\x7F' & *self) == '\x00' - } -} - -/// Trait for copyless casting to an ascii vector. -pub trait OwnedAsciiCast { - /// Take ownership and cast to an ascii vector without trailing zero element. - fn to_ascii_consume(self) -> ~[Ascii]; -} - -impl OwnedAsciiCast for ~[u8] { - #[inline(always)] - fn to_ascii_consume(self) -> ~[Ascii] { - assert!(self.is_ascii()); - unsafe {cast::transmute(self)} - } -} - -impl OwnedAsciiCast for ~str { - #[inline(always)] - fn to_ascii_consume(self) -> ~[Ascii] { - assert!(self.is_ascii()); - let mut s = self; - unsafe { - str::raw::pop_byte(&mut s); - cast::transmute(s) - } - } -} - -/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str` -pub trait AsciiStr { - /// Convert to a string. - fn to_str_ascii(&self) -> ~str; - - /// Convert to vector representing a lower cased ascii string. - fn to_lower(&self) -> ~[Ascii]; - - /// Convert to vector representing a upper cased ascii string. - fn to_upper(&self) -> ~[Ascii]; - -} - -impl<'self> AsciiStr for &'self [Ascii] { - #[inline(always)] - fn to_str_ascii(&self) -> ~str { - let mut cpy = self.to_owned(); - cpy.push(0u8.to_ascii()); - unsafe {cast::transmute(cpy)} - } - - #[inline(always)] - fn to_lower(&self) -> ~[Ascii] { - self.map(|a| a.to_lower()) - } - - #[inline(always)] - fn to_upper(&self) -> ~[Ascii] { - self.map(|a| a.to_upper()) - } -} - -impl ToStrConsume for ~[Ascii] { - #[inline(always)] - fn to_str_consume(self) -> ~str { - let mut cpy = self; - cpy.push(0u8.to_ascii()); - unsafe {cast::transmute(cpy)} - } -} - -#[cfg(test)] -mod tests { - use super::*; - use str; - - macro_rules! v2ascii ( - ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]); - (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]); - ) - - #[test] - fn test_ascii() { - assert_eq!(65u8.to_ascii().to_byte(), 65u8); - assert_eq!(65u8.to_ascii().to_char(), 'A'); - assert_eq!('A'.to_ascii().to_char(), 'A'); - assert_eq!('A'.to_ascii().to_byte(), 65u8); - - assert_eq!('A'.to_ascii().to_lower().to_char(), 'a'); - assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z'); - assert_eq!('a'.to_ascii().to_upper().to_char(), 'A'); - assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z'); - - assert_eq!('@'.to_ascii().to_lower().to_char(), '@'); - assert_eq!('['.to_ascii().to_lower().to_char(), '['); - 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())); - } - - #[test] - fn test_ascii_vec() { - assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59])); - assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59])); - // FIXME: #5475 borrowchk error, owned vectors do not live long enough - // if chained-from directly - let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59])); - let v = ~"( ;"; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59])); - - assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#"); - assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#"); - - assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~""); - assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca"); - assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;"); - - assert!("".is_ascii()); - assert!("a".is_ascii()); - assert!(!"\u2009".is_ascii()); - - } - - #[test] - fn test_owned_ascii_vec() { - // FIXME: #4318 Compiler crashes on moving self - //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59])); - //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59])); - //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0])); - //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(), - // v2ascii!(~[40, 32, 59, 0])); - } - - #[test] - fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); } - - #[test] - fn test_ascii_to_str_consume() { - // FIXME: #4318 Compiler crashes on moving self - //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;"); - } - - #[test] #[should_fail] - fn test_ascii_vec_fail_u8_slice() { (&[127u8, 128u8, 255u8]).to_ascii(); } - - #[test] #[should_fail] - fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); } - - #[test] #[should_fail] - fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); } - - #[test] #[should_fail] - fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); } -} diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs deleted file mode 100644 index 137070ce202..00000000000 --- a/src/libcore/sys.rs +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Misc low level stuff - -use option::{Some, None}; -use cast; -use cmp::{Eq, Ord}; -use gc; -use io; -use libc; -use libc::{c_void, c_char, size_t}; -use repr; -use str; -use unstable::intrinsics; - -pub type FreeGlue<'self> = &'self fn(*TypeDesc, *c_void); - -// Corresponds to runtime type_desc type -pub struct TypeDesc { - size: uint, - align: uint, - take_glue: uint, - drop_glue: uint, - free_glue: uint - // Remaining fields not listed -} - -/// The representation of a Rust closure -pub struct Closure { - code: *(), - env: *(), -} - -pub mod rustrt { - use libc::{c_char, size_t}; - - pub extern { - #[rust_stack] - unsafe fn rust_upcall_fail(expr: *c_char, - file: *c_char, - line: size_t); - } -} - -/// 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. - * - * Useful for calling certain function in the Rust runtime or otherwise - * performing dark magick. - */ -#[inline(always)] -pub fn get_type_desc<T>() -> *TypeDesc { - unsafe { intrinsics::get_tydesc::<T>() as *TypeDesc } -} - -/// Returns a pointer to a type descriptor. -#[inline(always)] -pub fn get_type_desc_val<T>(_val: &T) -> *TypeDesc { - get_type_desc::<T>() -} - -/// Returns the size of a type -#[inline(always)] -pub fn size_of<T>() -> uint { - unsafe { intrinsics::size_of::<T>() } -} - -/// Returns the size of the type that `_val` points to -#[inline(always)] -pub fn size_of_val<T>(_val: &T) -> uint { - size_of::<T>() -} - -/** - * Returns the size of a type, or 1 if the actual size is zero. - * - * Useful for building structures containing variable-length arrays. - */ -#[inline(always)] -pub fn nonzero_size_of<T>() -> uint { - let s = size_of::<T>(); - if s == 0 { 1 } else { s } -} - -/// Returns the size of the type of the value that `_val` points to -#[inline(always)] -pub fn nonzero_size_of_val<T>(_val: &T) -> uint { - nonzero_size_of::<T>() -} - - -/** - * Returns the ABI-required minimum alignment of a type - * - * This is the alignment used for struct fields. It may be smaller - * than the preferred alignment. - */ -#[inline(always)] -pub fn min_align_of<T>() -> uint { - unsafe { intrinsics::min_align_of::<T>() } -} - -/// Returns the ABI-required minimum alignment of the type of the value that -/// `_val` points to -#[inline(always)] -pub fn min_align_of_val<T>(_val: &T) -> uint { - min_align_of::<T>() -} - -/// Returns the preferred alignment of a type -#[inline(always)] -pub fn pref_align_of<T>() -> uint { - unsafe { intrinsics::pref_align_of::<T>() } -} - -/// Returns the preferred alignment of the type of the value that -/// `_val` points to -#[inline(always)] -pub fn pref_align_of_val<T>(_val: &T) -> uint { - pref_align_of::<T>() -} - -/// Returns the refcount of a shared box (as just before calling this) -#[inline(always)] -pub fn refcount<T>(t: @T) -> uint { - unsafe { - let ref_ptr: *uint = cast::transmute_copy(&t); - *ref_ptr - 1 - } -} - -pub fn log_str<T>(t: &T) -> ~str { - do io::with_str_writer |wr| { - repr::write_repr(wr, t) - } -} - -/// Trait for initiating task failure. -pub trait FailWithCause { - /// Fail the current task, taking ownership of `cause` - fn fail_with(cause: Self, file: &'static str, line: uint) -> !; -} - -impl FailWithCause for ~str { - fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! { - do str::as_buf(cause) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { - unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) - } - } - } - } -} - -impl FailWithCause for &'static str { - fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! { - do str::as_buf(cause) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { - unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) - } - } - } - } -} - -// FIXME #4427: Temporary until rt::rt_fail_ goes away -pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { - use option::Option; - use rt::{context, OldTaskContext, TaskContext}; - use rt::task::{Task, Unwinder}; - use rt::local::Local; - - let context = context(); - match context { - OldTaskContext => { - unsafe { - gc::cleanup_stack_for_failure(); - rustrt::rust_upcall_fail(msg, file, line); - cast::transmute(()) - } - } - _ => { - unsafe { - // XXX: Bad re-allocations. fail! needs some refactoring - let msg = str::raw::from_c_str(msg); - let file = str::raw::from_c_str(file); - - let outmsg = fmt!("%s at line %i of file %s", msg, line as int, file); - - // XXX: Logging doesn't work correctly in non-task context because it - // invokes the local heap - if context == TaskContext { - error!(outmsg); - } else { - rtdebug!("%s", outmsg); - } - - 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") - } - } - } - } -} - -#[cfg(test)] -mod tests { - use cast; - use sys::*; - - #[test] - fn size_of_basic() { - assert_eq!(size_of::<u8>(), 1u); - assert_eq!(size_of::<u16>(), 2u); - assert_eq!(size_of::<u32>(), 4u); - assert_eq!(size_of::<u64>(), 8u); - } - - #[test] - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] - #[cfg(target_arch = "mips")] - fn size_of_32() { - assert_eq!(size_of::<uint>(), 4u); - assert_eq!(size_of::<*uint>(), 4u); - } - - #[test] - #[cfg(target_arch = "x86_64")] - fn size_of_64() { - assert_eq!(size_of::<uint>(), 8u); - assert_eq!(size_of::<*uint>(), 8u); - } - - #[test] - fn size_of_val_basic() { - assert_eq!(size_of_val(&1u8), 1); - assert_eq!(size_of_val(&1u16), 2); - assert_eq!(size_of_val(&1u32), 4); - assert_eq!(size_of_val(&1u64), 8); - } - - #[test] - fn nonzero_size_of_basic() { - type Z = [i8, ..0]; - assert_eq!(size_of::<Z>(), 0u); - assert_eq!(nonzero_size_of::<Z>(), 1u); - assert_eq!(nonzero_size_of::<uint>(), size_of::<uint>()); - } - - #[test] - fn nonzero_size_of_val_basic() { - let z = [0u8, ..0]; - assert_eq!(size_of_val(&z), 0u); - assert_eq!(nonzero_size_of_val(&z), 1u); - assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u)); - } - - #[test] - fn align_of_basic() { - assert_eq!(pref_align_of::<u8>(), 1u); - assert_eq!(pref_align_of::<u16>(), 2u); - assert_eq!(pref_align_of::<u32>(), 4u); - } - - #[test] - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "arm")] - #[cfg(target_arch = "mips")] - fn align_of_32() { - assert_eq!(pref_align_of::<uint>(), 4u); - assert_eq!(pref_align_of::<*uint>(), 4u); - } - - #[test] - #[cfg(target_arch = "x86_64")] - fn align_of_64() { - assert_eq!(pref_align_of::<uint>(), 8u); - assert_eq!(pref_align_of::<*uint>(), 8u); - } - - #[test] - fn align_of_val_basic() { - assert_eq!(pref_align_of_val(&1u8), 1u); - assert_eq!(pref_align_of_val(&1u16), 2u); - assert_eq!(pref_align_of_val(&1u32), 4u); - } - - #[test] - fn synthesize_closure() { - unsafe { - let x = 10; - let f: &fn(int) -> int = |y| x + y; - - assert_eq!(f(20), 30); - - let original_closure: Closure = cast::transmute(f); - - let actual_function_pointer = original_closure.code; - let environment = original_closure.env; - - let new_closure = Closure { - code: actual_function_pointer, - env: environment - }; - - let new_f: &fn(int) -> int = cast::transmute(new_closure); - assert_eq!(new_f(20), 30); - } - } - - #[test] - #[should_fail] - fn fail_static() { FailWithCause::fail_with("cause", file!(), line!()) } - - #[test] - #[should_fail] - fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) } -} diff --git a/src/libcore/task/local_data_priv.rs b/src/libcore/task/local_data_priv.rs deleted file mode 100644 index 2f97eaacf4b..00000000000 --- a/src/libcore/task/local_data_priv.rs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; // FIXME #3538 - -use cast; -use cmp::Eq; -use libc; -use prelude::*; -use task::rt; -use local_data::LocalDataKey; - -use super::rt::rust_task; -use rt::task::{Task, LocalStorage}; - -pub enum Handle { - OldHandle(*rust_task), - NewHandle(*mut LocalStorage) -} - -impl Handle { - pub fn new() -> Handle { - use rt::{context, OldTaskContext}; - use rt::local::Local; - unsafe { - match context() { - OldTaskContext => { - OldHandle(rt::rust_get_task()) - } - _ => { - let task = Local::unsafe_borrow::<Task>(); - NewHandle(&mut (*task).storage) - } - } - } - } -} - -pub trait LocalData { } -impl<T: 'static> LocalData for @T { } - -impl Eq for @LocalData { - fn eq(&self, other: &@LocalData) -> bool { - unsafe { - let ptr_a: &(uint, uint) = cast::transmute(self); - let ptr_b: &(uint, uint) = cast::transmute(other); - return ptr_a == ptr_b; - } - } - fn ne(&self, other: &@LocalData) -> bool { !(*self).eq(other) } -} - -// If TLS is used heavily in future, this could be made more efficient with a -// proper map. -type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData); -// Has to be a pointer at outermost layer; the foreign call returns void *. -type TaskLocalMap = @mut ~[Option<TaskLocalElement>]; - -fn cleanup_task_local_map(map_ptr: *libc::c_void) { - unsafe { - assert!(!map_ptr.is_null()); - // Get and keep the single reference that was created at the - // beginning. - let _map: TaskLocalMap = cast::transmute(map_ptr); - // All local_data will be destroyed along with the map. - } -} - -// Gets the map from the runtime. Lazily initialises if not done so already. -unsafe fn get_local_map(handle: Handle) -> TaskLocalMap { - match handle { - OldHandle(task) => get_task_local_map(task), - NewHandle(local_storage) => get_newsched_local_map(local_storage) - } -} - -unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { - - extern fn cleanup_task_local_map_extern_cb(map_ptr: *libc::c_void) { - cleanup_task_local_map(map_ptr); - } - - // Relies on the runtime initialising the pointer to null. - // Note: The map's box lives in TLS invisibly referenced once. Each time - // we retrieve it for get/set, we make another reference, which get/set - // drop when they finish. No "re-storing after modifying" is needed. - let map_ptr = rt::rust_get_task_local_data(task); - if map_ptr.is_null() { - let map: TaskLocalMap = @mut ~[]; - // NB: This bumps the ref count before converting to an unsafe pointer, - // keeping the map alive until TLS is destroyed - rt::rust_set_task_local_data(task, cast::transmute(map)); - rt::rust_task_local_data_atexit(task, cleanup_task_local_map_extern_cb); - map - } else { - let map = cast::transmute(map_ptr); - let nonmut = cast::transmute::<TaskLocalMap, - @~[Option<TaskLocalElement>]>(map); - cast::bump_box_refcount(nonmut); - map - } -} - -unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap { - match &mut *local { - &LocalStorage(map_ptr, Some(_)) => { - assert!(map_ptr.is_not_null()); - let map = cast::transmute(map_ptr); - let nonmut = cast::transmute::<TaskLocalMap, - @~[Option<TaskLocalElement>]>(map); - cast::bump_box_refcount(nonmut); - return map; - } - &LocalStorage(ref mut map_ptr, ref mut at_exit) => { - assert!((*map_ptr).is_null()); - let map: TaskLocalMap = @mut ~[]; - *map_ptr = cast::transmute(map); - let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p); - *at_exit = Some(at_exit_fn); - return map; - } - } -} - -unsafe fn key_to_key_value<T: 'static>(key: LocalDataKey<T>) -> *libc::c_void { - // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr. - // Use reinterpret_cast -- transmute would leak (forget) the closure. - let pair: (*libc::c_void, *libc::c_void) = cast::transmute_copy(&key); - pair.first() -} - -// If returning Some(..), returns with @T with the map's reference. Careful! -unsafe fn local_data_lookup<T: 'static>( - map: TaskLocalMap, key: LocalDataKey<T>) - -> Option<(uint, *libc::c_void)> { - - let key_value = key_to_key_value(key); - let map_pos = (*map).position(|entry| - match *entry { - Some((k,_,_)) => k == key_value, - None => false - } - ); - do map_pos.map |index| { - // .get() is guaranteed because of "None { false }" above. - let (_, data_ptr, _) = (*map)[*index].get(); - (*index, data_ptr) - } -} - -unsafe fn local_get_helper<T: 'static>( - handle: Handle, key: LocalDataKey<T>, - do_pop: bool) -> Option<@T> { - - let map = get_local_map(handle); - // Interpreturn our findings from the map - do local_data_lookup(map, key).map |result| { - // A reference count magically appears on 'data' out of thin air. It - // was referenced in the local_data box, though, not here, so before - // overwriting the local_data_box we need to give an extra reference. - // We must also give an extra reference when not removing. - let (index, data_ptr) = *result; - let data: @T = cast::transmute(data_ptr); - cast::bump_box_refcount(data); - if do_pop { - map[index] = None; - } - data - } -} - - -pub unsafe fn local_pop<T: 'static>( - handle: Handle, - key: LocalDataKey<T>) -> Option<@T> { - - local_get_helper(handle, key, true) -} - -pub unsafe fn local_get<T: 'static>( - handle: Handle, - key: LocalDataKey<T>) -> Option<@T> { - - local_get_helper(handle, key, false) -} - -pub unsafe fn local_set<T: 'static>( - handle: Handle, key: LocalDataKey<T>, data: @T) { - - let map = get_local_map(handle); - // Store key+data as *voids. Data is invisibly referenced once; key isn't. - let keyval = key_to_key_value(key); - // We keep the data in two forms: one as an unsafe pointer, so we can get - // it back by casting; another in an existential box, so the reference we - // own on it can be dropped when the box is destroyed. The unsafe pointer - // does not have a reference associated with it, so it may become invalid - // when the box is destroyed. - let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data); - let data_box = @data as @LocalData; - // Construct new entry to store in the map. - let new_entry = Some((keyval, data_ptr, data_box)); - // Find a place to put it. - match local_data_lookup(map, key) { - Some((index, _old_data_ptr)) => { - // Key already had a value set, _old_data_ptr, whose reference - // will get dropped when the local_data box is overwritten. - map[index] = new_entry; - } - None => { - // Find an empty slot. If not, grow the vector. - match (*map).position(|x| x.is_none()) { - Some(empty_index) => { map[empty_index] = new_entry; } - None => { map.push(new_entry); } - } - } - } -} - -pub unsafe fn local_modify<T: 'static>( - handle: Handle, key: LocalDataKey<T>, - modify_fn: &fn(Option<@T>) -> Option<@T>) { - - // Could be more efficient by doing the lookup work, but this is easy. - let newdata = modify_fn(local_pop(handle, key)); - if newdata.is_some() { - local_set(handle, key, newdata.unwrap()); - } -} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs deleted file mode 100644 index 490a69248ee..00000000000 --- a/src/libcore/task/mod.rs +++ /dev/null @@ -1,1189 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * Task management. - * - * An executing Rust program consists of a tree of tasks, each with their own - * stack, and sole ownership of their allocated heap data. Tasks communicate - * with each other using ports and channels. - * - * When a task fails, that failure will propagate to its parent (the task - * that spawned it) and the parent will fail as well. The reverse is not - * true: when a parent task fails its children will continue executing. When - * the root (main) task fails, all tasks fail, and then so does the entire - * process. - * - * Tasks may execute in parallel and are scheduled automatically by the - * runtime. - * - * # Example - * - * ~~~ - * do spawn { - * log(error, "Hello, World!"); - * } - * ~~~ - */ - -use cell::Cell; -use cmp::Eq; -use result::Result; -use comm::{stream, Chan, GenericChan, GenericPort, Port}; -use prelude::*; -use result; -use task::rt::{task_id, sched_id}; -use util; -use util::replace; -use unstable::finally::Finally; -use rt::{context, OldTaskContext}; - -#[cfg(test)] use comm::SharedChan; - -mod local_data_priv; -pub mod rt; -pub mod spawn; - -/// A handle to a scheduler -#[deriving(Eq)] -pub enum Scheduler { - SchedulerHandle(sched_id) -} - -/// A handle to a task -#[deriving(Eq)] -pub enum Task { - TaskHandle(task_id) -} - -/** - * Indicates the manner in which a task exited. - * - * A task that completes without failing is considered to exit successfully. - * Supervised ancestors and linked siblings may yet fail after this task - * succeeds. Also note that in such a case, it may be nondeterministic whether - * linked failure or successful exit happen first. - * - * If you wish for this result's delivery to block until all linked and/or - * children tasks complete, recommend using a result future. - */ -#[deriving(Eq)] -pub enum TaskResult { - Success, - Failure, -} - -/// Scheduler modes -#[deriving(Eq)] -pub enum SchedMode { - /// Run task on the default scheduler - DefaultScheduler, - /// Run task on the current scheduler - CurrentScheduler, - /// Run task on a specific scheduler - ExistingScheduler(Scheduler), - /** - * Tasks are scheduled on the main OS thread - * - * The main OS thread is the thread used to launch the runtime which, - * in most cases, is the process's initial thread as created by the OS. - */ - PlatformThread, - /// All tasks run in the same OS thread - SingleThreaded, - /// Tasks are distributed among available CPUs - ThreadPerCore, - /// Each task runs in its own OS thread - ThreadPerTask, - /// Tasks are distributed among a fixed number of OS threads - ManualThreads(uint), -} - -/** - * Scheduler configuration options - * - * # Fields - * - * * sched_mode - The operating mode of the scheduler - * - * * foreign_stack_size - The size of the foreign stack, in bytes - * - * Rust code runs on Rust-specific stacks. When Rust code calls foreign - * code (via functions in foreign modules) it switches to a typical, large - * stack appropriate for running code written in languages like C. By - * default these foreign stacks have unspecified size, but with this - * option their size can be precisely specified. - */ -pub struct SchedOpts { - mode: SchedMode, - foreign_stack_size: Option<uint>, -} - -/** - * Task configuration options - * - * # Fields - * - * * linked - Propagate failure bidirectionally between child and parent. - * True by default. If both this and 'supervised' are false, then - * either task's failure will not affect the other ("unlinked"). - * - * * supervised - Propagate failure unidirectionally from parent to child, - * but not from child to parent. False by default. - * - * * notify_chan - Enable lifecycle notifications on the given channel - * - * * sched - Specify the configuration of a new scheduler to create the task - * in - * - * By default, every task is created in the same scheduler as its - * parent, where it is scheduled cooperatively with all other tasks - * in that scheduler. Some specialized applications may want more - * control over their scheduling, in which case they can be spawned - * into a new scheduler with the specific properties required. - * - * This is of particular importance for libraries which want to call - * into foreign code that blocks. Without doing so in a different - * scheduler other tasks will be impeded or even blocked indefinitely. - */ -pub struct TaskOpts { - linked: bool, - supervised: bool, - notify_chan: Option<Chan<TaskResult>>, - sched: SchedOpts -} - -/** - * The task builder type. - * - * Provides detailed control over the properties and behavior of new tasks. - */ -// NB: Builders are designed to be single-use because they do stateful -// things that get weird when reusing - e.g. if you create a result future -// it only applies to a single task, so then you have to maintain Some -// potentially tricky state to ensure that everything behaves correctly -// when you try to reuse the builder to spawn a new task. We'll just -// sidestep that whole issue by making builders uncopyable and making -// the run function move them in. - -// FIXME (#3724): Replace the 'consumed' bit with move mode on self -pub struct TaskBuilder { - opts: TaskOpts, - gen_body: Option<~fn(v: ~fn()) -> ~fn()>, - can_not_copy: Option<util::NonCopyable>, - consumed: bool, -} - -/** - * Generate the base configuration for spawning a task, off of which more - * configuration methods can be chained. - * For example, task().unlinked().spawn is equivalent to spawn_unlinked. - */ -pub fn task() -> TaskBuilder { - TaskBuilder { - opts: default_task_opts(), - gen_body: None, - can_not_copy: None, - consumed: false, - } -} - -#[doc(hidden)] // FIXME #3538 -priv impl TaskBuilder { - fn consume(&mut self) -> TaskBuilder { - if self.consumed { - fail!("Cannot copy a task_builder"); // Fake move mode on self - } - self.consumed = true; - let gen_body = replace(&mut self.gen_body, None); - let notify_chan = replace(&mut self.opts.notify_chan, None); - TaskBuilder { - opts: TaskOpts { - linked: self.opts.linked, - supervised: self.opts.supervised, - notify_chan: notify_chan, - sched: self.opts.sched - }, - gen_body: gen_body, - can_not_copy: None, - consumed: false - } - } -} - -pub 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) { - 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) { - 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) { - self.opts.linked = true; - self.opts.supervised = false; - } - - /** - * Get a future representing the exit status of the task. - * - * Taking the value of the future will block until the child task - * terminates. The future-receiving callback specified will be called - * *before* the task is spawned; as such, do not invoke .get() within the - * closure; rather, store it in an outer variable/list for later use. - * - * Note that the future returning by this function is only useful for - * obtaining the value of the next task to be spawning with the - * builder. If additional tasks are spawned with the same builder - * then a new result future must be obtained prior to spawning each - * task. - * - * # Failure - * Fails if a future_result was already set for this task. - */ - 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 - // sending out messages. - - if self.opts.notify_chan.is_some() { - fail!("Can't set multiple future_results for one task!"); - } - - // Construct the future and give it to the caller. - let (notify_pipe_po, notify_pipe_ch) = stream::<TaskResult>(); - - blk(notify_pipe_po); - - // Reconfigure self to use a notify channel. - self.opts.notify_chan = Some(notify_pipe_ch); - } - - /// Configure a custom scheduler mode for the task. - fn sched_mode(&mut self, mode: SchedMode) { - self.opts.sched.mode = mode; - } - - /** - * Add a wrapper to the body of the spawned task. - * - * Before the task is spawned it is passed through a 'body generator' - * function that may perform local setup operations as well as wrap - * the task body in remote setup operations. With this the behavior - * of tasks can be extended in simple ways. - * - * This function augments the current body generator with a new body - * 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()) { - let prev_gen_body = replace(&mut self.gen_body, None); - let prev_gen_body = match prev_gen_body { - Some(gen) => gen, - None => { - let f: ~fn(~fn()) -> ~fn() = |body| body; - f - } - }; - let prev_gen_body = Cell(prev_gen_body); - let next_gen_body = { - let f: ~fn(~fn()) -> ~fn() = |body| { - let prev_gen_body = prev_gen_body.take(); - wrapper(prev_gen_body(body)) - }; - f - }; - self.gen_body = Some(next_gen_body); - } - - /** - * Creates and executes a new child task - * - * Sets up a new task with its own call stack and schedules it to run - * the provided unique closure. The task has the properties and behavior - * specified by the task_builder. - * - * # Failure - * - * When spawning into a new scheduler, the number of threads requested - * must be greater than zero. - */ - 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(); - let opts = TaskOpts { - linked: x.opts.linked, - supervised: x.opts.supervised, - notify_chan: notify_chan, - sched: x.opts.sched - }; - let f = match gen_body { - Some(gen) => { - gen(f) - } - None => { - f - } - }; - spawn::spawn_raw(opts, f); - } - - /// 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); - do self.spawn { - f(arg.take()); - } - } - - /** - * Execute a function in another task and return either the return value - * of the function or result::err. - * - * # Return value - * - * If the function executed successfully then try returns result::ok - * containing the value returned by the function. If the function fails - * then try returns result::err containing nil. - * - * # Failure - * Fails if a future_result was already set for this task. - */ - fn try<T:Owned>(&mut self, f: ~fn() -> T) -> Result<T,()> { - let (po, ch) = stream::<T>(); - let mut result = None; - - self.future_result(|r| { result = Some(r); }); - - do self.spawn { - ch.send(f()); - } - - match result.unwrap().recv() { - Success => result::Ok(po.recv()), - Failure => result::Err(()) - } - } -} - - -/* Task construction */ - -pub fn default_task_opts() -> TaskOpts { - /*! - * The default task options - * - * By default all tasks are supervised by their parent, are spawned - * into the same scheduler, and do not post lifecycle notifications. - */ - - TaskOpts { - linked: true, - supervised: false, - notify_chan: None, - sched: SchedOpts { - mode: DefaultScheduler, - foreign_stack_size: None - } - } -} - -/* Spawn convenience functions */ - -/// Creates and executes a new child task -/// -/// Sets up a new task with its own call stack and schedules it to run -/// the provided unique closure. -/// -/// This function is equivalent to `task().spawn(f)`. -pub fn spawn(f: ~fn()) { - let mut task = task(); - task.spawn(f) -} - -/// Creates a child task unlinked from the current one. If either this -/// task or the child task fails, the other will not be killed. -pub fn spawn_unlinked(f: ~fn()) { - let mut task = task(); - task.unlinked(); - task.spawn(f) -} - -pub fn spawn_supervised(f: ~fn()) { - /*! - * Creates a child task supervised by the current one. If the child - * task fails, the parent will not be killed, but if the parent fails, - * the child will be killed. - */ - - let mut task = task(); - task.supervised(); - task.spawn(f) -} - -pub fn spawn_with<A:Owned>(arg: A, f: ~fn(v: A)) { - /*! - * Runs a task, while transfering ownership of one argument to the - * child. - * - * This is useful for transfering ownership of noncopyables to - * another task. - * - * This function is equivalent to `task().spawn_with(arg, f)`. - */ - - let mut task = task(); - task.spawn_with(arg, f) -} - -pub fn spawn_sched(mode: SchedMode, f: ~fn()) { - /*! - * Creates a new task on a new or existing scheduler - - * When there are no more tasks to execute the - * scheduler terminates. - * - * # Failure - * - * In manual threads mode the number of threads requested must be - * greater than zero. - */ - - let mut task = task(); - task.sched_mode(mode); - task.spawn(f) -} - -pub fn try<T:Owned>(f: ~fn() -> T) -> Result<T,()> { - /*! - * Execute a function in another task and return either the return value - * of the function or result::err. - * - * This is equivalent to task().supervised().try. - */ - - let mut task = task(); - task.supervised(); - task.try(f) -} - - -/* Lifecycle functions */ - -pub fn yield() { - //! Yield control to the task scheduler - - unsafe { - let task_ = rt::rust_get_task(); - let killed = rt::rust_task_yield(task_); - if killed && !failing() { - fail!("killed"); - } - } -} - -pub fn failing() -> bool { - //! True if the running task has failed - - use rt::{context, OldTaskContext}; - use rt::local::Local; - use rt::task::Task; - - match context() { - OldTaskContext => { - unsafe { - rt::rust_task_is_unwinding(rt::rust_get_task()) - } - } - _ => { - 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 - } - } - } - return unwinding; - } - } -} - -pub fn get_task() -> Task { - //! Get a handle to the running task - - unsafe { - TaskHandle(rt::get_task_id()) - } -} - -pub fn get_scheduler() -> Scheduler { - SchedulerHandle(unsafe { rt::rust_get_sched_id() }) -} - -/** - * Temporarily make the task unkillable - * - * # Example - * - * ~~~ - * do task::unkillable { - * // detach / yield / destroy must all be called together - * rustrt::rust_port_detach(po); - * // This must not result in the current task being killed - * task::yield(); - * rustrt::rust_port_destroy(po); - * } - * ~~~ - */ -pub unsafe fn unkillable<U>(f: &fn() -> U) -> U { - if context() == OldTaskContext { - let t = rt::rust_get_task(); - do (|| { - rt::rust_task_inhibit_kill(t); - f() - }).finally { - rt::rust_task_allow_kill(t); - } - } else { - // FIXME #6377 - f() - } -} - -/// The inverse of unkillable. Only ever to be used nested in unkillable(). -pub unsafe fn rekillable<U>(f: &fn() -> U) -> U { - if context() == OldTaskContext { - let t = rt::rust_get_task(); - do (|| { - rt::rust_task_allow_kill(t); - f() - }).finally { - rt::rust_task_inhibit_kill(t); - } - } else { - // FIXME #6377 - f() - } -} - -/** - * A stronger version of unkillable that also inhibits scheduling operations. - * For use with exclusive ARCs, which use pthread mutexes directly. - */ -pub unsafe fn atomically<U>(f: &fn() -> U) -> U { - if context() == OldTaskContext { - let t = rt::rust_get_task(); - do (|| { - rt::rust_task_inhibit_kill(t); - rt::rust_task_inhibit_yield(t); - f() - }).finally { - rt::rust_task_allow_yield(t); - rt::rust_task_allow_kill(t); - } - } else { - // FIXME #6377 - f() - } -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_cant_dup_task_builder() { - let mut builder = task(); - builder.unlinked(); - do builder.spawn {} - // FIXME(#3724): For now, this is a -runtime- failure, because we haven't - // got move mode on self. When 3724 is fixed, this test should fail to - // compile instead, and should go in tests/compile-fail. - do builder.spawn {} // b should have been consumed by the previous call -} - -// The following 8 tests test the following 2^3 combinations: -// {un,}linked {un,}supervised failure propagation {up,down}wards. - -// !!! These tests are dangerous. If Something is buggy, they will hang, !!! -// !!! instead of exiting cleanly. This might wedge the buildbots. !!! - -#[test] #[ignore(cfg(windows))] -fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port - let (po, ch) = stream(); - let ch = SharedChan::new(ch); - do spawn_unlinked { - let ch = ch.clone(); - do spawn_unlinked { - // Give middle task a chance to fail-but-not-kill-us. - for 16.times { task::yield(); } - ch.send(()); // If killed first, grandparent hangs. - } - fail!(); // Shouldn't kill either (grand)parent or (grand)child. - } - po.recv(); -} -#[test] #[ignore(cfg(windows))] -fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails - do spawn_unlinked { fail!(); } -} -#[test] #[ignore(cfg(windows))] -fn test_spawn_unlinked_sup_no_fail_up() { // child unlinked fails - do spawn_supervised { fail!(); } - // Give child a chance to fail-but-not-kill-us. - for 16.times { task::yield(); } -} -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_unlinked_sup_fail_down() { - do spawn_supervised { loop { task::yield(); } } - fail!(); // Shouldn't leave a child hanging around. -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_linked_sup_fail_up() { // child fails; parent fails - let (po, _ch) = stream::<()>(); - - // Unidirectional "parenting" shouldn't override bidirectional linked. - // We have to cheat with opts - the interface doesn't support them because - // they don't make sense (redundant with task().supervised()). - let mut b0 = task(); - b0.opts.linked = true; - b0.opts.supervised = true; - - do b0.spawn { - fail!(); - } - po.recv(); // We should get punted awake -} -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_linked_sup_fail_down() { // parent fails; child fails - // We have to cheat with opts - the interface doesn't support them because - // they don't make sense (redundant with task().supervised()). - let mut b0 = task(); - b0.opts.linked = true; - b0.opts.supervised = true; - do b0.spawn { - loop { - task::yield(); - } - } - fail!(); // *both* mechanisms would be wrong if this didn't kill the child -} -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails - let (po, _ch) = stream::<()>(); - // Default options are to spawn linked & unsupervised. - do spawn { fail!(); } - po.recv(); // We should get punted awake -} -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails - // Default options are to spawn linked & unsupervised. - do spawn { loop { task::yield(); } } - fail!(); -} -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails - // Make sure the above test is the same as this one. - let mut builder = task(); - builder.linked(); - do builder.spawn { - loop { - task::yield(); - } - } - fail!(); -} - -// A couple bonus linked failure tests - testing for failure propagation even -// when the middle task exits successfully early before kill signals are sent. - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_failure_propagate_grandchild() { - // Middle task exits; does grandparent's failure propagate across the gap? - do spawn_supervised { - do spawn_supervised { - loop { task::yield(); } - } - } - for 16.times { task::yield(); } - fail!(); -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_failure_propagate_secondborn() { - // First-born child exits; does parent's failure propagate to sibling? - do spawn_supervised { - do spawn { // linked - loop { task::yield(); } - } - } - for 16.times { task::yield(); } - fail!(); -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_failure_propagate_nephew_or_niece() { - // Our sibling exits; does our failure propagate to sibling's child? - do spawn { // linked - do spawn_supervised { - loop { task::yield(); } - } - } - for 16.times { task::yield(); } - fail!(); -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_spawn_linked_sup_propagate_sibling() { - // Middle sibling exits - does eldest's failure propagate to youngest? - do spawn { // linked - do spawn { // linked - loop { task::yield(); } - } - } - for 16.times { task::yield(); } - fail!(); -} - -#[test] -fn test_run_basic() { - let (po, ch) = stream::<()>(); - let mut builder = task(); - do builder.spawn { - ch.send(()); - } - po.recv(); -} - -#[cfg(test)] -struct Wrapper { - f: Option<Chan<()>> -} - -#[test] -fn test_add_wrapper() { - let (po, ch) = stream::<()>(); - let mut b0 = task(); - let ch = Cell(ch); - do b0.add_wrapper |body| { - let ch = Cell(ch.take()); - let result: ~fn() = || { - let ch = ch.take(); - body(); - ch.send(()); - }; - result - }; - do b0.spawn { } - po.recv(); -} - -#[test] -#[ignore(cfg(windows))] -fn test_future_result() { - let mut result = None; - let mut builder = task(); - builder.future_result(|r| result = Some(r)); - do builder.spawn {} - assert_eq!(result.unwrap().recv(), Success); - - result = None; - let mut builder = task(); - builder.future_result(|r| result = Some(r)); - builder.unlinked(); - do builder.spawn { - fail!(); - } - assert_eq!(result.unwrap().recv(), Failure); -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_back_to_the_future_result() { - let mut builder = task(); - builder.future_result(util::ignore); - builder.future_result(util::ignore); -} - -#[test] -fn test_try_success() { - match do try { - ~"Success!" - } { - result::Ok(~"Success!") => (), - _ => fail!() - } -} - -#[test] -#[ignore(cfg(windows))] -fn test_try_fail() { - match do try { - fail!() - } { - result::Err(()) => (), - result::Ok(()) => fail!() - } -} - -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_spawn_sched_no_threads() { - do spawn_sched(ManualThreads(0u)) { } -} - -#[test] -fn test_spawn_sched() { - let (po, ch) = stream::<()>(); - let ch = SharedChan::new(ch); - - fn f(i: int, ch: SharedChan<()>) { - let parent_sched_id = unsafe { rt::rust_get_sched_id() }; - - do spawn_sched(SingleThreaded) { - let child_sched_id = unsafe { rt::rust_get_sched_id() }; - assert!(parent_sched_id != child_sched_id); - - if (i == 0) { - ch.send(()); - } else { - f(i - 1, ch.clone()); - } - }; - - } - f(10, ch); - po.recv(); -} - -#[test] -fn test_spawn_sched_childs_on_default_sched() { - let (po, ch) = stream(); - - // Assuming tests run on the default scheduler - let default_id = unsafe { rt::rust_get_sched_id() }; - - let ch = Cell(ch); - do spawn_sched(SingleThreaded) { - let parent_sched_id = unsafe { rt::rust_get_sched_id() }; - let ch = Cell(ch.take()); - do spawn { - let ch = ch.take(); - let child_sched_id = unsafe { rt::rust_get_sched_id() }; - assert!(parent_sched_id != child_sched_id); - assert_eq!(child_sched_id, default_id); - ch.send(()); - }; - }; - - po.recv(); -} - -#[cfg(test)] -mod testrt { - use libc; - - #[nolink] - pub extern { - unsafe fn rust_dbg_lock_create() -> *libc::c_void; - unsafe fn rust_dbg_lock_destroy(lock: *libc::c_void); - unsafe fn rust_dbg_lock_lock(lock: *libc::c_void); - unsafe fn rust_dbg_lock_unlock(lock: *libc::c_void); - unsafe fn rust_dbg_lock_wait(lock: *libc::c_void); - unsafe fn rust_dbg_lock_signal(lock: *libc::c_void); - } -} - -#[test] -fn test_spawn_sched_blocking() { - unsafe { - - // Testing that a task in one scheduler can block in foreign code - // without affecting other schedulers - for 20u.times { - let (start_po, start_ch) = stream(); - let (fin_po, fin_ch) = stream(); - - let lock = testrt::rust_dbg_lock_create(); - - do spawn_sched(SingleThreaded) { - unsafe { - testrt::rust_dbg_lock_lock(lock); - - start_ch.send(()); - - // Block the scheduler thread - testrt::rust_dbg_lock_wait(lock); - testrt::rust_dbg_lock_unlock(lock); - - fin_ch.send(()); - } - }; - - // Wait until the other task has its lock - start_po.recv(); - - fn pingpong(po: &Port<int>, ch: &Chan<int>) { - let mut val = 20; - while val > 0 { - val = po.recv(); - ch.send(val - 1); - } - } - - let (setup_po, setup_ch) = stream(); - let (parent_po, parent_ch) = stream(); - do spawn { - let (child_po, child_ch) = stream(); - setup_ch.send(child_ch); - pingpong(&child_po, &parent_ch); - }; - - let child_ch = setup_po.recv(); - child_ch.send(20); - pingpong(&parent_po, &child_ch); - testrt::rust_dbg_lock_lock(lock); - testrt::rust_dbg_lock_signal(lock); - testrt::rust_dbg_lock_unlock(lock); - fin_po.recv(); - testrt::rust_dbg_lock_destroy(lock); - } - } -} - -#[cfg(test)] -fn avoid_copying_the_body(spawnfn: &fn(v: ~fn())) { - let (p, ch) = stream::<uint>(); - - let x = ~1; - let x_in_parent = ptr::to_unsafe_ptr(&*x) as uint; - - do spawnfn || { - let x_in_child = ptr::to_unsafe_ptr(&*x) as uint; - ch.send(x_in_child); - } - - let x_in_child = p.recv(); - assert_eq!(x_in_parent, x_in_child); -} - -#[test] -fn test_avoid_copying_the_body_spawn() { - avoid_copying_the_body(spawn); -} - -#[test] -fn test_avoid_copying_the_body_task_spawn() { - do avoid_copying_the_body |f| { - let mut builder = task(); - do builder.spawn || { - f(); - } - } -} - -#[test] -fn test_avoid_copying_the_body_try() { - do avoid_copying_the_body |f| { - do try || { - f() - }; - } -} - -#[test] -fn test_avoid_copying_the_body_unlinked() { - do avoid_copying_the_body |f| { - do spawn_unlinked || { - f(); - } - } -} - -#[test] -fn test_platform_thread() { - let (po, ch) = stream(); - let mut builder = task(); - builder.sched_mode(PlatformThread); - do builder.spawn { - ch.send(()); - } - po.recv(); -} - -#[test] -#[ignore(cfg(windows))] -#[should_fail] -fn test_unkillable() { - let (po, ch) = stream(); - - // We want to do this after failing - do spawn_unlinked { - for 10.times { yield() } - ch.send(()); - } - - do spawn { - yield(); - // We want to fail after the unkillable task - // blocks on recv - fail!(); - } - - unsafe { - do unkillable { - let p = ~0; - let pp: *uint = cast::transmute(p); - - // If we are killed here then the box will leak - po.recv(); - - let _p: ~int = cast::transmute(pp); - } - } - - // Now we can be killed - po.recv(); -} - -#[test] -#[ignore(cfg(windows))] -#[should_fail] -fn test_unkillable_nested() { - let (po, ch) = comm::stream(); - - // We want to do this after failing - do spawn_unlinked || { - for 10.times { yield() } - ch.send(()); - } - - do spawn { - yield(); - // We want to fail after the unkillable task - // blocks on recv - fail!(); - } - - unsafe { - do unkillable { - do unkillable {} // Here's the difference from the previous test. - let p = ~0; - let pp: *uint = cast::transmute(p); - - // If we are killed here then the box will leak - po.recv(); - - let _p: ~int = cast::transmute(pp); - } - } - - // Now we can be killed - po.recv(); -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_atomically() { - unsafe { do atomically { yield(); } } -} - -#[test] -fn test_atomically2() { - unsafe { do atomically { } } yield(); // shouldn't fail -} - -#[test] #[should_fail] #[ignore(cfg(windows))] -fn test_atomically_nested() { - unsafe { do atomically { do atomically { } yield(); } } -} - -#[test] -fn test_child_doesnt_ref_parent() { - // If the child refcounts the parent task, this will stack overflow when - // climbing the task tree to dereference each ancestor. (See #1789) - // (well, it would if the constant were 8000+ - I lowered it to be more - // valgrind-friendly. try this at home, instead..!) - static generations: uint = 16; - fn child_no(x: uint) -> ~fn() { - return || { - if x < generations { - task::spawn(child_no(x+1)); - } - } - } - task::spawn(child_no(0)); -} - -#[test] -fn test_sched_thread_per_core() { - let (port, chan) = comm::stream(); - - do spawn_sched(ThreadPerCore) || { - unsafe { - let cores = rt::rust_num_threads(); - let reported_threads = rt::rust_sched_threads(); - assert_eq!(cores as uint, reported_threads as uint); - chan.send(()); - } - } - - port.recv(); -} - -#[test] -fn test_spawn_thread_on_demand() { - let (port, chan) = comm::stream(); - - do spawn_sched(ManualThreads(2)) || { - unsafe { - let max_threads = rt::rust_sched_threads(); - assert_eq!(max_threads as int, 2); - let running_threads = rt::rust_sched_current_nonlazy_threads(); - assert_eq!(running_threads as int, 1); - - let (port2, chan2) = comm::stream(); - - do spawn_sched(CurrentScheduler) || { - chan2.send(()); - } - - let running_threads2 = rt::rust_sched_current_nonlazy_threads(); - assert_eq!(running_threads2 as int, 2); - - port2.recv(); - chan.send(()); - } - } - - port.recv(); -} - -#[test] -fn test_simple_newsched_spawn() { - use rt::test::run_in_newsched_task; - - do run_in_newsched_task { - spawn(||()) - } -} diff --git a/src/libcore/task/rt.rs b/src/libcore/task/rt.rs deleted file mode 100644 index 760812252bc..00000000000 --- a/src/libcore/task/rt.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The task interface to the runtime - -*/ - -#[doc(hidden)]; // FIXME #3538 - -use libc; - -#[allow(non_camel_case_types)] // runtime type -pub type sched_id = int; -#[allow(non_camel_case_types)] // runtime type -pub type task_id = int; - -// These are both opaque runtime/compiler types that we don't know the -// structure of and should only deal with via unsafe pointer -#[allow(non_camel_case_types)] // runtime type -pub type rust_task = libc::c_void; -#[allow(non_camel_case_types)] // runtime type -pub type rust_closure = libc::c_void; - -pub extern { - #[rust_stack] - fn rust_task_yield(task: *rust_task) -> bool; - - fn rust_get_sched_id() -> sched_id; - fn rust_new_sched(num_threads: libc::uintptr_t) -> sched_id; - fn rust_sched_threads() -> libc::size_t; - fn rust_sched_current_nonlazy_threads() -> libc::size_t; - fn rust_num_threads() -> libc::uintptr_t; - - fn get_task_id() -> task_id; - #[rust_stack] - fn rust_get_task() -> *rust_task; - - fn new_task() -> *rust_task; - fn rust_new_task_in_sched(id: sched_id) -> *rust_task; - - fn start_task(task: *rust_task, closure: *rust_closure); - - fn rust_task_is_unwinding(task: *rust_task) -> bool; - fn rust_osmain_sched_id() -> sched_id; - #[rust_stack] - fn rust_task_inhibit_kill(t: *rust_task); - #[rust_stack] - fn rust_task_allow_kill(t: *rust_task); - #[rust_stack] - fn rust_task_inhibit_yield(t: *rust_task); - #[rust_stack] - fn rust_task_allow_yield(t: *rust_task); - fn rust_task_kill_other(task: *rust_task); - fn rust_task_kill_all(task: *rust_task); - - #[rust_stack] - fn rust_get_task_local_data(task: *rust_task) -> *libc::c_void; - #[rust_stack] - fn rust_set_task_local_data(task: *rust_task, map: *libc::c_void); - #[rust_stack] - fn rust_task_local_data_atexit(task: *rust_task, cleanup_fn: *u8); -} diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs deleted file mode 100644 index 81e5af5caab..00000000000 --- a/src/libcore/task/spawn.rs +++ /dev/null @@ -1,791 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*!************************************************************************** - * Spawning & linked failure - * - * Several data structures are involved in task management to allow properly - * propagating failure across linked/supervised tasks. - * - * (1) The "taskgroup_arc" is an unsafe::exclusive which contains a hashset of - * all tasks that are part of the group. Some tasks are 'members', which - * means if they fail, they will kill everybody else in the taskgroup. - * Other tasks are 'descendants', which means they will not kill tasks - * from this group, but can be killed by failing members. - * - * A new one of these is created each spawn_linked or spawn_supervised. - * - * (2) The "tcb" is a per-task control structure that tracks a task's spawn - * configuration. It contains a reference to its taskgroup_arc, a - * reference to its node in the ancestor list (below), a flag for - * whether it's part of the 'main'/'root' taskgroup, and an optionally - * configured notification port. These are stored in TLS. - * - * (3) The "ancestor_list" is a cons-style list of unsafe::exclusives which - * tracks 'generations' of taskgroups -- a group's ancestors are groups - * which (directly or transitively) spawn_supervised-ed them. Each task - * is recorded in the 'descendants' of each of its ancestor groups. - * - * Spawning a supervised task is O(n) in the number of generations still - * alive, and exiting (by success or failure) that task is also O(n). - * - * This diagram depicts the references between these data structures: - * - * linked_________________________________ - * ___/ _________ \___ - * / \ | group X | / \ - * ( A ) - - - - - - - > | {A,B} {}|< - - -( B ) - * \___/ |_________| \___/ - * unlinked - * | __ (nil) - * | //| The following code causes this: - * |__ // /\ _________ - * / \ // || | group Y | fn taskA() { - * ( C )- - - ||- - - > |{C} {D,E}| spawn(taskB); - * \___/ / \=====> |_________| spawn_unlinked(taskC); - * supervise /gen \ ... - * | __ \ 00 / } - * | //| \__/ fn taskB() { ... } - * |__ // /\ _________ fn taskC() { - * / \/ || | group Z | spawn_supervised(taskD); - * ( D )- - - ||- - - > | {D} {E} | ... - * \___/ / \=====> |_________| } - * supervise /gen \ fn taskD() { - * | __ \ 01 / spawn_supervised(taskE); - * | //| \__/ ... - * |__ // _________ } - * / \/ | group W | fn taskE() { ... } - * ( E )- - - - - - - > | {E} {} | - * \___/ |_________| - * - * "tcb" "taskgroup_arc" - * "ancestor_list" - * - ****************************************************************************/ - -#[doc(hidden)]; // FIXME #3538 - -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}; -use task::rt::rust_task; -use task::rt; -use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded}; -use task::{Success, TaskOpts, TaskResult, ThreadPerCore, ThreadPerTask}; -use task::{ExistingScheduler, SchedulerHandle}; -use task::unkillable; -use uint; -use util; -use unstable::sync::{Exclusive, exclusive}; -use rt::local::Local; - -#[cfg(test)] use task::default_task_opts; - -macro_rules! move_it ( - { $x:expr } => ( unsafe { let y = *ptr::to_unsafe_ptr(&($x)); y } ) -) - -type TaskSet = HashSet<*rust_task>; - -fn new_taskset() -> TaskSet { - HashSet::new() -} -fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) { - let didnt_overwrite = tasks.insert(task); - assert!(didnt_overwrite); -} -fn taskset_remove(tasks: &mut TaskSet, task: *rust_task) { - let was_present = tasks.remove(&task); - assert!(was_present); -} -pub fn taskset_each(tasks: &TaskSet, blk: &fn(v: *rust_task) -> bool) -> bool { - tasks.each(|k| blk(*k)) -} - -// One of these per group of linked-failure tasks. -struct TaskGroupData { - // All tasks which might kill this group. When this is empty, the group - // can be "GC"ed (i.e., its link in the ancestor list can be removed). - members: TaskSet, - // All tasks unidirectionally supervised by (directly or transitively) - // tasks in this group. - descendants: TaskSet, -} -type TaskGroupArc = Exclusive<Option<TaskGroupData>>; - -type TaskGroupInner<'self> = &'self mut Option<TaskGroupData>; - -// A taskgroup is 'dead' when nothing can cause it to fail; only members can. -fn taskgroup_is_dead(tg: &TaskGroupData) -> bool { - (&const tg.members).is_empty() -} - -// A list-like structure by which taskgroups keep track of all ancestor groups -// which may kill them. Needed for tasks to be able to remove themselves from -// ancestor groups upon exit. The list has a node for each "generation", and -// ends either at the root taskgroup (which has no ancestors) or at a -// taskgroup which was spawned-unlinked. Tasks from intermediate generations -// have references to the middle of the list; when intermediate generations -// die, their node in the list will be collected at a descendant's spawn-time. -struct AncestorNode { - // Since the ancestor list is recursive, we end up with references to - // exclusives within other exclusives. This is dangerous business (if - // circular references arise, deadlock and memory leaks are imminent). - // Hence we assert that this counter monotonically decreases as we - // approach the tail of the list. - // FIXME(#3068): Make the generation counter togglable with #[cfg(debug)]. - generation: uint, - // Should really be a non-option. This way appeases borrowck. - parent_group: Option<TaskGroupArc>, - // Recursive rest of the list. - ancestors: AncestorList, -} - -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) -} - -#[inline(always)] -fn access_ancestors<U>(x: &Exclusive<AncestorNode>, - blk: &fn(x: &mut AncestorNode) -> U) -> U { - x.with(blk) -} - -// Iterates over an ancestor list. -// (1) Runs forward_blk on each ancestral taskgroup in the list -// (2) If forward_blk "break"s, runs optional bail_blk on all ancestral -// taskgroups that forward_blk already ran on successfully (Note: bail_blk -// is NOT called on the block that forward_blk broke on!). -// (3) As a bonus, coalesces away all 'dead' taskgroup nodes in the list. -// FIXME(#2190): Change Option<@fn(...)> to Option<&fn(...)>, to save on -// allocations. Once that bug is fixed, changing the sigil should suffice. -fn each_ancestor(list: &mut AncestorList, - bail_opt: Option<@fn(TaskGroupInner)>, - forward_blk: &fn(TaskGroupInner) -> bool) - -> bool { - // "Kickoff" call - there was no last generation. - return !coalesce(list, bail_opt, forward_blk, uint::max_value); - - // Recursively iterates, and coalesces afterwards if needed. Returns - // whether or not unwinding is needed (i.e., !successful iteration). - fn coalesce(list: &mut AncestorList, - bail_opt: Option<@fn(TaskGroupInner)>, - forward_blk: &fn(TaskGroupInner) -> bool, - last_generation: uint) -> bool { - // Need to swap the list out to use it, to appease borrowck. - let tmp_list = util::replace(&mut *list, AncestorList(None)); - let (coalesce_this, early_break) = - iterate(&tmp_list, bail_opt, forward_blk, last_generation); - // What should our next ancestor end up being? - if coalesce_this.is_some() { - // Needed coalesce. Our next ancestor becomes our old - // ancestor's next ancestor. ("next = old_next->next;") - *list = coalesce_this.unwrap(); - } else { - // No coalesce; restore from tmp. ("next = old_next;") - *list = tmp_list; - } - return early_break; - } - - // Returns an optional list-to-coalesce and whether unwinding is needed. - // Option<ancestor_list>: - // Whether or not the ancestor taskgroup being iterated over is - // dead or not; i.e., it has no more tasks left in it, whether or not - // it has descendants. If dead, the caller shall coalesce it away. - // bool: - // True if the supplied block did 'break', here or in any recursive - // calls. If so, must call the unwinder on all previous nodes. - fn iterate(ancestors: &AncestorList, - bail_opt: Option<@fn(TaskGroupInner)>, - forward_blk: &fn(TaskGroupInner) -> bool, - last_generation: uint) - -> (Option<AncestorList>, bool) { - // At each step of iteration, three booleans are at play which govern - // how the iteration should behave. - // 'nobe_is_dead' - Should the list should be coalesced at this point? - // Largely unrelated to the other two. - // 'need_unwind' - Should we run the bail_blk at this point? (i.e., - // do_continue was false not here, but down the line) - // 'do_continue' - Did the forward_blk succeed at this point? (i.e., - // should we recurse? or should our callers unwind?) - - // The map defaults to None, because if ancestors is None, we're at - // the end of the list, which doesn't make sense to coalesce. - return do (**ancestors).map_default((None,false)) |ancestor_arc| { - // NB: Takes a lock! (this ancestor node) - do access_ancestors(ancestor_arc) |nobe| { - // Check monotonicity - assert!(last_generation > nobe.generation); - /*##########################################################* - * Step 1: Look at this ancestor group (call iterator block). - *##########################################################*/ - let mut nobe_is_dead = false; - let do_continue = - // NB: Takes a lock! (this ancestor node's parent group) - do with_parent_tg(&mut nobe.parent_group) |tg_opt| { - // Decide whether this group is dead. Note that the - // group being *dead* is disjoint from it *failing*. - nobe_is_dead = match *tg_opt { - Some(ref tg) => taskgroup_is_dead(tg), - None => nobe_is_dead - }; - // Call iterator block. (If the group is dead, it's - // safe to skip it. This will leave our *rust_task - // hanging around in the group even after it's freed, - // but that's ok because, by virtue of the group being - // dead, nobody will ever kill-all (foreach) over it.) - if nobe_is_dead { true } else { forward_blk(tg_opt) } - }; - /*##########################################################* - * Step 2: Recurse on the rest of the list; maybe coalescing. - *##########################################################*/ - // 'need_unwind' is only set if blk returned true above, *and* - // the recursive call early-broke. - let mut need_unwind = false; - if do_continue { - // NB: Takes many locks! (ancestor nodes & parent groups) - need_unwind = coalesce(&mut nobe.ancestors, bail_opt, - forward_blk, nobe.generation); - } - /*##########################################################* - * Step 3: Maybe unwind; compute return info for our caller. - *##########################################################*/ - if need_unwind && !nobe_is_dead { - for bail_opt.each |bail_blk| { - do with_parent_tg(&mut nobe.parent_group) |tg_opt| { - (*bail_blk)(tg_opt) - } - } - } - // Decide whether our caller should unwind. - need_unwind = need_unwind || !do_continue; - // Tell caller whether or not to coalesce and/or unwind - if nobe_is_dead { - // Swap the list out here; the caller replaces us with it. - let rest = util::replace(&mut nobe.ancestors, - AncestorList(None)); - (Some(rest), need_unwind) - } else { - (None, need_unwind) - } - } - }; - - // Wrapper around exclusive::with that appeases borrowck. - fn with_parent_tg<U>(parent_group: &mut Option<TaskGroupArc>, - blk: &fn(TaskGroupInner) -> U) -> U { - // If this trips, more likely the problem is 'blk' failed inside. - let tmp_arc = parent_group.swap_unwrap(); - let result = do access_group(&tmp_arc) |tg_opt| { blk(tg_opt) }; - *parent_group = Some(tmp_arc); - result - } - } -} - -// One of these per task. -struct TCB { - me: *rust_task, - // List of tasks with whose fates this one's is intertwined. - tasks: TaskGroupArc, // 'none' means the group has failed. - // Lists of tasks who will kill us if they fail, but whom we won't kill. - ancestors: AncestorList, - is_main: bool, - notifier: Option<AutoNotify>, -} - -impl Drop for TCB { - // Runs on task exit. - fn finalize(&self) { - unsafe { - 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| { - x.failed = true; - } - // Take everybody down with us. - do access_group(&self.tasks) |tg| { - kill_taskgroup(tg, self.me, self.is_main); - } - } else { - // Remove ourselves from the group(s). - do access_group(&self.tasks) |tg| { - leave_taskgroup(tg, self.me, true); - } - } - // It doesn't matter whether this happens before or after dealing - // with our own taskgroup, so long as both happen before we die. - // We remove ourself from every ancestor we can, so no cleanup; no - // break. - for each_ancestor(&mut this.ancestors, None) |ancestor_group| { - leave_taskgroup(ancestor_group, self.me, false); - }; - } - } -} - -fn TCB(me: *rust_task, - tasks: TaskGroupArc, - ancestors: AncestorList, - is_main: bool, - mut notifier: Option<AutoNotify>) -> TCB { - for notifier.each_mut |x| { - x.failed = false; - } - - TCB { - me: me, - tasks: tasks, - ancestors: ancestors, - is_main: is_main, - notifier: notifier - } -} - -struct AutoNotify { - notify_chan: Chan<TaskResult>, - failed: bool, -} - -impl Drop for AutoNotify { - fn finalize(&self) { - let result = if self.failed { Failure } else { Success }; - self.notify_chan.send(result); - } -} - -fn AutoNotify(chan: Chan<TaskResult>) -> AutoNotify { - AutoNotify { - notify_chan: chan, - failed: true // Un-set above when taskgroup successfully made. - } -} - -fn enlist_in_taskgroup(state: TaskGroupInner, me: *rust_task, - is_member: bool) -> bool { - let newstate = util::replace(&mut *state, None); - // If 'None', the group was failing. Can't enlist. - if newstate.is_some() { - let mut group = newstate.unwrap(); - taskset_insert(if is_member { - &mut group.members - } else { - &mut group.descendants - }, me); - *state = Some(group); - true - } else { - false - } -} - -// NB: Runs in destructor/post-exit context. Can't 'fail'. -fn leave_taskgroup(state: TaskGroupInner, me: *rust_task, - is_member: bool) { - let newstate = util::replace(&mut *state, None); - // If 'None', already failing and we've already gotten a kill signal. - if newstate.is_some() { - let mut group = newstate.unwrap(); - taskset_remove(if is_member { - &mut group.members - } else { - &mut group.descendants - }, me); - *state = Some(group); - } -} - -// NB: Runs in destructor/post-exit context. Can't 'fail'. -fn kill_taskgroup(state: TaskGroupInner, me: *rust_task, is_main: bool) { - unsafe { - // NB: We could do the killing iteration outside of the group arc, by - // having "let mut newstate" here, swapping inside, and iterating - // after. But that would let other exiting tasks fall-through and exit - // while we were trying to kill them, causing potential - // use-after-free. A task's presence in the arc guarantees it's alive - // only while we hold the lock, so if we're failing, all concurrently - // exiting tasks must wait for us. To do it differently, we'd have to - // use the runtime's task refcounting, but that could leave task - // structs around long after their task exited. - let newstate = util::replace(state, None); - // Might already be None, if Somebody is failing simultaneously. - // That's ok; only one task needs to do the dirty work. (Might also - // see 'None' if Somebody already failed and we got a kill signal.) - if newstate.is_some() { - let group = newstate.unwrap(); - for taskset_each(&group.members) |sibling| { - // Skip self - killing ourself won't do much good. - if sibling != me { - rt::rust_task_kill_other(sibling); - } - } - for taskset_each(&group.descendants) |child| { - assert!(child != me); - rt::rust_task_kill_other(child); - } - // Only one task should ever do this. - if is_main { - rt::rust_task_kill_all(me); - } - // Do NOT restore state to Some(..)! It stays None to indicate - // that the whole taskgroup is failing, to forbid new spawns. - } - // (note: multiple tasks may reach this point) - } -} - -// FIXME (#2912): Work around core-vs-coretest function duplication. Can't use -// a proper closure because the #[test]s won't understand. Have to fake it. -macro_rules! taskgroup_key ( - // Use a "code pointer" value that will never be a real code pointer. - () => (cast::transmute((-2 as uint, 0u))) -) - -fn gen_child_taskgroup(linked: bool, supervised: bool) - -> (TaskGroupArc, AncestorList, bool) { - unsafe { - let spawner = rt::rust_get_task(); - /*##################################################################* - * Step 1. Get spawner's taskgroup info. - *##################################################################*/ - let spawner_group: @@mut TCB = - match local_get(OldHandle(spawner), taskgroup_key!()) { - None => { - // Main task, doing first spawn ever. Lazily initialise - // here. - let mut members = new_taskset(); - taskset_insert(&mut members, spawner); - let tasks = exclusive(Some(TaskGroupData { - members: members, - descendants: new_taskset(), - })); - // Main task/group has no ancestors, no notifier, etc. - let group = @@mut TCB(spawner, - tasks, - AncestorList(None), - true, - None); - local_set(OldHandle(spawner), taskgroup_key!(), group); - group - } - Some(group) => group - }; - let spawner_group: &mut TCB = *spawner_group; - - /*##################################################################* - * Step 2. Process spawn options for child. - *##################################################################*/ - return if linked { - // Child is in the same group as spawner. - let g = spawner_group.tasks.clone(); - // Child's ancestors are spawner's ancestors. - let a = share_ancestors(&mut spawner_group.ancestors); - // Propagate main-ness. - (g, a, spawner_group.is_main) - } else { - // Child is in a separate group from spawner. - let g = exclusive(Some(TaskGroupData { - members: new_taskset(), - descendants: new_taskset(), - })); - let a = if supervised { - // Child's ancestors start with the spawner. - let old_ancestors = - share_ancestors(&mut spawner_group.ancestors); - // FIXME(#3068) - The generation counter is only used for a - // debug assertion, but initialising it requires locking a - // mutex. Hence it should be enabled only in debug builds. - let new_generation = - match *old_ancestors { - Some(ref arc) => { - access_ancestors(arc, |a| a.generation+1) - } - None => 0 // the actual value doesn't really matter. - }; - assert!(new_generation < uint::max_value); - // Build a new node in the ancestor list. - AncestorList(Some(exclusive(AncestorNode { - generation: new_generation, - parent_group: Some(spawner_group.tasks.clone()), - ancestors: old_ancestors, - }))) - } else { - // Child has no ancestors. - AncestorList(None) - }; - (g, a, false) - }; - } - - fn share_ancestors(ancestors: &mut AncestorList) -> AncestorList { - // Appease the borrow-checker. Really this wants to be written as: - // match ancestors - // Some(ancestor_arc) { ancestor_list(Some(ancestor_arc.clone())) } - // None { ancestor_list(None) } - let tmp = util::replace(&mut **ancestors, None); - if tmp.is_some() { - let ancestor_arc = tmp.unwrap(); - let result = ancestor_arc.clone(); - **ancestors = Some(ancestor_arc); - AncestorList(Some(result)) - } else { - AncestorList(None) - } - } -} - -pub fn spawn_raw(opts: TaskOpts, f: ~fn()) { - use rt::*; - - match context() { - OldTaskContext => { - spawn_raw_oldsched(opts, f) - } - TaskContext => { - spawn_raw_newsched(opts, f) - } - SchedulerContext => { - fail!("can't spawn from scheduler context") - } - GlobalContext => { - fail!("can't spawn from global context") - } - } -} - -fn spawn_raw_newsched(_opts: TaskOpts, f: ~fn()) { - use rt::sched::*; - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::new(&mut sched.stack_pool, f); - sched.schedule_new_task(task); -} - -fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { - - let (child_tg, ancestors, is_main) = - gen_child_taskgroup(opts.linked, opts.supervised); - - unsafe { - let child_data = Cell((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) - let (child_tg, ancestors, f) = child_data.take(); - // Create child task. - let new_task = match opts.sched.mode { - DefaultScheduler => rt::new_task(), - _ => new_task_in_sched(opts.sched) - }; - assert!(!new_task.is_null()); - // Getting killed after here would leak the task. - let notify_chan = if opts.notify_chan.is_none() { - None - } else { - Some(opts.notify_chan.swap_unwrap()) - }; - - let child_wrapper = make_child_wrapper(new_task, child_tg, - ancestors, is_main, notify_chan, f); - - let closure = cast::transmute(&child_wrapper); - - // Getting killed between these two calls would free the child's - // closure. (Reordering them wouldn't help - then getting killed - // between them would leak.) - rt::start_task(new_task, closure); - cast::forget(child_wrapper); - } - } - - // This function returns a closure-wrapper that we pass to the child task. - // (1) It sets up the notification channel. - // (2) It attempts to enlist in the child's group and all ancestor groups. - // (3a) If any of those fails, it leaves all groups, and does nothing. - // (3b) Otherwise it builds a task control structure and puts it in TLS, - // (4) ...and runs the provided body function. - fn make_child_wrapper(child: *rust_task, child_arc: TaskGroupArc, - ancestors: AncestorList, is_main: bool, - notify_chan: Option<Chan<TaskResult>>, - f: ~fn()) - -> ~fn() { - let child_data = Cell((child_arc, ancestors)); - let result: ~fn() = || { - // Agh. Get move-mode items into the closure. FIXME (#2829) - let mut (child_arc, ancestors) = child_data.take(); - // Child task runs this code. - - // Even if the below code fails to kick the child off, we must - // send Something on the notify channel. - - //let mut notifier = None;//notify_chan.map(|c| AutoNotify(c)); - let notifier = match notify_chan { - Some(ref notify_chan_value) => { - let moved_ncv = move_it!(*notify_chan_value); - Some(AutoNotify(moved_ncv)) - } - _ => None - }; - - if enlist_many(child, &child_arc, &mut ancestors) { - let group = @@mut TCB(child, - child_arc, - ancestors, - is_main, - notifier); - unsafe { - local_set(OldHandle(child), taskgroup_key!(), group); - } - - // Run the child's body. - f(); - - // TLS cleanup code will exit the taskgroup. - } - - // Run the box annihilator. - // FIXME #4428: Crashy. - // unsafe { cleanup::annihilate(); } - }; - return result; - - // Set up membership in taskgroup and descendantship in all ancestor - // groups. If any enlistment fails, Some task was already failing, so - // don't let the child task run, and undo every successful enlistment. - fn enlist_many(child: *rust_task, child_arc: &TaskGroupArc, - ancestors: &mut AncestorList) -> bool { - // Join this taskgroup. - let mut result = - do access_group(child_arc) |child_tg| { - enlist_in_taskgroup(child_tg, child, true) // member - }; - if result { - // Unwinding function in case any ancestral enlisting fails - let bail: @fn(TaskGroupInner) = |tg| { - leave_taskgroup(tg, child, false) - }; - // Attempt to join every ancestor group. - result = - each_ancestor(ancestors, Some(bail), |ancestor_tg| { - // Enlist as a descendant, not as an actual member. - // Descendants don't kill ancestor groups on failure. - enlist_in_taskgroup(ancestor_tg, child, false) - }); - // If any ancestor group fails, need to exit this group too. - if !result { - do access_group(child_arc) |child_tg| { - leave_taskgroup(child_tg, child, true); // member - } - } - } - result - } - } - - fn new_task_in_sched(opts: SchedOpts) -> *rust_task { - if opts.foreign_stack_size != None { - fail!("foreign_stack_size scheduler option unimplemented"); - } - - let num_threads = match opts.mode { - DefaultScheduler - | CurrentScheduler - | ExistingScheduler(*) - | PlatformThread => 0u, /* Won't be used */ - SingleThreaded => 1u, - ThreadPerCore => unsafe { rt::rust_num_threads() }, - ThreadPerTask => { - fail!("ThreadPerTask scheduling mode unimplemented") - } - ManualThreads(threads) => { - if threads == 0u { - fail!("can not create a scheduler with no threads"); - } - threads - } - }; - - unsafe { - let sched_id = match opts.mode { - CurrentScheduler => rt::rust_get_sched_id(), - ExistingScheduler(SchedulerHandle(id)) => id, - PlatformThread => rt::rust_osmain_sched_id(), - _ => rt::rust_new_sched(num_threads) - }; - rt::rust_new_task_in_sched(sched_id) - } - } -} - -#[test] -fn test_spawn_raw_simple() { - let (po, ch) = stream(); - do spawn_raw(default_task_opts()) { - ch.send(()); - } - po.recv(); -} - -#[test] -#[ignore(cfg(windows))] -fn test_spawn_raw_unsupervise() { - let opts = task::TaskOpts { - linked: false, - notify_chan: None, - .. default_task_opts() - }; - do spawn_raw(opts) { - fail!(); - } -} - -#[test] -#[ignore(cfg(windows))] -fn test_spawn_raw_notify_success() { - let (notify_po, notify_ch) = comm::stream(); - - let opts = task::TaskOpts { - notify_chan: Some(notify_ch), - .. default_task_opts() - }; - do spawn_raw(opts) { - } - assert_eq!(notify_po.recv(), Success); -} - -#[test] -#[ignore(cfg(windows))] -fn test_spawn_raw_notify_failure() { - // New bindings for these - let (notify_po, notify_ch) = comm::stream(); - - let opts = task::TaskOpts { - linked: false, - notify_chan: Some(notify_ch), - .. default_task_opts() - }; - do spawn_raw(opts) { - fail!(); - } - assert_eq!(notify_po.recv(), Failure); -} diff --git a/src/libcore/to_bytes.rs b/src/libcore/to_bytes.rs deleted file mode 100644 index 5b66e94c1b4..00000000000 --- a/src/libcore/to_bytes.rs +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The `ToBytes` and `IterBytes` traits - -*/ - -use io; -use io::Writer; -use option::{None, Option, Some}; -use old_iter::BaseIter; -use str; - -pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool; - -/** - * A trait to implement in order to make a type hashable; - * This works in combination with the trait `Hash::Hash`, and - * may in the future be merged with that trait or otherwise - * modified when default methods and trait inheritence are - * completed. - */ -pub trait IterBytes { - /** - * Call the provided callback `f` one or more times with - * byte-slices that should be used when computing a hash - * value or otherwise "flattening" the structure into - * a sequence of bytes. The `lsb0` parameter conveys - * whether the caller is asking for little-endian bytes - * (`true`) or big-endian (`false`); this should only be - * relevant in implementations that represent a single - * multi-byte datum such as a 32 bit integer or 64 bit - * floating-point value. It can be safely ignored for - * larger structured types as they are usually processed - * left-to-right in declaration order, regardless of - * underlying memory endianness. - */ - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool; -} - -impl IterBytes for bool { - #[inline(always)] - fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { - f([ - *self as u8 - ]) - } -} - -impl IterBytes for u8 { - #[inline(always)] - fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { - f([ - *self - ]) - } -} - -impl IterBytes for u16 { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - if lsb0 { - f([ - *self as u8, - (*self >> 8) as u8 - ]) - } else { - f([ - (*self >> 8) as u8, - *self as u8 - ]) - } - } -} - -impl IterBytes for u32 { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - if lsb0 { - f([ - *self as u8, - (*self >> 8) as u8, - (*self >> 16) as u8, - (*self >> 24) as u8, - ]) - } else { - f([ - (*self >> 24) as u8, - (*self >> 16) as u8, - (*self >> 8) as u8, - *self as u8 - ]) - } - } -} - -impl IterBytes for u64 { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - if lsb0 { - f([ - *self as u8, - (*self >> 8) as u8, - (*self >> 16) as u8, - (*self >> 24) as u8, - (*self >> 32) as u8, - (*self >> 40) as u8, - (*self >> 48) as u8, - (*self >> 56) as u8 - ]) - } else { - f([ - (*self >> 56) as u8, - (*self >> 48) as u8, - (*self >> 40) as u8, - (*self >> 32) as u8, - (*self >> 24) as u8, - (*self >> 16) as u8, - (*self >> 8) as u8, - *self as u8 - ]) - } - } -} - -impl IterBytes for i8 { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as u8).iter_bytes(lsb0, f) - } -} - -impl IterBytes for i16 { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as u16).iter_bytes(lsb0, f) - } -} - -impl IterBytes for i32 { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as u32).iter_bytes(lsb0, f) - } -} - -impl IterBytes for i64 { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as u64).iter_bytes(lsb0, f) - } -} - -impl IterBytes for char { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as u32).iter_bytes(lsb0, f) - } -} - -#[cfg(target_word_size = "32")] -impl IterBytes for uint { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as u32).iter_bytes(lsb0, f) - } -} - -#[cfg(target_word_size = "64")] -impl IterBytes for uint { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as u64).iter_bytes(lsb0, f) - } -} - -impl IterBytes for int { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as uint).iter_bytes(lsb0, f) - } -} - -impl<'self,A:IterBytes> IterBytes for &'self [A] { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - self.each(|elt| elt.iter_bytes(lsb0, |b| f(b))) - } -} - -impl<A:IterBytes,B:IterBytes> IterBytes for (A,B) { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - match *self { - (ref a, ref b) => { a.iter_bytes(lsb0, f) && b.iter_bytes(lsb0, f) } - } - } -} - -impl<A:IterBytes,B:IterBytes,C:IterBytes> IterBytes for (A,B,C) { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - match *self { - (ref a, ref b, ref c) => { - a.iter_bytes(lsb0, f) && b.iter_bytes(lsb0, f) && c.iter_bytes(lsb0, f) - } - } - } -} - -// Move this to vec, probably. -fn borrow<'x,A>(a: &'x [A]) -> &'x [A] { - a -} - -impl<A:IterBytes> IterBytes for ~[A] { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - borrow(*self).iter_bytes(lsb0, f) - } -} - -impl<A:IterBytes> IterBytes for @[A] { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - borrow(*self).iter_bytes(lsb0, f) - } -} - -// NOTE: remove all of these after a snapshot, the new for-loop iteration -// protocol makes these unnecessary. - -#[inline(always)] -pub fn iter_bytes_2<A:IterBytes,B:IterBytes>(a: &A, b: &B, - lsb0: bool, z: Cb) -> bool { - a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) -} - -pub fn iter_bytes_3<A: IterBytes, - B: IterBytes, - C: IterBytes>(a: &A, b: &B, c: &C, lsb0: bool, z: Cb) -> bool { - a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) && c.iter_bytes(lsb0, z) -} - -pub fn iter_bytes_4<A: IterBytes, - B: IterBytes, - C: IterBytes, - D: IterBytes>(a: &A, b: &B, c: &C, - d: &D, - lsb0: bool, z: Cb) -> bool { - a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) && c.iter_bytes(lsb0, z) && - d.iter_bytes(lsb0, z) -} - -pub fn iter_bytes_5<A: IterBytes, - B: IterBytes, - C: IterBytes, - D: IterBytes, - E: IterBytes>(a: &A, b: &B, c: &C, - d: &D, e: &E, - lsb0: bool, z: Cb) -> bool { - a.iter_bytes(lsb0, z) && b.iter_bytes(lsb0, z) && c.iter_bytes(lsb0, z) && - d.iter_bytes(lsb0, z) && e.iter_bytes(lsb0, z) -} - -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) - } - } -} - -impl IterBytes for ~str { - #[inline(always)] - fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { - do str::byte_slice(*self) |bytes| { - f(bytes) - } - } -} - -impl IterBytes for @str { - #[inline(always)] - fn iter_bytes(&self, _lsb0: bool, f: Cb) -> bool { - do str::byte_slice(*self) |bytes| { - f(bytes) - } - } -} - -impl<A:IterBytes> IterBytes for Option<A> { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - match *self { - Some(ref a) => 0u8.iter_bytes(lsb0, f) && a.iter_bytes(lsb0, f), - None => 1u8.iter_bytes(lsb0, f) - } - } -} - -impl<'self,A:IterBytes> IterBytes for &'self A { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (**self).iter_bytes(lsb0, f) - } -} - -impl<A:IterBytes> IterBytes for @A { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (**self).iter_bytes(lsb0, f) - } -} - -impl<A:IterBytes> IterBytes for ~A { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (**self).iter_bytes(lsb0, f) - } -} - -// NB: raw-pointer IterBytes does _not_ dereference -// to the target; it just gives you the pointer-bytes. -impl<A> IterBytes for *const A { - #[inline(always)] - fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - (*self as uint).iter_bytes(lsb0, f) - } -} - -pub trait ToBytes { - fn to_bytes(&self, lsb0: bool) -> ~[u8]; -} - -impl<A:IterBytes> ToBytes for A { - fn to_bytes(&self, lsb0: bool) -> ~[u8] { - do io::with_bytes_writer |wr| { - for self.iter_bytes(lsb0) |bytes| { - wr.write(bytes) - } - } - } -} diff --git a/src/libcore/to_str.rs b/src/libcore/to_str.rs deleted file mode 100644 index 1469471b7ce..00000000000 --- a/src/libcore/to_str.rs +++ /dev/null @@ -1,240 +0,0 @@ -// 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. - -/*! - -The `ToStr` trait for converting to strings - -*/ - -use str::OwnedStr; -use hashmap::HashMap; -use hashmap::HashSet; -use container::Map; -use hash::Hash; -use cmp::Eq; -use old_iter::BaseIter; - -pub trait ToStr { - 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. - 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 { ~"()" } -} - -impl<A:ToStr> ToStr for (A,) { - #[inline(always)] - fn to_str(&self) -> ~str { - match *self { - (ref a,) => { - ~"(" + a.to_str() + ~", " + ~")" - } - } - } -} - -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; - for self.each |key, value| { - if first { - first = false; - } - else { - acc.push_str(", "); - } - acc.push_str(key.to_str()); - acc.push_str(": "); - acc.push_str(value.to_str()); - } - acc.push_char('}'); - acc - } -} - -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(", "); - } - acc.push_str(element.to_str()); - } - 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 - //let &(ref a, ref b) = self; - match *self { - (ref a, ref b) => { - ~"(" + a.to_str() + ~", " + b.to_str() + ~")" - } - } - } -} - -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 - //let &(ref a, ref b, ref c) = self; - match *self { - (ref a, ref b, ref c) => { - fmt!("(%s, %s, %s)", - (*a).to_str(), - (*b).to_str(), - (*c).to_str() - ) - } - } - } -} - -impl<'self,A:ToStr> ToStr for &'self [A] { - #[inline(always)] - fn to_str(&self) -> ~str { - let mut acc = ~"[", first = true; - for self.each |elt| { - if first { - first = false; - } - else { - acc.push_str(", "); - } - acc.push_str(elt.to_str()); - } - acc.push_char(']'); - acc - } -} - -impl<A:ToStr> ToStr for ~[A] { - #[inline(always)] - fn to_str(&self) -> ~str { - let mut acc = ~"[", first = true; - for self.each |elt| { - if first { - first = false; - } - else { - acc.push_str(", "); - } - acc.push_str(elt.to_str()); - } - acc.push_char(']'); - acc - } -} - -impl<A:ToStr> ToStr for @[A] { - #[inline(always)] - fn to_str(&self) -> ~str { - let mut acc = ~"[", first = true; - for self.each |elt| { - if first { - first = false; - } - else { - acc.push_str(", "); - } - acc.push_str(elt.to_str()); - } - acc.push_char(']'); - acc - } -} - -#[cfg(test)] -#[allow(non_implicitly_copyable_typarams)] -mod tests { - use hashmap::HashMap; - use hashmap::HashSet; - use container::Set; - #[test] - fn test_simple_types() { - assert_eq!(1i.to_str(), ~"1"); - assert_eq!((-1i).to_str(), ~"-1"); - assert_eq!(200u.to_str(), ~"200"); - assert_eq!(2u8.to_str(), ~"2"); - assert_eq!(true.to_str(), ~"true"); - assert_eq!(false.to_str(), ~"false"); - assert_eq!(().to_str(), ~"()"); - assert_eq!((~"hi").to_str(), ~"hi"); - assert_eq!((@"hi").to_str(), ~"hi"); - } - - #[test] - fn test_tuple_types() { - assert_eq!((1, 2).to_str(), ~"(1, 2)"); - assert_eq!((~"a", ~"b", false).to_str(), ~"(a, b, false)"); - assert_eq!(((), ((), 100)).to_str(), ~"((), ((), 100))"); - } - - #[test] - fn test_vectors() { - let x: ~[int] = ~[]; - assert_eq!(x.to_str(), ~"[]"); - assert_eq!((~[1]).to_str(), ~"[1]"); - assert_eq!((~[1, 2, 3]).to_str(), ~"[1, 2, 3]"); - assert!((~[~[], ~[1], ~[1, 1]]).to_str() == - ~"[[], [1], [1, 1]]"); - } - - #[test] - fn test_hashmap() { - let mut table: HashMap<int, int> = HashMap::new(); - let empty: HashMap<int, int> = HashMap::new(); - - table.insert(3, 4); - table.insert(1, 2); - - let table_str = table.to_str(); - - assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}"); - assert_eq!(empty.to_str(), ~"{}"); - } - - #[test] - fn test_hashset() { - let mut set: HashSet<int> = HashSet::new(); - let empty_set: HashSet<int> = HashSet::new(); - - set.insert(1); - set.insert(2); - - let set_str = set.to_str(); - - assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}"); - assert_eq!(empty_set.to_str(), ~"{}"); - } -} diff --git a/src/libcore/trie.rs b/src/libcore/trie.rs deleted file mode 100644 index 13b892e700e..00000000000 --- a/src/libcore/trie.rs +++ /dev/null @@ -1,548 +0,0 @@ -// 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. - -//! An ordered map and set for integer keys implemented as a radix trie - -use prelude::*; -use util::{swap, replace}; - -// FIXME: #5244: need to manually update the TrieNode constructor -static SHIFT: uint = 4; -static SIZE: uint = 1 << SHIFT; -static MASK: uint = SIZE - 1; - -enum Child<T> { - Internal(~TrieNode<T>), - External(uint, T), - Nothing -} - -pub struct TrieMap<T> { - priv root: TrieNode<T>, - priv length: uint -} - -impl<T> Container for TrieMap<T> { - /// Return the number of elements in the map - #[inline(always)] - fn len(&const self) -> uint { self.length } - - /// Return true if the map contains no elements - #[inline(always)] - fn is_empty(&const self) -> bool { self.len() == 0 } -} - -impl<T> Mutable for TrieMap<T> { - /// Clear the map, removing all values. - #[inline(always)] - fn clear(&mut self) { - self.root = TrieNode::new(); - self.length = 0; - } -} - -impl<T> Map<uint, T> for TrieMap<T> { - /// Return true if the map contains a value for the specified key - #[inline(always)] - fn contains_key(&self, key: &uint) -> bool { - self.find(key).is_some() - } - - /// Visit all key-value pairs in order - #[inline(always)] - fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - self.root.each(f) - } - - /// Visit all keys in order - #[inline(always)] - fn each_key(&self, f: &fn(&uint) -> bool) -> bool { - self.each(|k, _| f(k)) - } - - /// Visit all values in order - #[inline(always)] - fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) -> bool { - self.each(|_, v| f(v)) - } - - /// Iterate over the map and mutate the contained values - #[inline(always)] - fn mutate_values(&mut self, f: &fn(&uint, &mut T) -> bool) -> bool { - self.root.mutate_values(f) - } - - /// Return a reference to the value corresponding to the key - #[inline(hint)] - fn find<'a>(&'a self, key: &uint) -> Option<&'a T> { - let mut node: &'a TrieNode<T> = &self.root; - let mut idx = 0; - loop { - match node.children[chunk(*key, idx)] { - Internal(ref x) => node = &**x, - External(stored, ref value) => { - if stored == *key { - return Some(value) - } else { - return None - } - } - Nothing => return None - } - idx += 1; - } - } - - /// Return a mutable reference to the value corresponding to the key - #[inline(always)] - fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut T> { - find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) - } - - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - #[inline(always)] - fn insert(&mut self, key: uint, value: T) -> bool { - self.swap(key, value).is_none() - } - - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - #[inline(always)] - fn remove(&mut self, key: &uint) -> bool { - self.pop(key).is_some() - } - - /// Insert a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, key: uint, value: T) -> Option<T> { - let ret = insert(&mut self.root.count, - &mut self.root.children[chunk(key, 0)], - key, value, 1); - if ret.is_none() { self.length += 1 } - ret - } - - /// Removes a key from the map, returning the value at the key if the key - /// was previously in the map. - fn pop(&mut self, key: &uint) -> Option<T> { - let ret = remove(&mut self.root.count, - &mut self.root.children[chunk(*key, 0)], - *key, 1); - if ret.is_some() { self.length -= 1 } - ret - } -} - -pub impl<T> TrieMap<T> { - /// Create an empty TrieMap - #[inline(always)] - 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 { - self.root.each_reverse(f) - } - - /// Visit all keys in reverse order - #[inline(always)] - 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 { - self.each_reverse(|_, v| f(v)) - } -} - -pub struct TrieSet { - priv map: TrieMap<()> -} - -impl BaseIter<uint> for TrieSet { - /// Visit all values in order - #[inline(always)] - fn each(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key(f) } - #[inline(always)] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -impl ReverseIter<uint> for TrieSet { - /// Visit all values in reverse order - #[inline(always)] - fn each_reverse(&self, f: &fn(&uint) -> bool) -> bool { - self.map.each_key_reverse(f) - } -} - -impl Container for TrieSet { - /// Return the number of elements in the set - #[inline(always)] - fn len(&const self) -> uint { self.map.len() } - - /// Return true if the set contains no elements - #[inline(always)] - fn is_empty(&const self) -> bool { self.map.is_empty() } -} - -impl Mutable for TrieSet { - /// Clear the set, removing all values. - #[inline(always)] - fn clear(&mut self) { self.map.clear() } -} - -pub impl TrieSet { - /// Create an empty TrieSet - #[inline(always)] - fn new() -> TrieSet { - TrieSet{map: TrieMap::new()} - } - - /// Return true if the set contains a value - #[inline(always)] - 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, ()) } - - /// 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) } -} - -struct TrieNode<T> { - count: uint, - children: [Child<T>, ..SIZE] -} - -impl<T> TrieNode<T> { - #[inline(always)] - fn new() -> TrieNode<T> { - // FIXME: #5244: [Nothing, ..SIZE] should be possible without Copy - TrieNode{count: 0, - children: [Nothing, Nothing, Nothing, Nothing, - Nothing, Nothing, Nothing, Nothing, - Nothing, Nothing, Nothing, Nothing, - Nothing, Nothing, Nothing, Nothing]} - } -} - -impl<T> TrieNode<T> { - fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - for uint::range(0, self.children.len()) |idx| { - match self.children[idx] { - Internal(ref x) => if !x.each(f) { return false }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { - for uint::range_rev(self.children.len(), 0) |idx| { - match self.children[idx - 1] { - Internal(ref x) => if !x.each_reverse(f) { return false }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { - for vec::each_mut(self.children) |child| { - match *child { - Internal(ref mut x) => if !x.mutate_values(f) { - return false - }, - External(k, ref mut v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } -} - -// if this was done via a trait, the key could be generic -#[inline(always)] -fn chunk(n: uint, idx: uint) -> uint { - let sh = uint::bits - (SHIFT * (idx + 1)); - (n >> sh) & MASK -} - -fn find_mut<'r, T>(child: &'r mut Child<T>, key: uint, idx: uint) -> Option<&'r mut T> { - match *child { - External(_, ref mut value) => Some(value), - Internal(ref mut x) => find_mut(&mut x.children[chunk(key, idx)], key, idx + 1), - Nothing => None - } -} - -fn insert<T>(count: &mut uint, child: &mut Child<T>, key: uint, value: T, - idx: uint) -> Option<T> { - let mut tmp = Nothing; - let ret; - swap(&mut tmp, child); - - *child = match tmp { - External(stored_key, stored_value) => { - if stored_key == key { - ret = Some(stored_value); - External(stored_key, value) - } else { - // conflict - split the node - let mut new = ~TrieNode::new(); - insert(&mut new.count, - &mut new.children[chunk(stored_key, idx)], - stored_key, stored_value, idx + 1); - ret = insert(&mut new.count, &mut new.children[chunk(key, idx)], - key, value, idx + 1); - Internal(new) - } - } - Internal(x) => { - let mut x = x; - ret = insert(&mut x.count, &mut x.children[chunk(key, idx)], key, - value, idx + 1); - Internal(x) - } - Nothing => { - *count += 1; - ret = None; - External(key, value) - } - }; - return ret; -} - -fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint, - idx: uint) -> Option<T> { - let (ret, this) = match *child { - External(stored, _) if stored == key => { - match replace(child, Nothing) { - External(_, value) => (Some(value), true), - _ => fail!() - } - } - External(*) => (None, false), - Internal(ref mut x) => { - let ret = remove(&mut x.count, &mut x.children[chunk(key, idx)], - key, idx + 1); - (ret, x.count == 0) - } - Nothing => (None, false) - }; - - if this { - *child = Nothing; - *count -= 1; - } - return ret; -} - -#[cfg(test)] -pub fn check_integrity<T>(trie: &TrieNode<T>) { - assert!(trie.count != 0); - - let mut sum = 0; - - for trie.children.each |x| { - match *x { - Nothing => (), - Internal(ref y) => { - check_integrity(&**y); - sum += 1 - } - External(_, _) => { sum += 1 } - } - } - - assert_eq!(sum, trie.count); -} - -#[cfg(test)] -mod tests { - use super::*; - use core::option::{Some, None}; - use uint; - - #[test] - fn test_find_mut() { - let mut m = TrieMap::new(); - assert!(m.insert(1, 12)); - assert!(m.insert(2, 8)); - assert!(m.insert(5, 14)); - let new = 100; - match m.find_mut(&5) { - None => fail!(), Some(x) => *x = new - } - assert_eq!(m.find(&5), Some(&new)); - } - - #[test] - fn test_step() { - let mut trie = TrieMap::new(); - let n = 300; - - for uint::range_step(1, n, 2) |x| { - assert!(trie.insert(x, x + 1)); - assert!(trie.contains_key(&x)); - check_integrity(&trie.root); - } - - for uint::range_step(0, n, 2) |x| { - assert!(!trie.contains_key(&x)); - assert!(trie.insert(x, x + 1)); - check_integrity(&trie.root); - } - - for uint::range(0, n) |x| { - assert!(trie.contains_key(&x)); - assert!(!trie.insert(x, x + 1)); - check_integrity(&trie.root); - } - - for uint::range_step(1, n, 2) |x| { - assert!(trie.remove(&x)); - assert!(!trie.contains_key(&x)); - check_integrity(&trie.root); - } - - for uint::range_step(0, n, 2) |x| { - assert!(trie.contains_key(&x)); - assert!(!trie.insert(x, x + 1)); - check_integrity(&trie.root); - } - } - - #[test] - fn test_each() { - let mut m = TrieMap::new(); - - assert!(m.insert(3, 6)); - assert!(m.insert(0, 0)); - assert!(m.insert(4, 8)); - assert!(m.insert(2, 4)); - assert!(m.insert(1, 2)); - - let mut n = 0; - for m.each |k, v| { - assert_eq!(*k, n); - assert_eq!(*v, n * 2); - n += 1; - } - } - - #[test] - fn test_each_break() { - let mut m = TrieMap::new(); - - for uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { - m.insert(x, x / 2); - } - - let mut n = uint::max_value - 9999; - for m.each |k, v| { - if n == uint::max_value - 5000 { break } - assert!(n < uint::max_value - 5000); - - assert_eq!(*k, n); - assert_eq!(*v, n / 2); - n += 1; - } - } - - #[test] - fn test_each_reverse() { - let mut m = TrieMap::new(); - - assert!(m.insert(3, 6)); - assert!(m.insert(0, 0)); - assert!(m.insert(4, 8)); - assert!(m.insert(2, 4)); - assert!(m.insert(1, 2)); - - let mut n = 4; - for m.each_reverse |k, v| { - assert_eq!(*k, n); - assert_eq!(*v, n * 2); - n -= 1; - } - } - - #[test] - fn test_each_reverse_break() { - let mut m = TrieMap::new(); - - for uint::range_rev(uint::max_value, uint::max_value - 10000) |x| { - m.insert(x, x / 2); - } - - let mut n = uint::max_value; - for m.each_reverse |k, v| { - if n == uint::max_value - 5000 { break } - assert!(n > uint::max_value - 5000); - - assert_eq!(*k, n); - assert_eq!(*v, n / 2); - n -= 1; - } - } - - #[test] - fn test_sane_chunk() { - let x = 1; - let y = 1 << (uint::bits - 1); - - let mut trie = TrieSet::new(); - - assert!(trie.insert(x)); - assert!(trie.insert(y)); - - assert_eq!(trie.len(), 2); - - let expected = [x, y]; - - let mut i = 0; - - for trie.each |x| { - assert_eq!(expected[i], *x); - i += 1; - } - } - - #[test] - fn test_swap() { - let mut m = TrieMap::new(); - assert_eq!(m.swap(1, 2), None); - assert_eq!(m.swap(1, 3), Some(2)); - assert_eq!(m.swap(1, 4), Some(3)); - } - - #[test] - fn test_pop() { - let mut m = TrieMap::new(); - m.insert(1, 2); - assert_eq!(m.pop(&1), Some(2)); - assert_eq!(m.pop(&1), None); - } -} diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs deleted file mode 100644 index 639df89a377..00000000000 --- a/src/libcore/tuple.rs +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations on tuples - -use kinds::Copy; -use vec; - -pub use self::inner::*; - -pub trait CopyableTuple<T, U> { - fn first(&self) -> T; - fn second(&self) -> U; - fn swap(&self) -> (U, T); -} - -impl<T:Copy,U:Copy> CopyableTuple<T, U> for (T, U) { - /// Return the first element of self - #[inline(always)] - fn first(&self) -> T { - match *self { - (t, _) => t, - } - } - - /// Return the second element of self - #[inline(always)] - fn second(&self) -> U { - match *self { - (_, u) => u, - } - } - - /// Return the results of swapping the two elements of self - #[inline(always)] - fn swap(&self) -> (U, T) { - match *self { - (t, u) => (u, t), - } - } -} - -pub trait ImmutableTuple<T, U> { - fn first_ref<'a>(&'a self) -> &'a T; - fn second_ref<'a>(&'a self) -> &'a U; -} - -impl<T, U> ImmutableTuple<T, U> for (T, U) { - #[inline(always)] - fn first_ref<'a>(&'a self) -> &'a T { - match *self { - (ref t, _) => t, - } - } - #[inline(always)] - fn second_ref<'a>(&'a self) -> &'a U { - match *self { - (_, ref u) => u, - } - } -} - -pub trait ExtendedTupleOps<A,B> { - fn zip(&self) -> ~[(A, B)]; - fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C]; -} - -impl<'self,A:Copy,B:Copy> ExtendedTupleOps<A,B> for (&'self [A], &'self [B]) { - #[inline(always)] - fn zip(&self) -> ~[(A, B)] { - match *self { - (ref a, ref b) => { - vec::zip_slice(*a, *b) - } - } - } - - #[inline(always)] - fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] { - match *self { - (ref a, ref b) => { - vec::map_zip(*a, *b, f) - } - } - } -} - -impl<A:Copy,B:Copy> ExtendedTupleOps<A,B> for (~[A], ~[B]) { - #[inline(always)] - fn zip(&self) -> ~[(A, B)] { - match *self { - (ref a, ref b) => { - vec::zip_slice(*a, *b) - } - } - } - - #[inline(always)] - fn map<C>(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C] { - match *self { - (ref a, ref b) => { - vec::map_zip(*a, *b, f) - } - } - } -} - -// macro for implementing n-ary tuple functions and operations - -macro_rules! tuple_impls { - ($( - ($cloneable_trait:ident, $immutable_trait:ident) { - $(($get_fn:ident, $get_ref_fn:ident) -> $T:ident { - $get_pattern:pat => $ret:expr - })+ - } - )+) => { - pub mod inner { - use clone::Clone; - #[cfg(not(test))] use cmp::*; - - $( - pub trait $cloneable_trait<$($T),+> { - $(fn $get_fn(&self) -> $T;)+ - } - - impl<$($T:Clone),+> $cloneable_trait<$($T),+> for ($($T),+) { - $( - #[inline(always)] - fn $get_fn(&self) -> $T { - self.$get_ref_fn().clone() - } - )+ - } - - pub trait $immutable_trait<$($T),+> { - $(fn $get_ref_fn<'a>(&'a self) -> &'a $T;)+ - } - - impl<$($T),+> $immutable_trait<$($T),+> for ($($T),+) { - $( - #[inline(always)] - fn $get_ref_fn<'a>(&'a self) -> &'a $T { - match *self { $get_pattern => $ret } - } - )+ - } - - impl<$($T:Clone),+> Clone for ($($T),+) { - fn clone(&self) -> ($($T),+) { - ($(self.$get_ref_fn().clone()),+) - } - } - - #[cfg(not(test))] - impl<$($T:Eq),+> Eq for ($($T),+) { - #[inline(always)] - fn eq(&self, other: &($($T),+)) -> bool { - $(*self.$get_ref_fn() == *other.$get_ref_fn())&&+ - } - #[inline(always)] - fn ne(&self, other: &($($T),+)) -> bool { - !(*self == *other) - } - } - - #[cfg(not(test))] - impl<$($T:TotalEq),+> TotalEq for ($($T),+) { - #[inline(always)] - fn equals(&self, other: &($($T),+)) -> bool { - $(self.$get_ref_fn().equals(other.$get_ref_fn()))&&+ - } - } - - #[cfg(not(test))] - impl<$($T:Ord),+> Ord for ($($T),+) { - #[inline(always)] - fn lt(&self, other: &($($T),+)) -> bool { - lexical_lt!($(self.$get_ref_fn(), other.$get_ref_fn()),+) - } - #[inline(always)] - fn le(&self, other: &($($T),+)) -> bool { !(*other).lt(&(*self)) } - #[inline(always)] - fn ge(&self, other: &($($T),+)) -> bool { !(*self).lt(other) } - #[inline(always)] - fn gt(&self, other: &($($T),+)) -> bool { (*other).lt(&(*self)) } - } - - #[cfg(not(test))] - impl<$($T:TotalOrd),+> TotalOrd for ($($T),+) { - #[inline] - fn cmp(&self, other: &($($T),+)) -> Ordering { - lexical_cmp!($(self.$get_ref_fn(), other.$get_ref_fn()),+) - } - } - )+ - } - } -} - -// Constructs an expression that performs a lexical less-than -// ordering. The values are interleaved, so the macro invocation for -// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_lt!(a1, b1, a2, b2, -// a3, b3)` (and similarly for `lexical_cmp`) -macro_rules! lexical_lt { - ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { - if *$a < *$b { true } - else if !(*$b < *$a) { lexical_lt!($($rest_a, $rest_b),+) } - else { false } - }; - ($a:expr, $b:expr) => { *$a < *$b }; -} - -macro_rules! lexical_cmp { - ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { - match ($a).cmp($b) { - Equal => lexical_cmp!($($rest_a, $rest_b),+), - ordering => ordering - } - }; - ($a:expr, $b:expr) => { ($a).cmp($b) }; -} - - -tuple_impls! { - (CloneableTuple2, ImmutableTuple2) { - (n0, n0_ref) -> A { (ref a,_) => a } - (n1, n1_ref) -> B { (_,ref b) => b } - } - - (CloneableTuple3, ImmutableTuple3) { - (n0, n0_ref) -> A { (ref a,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_) => b } - (n2, n2_ref) -> C { (_,_,ref c) => c } - } - - (CloneableTuple4, ImmutableTuple4) { - (n0, n0_ref) -> A { (ref a,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d) => d } - } - - (CloneableTuple5, ImmutableTuple5) { - (n0, n0_ref) -> A { (ref a,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e) => e } - } - - (CloneableTuple6, ImmutableTuple6) { - (n0, n0_ref) -> A { (ref a,_,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e,_) => e } - (n5, n5_ref) -> F { (_,_,_,_,_,ref f) => f } - } - - (CloneableTuple7, ImmutableTuple7) { - (n0, n0_ref) -> A { (ref a,_,_,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_,_,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e,_,_) => e } - (n5, n5_ref) -> F { (_,_,_,_,_,ref f,_) => f } - (n6, n6_ref) -> G { (_,_,_,_,_,_,ref g) => g } - } - - (CloneableTuple8, ImmutableTuple8) { - (n0, n0_ref) -> A { (ref a,_,_,_,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_,_,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_,_,_,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e,_,_,_) => e } - (n5, n5_ref) -> F { (_,_,_,_,_,ref f,_,_) => f } - (n6, n6_ref) -> G { (_,_,_,_,_,_,ref g,_) => g } - (n7, n7_ref) -> H { (_,_,_,_,_,_,_,ref h) => h } - } - - (CloneableTuple9, ImmutableTuple9) { - (n0, n0_ref) -> A { (ref a,_,_,_,_,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_,_,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_,_,_,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_,_,_,_,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e,_,_,_,_) => e } - (n5, n5_ref) -> F { (_,_,_,_,_,ref f,_,_,_) => f } - (n6, n6_ref) -> G { (_,_,_,_,_,_,ref g,_,_) => g } - (n7, n7_ref) -> H { (_,_,_,_,_,_,_,ref h,_) => h } - (n8, n8_ref) -> I { (_,_,_,_,_,_,_,_,ref i) => i } - } - - (CloneableTuple10, ImmutableTuple10) { - (n0, n0_ref) -> A { (ref a,_,_,_,_,_,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_,_,_,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_,_,_,_,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_,_,_,_,_,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e,_,_,_,_,_) => e } - (n5, n5_ref) -> F { (_,_,_,_,_,ref f,_,_,_,_) => f } - (n6, n6_ref) -> G { (_,_,_,_,_,_,ref g,_,_,_) => g } - (n7, n7_ref) -> H { (_,_,_,_,_,_,_,ref h,_,_) => h } - (n8, n8_ref) -> I { (_,_,_,_,_,_,_,_,ref i,_) => i } - (n9, n9_ref) -> J { (_,_,_,_,_,_,_,_,_,ref j) => j } - } - - (CloneableTuple11, ImmutableTuple11) { - (n0, n0_ref) -> A { (ref a,_,_,_,_,_,_,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_,_,_,_,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_,_,_,_,_,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_,_,_,_,_,_,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e,_,_,_,_,_,_) => e } - (n5, n5_ref) -> F { (_,_,_,_,_,ref f,_,_,_,_,_) => f } - (n6, n6_ref) -> G { (_,_,_,_,_,_,ref g,_,_,_,_) => g } - (n7, n7_ref) -> H { (_,_,_,_,_,_,_,ref h,_,_,_) => h } - (n8, n8_ref) -> I { (_,_,_,_,_,_,_,_,ref i,_,_) => i } - (n9, n9_ref) -> J { (_,_,_,_,_,_,_,_,_,ref j,_) => j } - (n10, n10_ref) -> K { (_,_,_,_,_,_,_,_,_,_,ref k) => k } - } - - (CloneableTuple12, ImmutableTuple12) { - (n0, n0_ref) -> A { (ref a,_,_,_,_,_,_,_,_,_,_,_) => a } - (n1, n1_ref) -> B { (_,ref b,_,_,_,_,_,_,_,_,_,_) => b } - (n2, n2_ref) -> C { (_,_,ref c,_,_,_,_,_,_,_,_,_) => c } - (n3, n3_ref) -> D { (_,_,_,ref d,_,_,_,_,_,_,_,_) => d } - (n4, n4_ref) -> E { (_,_,_,_,ref e,_,_,_,_,_,_,_) => e } - (n5, n5_ref) -> F { (_,_,_,_,_,ref f,_,_,_,_,_,_) => f } - (n6, n6_ref) -> G { (_,_,_,_,_,_,ref g,_,_,_,_,_) => g } - (n7, n7_ref) -> H { (_,_,_,_,_,_,_,ref h,_,_,_,_) => h } - (n8, n8_ref) -> I { (_,_,_,_,_,_,_,_,ref i,_,_,_) => i } - (n9, n9_ref) -> J { (_,_,_,_,_,_,_,_,_,ref j,_,_) => j } - (n10, n10_ref) -> K { (_,_,_,_,_,_,_,_,_,_,ref k,_) => k } - (n11, n11_ref) -> L { (_,_,_,_,_,_,_,_,_,_,_,ref l) => l } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use clone::Clone; - use cmp::*; - - #[test] - fn test_tuple_ref() { - let x = (~"foo", ~"bar"); - assert_eq!(x.first_ref(), &~"foo"); - assert_eq!(x.second_ref(), &~"bar"); - } - - #[test] - #[allow(non_implicitly_copyable_typarams)] - fn test_tuple() { - assert_eq!((948, 4039.48).first(), 948); - assert_eq!((34.5, ~"foo").second(), ~"foo"); - assert_eq!(('a', 2).swap(), (2, 'a')); - } - - #[test] - fn test_clone() { - let a = (1, ~"2"); - let b = a.clone(); - assert_eq!(a.first(), b.first()); - assert_eq!(a.second(), b.second()); - } - - #[test] - fn test_n_tuple() { - let t = (0u8, 1u16, 2u32, 3u64, 4u, 5i8, 6i16, 7i32, 8i64, 9i, 10f32, 11f64); - assert_eq!(t.n0(), 0u8); - assert_eq!(t.n1(), 1u16); - assert_eq!(t.n2(), 2u32); - assert_eq!(t.n3(), 3u64); - assert_eq!(t.n4(), 4u); - assert_eq!(t.n5(), 5i8); - assert_eq!(t.n6(), 6i16); - assert_eq!(t.n7(), 7i32); - assert_eq!(t.n8(), 8i64); - assert_eq!(t.n9(), 9i); - assert_eq!(t.n10(), 10f32); - assert_eq!(t.n11(), 11f64); - - assert_eq!(t.n0_ref(), &0u8); - assert_eq!(t.n1_ref(), &1u16); - assert_eq!(t.n2_ref(), &2u32); - assert_eq!(t.n3_ref(), &3u64); - assert_eq!(t.n4_ref(), &4u); - assert_eq!(t.n5_ref(), &5i8); - assert_eq!(t.n6_ref(), &6i16); - assert_eq!(t.n7_ref(), &7i32); - assert_eq!(t.n8_ref(), &8i64); - assert_eq!(t.n9_ref(), &9i); - assert_eq!(t.n10_ref(), &10f32); - assert_eq!(t.n11_ref(), &11f64); - } - - #[test] - fn test_tuple_cmp() { - let small = (1u, 2u, 3u), big = (3u, 2u, 1u); - - // Eq - assert_eq!(small, small); - assert_eq!(big, big); - assert!(small != big); - assert!(big != small); - - // Ord - assert!(small < big); - assert!(!(small < small)); - assert!(!(big < small)); - assert!(!(big < big)); - - assert!(small <= small); - assert!(big <= big); - - assert!(big > small); - assert!(small >= small); - assert!(big >= small); - assert!(big >= big); - - // TotalEq - assert!(small.equals(&small)); - assert!(big.equals(&big)); - assert!(!small.equals(&big)); - assert!(!big.equals(&small)); - - // TotalOrd - assert_eq!(small.cmp(&small), Equal); - assert_eq!(big.cmp(&big), Equal); - assert_eq!(small.cmp(&big), Less); - assert_eq!(big.cmp(&small), Greater); - } -} diff --git a/src/libcore/unicode.rs b/src/libcore/unicode.rs deleted file mode 100644 index d76da6fcc66..00000000000 --- a/src/libcore/unicode.rs +++ /dev/null @@ -1,2642 +0,0 @@ -// 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. - -#[doc(hidden)]; // FIXME #3538 - -// The following code was generated by "src/etc/unicode.py" - -pub mod general_category { - - fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { - use cmp::{Equal, Less, Greater}; - use vec::bsearch; - use option::None; - (do bsearch(r) |&(lo,hi)| { cond!( - (lo <= c && c <= hi) { Equal } - (hi < c) { Less } - _ { Greater } - )}) != None - } - - - static Cc_table : &'static [(char,char)] = &[ - ('\x00', '\x1f'), ('\x7f', '\x9f') - ]; - - pub fn Cc(c: char) -> bool { - bsearch_range_table(c, Cc_table) - } - - static Cf_table : &'static [(char,char)] = &[ - ('\xad', '\xad'), ('\u0600', '\u0604'), - ('\u06dd', '\u06dd'), ('\u070f', '\u070f'), - ('\u200b', '\u200f'), ('\u202a', '\u202e'), - ('\u2060', '\u206f'), ('\ufeff', '\ufeff'), - ('\ufff9', '\ufffb'), ('\U000110bd', '\U000110bd'), - ('\U0001d173', '\U0001d17a'), ('\U000e0001', '\U000e007f') - ]; - - pub fn Cf(c: char) -> bool { - bsearch_range_table(c, Cf_table) - } - - static Co_table : &'static [(char,char)] = &[ - ('\ue000', '\uf8ff') - ]; - - pub fn Co(c: char) -> bool { - bsearch_range_table(c, Co_table) - } - - static Cs_table : &'static [(char,char)] = &[ - ('\ud800', '\udfff') - ]; - - pub fn Cs(c: char) -> bool { - bsearch_range_table(c, Cs_table) - } - - static Ll_table : &'static [(char,char)] = &[ - ('\x61', '\x7a'), ('\xb5', '\xb5'), - ('\xdf', '\xf6'), ('\xf8', '\xff'), - ('\u0101', '\u0101'), ('\u0103', '\u0103'), - ('\u0105', '\u0105'), ('\u0107', '\u0107'), - ('\u0109', '\u0109'), ('\u010b', '\u010b'), - ('\u010d', '\u010d'), ('\u010f', '\u010f'), - ('\u0111', '\u0111'), ('\u0113', '\u0113'), - ('\u0115', '\u0115'), ('\u0117', '\u0117'), - ('\u0119', '\u0119'), ('\u011b', '\u011b'), - ('\u011d', '\u011d'), ('\u011f', '\u011f'), - ('\u0121', '\u0121'), ('\u0123', '\u0123'), - ('\u0125', '\u0125'), ('\u0127', '\u0127'), - ('\u0129', '\u0129'), ('\u012b', '\u012b'), - ('\u012d', '\u012d'), ('\u012f', '\u012f'), - ('\u0131', '\u0131'), ('\u0133', '\u0133'), - ('\u0135', '\u0135'), ('\u0137', '\u0138'), - ('\u013a', '\u013a'), ('\u013c', '\u013c'), - ('\u013e', '\u013e'), ('\u0140', '\u0140'), - ('\u0142', '\u0142'), ('\u0144', '\u0144'), - ('\u0146', '\u0146'), ('\u0148', '\u0149'), - ('\u014b', '\u014b'), ('\u014d', '\u014d'), - ('\u014f', '\u014f'), ('\u0151', '\u0151'), - ('\u0153', '\u0153'), ('\u0155', '\u0155'), - ('\u0157', '\u0157'), ('\u0159', '\u0159'), - ('\u015b', '\u015b'), ('\u015d', '\u015d'), - ('\u015f', '\u015f'), ('\u0161', '\u0161'), - ('\u0163', '\u0163'), ('\u0165', '\u0165'), - ('\u0167', '\u0167'), ('\u0169', '\u0169'), - ('\u016b', '\u016b'), ('\u016d', '\u016d'), - ('\u016f', '\u016f'), ('\u0171', '\u0171'), - ('\u0173', '\u0173'), ('\u0175', '\u0175'), - ('\u0177', '\u0177'), ('\u017a', '\u017a'), - ('\u017c', '\u017c'), ('\u017e', '\u0180'), - ('\u0183', '\u0183'), ('\u0185', '\u0185'), - ('\u0188', '\u0188'), ('\u018c', '\u018d'), - ('\u0192', '\u0192'), ('\u0195', '\u0195'), - ('\u0199', '\u019b'), ('\u019e', '\u019e'), - ('\u01a1', '\u01a1'), ('\u01a3', '\u01a3'), - ('\u01a5', '\u01a5'), ('\u01a8', '\u01a8'), - ('\u01aa', '\u01ab'), ('\u01ad', '\u01ad'), - ('\u01b0', '\u01b0'), ('\u01b4', '\u01b4'), - ('\u01b6', '\u01b6'), ('\u01b9', '\u01ba'), - ('\u01bd', '\u01bf'), ('\u01c6', '\u01c6'), - ('\u01c9', '\u01c9'), ('\u01cc', '\u01cc'), - ('\u01ce', '\u01ce'), ('\u01d0', '\u01d0'), - ('\u01d2', '\u01d2'), ('\u01d4', '\u01d4'), - ('\u01d6', '\u01d6'), ('\u01d8', '\u01d8'), - ('\u01da', '\u01da'), ('\u01dc', '\u01dd'), - ('\u01df', '\u01df'), ('\u01e1', '\u01e1'), - ('\u01e3', '\u01e3'), ('\u01e5', '\u01e5'), - ('\u01e7', '\u01e7'), ('\u01e9', '\u01e9'), - ('\u01eb', '\u01eb'), ('\u01ed', '\u01ed'), - ('\u01ef', '\u01f0'), ('\u01f3', '\u01f3'), - ('\u01f5', '\u01f5'), ('\u01f9', '\u01f9'), - ('\u01fb', '\u01fb'), ('\u01fd', '\u01fd'), - ('\u01ff', '\u01ff'), ('\u0201', '\u0201'), - ('\u0203', '\u0203'), ('\u0205', '\u0205'), - ('\u0207', '\u0207'), ('\u0209', '\u0209'), - ('\u020b', '\u020b'), ('\u020d', '\u020d'), - ('\u020f', '\u020f'), ('\u0211', '\u0211'), - ('\u0213', '\u0213'), ('\u0215', '\u0215'), - ('\u0217', '\u0217'), ('\u0219', '\u0219'), - ('\u021b', '\u021b'), ('\u021d', '\u021d'), - ('\u021f', '\u021f'), ('\u0221', '\u0221'), - ('\u0223', '\u0223'), ('\u0225', '\u0225'), - ('\u0227', '\u0227'), ('\u0229', '\u0229'), - ('\u022b', '\u022b'), ('\u022d', '\u022d'), - ('\u022f', '\u022f'), ('\u0231', '\u0231'), - ('\u0233', '\u0239'), ('\u023c', '\u023c'), - ('\u023f', '\u0240'), ('\u0242', '\u0242'), - ('\u0247', '\u0247'), ('\u0249', '\u0249'), - ('\u024b', '\u024b'), ('\u024d', '\u024d'), - ('\u024f', '\u0293'), ('\u0295', '\u02af'), - ('\u0371', '\u0371'), ('\u0373', '\u0373'), - ('\u0377', '\u0377'), ('\u037b', '\u037d'), - ('\u0390', '\u0390'), ('\u03ac', '\u03ce'), - ('\u03d0', '\u03d1'), ('\u03d5', '\u03d7'), - ('\u03d9', '\u03d9'), ('\u03db', '\u03db'), - ('\u03dd', '\u03dd'), ('\u03df', '\u03df'), - ('\u03e1', '\u03e1'), ('\u03e3', '\u03e3'), - ('\u03e5', '\u03e5'), ('\u03e7', '\u03e7'), - ('\u03e9', '\u03e9'), ('\u03eb', '\u03eb'), - ('\u03ed', '\u03ed'), ('\u03ef', '\u03f3'), - ('\u03f5', '\u03f5'), ('\u03f8', '\u03f8'), - ('\u03fb', '\u03fc'), ('\u0430', '\u045f'), - ('\u0461', '\u0461'), ('\u0463', '\u0463'), - ('\u0465', '\u0465'), ('\u0467', '\u0467'), - ('\u0469', '\u0469'), ('\u046b', '\u046b'), - ('\u046d', '\u046d'), ('\u046f', '\u046f'), - ('\u0471', '\u0471'), ('\u0473', '\u0473'), - ('\u0475', '\u0475'), ('\u0477', '\u0477'), - ('\u0479', '\u0479'), ('\u047b', '\u047b'), - ('\u047d', '\u047d'), ('\u047f', '\u047f'), - ('\u0481', '\u0481'), ('\u048b', '\u048b'), - ('\u048d', '\u048d'), ('\u048f', '\u048f'), - ('\u0491', '\u0491'), ('\u0493', '\u0493'), - ('\u0495', '\u0495'), ('\u0497', '\u0497'), - ('\u0499', '\u0499'), ('\u049b', '\u049b'), - ('\u049d', '\u049d'), ('\u049f', '\u049f'), - ('\u04a1', '\u04a1'), ('\u04a3', '\u04a3'), - ('\u04a5', '\u04a5'), ('\u04a7', '\u04a7'), - ('\u04a9', '\u04a9'), ('\u04ab', '\u04ab'), - ('\u04ad', '\u04ad'), ('\u04af', '\u04af'), - ('\u04b1', '\u04b1'), ('\u04b3', '\u04b3'), - ('\u04b5', '\u04b5'), ('\u04b7', '\u04b7'), - ('\u04b9', '\u04b9'), ('\u04bb', '\u04bb'), - ('\u04bd', '\u04bd'), ('\u04bf', '\u04bf'), - ('\u04c2', '\u04c2'), ('\u04c4', '\u04c4'), - ('\u04c6', '\u04c6'), ('\u04c8', '\u04c8'), - ('\u04ca', '\u04ca'), ('\u04cc', '\u04cc'), - ('\u04ce', '\u04cf'), ('\u04d1', '\u04d1'), - ('\u04d3', '\u04d3'), ('\u04d5', '\u04d5'), - ('\u04d7', '\u04d7'), ('\u04d9', '\u04d9'), - ('\u04db', '\u04db'), ('\u04dd', '\u04dd'), - ('\u04df', '\u04df'), ('\u04e1', '\u04e1'), - ('\u04e3', '\u04e3'), ('\u04e5', '\u04e5'), - ('\u04e7', '\u04e7'), ('\u04e9', '\u04e9'), - ('\u04eb', '\u04eb'), ('\u04ed', '\u04ed'), - ('\u04ef', '\u04ef'), ('\u04f1', '\u04f1'), - ('\u04f3', '\u04f3'), ('\u04f5', '\u04f5'), - ('\u04f7', '\u04f7'), ('\u04f9', '\u04f9'), - ('\u04fb', '\u04fb'), ('\u04fd', '\u04fd'), - ('\u04ff', '\u04ff'), ('\u0501', '\u0501'), - ('\u0503', '\u0503'), ('\u0505', '\u0505'), - ('\u0507', '\u0507'), ('\u0509', '\u0509'), - ('\u050b', '\u050b'), ('\u050d', '\u050d'), - ('\u050f', '\u050f'), ('\u0511', '\u0511'), - ('\u0513', '\u0513'), ('\u0515', '\u0515'), - ('\u0517', '\u0517'), ('\u0519', '\u0519'), - ('\u051b', '\u051b'), ('\u051d', '\u051d'), - ('\u051f', '\u051f'), ('\u0521', '\u0521'), - ('\u0523', '\u0523'), ('\u0525', '\u0525'), - ('\u0527', '\u0527'), ('\u0561', '\u0587'), - ('\u1d00', '\u1d2b'), ('\u1d6b', '\u1d77'), - ('\u1d79', '\u1d9a'), ('\u1e01', '\u1e01'), - ('\u1e03', '\u1e03'), ('\u1e05', '\u1e05'), - ('\u1e07', '\u1e07'), ('\u1e09', '\u1e09'), - ('\u1e0b', '\u1e0b'), ('\u1e0d', '\u1e0d'), - ('\u1e0f', '\u1e0f'), ('\u1e11', '\u1e11'), - ('\u1e13', '\u1e13'), ('\u1e15', '\u1e15'), - ('\u1e17', '\u1e17'), ('\u1e19', '\u1e19'), - ('\u1e1b', '\u1e1b'), ('\u1e1d', '\u1e1d'), - ('\u1e1f', '\u1e1f'), ('\u1e21', '\u1e21'), - ('\u1e23', '\u1e23'), ('\u1e25', '\u1e25'), - ('\u1e27', '\u1e27'), ('\u1e29', '\u1e29'), - ('\u1e2b', '\u1e2b'), ('\u1e2d', '\u1e2d'), - ('\u1e2f', '\u1e2f'), ('\u1e31', '\u1e31'), - ('\u1e33', '\u1e33'), ('\u1e35', '\u1e35'), - ('\u1e37', '\u1e37'), ('\u1e39', '\u1e39'), - ('\u1e3b', '\u1e3b'), ('\u1e3d', '\u1e3d'), - ('\u1e3f', '\u1e3f'), ('\u1e41', '\u1e41'), - ('\u1e43', '\u1e43'), ('\u1e45', '\u1e45'), - ('\u1e47', '\u1e47'), ('\u1e49', '\u1e49'), - ('\u1e4b', '\u1e4b'), ('\u1e4d', '\u1e4d'), - ('\u1e4f', '\u1e4f'), ('\u1e51', '\u1e51'), - ('\u1e53', '\u1e53'), ('\u1e55', '\u1e55'), - ('\u1e57', '\u1e57'), ('\u1e59', '\u1e59'), - ('\u1e5b', '\u1e5b'), ('\u1e5d', '\u1e5d'), - ('\u1e5f', '\u1e5f'), ('\u1e61', '\u1e61'), - ('\u1e63', '\u1e63'), ('\u1e65', '\u1e65'), - ('\u1e67', '\u1e67'), ('\u1e69', '\u1e69'), - ('\u1e6b', '\u1e6b'), ('\u1e6d', '\u1e6d'), - ('\u1e6f', '\u1e6f'), ('\u1e71', '\u1e71'), - ('\u1e73', '\u1e73'), ('\u1e75', '\u1e75'), - ('\u1e77', '\u1e77'), ('\u1e79', '\u1e79'), - ('\u1e7b', '\u1e7b'), ('\u1e7d', '\u1e7d'), - ('\u1e7f', '\u1e7f'), ('\u1e81', '\u1e81'), - ('\u1e83', '\u1e83'), ('\u1e85', '\u1e85'), - ('\u1e87', '\u1e87'), ('\u1e89', '\u1e89'), - ('\u1e8b', '\u1e8b'), ('\u1e8d', '\u1e8d'), - ('\u1e8f', '\u1e8f'), ('\u1e91', '\u1e91'), - ('\u1e93', '\u1e93'), ('\u1e95', '\u1e9d'), - ('\u1e9f', '\u1e9f'), ('\u1ea1', '\u1ea1'), - ('\u1ea3', '\u1ea3'), ('\u1ea5', '\u1ea5'), - ('\u1ea7', '\u1ea7'), ('\u1ea9', '\u1ea9'), - ('\u1eab', '\u1eab'), ('\u1ead', '\u1ead'), - ('\u1eaf', '\u1eaf'), ('\u1eb1', '\u1eb1'), - ('\u1eb3', '\u1eb3'), ('\u1eb5', '\u1eb5'), - ('\u1eb7', '\u1eb7'), ('\u1eb9', '\u1eb9'), - ('\u1ebb', '\u1ebb'), ('\u1ebd', '\u1ebd'), - ('\u1ebf', '\u1ebf'), ('\u1ec1', '\u1ec1'), - ('\u1ec3', '\u1ec3'), ('\u1ec5', '\u1ec5'), - ('\u1ec7', '\u1ec7'), ('\u1ec9', '\u1ec9'), - ('\u1ecb', '\u1ecb'), ('\u1ecd', '\u1ecd'), - ('\u1ecf', '\u1ecf'), ('\u1ed1', '\u1ed1'), - ('\u1ed3', '\u1ed3'), ('\u1ed5', '\u1ed5'), - ('\u1ed7', '\u1ed7'), ('\u1ed9', '\u1ed9'), - ('\u1edb', '\u1edb'), ('\u1edd', '\u1edd'), - ('\u1edf', '\u1edf'), ('\u1ee1', '\u1ee1'), - ('\u1ee3', '\u1ee3'), ('\u1ee5', '\u1ee5'), - ('\u1ee7', '\u1ee7'), ('\u1ee9', '\u1ee9'), - ('\u1eeb', '\u1eeb'), ('\u1eed', '\u1eed'), - ('\u1eef', '\u1eef'), ('\u1ef1', '\u1ef1'), - ('\u1ef3', '\u1ef3'), ('\u1ef5', '\u1ef5'), - ('\u1ef7', '\u1ef7'), ('\u1ef9', '\u1ef9'), - ('\u1efb', '\u1efb'), ('\u1efd', '\u1efd'), - ('\u1eff', '\u1f07'), ('\u1f10', '\u1f15'), - ('\u1f20', '\u1f27'), ('\u1f30', '\u1f37'), - ('\u1f40', '\u1f45'), ('\u1f50', '\u1f57'), - ('\u1f60', '\u1f67'), ('\u1f70', '\u1f87'), - ('\u1f90', '\u1f97'), ('\u1fa0', '\u1fa7'), - ('\u1fb0', '\u1fb7'), ('\u1fbe', '\u1fbe'), - ('\u1fc2', '\u1fc7'), ('\u1fd0', '\u1fd7'), - ('\u1fe0', '\u1fe7'), ('\u1ff2', '\u1ff7'), - ('\u210a', '\u210a'), ('\u210e', '\u210f'), - ('\u2113', '\u2113'), ('\u212f', '\u212f'), - ('\u2134', '\u2134'), ('\u2139', '\u2139'), - ('\u213c', '\u213d'), ('\u2146', '\u2149'), - ('\u214e', '\u214e'), ('\u2184', '\u2184'), - ('\u2c30', '\u2c5e'), ('\u2c61', '\u2c61'), - ('\u2c65', '\u2c66'), ('\u2c68', '\u2c68'), - ('\u2c6a', '\u2c6a'), ('\u2c6c', '\u2c6c'), - ('\u2c71', '\u2c71'), ('\u2c73', '\u2c74'), - ('\u2c76', '\u2c7b'), ('\u2c81', '\u2c81'), - ('\u2c83', '\u2c83'), ('\u2c85', '\u2c85'), - ('\u2c87', '\u2c87'), ('\u2c89', '\u2c89'), - ('\u2c8b', '\u2c8b'), ('\u2c8d', '\u2c8d'), - ('\u2c8f', '\u2c8f'), ('\u2c91', '\u2c91'), - ('\u2c93', '\u2c93'), ('\u2c95', '\u2c95'), - ('\u2c97', '\u2c97'), ('\u2c99', '\u2c99'), - ('\u2c9b', '\u2c9b'), ('\u2c9d', '\u2c9d'), - ('\u2c9f', '\u2c9f'), ('\u2ca1', '\u2ca1'), - ('\u2ca3', '\u2ca3'), ('\u2ca5', '\u2ca5'), - ('\u2ca7', '\u2ca7'), ('\u2ca9', '\u2ca9'), - ('\u2cab', '\u2cab'), ('\u2cad', '\u2cad'), - ('\u2caf', '\u2caf'), ('\u2cb1', '\u2cb1'), - ('\u2cb3', '\u2cb3'), ('\u2cb5', '\u2cb5'), - ('\u2cb7', '\u2cb7'), ('\u2cb9', '\u2cb9'), - ('\u2cbb', '\u2cbb'), ('\u2cbd', '\u2cbd'), - ('\u2cbf', '\u2cbf'), ('\u2cc1', '\u2cc1'), - ('\u2cc3', '\u2cc3'), ('\u2cc5', '\u2cc5'), - ('\u2cc7', '\u2cc7'), ('\u2cc9', '\u2cc9'), - ('\u2ccb', '\u2ccb'), ('\u2ccd', '\u2ccd'), - ('\u2ccf', '\u2ccf'), ('\u2cd1', '\u2cd1'), - ('\u2cd3', '\u2cd3'), ('\u2cd5', '\u2cd5'), - ('\u2cd7', '\u2cd7'), ('\u2cd9', '\u2cd9'), - ('\u2cdb', '\u2cdb'), ('\u2cdd', '\u2cdd'), - ('\u2cdf', '\u2cdf'), ('\u2ce1', '\u2ce1'), - ('\u2ce3', '\u2ce4'), ('\u2cec', '\u2cec'), - ('\u2cee', '\u2cee'), ('\u2cf3', '\u2cf3'), - ('\u2d00', '\u2d2d'), ('\ua641', '\ua641'), - ('\ua643', '\ua643'), ('\ua645', '\ua645'), - ('\ua647', '\ua647'), ('\ua649', '\ua649'), - ('\ua64b', '\ua64b'), ('\ua64d', '\ua64d'), - ('\ua64f', '\ua64f'), ('\ua651', '\ua651'), - ('\ua653', '\ua653'), ('\ua655', '\ua655'), - ('\ua657', '\ua657'), ('\ua659', '\ua659'), - ('\ua65b', '\ua65b'), ('\ua65d', '\ua65d'), - ('\ua65f', '\ua65f'), ('\ua661', '\ua661'), - ('\ua663', '\ua663'), ('\ua665', '\ua665'), - ('\ua667', '\ua667'), ('\ua669', '\ua669'), - ('\ua66b', '\ua66b'), ('\ua66d', '\ua66d'), - ('\ua681', '\ua681'), ('\ua683', '\ua683'), - ('\ua685', '\ua685'), ('\ua687', '\ua687'), - ('\ua689', '\ua689'), ('\ua68b', '\ua68b'), - ('\ua68d', '\ua68d'), ('\ua68f', '\ua68f'), - ('\ua691', '\ua691'), ('\ua693', '\ua693'), - ('\ua695', '\ua695'), ('\ua697', '\ua697'), - ('\ua723', '\ua723'), ('\ua725', '\ua725'), - ('\ua727', '\ua727'), ('\ua729', '\ua729'), - ('\ua72b', '\ua72b'), ('\ua72d', '\ua72d'), - ('\ua72f', '\ua731'), ('\ua733', '\ua733'), - ('\ua735', '\ua735'), ('\ua737', '\ua737'), - ('\ua739', '\ua739'), ('\ua73b', '\ua73b'), - ('\ua73d', '\ua73d'), ('\ua73f', '\ua73f'), - ('\ua741', '\ua741'), ('\ua743', '\ua743'), - ('\ua745', '\ua745'), ('\ua747', '\ua747'), - ('\ua749', '\ua749'), ('\ua74b', '\ua74b'), - ('\ua74d', '\ua74d'), ('\ua74f', '\ua74f'), - ('\ua751', '\ua751'), ('\ua753', '\ua753'), - ('\ua755', '\ua755'), ('\ua757', '\ua757'), - ('\ua759', '\ua759'), ('\ua75b', '\ua75b'), - ('\ua75d', '\ua75d'), ('\ua75f', '\ua75f'), - ('\ua761', '\ua761'), ('\ua763', '\ua763'), - ('\ua765', '\ua765'), ('\ua767', '\ua767'), - ('\ua769', '\ua769'), ('\ua76b', '\ua76b'), - ('\ua76d', '\ua76d'), ('\ua76f', '\ua76f'), - ('\ua771', '\ua778'), ('\ua77a', '\ua77a'), - ('\ua77c', '\ua77c'), ('\ua77f', '\ua77f'), - ('\ua781', '\ua781'), ('\ua783', '\ua783'), - ('\ua785', '\ua785'), ('\ua787', '\ua787'), - ('\ua78c', '\ua78c'), ('\ua78e', '\ua78e'), - ('\ua791', '\ua791'), ('\ua793', '\ua793'), - ('\ua7a1', '\ua7a1'), ('\ua7a3', '\ua7a3'), - ('\ua7a5', '\ua7a5'), ('\ua7a7', '\ua7a7'), - ('\ua7a9', '\ua7a9'), ('\ua7fa', '\ua7fa'), - ('\ufb00', '\ufb17'), ('\uff41', '\uff5a'), - ('\U00010428', '\U0001044f'), ('\U0001d41a', '\U0001d433'), - ('\U0001d44e', '\U0001d467'), ('\U0001d482', '\U0001d49b'), - ('\U0001d4b6', '\U0001d4cf'), ('\U0001d4ea', '\U0001d503'), - ('\U0001d51e', '\U0001d537'), ('\U0001d552', '\U0001d56b'), - ('\U0001d586', '\U0001d59f'), ('\U0001d5ba', '\U0001d5d3'), - ('\U0001d5ee', '\U0001d607'), ('\U0001d622', '\U0001d63b'), - ('\U0001d656', '\U0001d66f'), ('\U0001d68a', '\U0001d6a5'), - ('\U0001d6c2', '\U0001d6da'), ('\U0001d6dc', '\U0001d6e1'), - ('\U0001d6fc', '\U0001d714'), ('\U0001d716', '\U0001d71b'), - ('\U0001d736', '\U0001d74e'), ('\U0001d750', '\U0001d755'), - ('\U0001d770', '\U0001d788'), ('\U0001d78a', '\U0001d78f'), - ('\U0001d7aa', '\U0001d7c2'), ('\U0001d7c4', '\U0001d7c9'), - ('\U0001d7cb', '\U0001d7cb') - ]; - - pub fn Ll(c: char) -> bool { - bsearch_range_table(c, Ll_table) - } - - static Lm_table : &'static [(char,char)] = &[ - ('\u02b0', '\u02c1'), ('\u02c6', '\u02d1'), - ('\u02e0', '\u02e4'), ('\u02ec', '\u02ec'), - ('\u02ee', '\u02ee'), ('\u0374', '\u0374'), - ('\u037a', '\u037a'), ('\u0559', '\u0559'), - ('\u0640', '\u0640'), ('\u06e5', '\u06e6'), - ('\u07f4', '\u07f5'), ('\u07fa', '\u07fa'), - ('\u081a', '\u081a'), ('\u0824', '\u0824'), - ('\u0828', '\u0828'), ('\u0971', '\u0971'), - ('\u0e46', '\u0e46'), ('\u0ec6', '\u0ec6'), - ('\u10fc', '\u10fc'), ('\u17d7', '\u17d7'), - ('\u1843', '\u1843'), ('\u1aa7', '\u1aa7'), - ('\u1c78', '\u1c7d'), ('\u1d2c', '\u1d6a'), - ('\u1d78', '\u1d78'), ('\u1d9b', '\u1dbf'), - ('\u2071', '\u2071'), ('\u207f', '\u207f'), - ('\u2090', '\u209c'), ('\u2c7c', '\u2c7d'), - ('\u2d6f', '\u2d6f'), ('\u2e2f', '\u2e2f'), - ('\u3005', '\u3005'), ('\u3031', '\u3035'), - ('\u303b', '\u303b'), ('\u309d', '\u309e'), - ('\u30fc', '\u30fe'), ('\ua015', '\ua015'), - ('\ua4f8', '\ua4fd'), ('\ua60c', '\ua60c'), - ('\ua67f', '\ua67f'), ('\ua717', '\ua71f'), - ('\ua770', '\ua770'), ('\ua788', '\ua788'), - ('\ua7f8', '\ua7f9'), ('\ua9cf', '\ua9cf'), - ('\uaa70', '\uaa70'), ('\uaadd', '\uaadd'), - ('\uaaf3', '\uaaf4'), ('\uff70', '\uff70'), - ('\uff9e', '\uff9f'), ('\U00016f93', '\U00016f9f') - ]; - - pub fn Lm(c: char) -> bool { - bsearch_range_table(c, Lm_table) - } - - static Lo_table : &'static [(char,char)] = &[ - ('\xaa', '\xaa'), ('\xba', '\xba'), - ('\u01bb', '\u01bb'), ('\u01c0', '\u01c3'), - ('\u0294', '\u0294'), ('\u05d0', '\u05f2'), - ('\u0620', '\u063f'), ('\u0641', '\u064a'), - ('\u066e', '\u066f'), ('\u0671', '\u06d3'), - ('\u06d5', '\u06d5'), ('\u06ee', '\u06ef'), - ('\u06fa', '\u06fc'), ('\u06ff', '\u06ff'), - ('\u0710', '\u0710'), ('\u0712', '\u072f'), - ('\u074d', '\u07a5'), ('\u07b1', '\u07b1'), - ('\u07ca', '\u07ea'), ('\u0800', '\u0815'), - ('\u0840', '\u0858'), ('\u08a0', '\u08ac'), - ('\u0904', '\u0939'), ('\u093d', '\u093d'), - ('\u0950', '\u0950'), ('\u0958', '\u0961'), - ('\u0972', '\u097f'), ('\u0985', '\u09b9'), - ('\u09bd', '\u09bd'), ('\u09ce', '\u09ce'), - ('\u09dc', '\u09e1'), ('\u09f0', '\u09f1'), - ('\u0a05', '\u0a39'), ('\u0a59', '\u0a5e'), - ('\u0a72', '\u0a74'), ('\u0a85', '\u0ab9'), - ('\u0abd', '\u0abd'), ('\u0ad0', '\u0ae1'), - ('\u0b05', '\u0b39'), ('\u0b3d', '\u0b3d'), - ('\u0b5c', '\u0b61'), ('\u0b71', '\u0b71'), - ('\u0b83', '\u0bb9'), ('\u0bd0', '\u0bd0'), - ('\u0c05', '\u0c3d'), ('\u0c58', '\u0c61'), - ('\u0c85', '\u0cb9'), ('\u0cbd', '\u0cbd'), - ('\u0cde', '\u0ce1'), ('\u0cf1', '\u0cf2'), - ('\u0d05', '\u0d3d'), ('\u0d4e', '\u0d4e'), - ('\u0d60', '\u0d61'), ('\u0d7a', '\u0d7f'), - ('\u0d85', '\u0dc6'), ('\u0e01', '\u0e30'), - ('\u0e32', '\u0e33'), ('\u0e40', '\u0e45'), - ('\u0e81', '\u0eb0'), ('\u0eb2', '\u0eb3'), - ('\u0ebd', '\u0ec4'), ('\u0edc', '\u0f00'), - ('\u0f40', '\u0f6c'), ('\u0f88', '\u0f8c'), - ('\u1000', '\u102a'), ('\u103f', '\u103f'), - ('\u1050', '\u1055'), ('\u105a', '\u105d'), - ('\u1061', '\u1061'), ('\u1065', '\u1066'), - ('\u106e', '\u1070'), ('\u1075', '\u1081'), - ('\u108e', '\u108e'), ('\u10d0', '\u10fa'), - ('\u10fd', '\u135a'), ('\u1380', '\u138f'), - ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), - ('\u166f', '\u167f'), ('\u1681', '\u169a'), - ('\u16a0', '\u16ea'), ('\u1700', '\u1711'), - ('\u1720', '\u1731'), ('\u1740', '\u1751'), - ('\u1760', '\u1770'), ('\u1780', '\u17b3'), - ('\u17dc', '\u17dc'), ('\u1820', '\u1842'), - ('\u1844', '\u18a8'), ('\u18aa', '\u191c'), - ('\u1950', '\u19ab'), ('\u19c1', '\u19c7'), - ('\u1a00', '\u1a16'), ('\u1a20', '\u1a54'), - ('\u1b05', '\u1b33'), ('\u1b45', '\u1b4b'), - ('\u1b83', '\u1ba0'), ('\u1bae', '\u1baf'), - ('\u1bba', '\u1be5'), ('\u1c00', '\u1c23'), - ('\u1c4d', '\u1c4f'), ('\u1c5a', '\u1c77'), - ('\u1ce9', '\u1cec'), ('\u1cee', '\u1cf1'), - ('\u1cf5', '\u1cf6'), ('\u2135', '\u2138'), - ('\u2d30', '\u2d67'), ('\u2d80', '\u2dde'), - ('\u3006', '\u3006'), ('\u303c', '\u303c'), - ('\u3041', '\u3096'), ('\u309f', '\u309f'), - ('\u30a1', '\u30fa'), ('\u30ff', '\u318e'), - ('\u31a0', '\u31ba'), ('\u31f0', '\u31ff'), - ('\u3400', '\u4db5'), ('\u4e00', '\ua014'), - ('\ua016', '\ua48c'), ('\ua4d0', '\ua4f7'), - ('\ua500', '\ua60b'), ('\ua610', '\ua61f'), - ('\ua62a', '\ua62b'), ('\ua66e', '\ua66e'), - ('\ua6a0', '\ua6e5'), ('\ua7fb', '\ua801'), - ('\ua803', '\ua805'), ('\ua807', '\ua80a'), - ('\ua80c', '\ua822'), ('\ua840', '\ua873'), - ('\ua882', '\ua8b3'), ('\ua8f2', '\ua8f7'), - ('\ua8fb', '\ua8fb'), ('\ua90a', '\ua925'), - ('\ua930', '\ua946'), ('\ua960', '\ua97c'), - ('\ua984', '\ua9b2'), ('\uaa00', '\uaa28'), - ('\uaa40', '\uaa42'), ('\uaa44', '\uaa4b'), - ('\uaa60', '\uaa6f'), ('\uaa71', '\uaa76'), - ('\uaa7a', '\uaa7a'), ('\uaa80', '\uaaaf'), - ('\uaab1', '\uaab1'), ('\uaab5', '\uaab6'), - ('\uaab9', '\uaabd'), ('\uaac0', '\uaac0'), - ('\uaac2', '\uaadc'), ('\uaae0', '\uaaea'), - ('\uaaf2', '\uaaf2'), ('\uab01', '\uabe2'), - ('\uac00', '\ud7fb'), ('\uf900', '\ufad9'), - ('\ufb1d', '\ufb1d'), ('\ufb1f', '\ufb28'), - ('\ufb2a', '\ufbb1'), ('\ufbd3', '\ufd3d'), - ('\ufd50', '\ufdfb'), ('\ufe70', '\ufefc'), - ('\uff66', '\uff6f'), ('\uff71', '\uff9d'), - ('\uffa0', '\uffdc'), ('\U00010000', '\U000100fa'), - ('\U00010280', '\U0001031e'), ('\U00010330', '\U00010340'), - ('\U00010342', '\U00010349'), ('\U00010380', '\U0001039d'), - ('\U000103a0', '\U000103cf'), ('\U00010450', '\U0001049d'), - ('\U00010800', '\U00010855'), ('\U00010900', '\U00010915'), - ('\U00010920', '\U00010939'), ('\U00010980', '\U00010a00'), - ('\U00010a10', '\U00010a33'), ('\U00010a60', '\U00010a7c'), - ('\U00010b00', '\U00010b35'), ('\U00010b40', '\U00010b55'), - ('\U00010b60', '\U00010b72'), ('\U00010c00', '\U00010c48'), - ('\U00011003', '\U00011037'), ('\U00011083', '\U000110af'), - ('\U000110d0', '\U000110e8'), ('\U00011103', '\U00011126'), - ('\U00011183', '\U000111b2'), ('\U000111c1', '\U000111c4'), - ('\U00011680', '\U000116aa'), ('\U00012000', '\U0001236e'), - ('\U00013000', '\U00016f50'), ('\U0001b000', '\U0001b001'), - ('\U0001ee00', '\U0001eebb'), ('\U00020000', '\U0002fa1d') - ]; - - pub fn Lo(c: char) -> bool { - bsearch_range_table(c, Lo_table) - } - - static Lt_table : &'static [(char,char)] = &[ - ('\u01c5', '\u01c5'), ('\u01c8', '\u01c8'), - ('\u01cb', '\u01cb'), ('\u01f2', '\u01f2'), - ('\u1f88', '\u1f8f'), ('\u1f98', '\u1f9f'), - ('\u1fa8', '\u1faf'), ('\u1fbc', '\u1fbc'), - ('\u1fcc', '\u1fcc'), ('\u1ffc', '\u1ffc') - ]; - - pub fn Lt(c: char) -> bool { - bsearch_range_table(c, Lt_table) - } - - static Lu_table : &'static [(char,char)] = &[ - ('\x41', '\x5a'), ('\xc0', '\xd6'), - ('\xd8', '\xde'), ('\u0100', '\u0100'), - ('\u0102', '\u0102'), ('\u0104', '\u0104'), - ('\u0106', '\u0106'), ('\u0108', '\u0108'), - ('\u010a', '\u010a'), ('\u010c', '\u010c'), - ('\u010e', '\u010e'), ('\u0110', '\u0110'), - ('\u0112', '\u0112'), ('\u0114', '\u0114'), - ('\u0116', '\u0116'), ('\u0118', '\u0118'), - ('\u011a', '\u011a'), ('\u011c', '\u011c'), - ('\u011e', '\u011e'), ('\u0120', '\u0120'), - ('\u0122', '\u0122'), ('\u0124', '\u0124'), - ('\u0126', '\u0126'), ('\u0128', '\u0128'), - ('\u012a', '\u012a'), ('\u012c', '\u012c'), - ('\u012e', '\u012e'), ('\u0130', '\u0130'), - ('\u0132', '\u0132'), ('\u0134', '\u0134'), - ('\u0136', '\u0136'), ('\u0139', '\u0139'), - ('\u013b', '\u013b'), ('\u013d', '\u013d'), - ('\u013f', '\u013f'), ('\u0141', '\u0141'), - ('\u0143', '\u0143'), ('\u0145', '\u0145'), - ('\u0147', '\u0147'), ('\u014a', '\u014a'), - ('\u014c', '\u014c'), ('\u014e', '\u014e'), - ('\u0150', '\u0150'), ('\u0152', '\u0152'), - ('\u0154', '\u0154'), ('\u0156', '\u0156'), - ('\u0158', '\u0158'), ('\u015a', '\u015a'), - ('\u015c', '\u015c'), ('\u015e', '\u015e'), - ('\u0160', '\u0160'), ('\u0162', '\u0162'), - ('\u0164', '\u0164'), ('\u0166', '\u0166'), - ('\u0168', '\u0168'), ('\u016a', '\u016a'), - ('\u016c', '\u016c'), ('\u016e', '\u016e'), - ('\u0170', '\u0170'), ('\u0172', '\u0172'), - ('\u0174', '\u0174'), ('\u0176', '\u0176'), - ('\u0178', '\u0179'), ('\u017b', '\u017b'), - ('\u017d', '\u017d'), ('\u0181', '\u0182'), - ('\u0184', '\u0184'), ('\u0186', '\u0187'), - ('\u0189', '\u018b'), ('\u018e', '\u0191'), - ('\u0193', '\u0194'), ('\u0196', '\u0198'), - ('\u019c', '\u019d'), ('\u019f', '\u01a0'), - ('\u01a2', '\u01a2'), ('\u01a4', '\u01a4'), - ('\u01a6', '\u01a7'), ('\u01a9', '\u01a9'), - ('\u01ac', '\u01ac'), ('\u01ae', '\u01af'), - ('\u01b1', '\u01b3'), ('\u01b5', '\u01b5'), - ('\u01b7', '\u01b8'), ('\u01bc', '\u01bc'), - ('\u01c4', '\u01c4'), ('\u01c7', '\u01c7'), - ('\u01ca', '\u01ca'), ('\u01cd', '\u01cd'), - ('\u01cf', '\u01cf'), ('\u01d1', '\u01d1'), - ('\u01d3', '\u01d3'), ('\u01d5', '\u01d5'), - ('\u01d7', '\u01d7'), ('\u01d9', '\u01d9'), - ('\u01db', '\u01db'), ('\u01de', '\u01de'), - ('\u01e0', '\u01e0'), ('\u01e2', '\u01e2'), - ('\u01e4', '\u01e4'), ('\u01e6', '\u01e6'), - ('\u01e8', '\u01e8'), ('\u01ea', '\u01ea'), - ('\u01ec', '\u01ec'), ('\u01ee', '\u01ee'), - ('\u01f1', '\u01f1'), ('\u01f4', '\u01f4'), - ('\u01f6', '\u01f8'), ('\u01fa', '\u01fa'), - ('\u01fc', '\u01fc'), ('\u01fe', '\u01fe'), - ('\u0200', '\u0200'), ('\u0202', '\u0202'), - ('\u0204', '\u0204'), ('\u0206', '\u0206'), - ('\u0208', '\u0208'), ('\u020a', '\u020a'), - ('\u020c', '\u020c'), ('\u020e', '\u020e'), - ('\u0210', '\u0210'), ('\u0212', '\u0212'), - ('\u0214', '\u0214'), ('\u0216', '\u0216'), - ('\u0218', '\u0218'), ('\u021a', '\u021a'), - ('\u021c', '\u021c'), ('\u021e', '\u021e'), - ('\u0220', '\u0220'), ('\u0222', '\u0222'), - ('\u0224', '\u0224'), ('\u0226', '\u0226'), - ('\u0228', '\u0228'), ('\u022a', '\u022a'), - ('\u022c', '\u022c'), ('\u022e', '\u022e'), - ('\u0230', '\u0230'), ('\u0232', '\u0232'), - ('\u023a', '\u023b'), ('\u023d', '\u023e'), - ('\u0241', '\u0241'), ('\u0243', '\u0246'), - ('\u0248', '\u0248'), ('\u024a', '\u024a'), - ('\u024c', '\u024c'), ('\u024e', '\u024e'), - ('\u0370', '\u0370'), ('\u0372', '\u0372'), - ('\u0376', '\u0376'), ('\u0386', '\u0386'), - ('\u0388', '\u038f'), ('\u0391', '\u03ab'), - ('\u03cf', '\u03cf'), ('\u03d2', '\u03d4'), - ('\u03d8', '\u03d8'), ('\u03da', '\u03da'), - ('\u03dc', '\u03dc'), ('\u03de', '\u03de'), - ('\u03e0', '\u03e0'), ('\u03e2', '\u03e2'), - ('\u03e4', '\u03e4'), ('\u03e6', '\u03e6'), - ('\u03e8', '\u03e8'), ('\u03ea', '\u03ea'), - ('\u03ec', '\u03ec'), ('\u03ee', '\u03ee'), - ('\u03f4', '\u03f4'), ('\u03f7', '\u03f7'), - ('\u03f9', '\u03fa'), ('\u03fd', '\u042f'), - ('\u0460', '\u0460'), ('\u0462', '\u0462'), - ('\u0464', '\u0464'), ('\u0466', '\u0466'), - ('\u0468', '\u0468'), ('\u046a', '\u046a'), - ('\u046c', '\u046c'), ('\u046e', '\u046e'), - ('\u0470', '\u0470'), ('\u0472', '\u0472'), - ('\u0474', '\u0474'), ('\u0476', '\u0476'), - ('\u0478', '\u0478'), ('\u047a', '\u047a'), - ('\u047c', '\u047c'), ('\u047e', '\u047e'), - ('\u0480', '\u0480'), ('\u048a', '\u048a'), - ('\u048c', '\u048c'), ('\u048e', '\u048e'), - ('\u0490', '\u0490'), ('\u0492', '\u0492'), - ('\u0494', '\u0494'), ('\u0496', '\u0496'), - ('\u0498', '\u0498'), ('\u049a', '\u049a'), - ('\u049c', '\u049c'), ('\u049e', '\u049e'), - ('\u04a0', '\u04a0'), ('\u04a2', '\u04a2'), - ('\u04a4', '\u04a4'), ('\u04a6', '\u04a6'), - ('\u04a8', '\u04a8'), ('\u04aa', '\u04aa'), - ('\u04ac', '\u04ac'), ('\u04ae', '\u04ae'), - ('\u04b0', '\u04b0'), ('\u04b2', '\u04b2'), - ('\u04b4', '\u04b4'), ('\u04b6', '\u04b6'), - ('\u04b8', '\u04b8'), ('\u04ba', '\u04ba'), - ('\u04bc', '\u04bc'), ('\u04be', '\u04be'), - ('\u04c0', '\u04c1'), ('\u04c3', '\u04c3'), - ('\u04c5', '\u04c5'), ('\u04c7', '\u04c7'), - ('\u04c9', '\u04c9'), ('\u04cb', '\u04cb'), - ('\u04cd', '\u04cd'), ('\u04d0', '\u04d0'), - ('\u04d2', '\u04d2'), ('\u04d4', '\u04d4'), - ('\u04d6', '\u04d6'), ('\u04d8', '\u04d8'), - ('\u04da', '\u04da'), ('\u04dc', '\u04dc'), - ('\u04de', '\u04de'), ('\u04e0', '\u04e0'), - ('\u04e2', '\u04e2'), ('\u04e4', '\u04e4'), - ('\u04e6', '\u04e6'), ('\u04e8', '\u04e8'), - ('\u04ea', '\u04ea'), ('\u04ec', '\u04ec'), - ('\u04ee', '\u04ee'), ('\u04f0', '\u04f0'), - ('\u04f2', '\u04f2'), ('\u04f4', '\u04f4'), - ('\u04f6', '\u04f6'), ('\u04f8', '\u04f8'), - ('\u04fa', '\u04fa'), ('\u04fc', '\u04fc'), - ('\u04fe', '\u04fe'), ('\u0500', '\u0500'), - ('\u0502', '\u0502'), ('\u0504', '\u0504'), - ('\u0506', '\u0506'), ('\u0508', '\u0508'), - ('\u050a', '\u050a'), ('\u050c', '\u050c'), - ('\u050e', '\u050e'), ('\u0510', '\u0510'), - ('\u0512', '\u0512'), ('\u0514', '\u0514'), - ('\u0516', '\u0516'), ('\u0518', '\u0518'), - ('\u051a', '\u051a'), ('\u051c', '\u051c'), - ('\u051e', '\u051e'), ('\u0520', '\u0520'), - ('\u0522', '\u0522'), ('\u0524', '\u0524'), - ('\u0526', '\u0526'), ('\u0531', '\u0556'), - ('\u10a0', '\u10cd'), ('\u1e00', '\u1e00'), - ('\u1e02', '\u1e02'), ('\u1e04', '\u1e04'), - ('\u1e06', '\u1e06'), ('\u1e08', '\u1e08'), - ('\u1e0a', '\u1e0a'), ('\u1e0c', '\u1e0c'), - ('\u1e0e', '\u1e0e'), ('\u1e10', '\u1e10'), - ('\u1e12', '\u1e12'), ('\u1e14', '\u1e14'), - ('\u1e16', '\u1e16'), ('\u1e18', '\u1e18'), - ('\u1e1a', '\u1e1a'), ('\u1e1c', '\u1e1c'), - ('\u1e1e', '\u1e1e'), ('\u1e20', '\u1e20'), - ('\u1e22', '\u1e22'), ('\u1e24', '\u1e24'), - ('\u1e26', '\u1e26'), ('\u1e28', '\u1e28'), - ('\u1e2a', '\u1e2a'), ('\u1e2c', '\u1e2c'), - ('\u1e2e', '\u1e2e'), ('\u1e30', '\u1e30'), - ('\u1e32', '\u1e32'), ('\u1e34', '\u1e34'), - ('\u1e36', '\u1e36'), ('\u1e38', '\u1e38'), - ('\u1e3a', '\u1e3a'), ('\u1e3c', '\u1e3c'), - ('\u1e3e', '\u1e3e'), ('\u1e40', '\u1e40'), - ('\u1e42', '\u1e42'), ('\u1e44', '\u1e44'), - ('\u1e46', '\u1e46'), ('\u1e48', '\u1e48'), - ('\u1e4a', '\u1e4a'), ('\u1e4c', '\u1e4c'), - ('\u1e4e', '\u1e4e'), ('\u1e50', '\u1e50'), - ('\u1e52', '\u1e52'), ('\u1e54', '\u1e54'), - ('\u1e56', '\u1e56'), ('\u1e58', '\u1e58'), - ('\u1e5a', '\u1e5a'), ('\u1e5c', '\u1e5c'), - ('\u1e5e', '\u1e5e'), ('\u1e60', '\u1e60'), - ('\u1e62', '\u1e62'), ('\u1e64', '\u1e64'), - ('\u1e66', '\u1e66'), ('\u1e68', '\u1e68'), - ('\u1e6a', '\u1e6a'), ('\u1e6c', '\u1e6c'), - ('\u1e6e', '\u1e6e'), ('\u1e70', '\u1e70'), - ('\u1e72', '\u1e72'), ('\u1e74', '\u1e74'), - ('\u1e76', '\u1e76'), ('\u1e78', '\u1e78'), - ('\u1e7a', '\u1e7a'), ('\u1e7c', '\u1e7c'), - ('\u1e7e', '\u1e7e'), ('\u1e80', '\u1e80'), - ('\u1e82', '\u1e82'), ('\u1e84', '\u1e84'), - ('\u1e86', '\u1e86'), ('\u1e88', '\u1e88'), - ('\u1e8a', '\u1e8a'), ('\u1e8c', '\u1e8c'), - ('\u1e8e', '\u1e8e'), ('\u1e90', '\u1e90'), - ('\u1e92', '\u1e92'), ('\u1e94', '\u1e94'), - ('\u1e9e', '\u1e9e'), ('\u1ea0', '\u1ea0'), - ('\u1ea2', '\u1ea2'), ('\u1ea4', '\u1ea4'), - ('\u1ea6', '\u1ea6'), ('\u1ea8', '\u1ea8'), - ('\u1eaa', '\u1eaa'), ('\u1eac', '\u1eac'), - ('\u1eae', '\u1eae'), ('\u1eb0', '\u1eb0'), - ('\u1eb2', '\u1eb2'), ('\u1eb4', '\u1eb4'), - ('\u1eb6', '\u1eb6'), ('\u1eb8', '\u1eb8'), - ('\u1eba', '\u1eba'), ('\u1ebc', '\u1ebc'), - ('\u1ebe', '\u1ebe'), ('\u1ec0', '\u1ec0'), - ('\u1ec2', '\u1ec2'), ('\u1ec4', '\u1ec4'), - ('\u1ec6', '\u1ec6'), ('\u1ec8', '\u1ec8'), - ('\u1eca', '\u1eca'), ('\u1ecc', '\u1ecc'), - ('\u1ece', '\u1ece'), ('\u1ed0', '\u1ed0'), - ('\u1ed2', '\u1ed2'), ('\u1ed4', '\u1ed4'), - ('\u1ed6', '\u1ed6'), ('\u1ed8', '\u1ed8'), - ('\u1eda', '\u1eda'), ('\u1edc', '\u1edc'), - ('\u1ede', '\u1ede'), ('\u1ee0', '\u1ee0'), - ('\u1ee2', '\u1ee2'), ('\u1ee4', '\u1ee4'), - ('\u1ee6', '\u1ee6'), ('\u1ee8', '\u1ee8'), - ('\u1eea', '\u1eea'), ('\u1eec', '\u1eec'), - ('\u1eee', '\u1eee'), ('\u1ef0', '\u1ef0'), - ('\u1ef2', '\u1ef2'), ('\u1ef4', '\u1ef4'), - ('\u1ef6', '\u1ef6'), ('\u1ef8', '\u1ef8'), - ('\u1efa', '\u1efa'), ('\u1efc', '\u1efc'), - ('\u1efe', '\u1efe'), ('\u1f08', '\u1f0f'), - ('\u1f18', '\u1f1d'), ('\u1f28', '\u1f2f'), - ('\u1f38', '\u1f3f'), ('\u1f48', '\u1f4d'), - ('\u1f59', '\u1f5f'), ('\u1f68', '\u1f6f'), - ('\u1fb8', '\u1fbb'), ('\u1fc8', '\u1fcb'), - ('\u1fd8', '\u1fdb'), ('\u1fe8', '\u1fec'), - ('\u1ff8', '\u1ffb'), ('\u2102', '\u2102'), - ('\u2107', '\u2107'), ('\u210b', '\u210d'), - ('\u2110', '\u2112'), ('\u2115', '\u2115'), - ('\u2119', '\u211d'), ('\u2124', '\u2124'), - ('\u2126', '\u2126'), ('\u2128', '\u2128'), - ('\u212a', '\u212d'), ('\u2130', '\u2133'), - ('\u213e', '\u213f'), ('\u2145', '\u2145'), - ('\u2183', '\u2183'), ('\u2c00', '\u2c2e'), - ('\u2c60', '\u2c60'), ('\u2c62', '\u2c64'), - ('\u2c67', '\u2c67'), ('\u2c69', '\u2c69'), - ('\u2c6b', '\u2c6b'), ('\u2c6d', '\u2c70'), - ('\u2c72', '\u2c72'), ('\u2c75', '\u2c75'), - ('\u2c7e', '\u2c80'), ('\u2c82', '\u2c82'), - ('\u2c84', '\u2c84'), ('\u2c86', '\u2c86'), - ('\u2c88', '\u2c88'), ('\u2c8a', '\u2c8a'), - ('\u2c8c', '\u2c8c'), ('\u2c8e', '\u2c8e'), - ('\u2c90', '\u2c90'), ('\u2c92', '\u2c92'), - ('\u2c94', '\u2c94'), ('\u2c96', '\u2c96'), - ('\u2c98', '\u2c98'), ('\u2c9a', '\u2c9a'), - ('\u2c9c', '\u2c9c'), ('\u2c9e', '\u2c9e'), - ('\u2ca0', '\u2ca0'), ('\u2ca2', '\u2ca2'), - ('\u2ca4', '\u2ca4'), ('\u2ca6', '\u2ca6'), - ('\u2ca8', '\u2ca8'), ('\u2caa', '\u2caa'), - ('\u2cac', '\u2cac'), ('\u2cae', '\u2cae'), - ('\u2cb0', '\u2cb0'), ('\u2cb2', '\u2cb2'), - ('\u2cb4', '\u2cb4'), ('\u2cb6', '\u2cb6'), - ('\u2cb8', '\u2cb8'), ('\u2cba', '\u2cba'), - ('\u2cbc', '\u2cbc'), ('\u2cbe', '\u2cbe'), - ('\u2cc0', '\u2cc0'), ('\u2cc2', '\u2cc2'), - ('\u2cc4', '\u2cc4'), ('\u2cc6', '\u2cc6'), - ('\u2cc8', '\u2cc8'), ('\u2cca', '\u2cca'), - ('\u2ccc', '\u2ccc'), ('\u2cce', '\u2cce'), - ('\u2cd0', '\u2cd0'), ('\u2cd2', '\u2cd2'), - ('\u2cd4', '\u2cd4'), ('\u2cd6', '\u2cd6'), - ('\u2cd8', '\u2cd8'), ('\u2cda', '\u2cda'), - ('\u2cdc', '\u2cdc'), ('\u2cde', '\u2cde'), - ('\u2ce0', '\u2ce0'), ('\u2ce2', '\u2ce2'), - ('\u2ceb', '\u2ceb'), ('\u2ced', '\u2ced'), - ('\u2cf2', '\u2cf2'), ('\ua640', '\ua640'), - ('\ua642', '\ua642'), ('\ua644', '\ua644'), - ('\ua646', '\ua646'), ('\ua648', '\ua648'), - ('\ua64a', '\ua64a'), ('\ua64c', '\ua64c'), - ('\ua64e', '\ua64e'), ('\ua650', '\ua650'), - ('\ua652', '\ua652'), ('\ua654', '\ua654'), - ('\ua656', '\ua656'), ('\ua658', '\ua658'), - ('\ua65a', '\ua65a'), ('\ua65c', '\ua65c'), - ('\ua65e', '\ua65e'), ('\ua660', '\ua660'), - ('\ua662', '\ua662'), ('\ua664', '\ua664'), - ('\ua666', '\ua666'), ('\ua668', '\ua668'), - ('\ua66a', '\ua66a'), ('\ua66c', '\ua66c'), - ('\ua680', '\ua680'), ('\ua682', '\ua682'), - ('\ua684', '\ua684'), ('\ua686', '\ua686'), - ('\ua688', '\ua688'), ('\ua68a', '\ua68a'), - ('\ua68c', '\ua68c'), ('\ua68e', '\ua68e'), - ('\ua690', '\ua690'), ('\ua692', '\ua692'), - ('\ua694', '\ua694'), ('\ua696', '\ua696'), - ('\ua722', '\ua722'), ('\ua724', '\ua724'), - ('\ua726', '\ua726'), ('\ua728', '\ua728'), - ('\ua72a', '\ua72a'), ('\ua72c', '\ua72c'), - ('\ua72e', '\ua72e'), ('\ua732', '\ua732'), - ('\ua734', '\ua734'), ('\ua736', '\ua736'), - ('\ua738', '\ua738'), ('\ua73a', '\ua73a'), - ('\ua73c', '\ua73c'), ('\ua73e', '\ua73e'), - ('\ua740', '\ua740'), ('\ua742', '\ua742'), - ('\ua744', '\ua744'), ('\ua746', '\ua746'), - ('\ua748', '\ua748'), ('\ua74a', '\ua74a'), - ('\ua74c', '\ua74c'), ('\ua74e', '\ua74e'), - ('\ua750', '\ua750'), ('\ua752', '\ua752'), - ('\ua754', '\ua754'), ('\ua756', '\ua756'), - ('\ua758', '\ua758'), ('\ua75a', '\ua75a'), - ('\ua75c', '\ua75c'), ('\ua75e', '\ua75e'), - ('\ua760', '\ua760'), ('\ua762', '\ua762'), - ('\ua764', '\ua764'), ('\ua766', '\ua766'), - ('\ua768', '\ua768'), ('\ua76a', '\ua76a'), - ('\ua76c', '\ua76c'), ('\ua76e', '\ua76e'), - ('\ua779', '\ua779'), ('\ua77b', '\ua77b'), - ('\ua77d', '\ua77e'), ('\ua780', '\ua780'), - ('\ua782', '\ua782'), ('\ua784', '\ua784'), - ('\ua786', '\ua786'), ('\ua78b', '\ua78b'), - ('\ua78d', '\ua78d'), ('\ua790', '\ua790'), - ('\ua792', '\ua792'), ('\ua7a0', '\ua7a0'), - ('\ua7a2', '\ua7a2'), ('\ua7a4', '\ua7a4'), - ('\ua7a6', '\ua7a6'), ('\ua7a8', '\ua7a8'), - ('\ua7aa', '\ua7aa'), ('\uff21', '\uff3a'), - ('\U00010400', '\U00010427'), ('\U0001d400', '\U0001d419'), - ('\U0001d434', '\U0001d44d'), ('\U0001d468', '\U0001d481'), - ('\U0001d49c', '\U0001d4b5'), ('\U0001d4d0', '\U0001d4e9'), - ('\U0001d504', '\U0001d51c'), ('\U0001d538', '\U0001d550'), - ('\U0001d56c', '\U0001d585'), ('\U0001d5a0', '\U0001d5b9'), - ('\U0001d5d4', '\U0001d5ed'), ('\U0001d608', '\U0001d621'), - ('\U0001d63c', '\U0001d655'), ('\U0001d670', '\U0001d689'), - ('\U0001d6a8', '\U0001d6c0'), ('\U0001d6e2', '\U0001d6fa'), - ('\U0001d71c', '\U0001d734'), ('\U0001d756', '\U0001d76e'), - ('\U0001d790', '\U0001d7a8'), ('\U0001d7ca', '\U0001d7ca') - ]; - - pub fn Lu(c: char) -> bool { - bsearch_range_table(c, Lu_table) - } - - static Mc_table : &'static [(char,char)] = &[ - ('\u0903', '\u0903'), ('\u093b', '\u093b'), - ('\u093e', '\u0940'), ('\u0949', '\u094c'), - ('\u094e', '\u094f'), ('\u0982', '\u0983'), - ('\u09be', '\u09c0'), ('\u09c7', '\u09cc'), - ('\u09d7', '\u09d7'), ('\u0a03', '\u0a03'), - ('\u0a3e', '\u0a40'), ('\u0a83', '\u0a83'), - ('\u0abe', '\u0ac0'), ('\u0ac9', '\u0acc'), - ('\u0b02', '\u0b03'), ('\u0b3e', '\u0b3e'), - ('\u0b40', '\u0b40'), ('\u0b47', '\u0b4c'), - ('\u0b57', '\u0b57'), ('\u0bbe', '\u0bbf'), - ('\u0bc1', '\u0bcc'), ('\u0bd7', '\u0bd7'), - ('\u0c01', '\u0c03'), ('\u0c41', '\u0c44'), - ('\u0c82', '\u0c83'), ('\u0cbe', '\u0cbe'), - ('\u0cc0', '\u0cc4'), ('\u0cc7', '\u0ccb'), - ('\u0cd5', '\u0cd6'), ('\u0d02', '\u0d03'), - ('\u0d3e', '\u0d40'), ('\u0d46', '\u0d4c'), - ('\u0d57', '\u0d57'), ('\u0d82', '\u0d83'), - ('\u0dcf', '\u0dd1'), ('\u0dd8', '\u0df3'), - ('\u0f3e', '\u0f3f'), ('\u0f7f', '\u0f7f'), - ('\u102b', '\u102c'), ('\u1031', '\u1031'), - ('\u1038', '\u1038'), ('\u103b', '\u103c'), - ('\u1056', '\u1057'), ('\u1062', '\u1064'), - ('\u1067', '\u106d'), ('\u1083', '\u1084'), - ('\u1087', '\u108c'), ('\u108f', '\u108f'), - ('\u109a', '\u109c'), ('\u17b6', '\u17b6'), - ('\u17be', '\u17c5'), ('\u17c7', '\u17c8'), - ('\u1923', '\u1926'), ('\u1929', '\u1931'), - ('\u1933', '\u1938'), ('\u19b0', '\u19c0'), - ('\u19c8', '\u19c9'), ('\u1a19', '\u1a1b'), - ('\u1a55', '\u1a55'), ('\u1a57', '\u1a57'), - ('\u1a61', '\u1a61'), ('\u1a63', '\u1a64'), - ('\u1a6d', '\u1a72'), ('\u1b04', '\u1b04'), - ('\u1b35', '\u1b35'), ('\u1b3b', '\u1b3b'), - ('\u1b3d', '\u1b41'), ('\u1b43', '\u1b44'), - ('\u1b82', '\u1b82'), ('\u1ba1', '\u1ba1'), - ('\u1ba6', '\u1ba7'), ('\u1baa', '\u1baa'), - ('\u1bac', '\u1bad'), ('\u1be7', '\u1be7'), - ('\u1bea', '\u1bec'), ('\u1bee', '\u1bee'), - ('\u1bf2', '\u1bf3'), ('\u1c24', '\u1c2b'), - ('\u1c34', '\u1c35'), ('\u1ce1', '\u1ce1'), - ('\u1cf2', '\u1cf3'), ('\u302e', '\u302f'), - ('\ua823', '\ua824'), ('\ua827', '\ua827'), - ('\ua880', '\ua881'), ('\ua8b4', '\ua8c3'), - ('\ua952', '\ua953'), ('\ua983', '\ua983'), - ('\ua9b4', '\ua9b5'), ('\ua9ba', '\ua9bb'), - ('\ua9bd', '\ua9c0'), ('\uaa2f', '\uaa30'), - ('\uaa33', '\uaa34'), ('\uaa4d', '\uaa4d'), - ('\uaa7b', '\uaa7b'), ('\uaaeb', '\uaaeb'), - ('\uaaee', '\uaaef'), ('\uaaf5', '\uaaf5'), - ('\uabe3', '\uabe4'), ('\uabe6', '\uabe7'), - ('\uabe9', '\uabea'), ('\uabec', '\uabec'), - ('\U00011000', '\U00011000'), ('\U00011002', '\U00011002'), - ('\U00011082', '\U00011082'), ('\U000110b0', '\U000110b2'), - ('\U000110b7', '\U000110b8'), ('\U0001112c', '\U0001112c'), - ('\U00011182', '\U00011182'), ('\U000111b3', '\U000111b5'), - ('\U000111bf', '\U000111c0'), ('\U000116ac', '\U000116ac'), - ('\U000116ae', '\U000116af'), ('\U000116b6', '\U000116b6'), - ('\U00016f51', '\U00016f7e'), ('\U0001d165', '\U0001d166'), - ('\U0001d16d', '\U0001d172') - ]; - - pub fn Mc(c: char) -> bool { - bsearch_range_table(c, Mc_table) - } - - static Me_table : &'static [(char,char)] = &[ - ('\u0488', '\u0489'), ('\u20dd', '\u20e0'), - ('\u20e2', '\u20e4'), ('\ua670', '\ua672') - ]; - - pub fn Me(c: char) -> bool { - bsearch_range_table(c, Me_table) - } - - static Mn_table : &'static [(char,char)] = &[ - ('\u0300', '\u036f'), ('\u0483', '\u0487'), - ('\u0591', '\u05bd'), ('\u05bf', '\u05bf'), - ('\u05c1', '\u05c2'), ('\u05c4', '\u05c5'), - ('\u05c7', '\u05c7'), ('\u0610', '\u061a'), - ('\u064b', '\u065f'), ('\u0670', '\u0670'), - ('\u06d6', '\u06dc'), ('\u06df', '\u06e4'), - ('\u06e7', '\u06e8'), ('\u06ea', '\u06ed'), - ('\u0711', '\u0711'), ('\u0730', '\u074a'), - ('\u07a6', '\u07b0'), ('\u07eb', '\u07f3'), - ('\u0816', '\u0819'), ('\u081b', '\u0823'), - ('\u0825', '\u0827'), ('\u0829', '\u082d'), - ('\u0859', '\u085b'), ('\u08e4', '\u0902'), - ('\u093a', '\u093a'), ('\u093c', '\u093c'), - ('\u0941', '\u0948'), ('\u094d', '\u094d'), - ('\u0951', '\u0957'), ('\u0962', '\u0963'), - ('\u0981', '\u0981'), ('\u09bc', '\u09bc'), - ('\u09c1', '\u09c4'), ('\u09cd', '\u09cd'), - ('\u09e2', '\u09e3'), ('\u0a01', '\u0a02'), - ('\u0a3c', '\u0a3c'), ('\u0a41', '\u0a51'), - ('\u0a70', '\u0a71'), ('\u0a75', '\u0a82'), - ('\u0abc', '\u0abc'), ('\u0ac1', '\u0ac8'), - ('\u0acd', '\u0acd'), ('\u0ae2', '\u0ae3'), - ('\u0b01', '\u0b01'), ('\u0b3c', '\u0b3c'), - ('\u0b3f', '\u0b3f'), ('\u0b41', '\u0b44'), - ('\u0b4d', '\u0b56'), ('\u0b62', '\u0b63'), - ('\u0b82', '\u0b82'), ('\u0bc0', '\u0bc0'), - ('\u0bcd', '\u0bcd'), ('\u0c3e', '\u0c40'), - ('\u0c46', '\u0c56'), ('\u0c62', '\u0c63'), - ('\u0cbc', '\u0cbc'), ('\u0cbf', '\u0cbf'), - ('\u0cc6', '\u0cc6'), ('\u0ccc', '\u0ccd'), - ('\u0ce2', '\u0ce3'), ('\u0d41', '\u0d44'), - ('\u0d4d', '\u0d4d'), ('\u0d62', '\u0d63'), - ('\u0dca', '\u0dca'), ('\u0dd2', '\u0dd6'), - ('\u0e31', '\u0e31'), ('\u0e34', '\u0e3a'), - ('\u0e47', '\u0e4e'), ('\u0eb1', '\u0eb1'), - ('\u0eb4', '\u0ebc'), ('\u0ec8', '\u0ecd'), - ('\u0f18', '\u0f19'), ('\u0f35', '\u0f35'), - ('\u0f37', '\u0f37'), ('\u0f39', '\u0f39'), - ('\u0f71', '\u0f7e'), ('\u0f80', '\u0f84'), - ('\u0f86', '\u0f87'), ('\u0f8d', '\u0fbc'), - ('\u0fc6', '\u0fc6'), ('\u102d', '\u1030'), - ('\u1032', '\u1037'), ('\u1039', '\u103a'), - ('\u103d', '\u103e'), ('\u1058', '\u1059'), - ('\u105e', '\u1060'), ('\u1071', '\u1074'), - ('\u1082', '\u1082'), ('\u1085', '\u1086'), - ('\u108d', '\u108d'), ('\u109d', '\u109d'), - ('\u135d', '\u135f'), ('\u1712', '\u1714'), - ('\u1732', '\u1734'), ('\u1752', '\u1753'), - ('\u1772', '\u1773'), ('\u17b4', '\u17b5'), - ('\u17b7', '\u17bd'), ('\u17c6', '\u17c6'), - ('\u17c9', '\u17d3'), ('\u17dd', '\u17dd'), - ('\u180b', '\u180d'), ('\u18a9', '\u18a9'), - ('\u1920', '\u1922'), ('\u1927', '\u1928'), - ('\u1932', '\u1932'), ('\u1939', '\u193b'), - ('\u1a17', '\u1a18'), ('\u1a56', '\u1a56'), - ('\u1a58', '\u1a60'), ('\u1a62', '\u1a62'), - ('\u1a65', '\u1a6c'), ('\u1a73', '\u1a7f'), - ('\u1b00', '\u1b03'), ('\u1b34', '\u1b34'), - ('\u1b36', '\u1b3a'), ('\u1b3c', '\u1b3c'), - ('\u1b42', '\u1b42'), ('\u1b6b', '\u1b73'), - ('\u1b80', '\u1b81'), ('\u1ba2', '\u1ba5'), - ('\u1ba8', '\u1ba9'), ('\u1bab', '\u1bab'), - ('\u1be6', '\u1be6'), ('\u1be8', '\u1be9'), - ('\u1bed', '\u1bed'), ('\u1bef', '\u1bf1'), - ('\u1c2c', '\u1c33'), ('\u1c36', '\u1c37'), - ('\u1cd0', '\u1cd2'), ('\u1cd4', '\u1ce0'), - ('\u1ce2', '\u1ce8'), ('\u1ced', '\u1ced'), - ('\u1cf4', '\u1cf4'), ('\u1dc0', '\u1dff'), - ('\u20d0', '\u20dc'), ('\u20e1', '\u20e1'), - ('\u20e5', '\u20f0'), ('\u2cef', '\u2cf1'), - ('\u2d7f', '\u2d7f'), ('\u2de0', '\u2dff'), - ('\u302a', '\u302d'), ('\u3099', '\u309a'), - ('\ua66f', '\ua66f'), ('\ua674', '\ua67d'), - ('\ua69f', '\ua69f'), ('\ua6f0', '\ua6f1'), - ('\ua802', '\ua802'), ('\ua806', '\ua806'), - ('\ua80b', '\ua80b'), ('\ua825', '\ua826'), - ('\ua8c4', '\ua8c4'), ('\ua8e0', '\ua8f1'), - ('\ua926', '\ua92d'), ('\ua947', '\ua951'), - ('\ua980', '\ua982'), ('\ua9b3', '\ua9b3'), - ('\ua9b6', '\ua9b9'), ('\ua9bc', '\ua9bc'), - ('\uaa29', '\uaa2e'), ('\uaa31', '\uaa32'), - ('\uaa35', '\uaa36'), ('\uaa43', '\uaa43'), - ('\uaa4c', '\uaa4c'), ('\uaab0', '\uaab0'), - ('\uaab2', '\uaab4'), ('\uaab7', '\uaab8'), - ('\uaabe', '\uaabf'), ('\uaac1', '\uaac1'), - ('\uaaec', '\uaaed'), ('\uaaf6', '\uaaf6'), - ('\uabe5', '\uabe5'), ('\uabe8', '\uabe8'), - ('\uabed', '\uabed'), ('\ufb1e', '\ufb1e'), - ('\ufe00', '\ufe0f'), ('\ufe20', '\ufe26'), - ('\U000101fd', '\U000101fd'), ('\U00010a01', '\U00010a0f'), - ('\U00010a38', '\U00010a3f'), ('\U00011001', '\U00011001'), - ('\U00011038', '\U00011046'), ('\U00011080', '\U00011081'), - ('\U000110b3', '\U000110b6'), ('\U000110b9', '\U000110ba'), - ('\U00011100', '\U00011102'), ('\U00011127', '\U0001112b'), - ('\U0001112d', '\U00011134'), ('\U00011180', '\U00011181'), - ('\U000111b6', '\U000111be'), ('\U000116ab', '\U000116ab'), - ('\U000116ad', '\U000116ad'), ('\U000116b0', '\U000116b5'), - ('\U000116b7', '\U000116b7'), ('\U00016f8f', '\U00016f92'), - ('\U0001d167', '\U0001d169'), ('\U0001d17b', '\U0001d182'), - ('\U0001d185', '\U0001d18b'), ('\U0001d1aa', '\U0001d1ad'), - ('\U0001d242', '\U0001d244'), ('\U000e0100', '\U000e01ef') - ]; - - pub fn Mn(c: char) -> bool { - bsearch_range_table(c, Mn_table) - } - - static Nd_table : &'static [(char,char)] = &[ - ('\x30', '\x39'), ('\u0660', '\u0669'), - ('\u06f0', '\u06f9'), ('\u07c0', '\u07c9'), - ('\u0966', '\u096f'), ('\u09e6', '\u09ef'), - ('\u0a66', '\u0a6f'), ('\u0ae6', '\u0aef'), - ('\u0b66', '\u0b6f'), ('\u0be6', '\u0bef'), - ('\u0c66', '\u0c6f'), ('\u0ce6', '\u0cef'), - ('\u0d66', '\u0d6f'), ('\u0e50', '\u0e59'), - ('\u0ed0', '\u0ed9'), ('\u0f20', '\u0f29'), - ('\u1040', '\u1049'), ('\u1090', '\u1099'), - ('\u17e0', '\u17e9'), ('\u1810', '\u1819'), - ('\u1946', '\u194f'), ('\u19d0', '\u19d9'), - ('\u1a80', '\u1a99'), ('\u1b50', '\u1b59'), - ('\u1bb0', '\u1bb9'), ('\u1c40', '\u1c49'), - ('\u1c50', '\u1c59'), ('\ua620', '\ua629'), - ('\ua8d0', '\ua8d9'), ('\ua900', '\ua909'), - ('\ua9d0', '\ua9d9'), ('\uaa50', '\uaa59'), - ('\uabf0', '\uabf9'), ('\uff10', '\uff19'), - ('\U000104a0', '\U000104a9'), ('\U00011066', '\U0001106f'), - ('\U000110f0', '\U000110f9'), ('\U00011136', '\U0001113f'), - ('\U000111d0', '\U000111d9'), ('\U000116c0', '\U000116c9'), - ('\U0001d7ce', '\U0001d7ff') - ]; - - pub fn Nd(c: char) -> bool { - bsearch_range_table(c, Nd_table) - } - - static Nl_table : &'static [(char,char)] = &[ - ('\u16ee', '\u16f0'), ('\u2160', '\u2182'), - ('\u2185', '\u2188'), ('\u3007', '\u3007'), - ('\u3021', '\u3029'), ('\u3038', '\u303a'), - ('\ua6e6', '\ua6ef'), ('\U00010140', '\U00010174'), - ('\U00010341', '\U00010341'), ('\U0001034a', '\U0001034a'), - ('\U000103d1', '\U000103d5'), ('\U00012400', '\U00012462') - ]; - - pub fn Nl(c: char) -> bool { - bsearch_range_table(c, Nl_table) - } - - static No_table : &'static [(char,char)] = &[ - ('\xb2', '\xb3'), ('\xb9', '\xb9'), - ('\xbc', '\xbe'), ('\u09f4', '\u09f9'), - ('\u0b72', '\u0b77'), ('\u0bf0', '\u0bf2'), - ('\u0c78', '\u0c7e'), ('\u0d70', '\u0d75'), - ('\u0f2a', '\u0f33'), ('\u1369', '\u137c'), - ('\u17f0', '\u17f9'), ('\u19da', '\u19da'), - ('\u2070', '\u2070'), ('\u2074', '\u2079'), - ('\u2080', '\u2089'), ('\u2150', '\u215f'), - ('\u2189', '\u2189'), ('\u2460', '\u249b'), - ('\u24ea', '\u24ff'), ('\u2776', '\u2793'), - ('\u2cfd', '\u2cfd'), ('\u3192', '\u3195'), - ('\u3220', '\u3229'), ('\u3248', '\u324f'), - ('\u3251', '\u325f'), ('\u3280', '\u3289'), - ('\u32b1', '\u32bf'), ('\ua830', '\ua835'), - ('\U00010107', '\U00010133'), ('\U00010175', '\U00010178'), - ('\U0001018a', '\U0001018a'), ('\U00010320', '\U00010323'), - ('\U00010858', '\U0001085f'), ('\U00010916', '\U0001091b'), - ('\U00010a40', '\U00010a47'), ('\U00010a7d', '\U00010a7e'), - ('\U00010b58', '\U00010b5f'), ('\U00010b78', '\U00010b7f'), - ('\U00010e60', '\U00010e7e'), ('\U00011052', '\U00011065'), - ('\U0001d360', '\U0001d371'), ('\U0001f100', '\U0001f10a') - ]; - - pub fn No(c: char) -> bool { - bsearch_range_table(c, No_table) - } - - static Pc_table : &'static [(char,char)] = &[ - ('\x5f', '\x5f'), ('\u203f', '\u2040'), - ('\u2054', '\u2054'), ('\ufe33', '\ufe34'), - ('\ufe4d', '\ufe4f'), ('\uff3f', '\uff3f') - ]; - - pub fn Pc(c: char) -> bool { - bsearch_range_table(c, Pc_table) - } - - static Pd_table : &'static [(char,char)] = &[ - ('\x2d', '\x2d'), ('\u058a', '\u058a'), - ('\u05be', '\u05be'), ('\u1400', '\u1400'), - ('\u1806', '\u1806'), ('\u2010', '\u2015'), - ('\u2e17', '\u2e17'), ('\u2e1a', '\u2e1a'), - ('\u2e3a', '\u2e3b'), ('\u301c', '\u301c'), - ('\u3030', '\u3030'), ('\u30a0', '\u30a0'), - ('\ufe31', '\ufe32'), ('\ufe58', '\ufe58'), - ('\ufe63', '\ufe63'), ('\uff0d', '\uff0d') - ]; - - pub fn Pd(c: char) -> bool { - bsearch_range_table(c, Pd_table) - } - - static Pe_table : &'static [(char,char)] = &[ - ('\x29', '\x29'), ('\x5d', '\x5d'), - ('\x7d', '\x7d'), ('\u0f3b', '\u0f3b'), - ('\u0f3d', '\u0f3d'), ('\u169c', '\u169c'), - ('\u2046', '\u2046'), ('\u207e', '\u207e'), - ('\u208e', '\u208e'), ('\u232a', '\u232a'), - ('\u2769', '\u2769'), ('\u276b', '\u276b'), - ('\u276d', '\u276d'), ('\u276f', '\u276f'), - ('\u2771', '\u2771'), ('\u2773', '\u2773'), - ('\u2775', '\u2775'), ('\u27c6', '\u27c6'), - ('\u27e7', '\u27e7'), ('\u27e9', '\u27e9'), - ('\u27eb', '\u27eb'), ('\u27ed', '\u27ed'), - ('\u27ef', '\u27ef'), ('\u2984', '\u2984'), - ('\u2986', '\u2986'), ('\u2988', '\u2988'), - ('\u298a', '\u298a'), ('\u298c', '\u298c'), - ('\u298e', '\u298e'), ('\u2990', '\u2990'), - ('\u2992', '\u2992'), ('\u2994', '\u2994'), - ('\u2996', '\u2996'), ('\u2998', '\u2998'), - ('\u29d9', '\u29d9'), ('\u29db', '\u29db'), - ('\u29fd', '\u29fd'), ('\u2e23', '\u2e23'), - ('\u2e25', '\u2e25'), ('\u2e27', '\u2e27'), - ('\u2e29', '\u2e29'), ('\u3009', '\u3009'), - ('\u300b', '\u300b'), ('\u300d', '\u300d'), - ('\u300f', '\u300f'), ('\u3011', '\u3011'), - ('\u3015', '\u3015'), ('\u3017', '\u3017'), - ('\u3019', '\u3019'), ('\u301b', '\u301b'), - ('\u301e', '\u301f'), ('\ufd3f', '\ufd3f'), - ('\ufe18', '\ufe18'), ('\ufe36', '\ufe36'), - ('\ufe38', '\ufe38'), ('\ufe3a', '\ufe3a'), - ('\ufe3c', '\ufe3c'), ('\ufe3e', '\ufe3e'), - ('\ufe40', '\ufe40'), ('\ufe42', '\ufe42'), - ('\ufe44', '\ufe44'), ('\ufe48', '\ufe48'), - ('\ufe5a', '\ufe5a'), ('\ufe5c', '\ufe5c'), - ('\ufe5e', '\ufe5e'), ('\uff09', '\uff09'), - ('\uff3d', '\uff3d'), ('\uff5d', '\uff5d'), - ('\uff60', '\uff60'), ('\uff63', '\uff63') - ]; - - pub fn Pe(c: char) -> bool { - bsearch_range_table(c, Pe_table) - } - - static Pf_table : &'static [(char,char)] = &[ - ('\xbb', '\xbb'), ('\u2019', '\u2019'), - ('\u201d', '\u201d'), ('\u203a', '\u203a'), - ('\u2e03', '\u2e03'), ('\u2e05', '\u2e05'), - ('\u2e0a', '\u2e0a'), ('\u2e0d', '\u2e0d'), - ('\u2e1d', '\u2e1d'), ('\u2e21', '\u2e21') - ]; - - pub fn Pf(c: char) -> bool { - bsearch_range_table(c, Pf_table) - } - - static Pi_table : &'static [(char,char)] = &[ - ('\xab', '\xab'), ('\u2018', '\u2018'), - ('\u201b', '\u201c'), ('\u201f', '\u201f'), - ('\u2039', '\u2039'), ('\u2e02', '\u2e02'), - ('\u2e04', '\u2e04'), ('\u2e09', '\u2e09'), - ('\u2e0c', '\u2e0c'), ('\u2e1c', '\u2e1c'), - ('\u2e20', '\u2e20') - ]; - - pub fn Pi(c: char) -> bool { - bsearch_range_table(c, Pi_table) - } - - static Po_table : &'static [(char,char)] = &[ - ('\x21', '\x23'), ('\x25', '\x27'), - ('\x2a', '\x2a'), ('\x2c', '\x2c'), - ('\x2e', '\x2f'), ('\x3a', '\x3b'), - ('\x3f', '\x40'), ('\x5c', '\x5c'), - ('\xa1', '\xa1'), ('\xa7', '\xa7'), - ('\xb6', '\xb7'), ('\xbf', '\xbf'), - ('\u037e', '\u037e'), ('\u0387', '\u0387'), - ('\u055a', '\u055f'), ('\u0589', '\u0589'), - ('\u05c0', '\u05c0'), ('\u05c3', '\u05c3'), - ('\u05c6', '\u05c6'), ('\u05f3', '\u05f4'), - ('\u0609', '\u060a'), ('\u060c', '\u060d'), - ('\u061b', '\u061f'), ('\u066a', '\u066d'), - ('\u06d4', '\u06d4'), ('\u0700', '\u070d'), - ('\u07f7', '\u07f9'), ('\u0830', '\u083e'), - ('\u085e', '\u085e'), ('\u0964', '\u0965'), - ('\u0970', '\u0970'), ('\u0af0', '\u0af0'), - ('\u0df4', '\u0df4'), ('\u0e4f', '\u0e4f'), - ('\u0e5a', '\u0e5b'), ('\u0f04', '\u0f12'), - ('\u0f14', '\u0f14'), ('\u0f85', '\u0f85'), - ('\u0fd0', '\u0fd4'), ('\u0fd9', '\u0fda'), - ('\u104a', '\u104f'), ('\u10fb', '\u10fb'), - ('\u1360', '\u1368'), ('\u166d', '\u166e'), - ('\u16eb', '\u16ed'), ('\u1735', '\u1736'), - ('\u17d4', '\u17d6'), ('\u17d8', '\u17da'), - ('\u1800', '\u1805'), ('\u1807', '\u180a'), - ('\u1944', '\u1945'), ('\u1a1e', '\u1a1f'), - ('\u1aa0', '\u1aa6'), ('\u1aa8', '\u1aad'), - ('\u1b5a', '\u1b60'), ('\u1bfc', '\u1bff'), - ('\u1c3b', '\u1c3f'), ('\u1c7e', '\u1cc7'), - ('\u1cd3', '\u1cd3'), ('\u2016', '\u2017'), - ('\u2020', '\u2027'), ('\u2030', '\u2038'), - ('\u203b', '\u203e'), ('\u2041', '\u2043'), - ('\u2047', '\u2051'), ('\u2053', '\u2053'), - ('\u2055', '\u205e'), ('\u2cf9', '\u2cfc'), - ('\u2cfe', '\u2cff'), ('\u2d70', '\u2d70'), - ('\u2e00', '\u2e01'), ('\u2e06', '\u2e08'), - ('\u2e0b', '\u2e0b'), ('\u2e0e', '\u2e16'), - ('\u2e18', '\u2e19'), ('\u2e1b', '\u2e1b'), - ('\u2e1e', '\u2e1f'), ('\u2e2a', '\u2e2e'), - ('\u2e30', '\u2e39'), ('\u3001', '\u3003'), - ('\u303d', '\u303d'), ('\u30fb', '\u30fb'), - ('\ua4fe', '\ua4ff'), ('\ua60d', '\ua60f'), - ('\ua673', '\ua673'), ('\ua67e', '\ua67e'), - ('\ua6f2', '\ua6f7'), ('\ua874', '\ua877'), - ('\ua8ce', '\ua8cf'), ('\ua8f8', '\ua8fa'), - ('\ua92e', '\ua92f'), ('\ua95f', '\ua95f'), - ('\ua9c1', '\ua9cd'), ('\ua9de', '\ua9df'), - ('\uaa5c', '\uaa5f'), ('\uaade', '\uaadf'), - ('\uaaf0', '\uaaf1'), ('\uabeb', '\uabeb'), - ('\ufe10', '\ufe16'), ('\ufe19', '\ufe19'), - ('\ufe30', '\ufe30'), ('\ufe45', '\ufe46'), - ('\ufe49', '\ufe4c'), ('\ufe50', '\ufe57'), - ('\ufe5f', '\ufe61'), ('\ufe68', '\ufe68'), - ('\ufe6a', '\ufe6b'), ('\uff01', '\uff03'), - ('\uff05', '\uff07'), ('\uff0a', '\uff0a'), - ('\uff0c', '\uff0c'), ('\uff0e', '\uff0f'), - ('\uff1a', '\uff1b'), ('\uff1f', '\uff20'), - ('\uff3c', '\uff3c'), ('\uff61', '\uff61'), - ('\uff64', '\uff65'), ('\U00010100', '\U00010102'), - ('\U0001039f', '\U0001039f'), ('\U000103d0', '\U000103d0'), - ('\U00010857', '\U00010857'), ('\U0001091f', '\U0001091f'), - ('\U0001093f', '\U0001093f'), ('\U00010a50', '\U00010a58'), - ('\U00010a7f', '\U00010a7f'), ('\U00010b39', '\U00010b3f'), - ('\U00011047', '\U0001104d'), ('\U000110bb', '\U000110bc'), - ('\U000110be', '\U000110c1'), ('\U00011140', '\U00011143'), - ('\U000111c5', '\U000111c8'), ('\U00012470', '\U00012473') - ]; - - pub fn Po(c: char) -> bool { - bsearch_range_table(c, Po_table) - } - - static Ps_table : &'static [(char,char)] = &[ - ('\x28', '\x28'), ('\x5b', '\x5b'), - ('\x7b', '\x7b'), ('\u0f3a', '\u0f3a'), - ('\u0f3c', '\u0f3c'), ('\u169b', '\u169b'), - ('\u201a', '\u201a'), ('\u201e', '\u201e'), - ('\u2045', '\u2045'), ('\u207d', '\u207d'), - ('\u208d', '\u208d'), ('\u2329', '\u2329'), - ('\u2768', '\u2768'), ('\u276a', '\u276a'), - ('\u276c', '\u276c'), ('\u276e', '\u276e'), - ('\u2770', '\u2770'), ('\u2772', '\u2772'), - ('\u2774', '\u2774'), ('\u27c5', '\u27c5'), - ('\u27e6', '\u27e6'), ('\u27e8', '\u27e8'), - ('\u27ea', '\u27ea'), ('\u27ec', '\u27ec'), - ('\u27ee', '\u27ee'), ('\u2983', '\u2983'), - ('\u2985', '\u2985'), ('\u2987', '\u2987'), - ('\u2989', '\u2989'), ('\u298b', '\u298b'), - ('\u298d', '\u298d'), ('\u298f', '\u298f'), - ('\u2991', '\u2991'), ('\u2993', '\u2993'), - ('\u2995', '\u2995'), ('\u2997', '\u2997'), - ('\u29d8', '\u29d8'), ('\u29da', '\u29da'), - ('\u29fc', '\u29fc'), ('\u2e22', '\u2e22'), - ('\u2e24', '\u2e24'), ('\u2e26', '\u2e26'), - ('\u2e28', '\u2e28'), ('\u3008', '\u3008'), - ('\u300a', '\u300a'), ('\u300c', '\u300c'), - ('\u300e', '\u300e'), ('\u3010', '\u3010'), - ('\u3014', '\u3014'), ('\u3016', '\u3016'), - ('\u3018', '\u3018'), ('\u301a', '\u301a'), - ('\u301d', '\u301d'), ('\ufd3e', '\ufd3e'), - ('\ufe17', '\ufe17'), ('\ufe35', '\ufe35'), - ('\ufe37', '\ufe37'), ('\ufe39', '\ufe39'), - ('\ufe3b', '\ufe3b'), ('\ufe3d', '\ufe3d'), - ('\ufe3f', '\ufe3f'), ('\ufe41', '\ufe41'), - ('\ufe43', '\ufe43'), ('\ufe47', '\ufe47'), - ('\ufe59', '\ufe59'), ('\ufe5b', '\ufe5b'), - ('\ufe5d', '\ufe5d'), ('\uff08', '\uff08'), - ('\uff3b', '\uff3b'), ('\uff5b', '\uff5b'), - ('\uff5f', '\uff5f'), ('\uff62', '\uff62') - ]; - - pub fn Ps(c: char) -> bool { - bsearch_range_table(c, Ps_table) - } - - static Sc_table : &'static [(char,char)] = &[ - ('\x24', '\x24'), ('\xa2', '\xa5'), - ('\u058f', '\u058f'), ('\u060b', '\u060b'), - ('\u09f2', '\u09f3'), ('\u09fb', '\u09fb'), - ('\u0af1', '\u0af1'), ('\u0bf9', '\u0bf9'), - ('\u0e3f', '\u0e3f'), ('\u17db', '\u17db'), - ('\u20a0', '\u20ba'), ('\ua838', '\ua838'), - ('\ufdfc', '\ufdfc'), ('\ufe69', '\ufe69'), - ('\uff04', '\uff04'), ('\uffe0', '\uffe1'), - ('\uffe5', '\uffe6') - ]; - - pub fn Sc(c: char) -> bool { - bsearch_range_table(c, Sc_table) - } - - static Sk_table : &'static [(char,char)] = &[ - ('\x5e', '\x5e'), ('\x60', '\x60'), - ('\xa8', '\xa8'), ('\xaf', '\xaf'), - ('\xb4', '\xb4'), ('\xb8', '\xb8'), - ('\u02c2', '\u02c5'), ('\u02d2', '\u02df'), - ('\u02e5', '\u02eb'), ('\u02ed', '\u02ed'), - ('\u02ef', '\u02ff'), ('\u0375', '\u0375'), - ('\u0384', '\u0385'), ('\u1fbd', '\u1fbd'), - ('\u1fbf', '\u1fc1'), ('\u1fcd', '\u1fcf'), - ('\u1fdd', '\u1fdf'), ('\u1fed', '\u1fef'), - ('\u1ffd', '\u1ffe'), ('\u309b', '\u309c'), - ('\ua700', '\ua716'), ('\ua720', '\ua721'), - ('\ua789', '\ua78a'), ('\ufbb2', '\ufbc1'), - ('\uff3e', '\uff3e'), ('\uff40', '\uff40'), - ('\uffe3', '\uffe3') - ]; - - pub fn Sk(c: char) -> bool { - bsearch_range_table(c, Sk_table) - } - - static Sm_table : &'static [(char,char)] = &[ - ('\x2b', '\x2b'), ('\x3c', '\x3e'), - ('\x7c', '\x7c'), ('\x7e', '\x7e'), - ('\xac', '\xac'), ('\xb1', '\xb1'), - ('\xd7', '\xd7'), ('\xf7', '\xf7'), - ('\u03f6', '\u03f6'), ('\u0606', '\u0608'), - ('\u2044', '\u2044'), ('\u2052', '\u2052'), - ('\u207a', '\u207c'), ('\u208a', '\u208c'), - ('\u2118', '\u2118'), ('\u2140', '\u2144'), - ('\u214b', '\u214b'), ('\u2190', '\u2194'), - ('\u219a', '\u219b'), ('\u21a0', '\u21a0'), - ('\u21a3', '\u21a3'), ('\u21a6', '\u21a6'), - ('\u21ae', '\u21ae'), ('\u21ce', '\u21cf'), - ('\u21d2', '\u21d2'), ('\u21d4', '\u21d4'), - ('\u21f4', '\u22ff'), ('\u2308', '\u230b'), - ('\u2320', '\u2321'), ('\u237c', '\u237c'), - ('\u239b', '\u23b3'), ('\u23dc', '\u23e1'), - ('\u25b7', '\u25b7'), ('\u25c1', '\u25c1'), - ('\u25f8', '\u25ff'), ('\u266f', '\u266f'), - ('\u27c0', '\u27c4'), ('\u27c7', '\u27e5'), - ('\u27f0', '\u27ff'), ('\u2900', '\u2982'), - ('\u2999', '\u29d7'), ('\u29dc', '\u29fb'), - ('\u29fe', '\u2aff'), ('\u2b30', '\u2b44'), - ('\u2b47', '\u2b4c'), ('\ufb29', '\ufb29'), - ('\ufe62', '\ufe62'), ('\ufe64', '\ufe66'), - ('\uff0b', '\uff0b'), ('\uff1c', '\uff1e'), - ('\uff5c', '\uff5c'), ('\uff5e', '\uff5e'), - ('\uffe2', '\uffe2'), ('\uffe9', '\uffec'), - ('\U0001d6c1', '\U0001d6c1'), ('\U0001d6db', '\U0001d6db'), - ('\U0001d6fb', '\U0001d6fb'), ('\U0001d715', '\U0001d715'), - ('\U0001d735', '\U0001d735'), ('\U0001d74f', '\U0001d74f'), - ('\U0001d76f', '\U0001d76f'), ('\U0001d789', '\U0001d789'), - ('\U0001d7a9', '\U0001d7a9'), ('\U0001d7c3', '\U0001d7c3'), - ('\U0001eef0', '\U0001eef1') - ]; - - pub fn Sm(c: char) -> bool { - bsearch_range_table(c, Sm_table) - } - - static So_table : &'static [(char,char)] = &[ - ('\xa6', '\xa6'), ('\xa9', '\xa9'), - ('\xae', '\xae'), ('\xb0', '\xb0'), - ('\u0482', '\u0482'), ('\u060e', '\u060f'), - ('\u06de', '\u06de'), ('\u06e9', '\u06e9'), - ('\u06fd', '\u06fe'), ('\u07f6', '\u07f6'), - ('\u09fa', '\u09fa'), ('\u0b70', '\u0b70'), - ('\u0bf3', '\u0bf8'), ('\u0bfa', '\u0bfa'), - ('\u0c7f', '\u0c7f'), ('\u0d79', '\u0d79'), - ('\u0f01', '\u0f03'), ('\u0f13', '\u0f13'), - ('\u0f15', '\u0f17'), ('\u0f1a', '\u0f1f'), - ('\u0f34', '\u0f34'), ('\u0f36', '\u0f36'), - ('\u0f38', '\u0f38'), ('\u0fbe', '\u0fc5'), - ('\u0fc7', '\u0fcf'), ('\u0fd5', '\u0fd8'), - ('\u109e', '\u109f'), ('\u1390', '\u1399'), - ('\u1940', '\u1940'), ('\u19de', '\u19ff'), - ('\u1b61', '\u1b6a'), ('\u1b74', '\u1b7c'), - ('\u2100', '\u2101'), ('\u2103', '\u2106'), - ('\u2108', '\u2109'), ('\u2114', '\u2114'), - ('\u2116', '\u2117'), ('\u211e', '\u2123'), - ('\u2125', '\u2125'), ('\u2127', '\u2127'), - ('\u2129', '\u2129'), ('\u212e', '\u212e'), - ('\u213a', '\u213b'), ('\u214a', '\u214a'), - ('\u214c', '\u214d'), ('\u214f', '\u214f'), - ('\u2195', '\u2199'), ('\u219c', '\u219f'), - ('\u21a1', '\u21a2'), ('\u21a4', '\u21a5'), - ('\u21a7', '\u21ad'), ('\u21af', '\u21cd'), - ('\u21d0', '\u21d1'), ('\u21d3', '\u21d3'), - ('\u21d5', '\u21f3'), ('\u2300', '\u2307'), - ('\u230c', '\u231f'), ('\u2322', '\u2328'), - ('\u232b', '\u237b'), ('\u237d', '\u239a'), - ('\u23b4', '\u23db'), ('\u23e2', '\u244a'), - ('\u249c', '\u24e9'), ('\u2500', '\u25b6'), - ('\u25b8', '\u25c0'), ('\u25c2', '\u25f7'), - ('\u2600', '\u266e'), ('\u2670', '\u2767'), - ('\u2794', '\u27bf'), ('\u2800', '\u28ff'), - ('\u2b00', '\u2b2f'), ('\u2b45', '\u2b46'), - ('\u2b50', '\u2b59'), ('\u2ce5', '\u2cea'), - ('\u2e80', '\u2ffb'), ('\u3004', '\u3004'), - ('\u3012', '\u3013'), ('\u3020', '\u3020'), - ('\u3036', '\u3037'), ('\u303e', '\u303f'), - ('\u3190', '\u3191'), ('\u3196', '\u319f'), - ('\u31c0', '\u31e3'), ('\u3200', '\u321e'), - ('\u322a', '\u3247'), ('\u3250', '\u3250'), - ('\u3260', '\u327f'), ('\u328a', '\u32b0'), - ('\u32c0', '\u33ff'), ('\u4dc0', '\u4dff'), - ('\ua490', '\ua4c6'), ('\ua828', '\ua82b'), - ('\ua836', '\ua837'), ('\ua839', '\ua839'), - ('\uaa77', '\uaa79'), ('\ufdfd', '\ufdfd'), - ('\uffe4', '\uffe4'), ('\uffe8', '\uffe8'), - ('\uffed', '\uffee'), ('\ufffc', '\ufffd'), - ('\U00010137', '\U0001013f'), ('\U00010179', '\U00010189'), - ('\U00010190', '\U000101fc'), ('\U0001d000', '\U0001d164'), - ('\U0001d16a', '\U0001d16c'), ('\U0001d183', '\U0001d184'), - ('\U0001d18c', '\U0001d1a9'), ('\U0001d1ae', '\U0001d241'), - ('\U0001d245', '\U0001d356'), ('\U0001f000', '\U0001f0df'), - ('\U0001f110', '\U0001f773') - ]; - - pub fn So(c: char) -> bool { - bsearch_range_table(c, So_table) - } - - static Zl_table : &'static [(char,char)] = &[ - ('\u2028', '\u2028') - ]; - - pub fn Zl(c: char) -> bool { - bsearch_range_table(c, Zl_table) - } - - static Zp_table : &'static [(char,char)] = &[ - ('\u2029', '\u2029') - ]; - - pub fn Zp(c: char) -> bool { - bsearch_range_table(c, Zp_table) - } - - static Zs_table : &'static [(char,char)] = &[ - ('\x20', '\x20'), ('\xa0', '\xa0'), - ('\u1680', '\u1680'), ('\u180e', '\u180e'), - ('\u2000', '\u200a'), ('\u202f', '\u202f'), - ('\u205f', '\u205f'), ('\u3000', '\u3000') - ]; - - pub fn Zs(c: char) -> bool { - bsearch_range_table(c, Zs_table) - } - -} - -pub mod derived_property { - fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { - use cmp::{Equal, Less, Greater}; - use vec::bsearch; - use option::None; - (do bsearch(r) |&(lo,hi)| { cond!( - (lo <= c && c <= hi) { Equal } - (hi < c) { Less } - _ { Greater } - )}) != None - } - - - static Alphabetic_table : &'static [(char,char)] = &[ - ('\x41', '\x5a'), ('\x61', '\x7a'), - ('\xaa', '\xaa'), ('\xb5', '\xb5'), - ('\xba', '\xba'), ('\xc0', '\xd6'), - ('\xd8', '\xf6'), ('\xf8', '\u01ba'), - ('\u01bb', '\u01bb'), ('\u01bc', '\u01bf'), - ('\u01c0', '\u01c3'), ('\u01c4', '\u0293'), - ('\u0294', '\u0294'), ('\u0295', '\u02af'), - ('\u02b0', '\u02c1'), ('\u02c6', '\u02d1'), - ('\u02e0', '\u02e4'), ('\u02ec', '\u02ec'), - ('\u02ee', '\u02ee'), ('\u0345', '\u0345'), - ('\u0370', '\u0373'), ('\u0374', '\u0374'), - ('\u0376', '\u0377'), ('\u037a', '\u037a'), - ('\u037b', '\u037d'), ('\u0386', '\u0386'), - ('\u0388', '\u038a'), ('\u038c', '\u038c'), - ('\u038e', '\u03a1'), ('\u03a3', '\u03f5'), - ('\u03f7', '\u0481'), ('\u048a', '\u0527'), - ('\u0531', '\u0556'), ('\u0559', '\u0559'), - ('\u0561', '\u0587'), ('\u05b0', '\u05bd'), - ('\u05bf', '\u05bf'), ('\u05c1', '\u05c2'), - ('\u05c4', '\u05c5'), ('\u05c7', '\u05c7'), - ('\u05d0', '\u05ea'), ('\u05f0', '\u05f2'), - ('\u0610', '\u061a'), ('\u0620', '\u063f'), - ('\u0640', '\u0640'), ('\u0641', '\u064a'), - ('\u064b', '\u0657'), ('\u0659', '\u065f'), - ('\u066e', '\u066f'), ('\u0670', '\u0670'), - ('\u0671', '\u06d3'), ('\u06d5', '\u06d5'), - ('\u06d6', '\u06dc'), ('\u06e1', '\u06e4'), - ('\u06e5', '\u06e6'), ('\u06e7', '\u06e8'), - ('\u06ed', '\u06ed'), ('\u06ee', '\u06ef'), - ('\u06fa', '\u06fc'), ('\u06ff', '\u06ff'), - ('\u0710', '\u0710'), ('\u0711', '\u0711'), - ('\u0712', '\u072f'), ('\u0730', '\u073f'), - ('\u074d', '\u07a5'), ('\u07a6', '\u07b0'), - ('\u07b1', '\u07b1'), ('\u07ca', '\u07ea'), - ('\u07f4', '\u07f5'), ('\u07fa', '\u07fa'), - ('\u0800', '\u0815'), ('\u0816', '\u0817'), - ('\u081a', '\u081a'), ('\u081b', '\u0823'), - ('\u0824', '\u0824'), ('\u0825', '\u0827'), - ('\u0828', '\u0828'), ('\u0829', '\u082c'), - ('\u0840', '\u0858'), ('\u08a0', '\u08a0'), - ('\u08a2', '\u08ac'), ('\u08e4', '\u08e9'), - ('\u08f0', '\u08fe'), ('\u0900', '\u0902'), - ('\u0903', '\u0903'), ('\u0904', '\u0939'), - ('\u093a', '\u093a'), ('\u093b', '\u093b'), - ('\u093d', '\u093d'), ('\u093e', '\u0940'), - ('\u0941', '\u0948'), ('\u0949', '\u094c'), - ('\u094e', '\u094f'), ('\u0950', '\u0950'), - ('\u0955', '\u0957'), ('\u0958', '\u0961'), - ('\u0962', '\u0963'), ('\u0971', '\u0971'), - ('\u0972', '\u0977'), ('\u0979', '\u097f'), - ('\u0981', '\u0981'), ('\u0982', '\u0983'), - ('\u0985', '\u098c'), ('\u098f', '\u0990'), - ('\u0993', '\u09a8'), ('\u09aa', '\u09b0'), - ('\u09b2', '\u09b2'), ('\u09b6', '\u09b9'), - ('\u09bd', '\u09bd'), ('\u09be', '\u09c0'), - ('\u09c1', '\u09c4'), ('\u09c7', '\u09c8'), - ('\u09cb', '\u09cc'), ('\u09ce', '\u09ce'), - ('\u09d7', '\u09d7'), ('\u09dc', '\u09dd'), - ('\u09df', '\u09e1'), ('\u09e2', '\u09e3'), - ('\u09f0', '\u09f1'), ('\u0a01', '\u0a02'), - ('\u0a03', '\u0a03'), ('\u0a05', '\u0a0a'), - ('\u0a0f', '\u0a10'), ('\u0a13', '\u0a28'), - ('\u0a2a', '\u0a30'), ('\u0a32', '\u0a33'), - ('\u0a35', '\u0a36'), ('\u0a38', '\u0a39'), - ('\u0a3e', '\u0a40'), ('\u0a41', '\u0a42'), - ('\u0a47', '\u0a48'), ('\u0a4b', '\u0a4c'), - ('\u0a51', '\u0a51'), ('\u0a59', '\u0a5c'), - ('\u0a5e', '\u0a5e'), ('\u0a70', '\u0a71'), - ('\u0a72', '\u0a74'), ('\u0a75', '\u0a75'), - ('\u0a81', '\u0a82'), ('\u0a83', '\u0a83'), - ('\u0a85', '\u0a8d'), ('\u0a8f', '\u0a91'), - ('\u0a93', '\u0aa8'), ('\u0aaa', '\u0ab0'), - ('\u0ab2', '\u0ab3'), ('\u0ab5', '\u0ab9'), - ('\u0abd', '\u0abd'), ('\u0abe', '\u0ac0'), - ('\u0ac1', '\u0ac5'), ('\u0ac7', '\u0ac8'), - ('\u0ac9', '\u0ac9'), ('\u0acb', '\u0acc'), - ('\u0ad0', '\u0ad0'), ('\u0ae0', '\u0ae1'), - ('\u0ae2', '\u0ae3'), ('\u0b01', '\u0b01'), - ('\u0b02', '\u0b03'), ('\u0b05', '\u0b0c'), - ('\u0b0f', '\u0b10'), ('\u0b13', '\u0b28'), - ('\u0b2a', '\u0b30'), ('\u0b32', '\u0b33'), - ('\u0b35', '\u0b39'), ('\u0b3d', '\u0b3d'), - ('\u0b3e', '\u0b3e'), ('\u0b3f', '\u0b3f'), - ('\u0b40', '\u0b40'), ('\u0b41', '\u0b44'), - ('\u0b47', '\u0b48'), ('\u0b4b', '\u0b4c'), - ('\u0b56', '\u0b56'), ('\u0b57', '\u0b57'), - ('\u0b5c', '\u0b5d'), ('\u0b5f', '\u0b61'), - ('\u0b62', '\u0b63'), ('\u0b71', '\u0b71'), - ('\u0b82', '\u0b82'), ('\u0b83', '\u0b83'), - ('\u0b85', '\u0b8a'), ('\u0b8e', '\u0b90'), - ('\u0b92', '\u0b95'), ('\u0b99', '\u0b9a'), - ('\u0b9c', '\u0b9c'), ('\u0b9e', '\u0b9f'), - ('\u0ba3', '\u0ba4'), ('\u0ba8', '\u0baa'), - ('\u0bae', '\u0bb9'), ('\u0bbe', '\u0bbf'), - ('\u0bc0', '\u0bc0'), ('\u0bc1', '\u0bc2'), - ('\u0bc6', '\u0bc8'), ('\u0bca', '\u0bcc'), - ('\u0bd0', '\u0bd0'), ('\u0bd7', '\u0bd7'), - ('\u0c01', '\u0c03'), ('\u0c05', '\u0c0c'), - ('\u0c0e', '\u0c10'), ('\u0c12', '\u0c28'), - ('\u0c2a', '\u0c33'), ('\u0c35', '\u0c39'), - ('\u0c3d', '\u0c3d'), ('\u0c3e', '\u0c40'), - ('\u0c41', '\u0c44'), ('\u0c46', '\u0c48'), - ('\u0c4a', '\u0c4c'), ('\u0c55', '\u0c56'), - ('\u0c58', '\u0c59'), ('\u0c60', '\u0c61'), - ('\u0c62', '\u0c63'), ('\u0c82', '\u0c83'), - ('\u0c85', '\u0c8c'), ('\u0c8e', '\u0c90'), - ('\u0c92', '\u0ca8'), ('\u0caa', '\u0cb3'), - ('\u0cb5', '\u0cb9'), ('\u0cbd', '\u0cbd'), - ('\u0cbe', '\u0cbe'), ('\u0cbf', '\u0cbf'), - ('\u0cc0', '\u0cc4'), ('\u0cc6', '\u0cc6'), - ('\u0cc7', '\u0cc8'), ('\u0cca', '\u0ccb'), - ('\u0ccc', '\u0ccc'), ('\u0cd5', '\u0cd6'), - ('\u0cde', '\u0cde'), ('\u0ce0', '\u0ce1'), - ('\u0ce2', '\u0ce3'), ('\u0cf1', '\u0cf2'), - ('\u0d02', '\u0d03'), ('\u0d05', '\u0d0c'), - ('\u0d0e', '\u0d10'), ('\u0d12', '\u0d3a'), - ('\u0d3d', '\u0d3d'), ('\u0d3e', '\u0d40'), - ('\u0d41', '\u0d44'), ('\u0d46', '\u0d48'), - ('\u0d4a', '\u0d4c'), ('\u0d4e', '\u0d4e'), - ('\u0d57', '\u0d57'), ('\u0d60', '\u0d61'), - ('\u0d62', '\u0d63'), ('\u0d7a', '\u0d7f'), - ('\u0d82', '\u0d83'), ('\u0d85', '\u0d96'), - ('\u0d9a', '\u0db1'), ('\u0db3', '\u0dbb'), - ('\u0dbd', '\u0dbd'), ('\u0dc0', '\u0dc6'), - ('\u0dcf', '\u0dd1'), ('\u0dd2', '\u0dd4'), - ('\u0dd6', '\u0dd6'), ('\u0dd8', '\u0ddf'), - ('\u0df2', '\u0df3'), ('\u0e01', '\u0e30'), - ('\u0e31', '\u0e31'), ('\u0e32', '\u0e33'), - ('\u0e34', '\u0e3a'), ('\u0e40', '\u0e45'), - ('\u0e46', '\u0e46'), ('\u0e4d', '\u0e4d'), - ('\u0e81', '\u0e82'), ('\u0e84', '\u0e84'), - ('\u0e87', '\u0e88'), ('\u0e8a', '\u0e8a'), - ('\u0e8d', '\u0e8d'), ('\u0e94', '\u0e97'), - ('\u0e99', '\u0e9f'), ('\u0ea1', '\u0ea3'), - ('\u0ea5', '\u0ea5'), ('\u0ea7', '\u0ea7'), - ('\u0eaa', '\u0eab'), ('\u0ead', '\u0eb0'), - ('\u0eb1', '\u0eb1'), ('\u0eb2', '\u0eb3'), - ('\u0eb4', '\u0eb9'), ('\u0ebb', '\u0ebc'), - ('\u0ebd', '\u0ebd'), ('\u0ec0', '\u0ec4'), - ('\u0ec6', '\u0ec6'), ('\u0ecd', '\u0ecd'), - ('\u0edc', '\u0edf'), ('\u0f00', '\u0f00'), - ('\u0f40', '\u0f47'), ('\u0f49', '\u0f6c'), - ('\u0f71', '\u0f7e'), ('\u0f7f', '\u0f7f'), - ('\u0f80', '\u0f81'), ('\u0f88', '\u0f8c'), - ('\u0f8d', '\u0f97'), ('\u0f99', '\u0fbc'), - ('\u1000', '\u102a'), ('\u102b', '\u102c'), - ('\u102d', '\u1030'), ('\u1031', '\u1031'), - ('\u1032', '\u1036'), ('\u1038', '\u1038'), - ('\u103b', '\u103c'), ('\u103d', '\u103e'), - ('\u103f', '\u103f'), ('\u1050', '\u1055'), - ('\u1056', '\u1057'), ('\u1058', '\u1059'), - ('\u105a', '\u105d'), ('\u105e', '\u1060'), - ('\u1061', '\u1061'), ('\u1062', '\u1062'), - ('\u1065', '\u1066'), ('\u1067', '\u1068'), - ('\u106e', '\u1070'), ('\u1071', '\u1074'), - ('\u1075', '\u1081'), ('\u1082', '\u1082'), - ('\u1083', '\u1084'), ('\u1085', '\u1086'), - ('\u108e', '\u108e'), ('\u109c', '\u109c'), - ('\u109d', '\u109d'), ('\u10a0', '\u10c5'), - ('\u10c7', '\u10c7'), ('\u10cd', '\u10cd'), - ('\u10d0', '\u10fa'), ('\u10fc', '\u10fc'), - ('\u10fd', '\u1248'), ('\u124a', '\u124d'), - ('\u1250', '\u1256'), ('\u1258', '\u1258'), - ('\u125a', '\u125d'), ('\u1260', '\u1288'), - ('\u128a', '\u128d'), ('\u1290', '\u12b0'), - ('\u12b2', '\u12b5'), ('\u12b8', '\u12be'), - ('\u12c0', '\u12c0'), ('\u12c2', '\u12c5'), - ('\u12c8', '\u12d6'), ('\u12d8', '\u1310'), - ('\u1312', '\u1315'), ('\u1318', '\u135a'), - ('\u135f', '\u135f'), ('\u1380', '\u138f'), - ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), - ('\u166f', '\u167f'), ('\u1681', '\u169a'), - ('\u16a0', '\u16ea'), ('\u16ee', '\u16f0'), - ('\u1700', '\u170c'), ('\u170e', '\u1711'), - ('\u1712', '\u1713'), ('\u1720', '\u1731'), - ('\u1732', '\u1733'), ('\u1740', '\u1751'), - ('\u1752', '\u1753'), ('\u1760', '\u176c'), - ('\u176e', '\u1770'), ('\u1772', '\u1773'), - ('\u1780', '\u17b3'), ('\u17b6', '\u17b6'), - ('\u17b7', '\u17bd'), ('\u17be', '\u17c5'), - ('\u17c6', '\u17c6'), ('\u17c7', '\u17c8'), - ('\u17d7', '\u17d7'), ('\u17dc', '\u17dc'), - ('\u1820', '\u1842'), ('\u1843', '\u1843'), - ('\u1844', '\u1877'), ('\u1880', '\u18a8'), - ('\u18a9', '\u18a9'), ('\u18aa', '\u18aa'), - ('\u18b0', '\u18f5'), ('\u1900', '\u191c'), - ('\u1920', '\u1922'), ('\u1923', '\u1926'), - ('\u1927', '\u1928'), ('\u1929', '\u192b'), - ('\u1930', '\u1931'), ('\u1932', '\u1932'), - ('\u1933', '\u1938'), ('\u1950', '\u196d'), - ('\u1970', '\u1974'), ('\u1980', '\u19ab'), - ('\u19b0', '\u19c0'), ('\u19c1', '\u19c7'), - ('\u19c8', '\u19c9'), ('\u1a00', '\u1a16'), - ('\u1a17', '\u1a18'), ('\u1a19', '\u1a1b'), - ('\u1a20', '\u1a54'), ('\u1a55', '\u1a55'), - ('\u1a56', '\u1a56'), ('\u1a57', '\u1a57'), - ('\u1a58', '\u1a5e'), ('\u1a61', '\u1a61'), - ('\u1a62', '\u1a62'), ('\u1a63', '\u1a64'), - ('\u1a65', '\u1a6c'), ('\u1a6d', '\u1a72'), - ('\u1a73', '\u1a74'), ('\u1aa7', '\u1aa7'), - ('\u1b00', '\u1b03'), ('\u1b04', '\u1b04'), - ('\u1b05', '\u1b33'), ('\u1b35', '\u1b35'), - ('\u1b36', '\u1b3a'), ('\u1b3b', '\u1b3b'), - ('\u1b3c', '\u1b3c'), ('\u1b3d', '\u1b41'), - ('\u1b42', '\u1b42'), ('\u1b43', '\u1b43'), - ('\u1b45', '\u1b4b'), ('\u1b80', '\u1b81'), - ('\u1b82', '\u1b82'), ('\u1b83', '\u1ba0'), - ('\u1ba1', '\u1ba1'), ('\u1ba2', '\u1ba5'), - ('\u1ba6', '\u1ba7'), ('\u1ba8', '\u1ba9'), - ('\u1bac', '\u1bad'), ('\u1bae', '\u1baf'), - ('\u1bba', '\u1be5'), ('\u1be7', '\u1be7'), - ('\u1be8', '\u1be9'), ('\u1bea', '\u1bec'), - ('\u1bed', '\u1bed'), ('\u1bee', '\u1bee'), - ('\u1bef', '\u1bf1'), ('\u1c00', '\u1c23'), - ('\u1c24', '\u1c2b'), ('\u1c2c', '\u1c33'), - ('\u1c34', '\u1c35'), ('\u1c4d', '\u1c4f'), - ('\u1c5a', '\u1c77'), ('\u1c78', '\u1c7d'), - ('\u1ce9', '\u1cec'), ('\u1cee', '\u1cf1'), - ('\u1cf2', '\u1cf3'), ('\u1cf5', '\u1cf6'), - ('\u1d00', '\u1d2b'), ('\u1d2c', '\u1d6a'), - ('\u1d6b', '\u1d77'), ('\u1d78', '\u1d78'), - ('\u1d79', '\u1d9a'), ('\u1d9b', '\u1dbf'), - ('\u1e00', '\u1f15'), ('\u1f18', '\u1f1d'), - ('\u1f20', '\u1f45'), ('\u1f48', '\u1f4d'), - ('\u1f50', '\u1f57'), ('\u1f59', '\u1f59'), - ('\u1f5b', '\u1f5b'), ('\u1f5d', '\u1f5d'), - ('\u1f5f', '\u1f7d'), ('\u1f80', '\u1fb4'), - ('\u1fb6', '\u1fbc'), ('\u1fbe', '\u1fbe'), - ('\u1fc2', '\u1fc4'), ('\u1fc6', '\u1fcc'), - ('\u1fd0', '\u1fd3'), ('\u1fd6', '\u1fdb'), - ('\u1fe0', '\u1fec'), ('\u1ff2', '\u1ff4'), - ('\u1ff6', '\u1ffc'), ('\u2071', '\u2071'), - ('\u207f', '\u207f'), ('\u2090', '\u209c'), - ('\u2102', '\u2102'), ('\u2107', '\u2107'), - ('\u210a', '\u2113'), ('\u2115', '\u2115'), - ('\u2119', '\u211d'), ('\u2124', '\u2124'), - ('\u2126', '\u2126'), ('\u2128', '\u2128'), - ('\u212a', '\u212d'), ('\u212f', '\u2134'), - ('\u2135', '\u2138'), ('\u2139', '\u2139'), - ('\u213c', '\u213f'), ('\u2145', '\u2149'), - ('\u214e', '\u214e'), ('\u2160', '\u2182'), - ('\u2183', '\u2184'), ('\u2185', '\u2188'), - ('\u24b6', '\u24e9'), ('\u2c00', '\u2c2e'), - ('\u2c30', '\u2c5e'), ('\u2c60', '\u2c7b'), - ('\u2c7c', '\u2c7d'), ('\u2c7e', '\u2ce4'), - ('\u2ceb', '\u2cee'), ('\u2cf2', '\u2cf3'), - ('\u2d00', '\u2d25'), ('\u2d27', '\u2d27'), - ('\u2d2d', '\u2d2d'), ('\u2d30', '\u2d67'), - ('\u2d6f', '\u2d6f'), ('\u2d80', '\u2d96'), - ('\u2da0', '\u2da6'), ('\u2da8', '\u2dae'), - ('\u2db0', '\u2db6'), ('\u2db8', '\u2dbe'), - ('\u2dc0', '\u2dc6'), ('\u2dc8', '\u2dce'), - ('\u2dd0', '\u2dd6'), ('\u2dd8', '\u2dde'), - ('\u2de0', '\u2dff'), ('\u2e2f', '\u2e2f'), - ('\u3005', '\u3005'), ('\u3006', '\u3006'), - ('\u3007', '\u3007'), ('\u3021', '\u3029'), - ('\u3031', '\u3035'), ('\u3038', '\u303a'), - ('\u303b', '\u303b'), ('\u303c', '\u303c'), - ('\u3041', '\u3096'), ('\u309d', '\u309e'), - ('\u309f', '\u309f'), ('\u30a1', '\u30fa'), - ('\u30fc', '\u30fe'), ('\u30ff', '\u30ff'), - ('\u3105', '\u312d'), ('\u3131', '\u318e'), - ('\u31a0', '\u31ba'), ('\u31f0', '\u31ff'), - ('\u3400', '\u4db5'), ('\u4e00', '\u9fcc'), - ('\ua000', '\ua014'), ('\ua015', '\ua015'), - ('\ua016', '\ua48c'), ('\ua4d0', '\ua4f7'), - ('\ua4f8', '\ua4fd'), ('\ua500', '\ua60b'), - ('\ua60c', '\ua60c'), ('\ua610', '\ua61f'), - ('\ua62a', '\ua62b'), ('\ua640', '\ua66d'), - ('\ua66e', '\ua66e'), ('\ua674', '\ua67b'), - ('\ua67f', '\ua67f'), ('\ua680', '\ua697'), - ('\ua69f', '\ua69f'), ('\ua6a0', '\ua6e5'), - ('\ua6e6', '\ua6ef'), ('\ua717', '\ua71f'), - ('\ua722', '\ua76f'), ('\ua770', '\ua770'), - ('\ua771', '\ua787'), ('\ua788', '\ua788'), - ('\ua78b', '\ua78e'), ('\ua790', '\ua793'), - ('\ua7a0', '\ua7aa'), ('\ua7f8', '\ua7f9'), - ('\ua7fa', '\ua7fa'), ('\ua7fb', '\ua801'), - ('\ua803', '\ua805'), ('\ua807', '\ua80a'), - ('\ua80c', '\ua822'), ('\ua823', '\ua824'), - ('\ua825', '\ua826'), ('\ua827', '\ua827'), - ('\ua840', '\ua873'), ('\ua880', '\ua881'), - ('\ua882', '\ua8b3'), ('\ua8b4', '\ua8c3'), - ('\ua8f2', '\ua8f7'), ('\ua8fb', '\ua8fb'), - ('\ua90a', '\ua925'), ('\ua926', '\ua92a'), - ('\ua930', '\ua946'), ('\ua947', '\ua951'), - ('\ua952', '\ua952'), ('\ua960', '\ua97c'), - ('\ua980', '\ua982'), ('\ua983', '\ua983'), - ('\ua984', '\ua9b2'), ('\ua9b4', '\ua9b5'), - ('\ua9b6', '\ua9b9'), ('\ua9ba', '\ua9bb'), - ('\ua9bc', '\ua9bc'), ('\ua9bd', '\ua9bf'), - ('\ua9cf', '\ua9cf'), ('\uaa00', '\uaa28'), - ('\uaa29', '\uaa2e'), ('\uaa2f', '\uaa30'), - ('\uaa31', '\uaa32'), ('\uaa33', '\uaa34'), - ('\uaa35', '\uaa36'), ('\uaa40', '\uaa42'), - ('\uaa43', '\uaa43'), ('\uaa44', '\uaa4b'), - ('\uaa4c', '\uaa4c'), ('\uaa4d', '\uaa4d'), - ('\uaa60', '\uaa6f'), ('\uaa70', '\uaa70'), - ('\uaa71', '\uaa76'), ('\uaa7a', '\uaa7a'), - ('\uaa80', '\uaaaf'), ('\uaab0', '\uaab0'), - ('\uaab1', '\uaab1'), ('\uaab2', '\uaab4'), - ('\uaab5', '\uaab6'), ('\uaab7', '\uaab8'), - ('\uaab9', '\uaabd'), ('\uaabe', '\uaabe'), - ('\uaac0', '\uaac0'), ('\uaac2', '\uaac2'), - ('\uaadb', '\uaadc'), ('\uaadd', '\uaadd'), - ('\uaae0', '\uaaea'), ('\uaaeb', '\uaaeb'), - ('\uaaec', '\uaaed'), ('\uaaee', '\uaaef'), - ('\uaaf2', '\uaaf2'), ('\uaaf3', '\uaaf4'), - ('\uaaf5', '\uaaf5'), ('\uab01', '\uab06'), - ('\uab09', '\uab0e'), ('\uab11', '\uab16'), - ('\uab20', '\uab26'), ('\uab28', '\uab2e'), - ('\uabc0', '\uabe2'), ('\uabe3', '\uabe4'), - ('\uabe5', '\uabe5'), ('\uabe6', '\uabe7'), - ('\uabe8', '\uabe8'), ('\uabe9', '\uabea'), - ('\uac00', '\ud7a3'), ('\ud7b0', '\ud7c6'), - ('\ud7cb', '\ud7fb'), ('\uf900', '\ufa6d'), - ('\ufa70', '\ufad9'), ('\ufb00', '\ufb06'), - ('\ufb13', '\ufb17'), ('\ufb1d', '\ufb1d'), - ('\ufb1e', '\ufb1e'), ('\ufb1f', '\ufb28'), - ('\ufb2a', '\ufb36'), ('\ufb38', '\ufb3c'), - ('\ufb3e', '\ufb3e'), ('\ufb40', '\ufb41'), - ('\ufb43', '\ufb44'), ('\ufb46', '\ufbb1'), - ('\ufbd3', '\ufd3d'), ('\ufd50', '\ufd8f'), - ('\ufd92', '\ufdc7'), ('\ufdf0', '\ufdfb'), - ('\ufe70', '\ufe74'), ('\ufe76', '\ufefc'), - ('\uff21', '\uff3a'), ('\uff41', '\uff5a'), - ('\uff66', '\uff6f'), ('\uff70', '\uff70'), - ('\uff71', '\uff9d'), ('\uff9e', '\uff9f'), - ('\uffa0', '\uffbe'), ('\uffc2', '\uffc7'), - ('\uffca', '\uffcf'), ('\uffd2', '\uffd7'), - ('\uffda', '\uffdc'), ('\U00010000', '\U0001000b'), - ('\U0001000d', '\U00010026'), ('\U00010028', '\U0001003a'), - ('\U0001003c', '\U0001003d'), ('\U0001003f', '\U0001004d'), - ('\U00010050', '\U0001005d'), ('\U00010080', '\U000100fa'), - ('\U00010140', '\U00010174'), ('\U00010280', '\U0001029c'), - ('\U000102a0', '\U000102d0'), ('\U00010300', '\U0001031e'), - ('\U00010330', '\U00010340'), ('\U00010341', '\U00010341'), - ('\U00010342', '\U00010349'), ('\U0001034a', '\U0001034a'), - ('\U00010380', '\U0001039d'), ('\U000103a0', '\U000103c3'), - ('\U000103c8', '\U000103cf'), ('\U000103d1', '\U000103d5'), - ('\U00010400', '\U0001044f'), ('\U00010450', '\U0001049d'), - ('\U00010800', '\U00010805'), ('\U00010808', '\U00010808'), - ('\U0001080a', '\U00010835'), ('\U00010837', '\U00010838'), - ('\U0001083c', '\U0001083c'), ('\U0001083f', '\U00010855'), - ('\U00010900', '\U00010915'), ('\U00010920', '\U00010939'), - ('\U00010980', '\U000109b7'), ('\U000109be', '\U000109bf'), - ('\U00010a00', '\U00010a00'), ('\U00010a01', '\U00010a03'), - ('\U00010a05', '\U00010a06'), ('\U00010a0c', '\U00010a0f'), - ('\U00010a10', '\U00010a13'), ('\U00010a15', '\U00010a17'), - ('\U00010a19', '\U00010a33'), ('\U00010a60', '\U00010a7c'), - ('\U00010b00', '\U00010b35'), ('\U00010b40', '\U00010b55'), - ('\U00010b60', '\U00010b72'), ('\U00010c00', '\U00010c48'), - ('\U00011000', '\U00011000'), ('\U00011001', '\U00011001'), - ('\U00011002', '\U00011002'), ('\U00011003', '\U00011037'), - ('\U00011038', '\U00011045'), ('\U00011082', '\U00011082'), - ('\U00011083', '\U000110af'), ('\U000110b0', '\U000110b2'), - ('\U000110b3', '\U000110b6'), ('\U000110b7', '\U000110b8'), - ('\U000110d0', '\U000110e8'), ('\U00011100', '\U00011102'), - ('\U00011103', '\U00011126'), ('\U00011127', '\U0001112b'), - ('\U0001112c', '\U0001112c'), ('\U0001112d', '\U00011132'), - ('\U00011180', '\U00011181'), ('\U00011182', '\U00011182'), - ('\U00011183', '\U000111b2'), ('\U000111b3', '\U000111b5'), - ('\U000111b6', '\U000111be'), ('\U000111bf', '\U000111bf'), - ('\U000111c1', '\U000111c4'), ('\U00011680', '\U000116aa'), - ('\U000116ab', '\U000116ab'), ('\U000116ac', '\U000116ac'), - ('\U000116ad', '\U000116ad'), ('\U000116ae', '\U000116af'), - ('\U000116b0', '\U000116b5'), ('\U00012000', '\U0001236e'), - ('\U00012400', '\U00012462'), ('\U00013000', '\U0001342e'), - ('\U00016800', '\U00016a38'), ('\U00016f00', '\U00016f44'), - ('\U00016f50', '\U00016f50'), ('\U00016f51', '\U00016f7e'), - ('\U00016f93', '\U00016f9f'), ('\U0001b000', '\U0001b001'), - ('\U0001d400', '\U0001d454'), ('\U0001d456', '\U0001d49c'), - ('\U0001d49e', '\U0001d49f'), ('\U0001d4a2', '\U0001d4a2'), - ('\U0001d4a5', '\U0001d4a6'), ('\U0001d4a9', '\U0001d4ac'), - ('\U0001d4ae', '\U0001d4b9'), ('\U0001d4bb', '\U0001d4bb'), - ('\U0001d4bd', '\U0001d4c3'), ('\U0001d4c5', '\U0001d505'), - ('\U0001d507', '\U0001d50a'), ('\U0001d50d', '\U0001d514'), - ('\U0001d516', '\U0001d51c'), ('\U0001d51e', '\U0001d539'), - ('\U0001d53b', '\U0001d53e'), ('\U0001d540', '\U0001d544'), - ('\U0001d546', '\U0001d546'), ('\U0001d54a', '\U0001d550'), - ('\U0001d552', '\U0001d6a5'), ('\U0001d6a8', '\U0001d6c0'), - ('\U0001d6c2', '\U0001d6da'), ('\U0001d6dc', '\U0001d6fa'), - ('\U0001d6fc', '\U0001d714'), ('\U0001d716', '\U0001d734'), - ('\U0001d736', '\U0001d74e'), ('\U0001d750', '\U0001d76e'), - ('\U0001d770', '\U0001d788'), ('\U0001d78a', '\U0001d7a8'), - ('\U0001d7aa', '\U0001d7c2'), ('\U0001d7c4', '\U0001d7cb'), - ('\U0001ee00', '\U0001ee03'), ('\U0001ee05', '\U0001ee1f'), - ('\U0001ee21', '\U0001ee22'), ('\U0001ee24', '\U0001ee24'), - ('\U0001ee27', '\U0001ee27'), ('\U0001ee29', '\U0001ee32'), - ('\U0001ee34', '\U0001ee37'), ('\U0001ee39', '\U0001ee39'), - ('\U0001ee3b', '\U0001ee3b'), ('\U0001ee42', '\U0001ee42'), - ('\U0001ee47', '\U0001ee47'), ('\U0001ee49', '\U0001ee49'), - ('\U0001ee4b', '\U0001ee4b'), ('\U0001ee4d', '\U0001ee4f'), - ('\U0001ee51', '\U0001ee52'), ('\U0001ee54', '\U0001ee54'), - ('\U0001ee57', '\U0001ee57'), ('\U0001ee59', '\U0001ee59'), - ('\U0001ee5b', '\U0001ee5b'), ('\U0001ee5d', '\U0001ee5d'), - ('\U0001ee5f', '\U0001ee5f'), ('\U0001ee61', '\U0001ee62'), - ('\U0001ee64', '\U0001ee64'), ('\U0001ee67', '\U0001ee6a'), - ('\U0001ee6c', '\U0001ee72'), ('\U0001ee74', '\U0001ee77'), - ('\U0001ee79', '\U0001ee7c'), ('\U0001ee7e', '\U0001ee7e'), - ('\U0001ee80', '\U0001ee89'), ('\U0001ee8b', '\U0001ee9b'), - ('\U0001eea1', '\U0001eea3'), ('\U0001eea5', '\U0001eea9'), - ('\U0001eeab', '\U0001eebb'), ('\U00020000', '\U0002a6d6'), - ('\U0002a700', '\U0002b734'), ('\U0002b740', '\U0002b81d'), - ('\U0002f800', '\U0002fa1d') - ]; - - pub fn Alphabetic(c: char) -> bool { - bsearch_range_table(c, Alphabetic_table) - } - - static XID_Continue_table : &'static [(char,char)] = &[ - ('\x30', '\x39'), ('\x41', '\x5a'), - ('\x5f', '\x5f'), ('\x61', '\x7a'), - ('\xaa', '\xaa'), ('\xb5', '\xb5'), - ('\xb7', '\xb7'), ('\xba', '\xba'), - ('\xc0', '\xd6'), ('\xd8', '\xf6'), - ('\xf8', '\u01ba'), ('\u01bb', '\u01bb'), - ('\u01bc', '\u01bf'), ('\u01c0', '\u01c3'), - ('\u01c4', '\u0293'), ('\u0294', '\u0294'), - ('\u0295', '\u02af'), ('\u02b0', '\u02c1'), - ('\u02c6', '\u02d1'), ('\u02e0', '\u02e4'), - ('\u02ec', '\u02ec'), ('\u02ee', '\u02ee'), - ('\u0300', '\u036f'), ('\u0370', '\u0373'), - ('\u0374', '\u0374'), ('\u0376', '\u0377'), - ('\u037b', '\u037d'), ('\u0386', '\u0386'), - ('\u0387', '\u0387'), ('\u0388', '\u038a'), - ('\u038c', '\u038c'), ('\u038e', '\u03a1'), - ('\u03a3', '\u03f5'), ('\u03f7', '\u0481'), - ('\u0483', '\u0487'), ('\u048a', '\u0527'), - ('\u0531', '\u0556'), ('\u0559', '\u0559'), - ('\u0561', '\u0587'), ('\u0591', '\u05bd'), - ('\u05bf', '\u05bf'), ('\u05c1', '\u05c2'), - ('\u05c4', '\u05c5'), ('\u05c7', '\u05c7'), - ('\u05d0', '\u05ea'), ('\u05f0', '\u05f2'), - ('\u0610', '\u061a'), ('\u0620', '\u063f'), - ('\u0640', '\u0640'), ('\u0641', '\u064a'), - ('\u064b', '\u065f'), ('\u0660', '\u0669'), - ('\u066e', '\u066f'), ('\u0670', '\u0670'), - ('\u0671', '\u06d3'), ('\u06d5', '\u06d5'), - ('\u06d6', '\u06dc'), ('\u06df', '\u06e4'), - ('\u06e5', '\u06e6'), ('\u06e7', '\u06e8'), - ('\u06ea', '\u06ed'), ('\u06ee', '\u06ef'), - ('\u06f0', '\u06f9'), ('\u06fa', '\u06fc'), - ('\u06ff', '\u06ff'), ('\u0710', '\u0710'), - ('\u0711', '\u0711'), ('\u0712', '\u072f'), - ('\u0730', '\u074a'), ('\u074d', '\u07a5'), - ('\u07a6', '\u07b0'), ('\u07b1', '\u07b1'), - ('\u07c0', '\u07c9'), ('\u07ca', '\u07ea'), - ('\u07eb', '\u07f3'), ('\u07f4', '\u07f5'), - ('\u07fa', '\u07fa'), ('\u0800', '\u0815'), - ('\u0816', '\u0819'), ('\u081a', '\u081a'), - ('\u081b', '\u0823'), ('\u0824', '\u0824'), - ('\u0825', '\u0827'), ('\u0828', '\u0828'), - ('\u0829', '\u082d'), ('\u0840', '\u0858'), - ('\u0859', '\u085b'), ('\u08a0', '\u08a0'), - ('\u08a2', '\u08ac'), ('\u08e4', '\u08fe'), - ('\u0900', '\u0902'), ('\u0903', '\u0903'), - ('\u0904', '\u0939'), ('\u093a', '\u093a'), - ('\u093b', '\u093b'), ('\u093c', '\u093c'), - ('\u093d', '\u093d'), ('\u093e', '\u0940'), - ('\u0941', '\u0948'), ('\u0949', '\u094c'), - ('\u094d', '\u094d'), ('\u094e', '\u094f'), - ('\u0950', '\u0950'), ('\u0951', '\u0957'), - ('\u0958', '\u0961'), ('\u0962', '\u0963'), - ('\u0966', '\u096f'), ('\u0971', '\u0971'), - ('\u0972', '\u0977'), ('\u0979', '\u097f'), - ('\u0981', '\u0981'), ('\u0982', '\u0983'), - ('\u0985', '\u098c'), ('\u098f', '\u0990'), - ('\u0993', '\u09a8'), ('\u09aa', '\u09b0'), - ('\u09b2', '\u09b2'), ('\u09b6', '\u09b9'), - ('\u09bc', '\u09bc'), ('\u09bd', '\u09bd'), - ('\u09be', '\u09c0'), ('\u09c1', '\u09c4'), - ('\u09c7', '\u09c8'), ('\u09cb', '\u09cc'), - ('\u09cd', '\u09cd'), ('\u09ce', '\u09ce'), - ('\u09d7', '\u09d7'), ('\u09dc', '\u09dd'), - ('\u09df', '\u09e1'), ('\u09e2', '\u09e3'), - ('\u09e6', '\u09ef'), ('\u09f0', '\u09f1'), - ('\u0a01', '\u0a02'), ('\u0a03', '\u0a03'), - ('\u0a05', '\u0a0a'), ('\u0a0f', '\u0a10'), - ('\u0a13', '\u0a28'), ('\u0a2a', '\u0a30'), - ('\u0a32', '\u0a33'), ('\u0a35', '\u0a36'), - ('\u0a38', '\u0a39'), ('\u0a3c', '\u0a3c'), - ('\u0a3e', '\u0a40'), ('\u0a41', '\u0a42'), - ('\u0a47', '\u0a48'), ('\u0a4b', '\u0a4d'), - ('\u0a51', '\u0a51'), ('\u0a59', '\u0a5c'), - ('\u0a5e', '\u0a5e'), ('\u0a66', '\u0a6f'), - ('\u0a70', '\u0a71'), ('\u0a72', '\u0a74'), - ('\u0a75', '\u0a75'), ('\u0a81', '\u0a82'), - ('\u0a83', '\u0a83'), ('\u0a85', '\u0a8d'), - ('\u0a8f', '\u0a91'), ('\u0a93', '\u0aa8'), - ('\u0aaa', '\u0ab0'), ('\u0ab2', '\u0ab3'), - ('\u0ab5', '\u0ab9'), ('\u0abc', '\u0abc'), - ('\u0abd', '\u0abd'), ('\u0abe', '\u0ac0'), - ('\u0ac1', '\u0ac5'), ('\u0ac7', '\u0ac8'), - ('\u0ac9', '\u0ac9'), ('\u0acb', '\u0acc'), - ('\u0acd', '\u0acd'), ('\u0ad0', '\u0ad0'), - ('\u0ae0', '\u0ae1'), ('\u0ae2', '\u0ae3'), - ('\u0ae6', '\u0aef'), ('\u0b01', '\u0b01'), - ('\u0b02', '\u0b03'), ('\u0b05', '\u0b0c'), - ('\u0b0f', '\u0b10'), ('\u0b13', '\u0b28'), - ('\u0b2a', '\u0b30'), ('\u0b32', '\u0b33'), - ('\u0b35', '\u0b39'), ('\u0b3c', '\u0b3c'), - ('\u0b3d', '\u0b3d'), ('\u0b3e', '\u0b3e'), - ('\u0b3f', '\u0b3f'), ('\u0b40', '\u0b40'), - ('\u0b41', '\u0b44'), ('\u0b47', '\u0b48'), - ('\u0b4b', '\u0b4c'), ('\u0b4d', '\u0b4d'), - ('\u0b56', '\u0b56'), ('\u0b57', '\u0b57'), - ('\u0b5c', '\u0b5d'), ('\u0b5f', '\u0b61'), - ('\u0b62', '\u0b63'), ('\u0b66', '\u0b6f'), - ('\u0b71', '\u0b71'), ('\u0b82', '\u0b82'), - ('\u0b83', '\u0b83'), ('\u0b85', '\u0b8a'), - ('\u0b8e', '\u0b90'), ('\u0b92', '\u0b95'), - ('\u0b99', '\u0b9a'), ('\u0b9c', '\u0b9c'), - ('\u0b9e', '\u0b9f'), ('\u0ba3', '\u0ba4'), - ('\u0ba8', '\u0baa'), ('\u0bae', '\u0bb9'), - ('\u0bbe', '\u0bbf'), ('\u0bc0', '\u0bc0'), - ('\u0bc1', '\u0bc2'), ('\u0bc6', '\u0bc8'), - ('\u0bca', '\u0bcc'), ('\u0bcd', '\u0bcd'), - ('\u0bd0', '\u0bd0'), ('\u0bd7', '\u0bd7'), - ('\u0be6', '\u0bef'), ('\u0c01', '\u0c03'), - ('\u0c05', '\u0c0c'), ('\u0c0e', '\u0c10'), - ('\u0c12', '\u0c28'), ('\u0c2a', '\u0c33'), - ('\u0c35', '\u0c39'), ('\u0c3d', '\u0c3d'), - ('\u0c3e', '\u0c40'), ('\u0c41', '\u0c44'), - ('\u0c46', '\u0c48'), ('\u0c4a', '\u0c4d'), - ('\u0c55', '\u0c56'), ('\u0c58', '\u0c59'), - ('\u0c60', '\u0c61'), ('\u0c62', '\u0c63'), - ('\u0c66', '\u0c6f'), ('\u0c82', '\u0c83'), - ('\u0c85', '\u0c8c'), ('\u0c8e', '\u0c90'), - ('\u0c92', '\u0ca8'), ('\u0caa', '\u0cb3'), - ('\u0cb5', '\u0cb9'), ('\u0cbc', '\u0cbc'), - ('\u0cbd', '\u0cbd'), ('\u0cbe', '\u0cbe'), - ('\u0cbf', '\u0cbf'), ('\u0cc0', '\u0cc4'), - ('\u0cc6', '\u0cc6'), ('\u0cc7', '\u0cc8'), - ('\u0cca', '\u0ccb'), ('\u0ccc', '\u0ccd'), - ('\u0cd5', '\u0cd6'), ('\u0cde', '\u0cde'), - ('\u0ce0', '\u0ce1'), ('\u0ce2', '\u0ce3'), - ('\u0ce6', '\u0cef'), ('\u0cf1', '\u0cf2'), - ('\u0d02', '\u0d03'), ('\u0d05', '\u0d0c'), - ('\u0d0e', '\u0d10'), ('\u0d12', '\u0d3a'), - ('\u0d3d', '\u0d3d'), ('\u0d3e', '\u0d40'), - ('\u0d41', '\u0d44'), ('\u0d46', '\u0d48'), - ('\u0d4a', '\u0d4c'), ('\u0d4d', '\u0d4d'), - ('\u0d4e', '\u0d4e'), ('\u0d57', '\u0d57'), - ('\u0d60', '\u0d61'), ('\u0d62', '\u0d63'), - ('\u0d66', '\u0d6f'), ('\u0d7a', '\u0d7f'), - ('\u0d82', '\u0d83'), ('\u0d85', '\u0d96'), - ('\u0d9a', '\u0db1'), ('\u0db3', '\u0dbb'), - ('\u0dbd', '\u0dbd'), ('\u0dc0', '\u0dc6'), - ('\u0dca', '\u0dca'), ('\u0dcf', '\u0dd1'), - ('\u0dd2', '\u0dd4'), ('\u0dd6', '\u0dd6'), - ('\u0dd8', '\u0ddf'), ('\u0df2', '\u0df3'), - ('\u0e01', '\u0e30'), ('\u0e31', '\u0e31'), - ('\u0e32', '\u0e33'), ('\u0e34', '\u0e3a'), - ('\u0e40', '\u0e45'), ('\u0e46', '\u0e46'), - ('\u0e47', '\u0e4e'), ('\u0e50', '\u0e59'), - ('\u0e81', '\u0e82'), ('\u0e84', '\u0e84'), - ('\u0e87', '\u0e88'), ('\u0e8a', '\u0e8a'), - ('\u0e8d', '\u0e8d'), ('\u0e94', '\u0e97'), - ('\u0e99', '\u0e9f'), ('\u0ea1', '\u0ea3'), - ('\u0ea5', '\u0ea5'), ('\u0ea7', '\u0ea7'), - ('\u0eaa', '\u0eab'), ('\u0ead', '\u0eb0'), - ('\u0eb1', '\u0eb1'), ('\u0eb2', '\u0eb3'), - ('\u0eb4', '\u0eb9'), ('\u0ebb', '\u0ebc'), - ('\u0ebd', '\u0ebd'), ('\u0ec0', '\u0ec4'), - ('\u0ec6', '\u0ec6'), ('\u0ec8', '\u0ecd'), - ('\u0ed0', '\u0ed9'), ('\u0edc', '\u0edf'), - ('\u0f00', '\u0f00'), ('\u0f18', '\u0f19'), - ('\u0f20', '\u0f29'), ('\u0f35', '\u0f35'), - ('\u0f37', '\u0f37'), ('\u0f39', '\u0f39'), - ('\u0f3e', '\u0f3f'), ('\u0f40', '\u0f47'), - ('\u0f49', '\u0f6c'), ('\u0f71', '\u0f7e'), - ('\u0f7f', '\u0f7f'), ('\u0f80', '\u0f84'), - ('\u0f86', '\u0f87'), ('\u0f88', '\u0f8c'), - ('\u0f8d', '\u0f97'), ('\u0f99', '\u0fbc'), - ('\u0fc6', '\u0fc6'), ('\u1000', '\u102a'), - ('\u102b', '\u102c'), ('\u102d', '\u1030'), - ('\u1031', '\u1031'), ('\u1032', '\u1037'), - ('\u1038', '\u1038'), ('\u1039', '\u103a'), - ('\u103b', '\u103c'), ('\u103d', '\u103e'), - ('\u103f', '\u103f'), ('\u1040', '\u1049'), - ('\u1050', '\u1055'), ('\u1056', '\u1057'), - ('\u1058', '\u1059'), ('\u105a', '\u105d'), - ('\u105e', '\u1060'), ('\u1061', '\u1061'), - ('\u1062', '\u1064'), ('\u1065', '\u1066'), - ('\u1067', '\u106d'), ('\u106e', '\u1070'), - ('\u1071', '\u1074'), ('\u1075', '\u1081'), - ('\u1082', '\u1082'), ('\u1083', '\u1084'), - ('\u1085', '\u1086'), ('\u1087', '\u108c'), - ('\u108d', '\u108d'), ('\u108e', '\u108e'), - ('\u108f', '\u108f'), ('\u1090', '\u1099'), - ('\u109a', '\u109c'), ('\u109d', '\u109d'), - ('\u10a0', '\u10c5'), ('\u10c7', '\u10c7'), - ('\u10cd', '\u10cd'), ('\u10d0', '\u10fa'), - ('\u10fc', '\u10fc'), ('\u10fd', '\u1248'), - ('\u124a', '\u124d'), ('\u1250', '\u1256'), - ('\u1258', '\u1258'), ('\u125a', '\u125d'), - ('\u1260', '\u1288'), ('\u128a', '\u128d'), - ('\u1290', '\u12b0'), ('\u12b2', '\u12b5'), - ('\u12b8', '\u12be'), ('\u12c0', '\u12c0'), - ('\u12c2', '\u12c5'), ('\u12c8', '\u12d6'), - ('\u12d8', '\u1310'), ('\u1312', '\u1315'), - ('\u1318', '\u135a'), ('\u135d', '\u135f'), - ('\u1369', '\u1371'), ('\u1380', '\u138f'), - ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), - ('\u166f', '\u167f'), ('\u1681', '\u169a'), - ('\u16a0', '\u16ea'), ('\u16ee', '\u16f0'), - ('\u1700', '\u170c'), ('\u170e', '\u1711'), - ('\u1712', '\u1714'), ('\u1720', '\u1731'), - ('\u1732', '\u1734'), ('\u1740', '\u1751'), - ('\u1752', '\u1753'), ('\u1760', '\u176c'), - ('\u176e', '\u1770'), ('\u1772', '\u1773'), - ('\u1780', '\u17b3'), ('\u17b4', '\u17b5'), - ('\u17b6', '\u17b6'), ('\u17b7', '\u17bd'), - ('\u17be', '\u17c5'), ('\u17c6', '\u17c6'), - ('\u17c7', '\u17c8'), ('\u17c9', '\u17d3'), - ('\u17d7', '\u17d7'), ('\u17dc', '\u17dc'), - ('\u17dd', '\u17dd'), ('\u17e0', '\u17e9'), - ('\u180b', '\u180d'), ('\u1810', '\u1819'), - ('\u1820', '\u1842'), ('\u1843', '\u1843'), - ('\u1844', '\u1877'), ('\u1880', '\u18a8'), - ('\u18a9', '\u18a9'), ('\u18aa', '\u18aa'), - ('\u18b0', '\u18f5'), ('\u1900', '\u191c'), - ('\u1920', '\u1922'), ('\u1923', '\u1926'), - ('\u1927', '\u1928'), ('\u1929', '\u192b'), - ('\u1930', '\u1931'), ('\u1932', '\u1932'), - ('\u1933', '\u1938'), ('\u1939', '\u193b'), - ('\u1946', '\u194f'), ('\u1950', '\u196d'), - ('\u1970', '\u1974'), ('\u1980', '\u19ab'), - ('\u19b0', '\u19c0'), ('\u19c1', '\u19c7'), - ('\u19c8', '\u19c9'), ('\u19d0', '\u19d9'), - ('\u19da', '\u19da'), ('\u1a00', '\u1a16'), - ('\u1a17', '\u1a18'), ('\u1a19', '\u1a1b'), - ('\u1a20', '\u1a54'), ('\u1a55', '\u1a55'), - ('\u1a56', '\u1a56'), ('\u1a57', '\u1a57'), - ('\u1a58', '\u1a5e'), ('\u1a60', '\u1a60'), - ('\u1a61', '\u1a61'), ('\u1a62', '\u1a62'), - ('\u1a63', '\u1a64'), ('\u1a65', '\u1a6c'), - ('\u1a6d', '\u1a72'), ('\u1a73', '\u1a7c'), - ('\u1a7f', '\u1a7f'), ('\u1a80', '\u1a89'), - ('\u1a90', '\u1a99'), ('\u1aa7', '\u1aa7'), - ('\u1b00', '\u1b03'), ('\u1b04', '\u1b04'), - ('\u1b05', '\u1b33'), ('\u1b34', '\u1b34'), - ('\u1b35', '\u1b35'), ('\u1b36', '\u1b3a'), - ('\u1b3b', '\u1b3b'), ('\u1b3c', '\u1b3c'), - ('\u1b3d', '\u1b41'), ('\u1b42', '\u1b42'), - ('\u1b43', '\u1b44'), ('\u1b45', '\u1b4b'), - ('\u1b50', '\u1b59'), ('\u1b6b', '\u1b73'), - ('\u1b80', '\u1b81'), ('\u1b82', '\u1b82'), - ('\u1b83', '\u1ba0'), ('\u1ba1', '\u1ba1'), - ('\u1ba2', '\u1ba5'), ('\u1ba6', '\u1ba7'), - ('\u1ba8', '\u1ba9'), ('\u1baa', '\u1baa'), - ('\u1bab', '\u1bab'), ('\u1bac', '\u1bad'), - ('\u1bae', '\u1baf'), ('\u1bb0', '\u1bb9'), - ('\u1bba', '\u1be5'), ('\u1be6', '\u1be6'), - ('\u1be7', '\u1be7'), ('\u1be8', '\u1be9'), - ('\u1bea', '\u1bec'), ('\u1bed', '\u1bed'), - ('\u1bee', '\u1bee'), ('\u1bef', '\u1bf1'), - ('\u1bf2', '\u1bf3'), ('\u1c00', '\u1c23'), - ('\u1c24', '\u1c2b'), ('\u1c2c', '\u1c33'), - ('\u1c34', '\u1c35'), ('\u1c36', '\u1c37'), - ('\u1c40', '\u1c49'), ('\u1c4d', '\u1c4f'), - ('\u1c50', '\u1c59'), ('\u1c5a', '\u1c77'), - ('\u1c78', '\u1c7d'), ('\u1cd0', '\u1cd2'), - ('\u1cd4', '\u1ce0'), ('\u1ce1', '\u1ce1'), - ('\u1ce2', '\u1ce8'), ('\u1ce9', '\u1cec'), - ('\u1ced', '\u1ced'), ('\u1cee', '\u1cf1'), - ('\u1cf2', '\u1cf3'), ('\u1cf4', '\u1cf4'), - ('\u1cf5', '\u1cf6'), ('\u1d00', '\u1d2b'), - ('\u1d2c', '\u1d6a'), ('\u1d6b', '\u1d77'), - ('\u1d78', '\u1d78'), ('\u1d79', '\u1d9a'), - ('\u1d9b', '\u1dbf'), ('\u1dc0', '\u1de6'), - ('\u1dfc', '\u1dff'), ('\u1e00', '\u1f15'), - ('\u1f18', '\u1f1d'), ('\u1f20', '\u1f45'), - ('\u1f48', '\u1f4d'), ('\u1f50', '\u1f57'), - ('\u1f59', '\u1f59'), ('\u1f5b', '\u1f5b'), - ('\u1f5d', '\u1f5d'), ('\u1f5f', '\u1f7d'), - ('\u1f80', '\u1fb4'), ('\u1fb6', '\u1fbc'), - ('\u1fbe', '\u1fbe'), ('\u1fc2', '\u1fc4'), - ('\u1fc6', '\u1fcc'), ('\u1fd0', '\u1fd3'), - ('\u1fd6', '\u1fdb'), ('\u1fe0', '\u1fec'), - ('\u1ff2', '\u1ff4'), ('\u1ff6', '\u1ffc'), - ('\u203f', '\u2040'), ('\u2054', '\u2054'), - ('\u2071', '\u2071'), ('\u207f', '\u207f'), - ('\u2090', '\u209c'), ('\u20d0', '\u20dc'), - ('\u20e1', '\u20e1'), ('\u20e5', '\u20f0'), - ('\u2102', '\u2102'), ('\u2107', '\u2107'), - ('\u210a', '\u2113'), ('\u2115', '\u2115'), - ('\u2118', '\u2118'), ('\u2119', '\u211d'), - ('\u2124', '\u2124'), ('\u2126', '\u2126'), - ('\u2128', '\u2128'), ('\u212a', '\u212d'), - ('\u212e', '\u212e'), ('\u212f', '\u2134'), - ('\u2135', '\u2138'), ('\u2139', '\u2139'), - ('\u213c', '\u213f'), ('\u2145', '\u2149'), - ('\u214e', '\u214e'), ('\u2160', '\u2182'), - ('\u2183', '\u2184'), ('\u2185', '\u2188'), - ('\u2c00', '\u2c2e'), ('\u2c30', '\u2c5e'), - ('\u2c60', '\u2c7b'), ('\u2c7c', '\u2c7d'), - ('\u2c7e', '\u2ce4'), ('\u2ceb', '\u2cee'), - ('\u2cef', '\u2cf1'), ('\u2cf2', '\u2cf3'), - ('\u2d00', '\u2d25'), ('\u2d27', '\u2d27'), - ('\u2d2d', '\u2d2d'), ('\u2d30', '\u2d67'), - ('\u2d6f', '\u2d6f'), ('\u2d7f', '\u2d7f'), - ('\u2d80', '\u2d96'), ('\u2da0', '\u2da6'), - ('\u2da8', '\u2dae'), ('\u2db0', '\u2db6'), - ('\u2db8', '\u2dbe'), ('\u2dc0', '\u2dc6'), - ('\u2dc8', '\u2dce'), ('\u2dd0', '\u2dd6'), - ('\u2dd8', '\u2dde'), ('\u2de0', '\u2dff'), - ('\u3005', '\u3005'), ('\u3006', '\u3006'), - ('\u3007', '\u3007'), ('\u3021', '\u3029'), - ('\u302a', '\u302d'), ('\u302e', '\u302f'), - ('\u3031', '\u3035'), ('\u3038', '\u303a'), - ('\u303b', '\u303b'), ('\u303c', '\u303c'), - ('\u3041', '\u3096'), ('\u3099', '\u309a'), - ('\u309d', '\u309e'), ('\u309f', '\u309f'), - ('\u30a1', '\u30fa'), ('\u30fc', '\u30fe'), - ('\u30ff', '\u30ff'), ('\u3105', '\u312d'), - ('\u3131', '\u318e'), ('\u31a0', '\u31ba'), - ('\u31f0', '\u31ff'), ('\u3400', '\u4db5'), - ('\u4e00', '\u9fcc'), ('\ua000', '\ua014'), - ('\ua015', '\ua015'), ('\ua016', '\ua48c'), - ('\ua4d0', '\ua4f7'), ('\ua4f8', '\ua4fd'), - ('\ua500', '\ua60b'), ('\ua60c', '\ua60c'), - ('\ua610', '\ua61f'), ('\ua620', '\ua629'), - ('\ua62a', '\ua62b'), ('\ua640', '\ua66d'), - ('\ua66e', '\ua66e'), ('\ua66f', '\ua66f'), - ('\ua674', '\ua67d'), ('\ua67f', '\ua67f'), - ('\ua680', '\ua697'), ('\ua69f', '\ua69f'), - ('\ua6a0', '\ua6e5'), ('\ua6e6', '\ua6ef'), - ('\ua6f0', '\ua6f1'), ('\ua717', '\ua71f'), - ('\ua722', '\ua76f'), ('\ua770', '\ua770'), - ('\ua771', '\ua787'), ('\ua788', '\ua788'), - ('\ua78b', '\ua78e'), ('\ua790', '\ua793'), - ('\ua7a0', '\ua7aa'), ('\ua7f8', '\ua7f9'), - ('\ua7fa', '\ua7fa'), ('\ua7fb', '\ua801'), - ('\ua802', '\ua802'), ('\ua803', '\ua805'), - ('\ua806', '\ua806'), ('\ua807', '\ua80a'), - ('\ua80b', '\ua80b'), ('\ua80c', '\ua822'), - ('\ua823', '\ua824'), ('\ua825', '\ua826'), - ('\ua827', '\ua827'), ('\ua840', '\ua873'), - ('\ua880', '\ua881'), ('\ua882', '\ua8b3'), - ('\ua8b4', '\ua8c3'), ('\ua8c4', '\ua8c4'), - ('\ua8d0', '\ua8d9'), ('\ua8e0', '\ua8f1'), - ('\ua8f2', '\ua8f7'), ('\ua8fb', '\ua8fb'), - ('\ua900', '\ua909'), ('\ua90a', '\ua925'), - ('\ua926', '\ua92d'), ('\ua930', '\ua946'), - ('\ua947', '\ua951'), ('\ua952', '\ua953'), - ('\ua960', '\ua97c'), ('\ua980', '\ua982'), - ('\ua983', '\ua983'), ('\ua984', '\ua9b2'), - ('\ua9b3', '\ua9b3'), ('\ua9b4', '\ua9b5'), - ('\ua9b6', '\ua9b9'), ('\ua9ba', '\ua9bb'), - ('\ua9bc', '\ua9bc'), ('\ua9bd', '\ua9c0'), - ('\ua9cf', '\ua9cf'), ('\ua9d0', '\ua9d9'), - ('\uaa00', '\uaa28'), ('\uaa29', '\uaa2e'), - ('\uaa2f', '\uaa30'), ('\uaa31', '\uaa32'), - ('\uaa33', '\uaa34'), ('\uaa35', '\uaa36'), - ('\uaa40', '\uaa42'), ('\uaa43', '\uaa43'), - ('\uaa44', '\uaa4b'), ('\uaa4c', '\uaa4c'), - ('\uaa4d', '\uaa4d'), ('\uaa50', '\uaa59'), - ('\uaa60', '\uaa6f'), ('\uaa70', '\uaa70'), - ('\uaa71', '\uaa76'), ('\uaa7a', '\uaa7a'), - ('\uaa7b', '\uaa7b'), ('\uaa80', '\uaaaf'), - ('\uaab0', '\uaab0'), ('\uaab1', '\uaab1'), - ('\uaab2', '\uaab4'), ('\uaab5', '\uaab6'), - ('\uaab7', '\uaab8'), ('\uaab9', '\uaabd'), - ('\uaabe', '\uaabf'), ('\uaac0', '\uaac0'), - ('\uaac1', '\uaac1'), ('\uaac2', '\uaac2'), - ('\uaadb', '\uaadc'), ('\uaadd', '\uaadd'), - ('\uaae0', '\uaaea'), ('\uaaeb', '\uaaeb'), - ('\uaaec', '\uaaed'), ('\uaaee', '\uaaef'), - ('\uaaf2', '\uaaf2'), ('\uaaf3', '\uaaf4'), - ('\uaaf5', '\uaaf5'), ('\uaaf6', '\uaaf6'), - ('\uab01', '\uab06'), ('\uab09', '\uab0e'), - ('\uab11', '\uab16'), ('\uab20', '\uab26'), - ('\uab28', '\uab2e'), ('\uabc0', '\uabe2'), - ('\uabe3', '\uabe4'), ('\uabe5', '\uabe5'), - ('\uabe6', '\uabe7'), ('\uabe8', '\uabe8'), - ('\uabe9', '\uabea'), ('\uabec', '\uabec'), - ('\uabed', '\uabed'), ('\uabf0', '\uabf9'), - ('\uac00', '\ud7a3'), ('\ud7b0', '\ud7c6'), - ('\ud7cb', '\ud7fb'), ('\uf900', '\ufa6d'), - ('\ufa70', '\ufad9'), ('\ufb00', '\ufb06'), - ('\ufb13', '\ufb17'), ('\ufb1d', '\ufb1d'), - ('\ufb1e', '\ufb1e'), ('\ufb1f', '\ufb28'), - ('\ufb2a', '\ufb36'), ('\ufb38', '\ufb3c'), - ('\ufb3e', '\ufb3e'), ('\ufb40', '\ufb41'), - ('\ufb43', '\ufb44'), ('\ufb46', '\ufbb1'), - ('\ufbd3', '\ufc5d'), ('\ufc64', '\ufd3d'), - ('\ufd50', '\ufd8f'), ('\ufd92', '\ufdc7'), - ('\ufdf0', '\ufdf9'), ('\ufe00', '\ufe0f'), - ('\ufe20', '\ufe26'), ('\ufe33', '\ufe34'), - ('\ufe4d', '\ufe4f'), ('\ufe71', '\ufe71'), - ('\ufe73', '\ufe73'), ('\ufe77', '\ufe77'), - ('\ufe79', '\ufe79'), ('\ufe7b', '\ufe7b'), - ('\ufe7d', '\ufe7d'), ('\ufe7f', '\ufefc'), - ('\uff10', '\uff19'), ('\uff21', '\uff3a'), - ('\uff3f', '\uff3f'), ('\uff41', '\uff5a'), - ('\uff66', '\uff6f'), ('\uff70', '\uff70'), - ('\uff71', '\uff9d'), ('\uff9e', '\uff9f'), - ('\uffa0', '\uffbe'), ('\uffc2', '\uffc7'), - ('\uffca', '\uffcf'), ('\uffd2', '\uffd7'), - ('\uffda', '\uffdc'), ('\U00010000', '\U0001000b'), - ('\U0001000d', '\U00010026'), ('\U00010028', '\U0001003a'), - ('\U0001003c', '\U0001003d'), ('\U0001003f', '\U0001004d'), - ('\U00010050', '\U0001005d'), ('\U00010080', '\U000100fa'), - ('\U00010140', '\U00010174'), ('\U000101fd', '\U000101fd'), - ('\U00010280', '\U0001029c'), ('\U000102a0', '\U000102d0'), - ('\U00010300', '\U0001031e'), ('\U00010330', '\U00010340'), - ('\U00010341', '\U00010341'), ('\U00010342', '\U00010349'), - ('\U0001034a', '\U0001034a'), ('\U00010380', '\U0001039d'), - ('\U000103a0', '\U000103c3'), ('\U000103c8', '\U000103cf'), - ('\U000103d1', '\U000103d5'), ('\U00010400', '\U0001044f'), - ('\U00010450', '\U0001049d'), ('\U000104a0', '\U000104a9'), - ('\U00010800', '\U00010805'), ('\U00010808', '\U00010808'), - ('\U0001080a', '\U00010835'), ('\U00010837', '\U00010838'), - ('\U0001083c', '\U0001083c'), ('\U0001083f', '\U00010855'), - ('\U00010900', '\U00010915'), ('\U00010920', '\U00010939'), - ('\U00010980', '\U000109b7'), ('\U000109be', '\U000109bf'), - ('\U00010a00', '\U00010a00'), ('\U00010a01', '\U00010a03'), - ('\U00010a05', '\U00010a06'), ('\U00010a0c', '\U00010a0f'), - ('\U00010a10', '\U00010a13'), ('\U00010a15', '\U00010a17'), - ('\U00010a19', '\U00010a33'), ('\U00010a38', '\U00010a3a'), - ('\U00010a3f', '\U00010a3f'), ('\U00010a60', '\U00010a7c'), - ('\U00010b00', '\U00010b35'), ('\U00010b40', '\U00010b55'), - ('\U00010b60', '\U00010b72'), ('\U00010c00', '\U00010c48'), - ('\U00011000', '\U00011000'), ('\U00011001', '\U00011001'), - ('\U00011002', '\U00011002'), ('\U00011003', '\U00011037'), - ('\U00011038', '\U00011046'), ('\U00011066', '\U0001106f'), - ('\U00011080', '\U00011081'), ('\U00011082', '\U00011082'), - ('\U00011083', '\U000110af'), ('\U000110b0', '\U000110b2'), - ('\U000110b3', '\U000110b6'), ('\U000110b7', '\U000110b8'), - ('\U000110b9', '\U000110ba'), ('\U000110d0', '\U000110e8'), - ('\U000110f0', '\U000110f9'), ('\U00011100', '\U00011102'), - ('\U00011103', '\U00011126'), ('\U00011127', '\U0001112b'), - ('\U0001112c', '\U0001112c'), ('\U0001112d', '\U00011134'), - ('\U00011136', '\U0001113f'), ('\U00011180', '\U00011181'), - ('\U00011182', '\U00011182'), ('\U00011183', '\U000111b2'), - ('\U000111b3', '\U000111b5'), ('\U000111b6', '\U000111be'), - ('\U000111bf', '\U000111c0'), ('\U000111c1', '\U000111c4'), - ('\U000111d0', '\U000111d9'), ('\U00011680', '\U000116aa'), - ('\U000116ab', '\U000116ab'), ('\U000116ac', '\U000116ac'), - ('\U000116ad', '\U000116ad'), ('\U000116ae', '\U000116af'), - ('\U000116b0', '\U000116b5'), ('\U000116b6', '\U000116b6'), - ('\U000116b7', '\U000116b7'), ('\U000116c0', '\U000116c9'), - ('\U00012000', '\U0001236e'), ('\U00012400', '\U00012462'), - ('\U00013000', '\U0001342e'), ('\U00016800', '\U00016a38'), - ('\U00016f00', '\U00016f44'), ('\U00016f50', '\U00016f50'), - ('\U00016f51', '\U00016f7e'), ('\U00016f8f', '\U00016f92'), - ('\U00016f93', '\U00016f9f'), ('\U0001b000', '\U0001b001'), - ('\U0001d165', '\U0001d166'), ('\U0001d167', '\U0001d169'), - ('\U0001d16d', '\U0001d172'), ('\U0001d17b', '\U0001d182'), - ('\U0001d185', '\U0001d18b'), ('\U0001d1aa', '\U0001d1ad'), - ('\U0001d242', '\U0001d244'), ('\U0001d400', '\U0001d454'), - ('\U0001d456', '\U0001d49c'), ('\U0001d49e', '\U0001d49f'), - ('\U0001d4a2', '\U0001d4a2'), ('\U0001d4a5', '\U0001d4a6'), - ('\U0001d4a9', '\U0001d4ac'), ('\U0001d4ae', '\U0001d4b9'), - ('\U0001d4bb', '\U0001d4bb'), ('\U0001d4bd', '\U0001d4c3'), - ('\U0001d4c5', '\U0001d505'), ('\U0001d507', '\U0001d50a'), - ('\U0001d50d', '\U0001d514'), ('\U0001d516', '\U0001d51c'), - ('\U0001d51e', '\U0001d539'), ('\U0001d53b', '\U0001d53e'), - ('\U0001d540', '\U0001d544'), ('\U0001d546', '\U0001d546'), - ('\U0001d54a', '\U0001d550'), ('\U0001d552', '\U0001d6a5'), - ('\U0001d6a8', '\U0001d6c0'), ('\U0001d6c2', '\U0001d6da'), - ('\U0001d6dc', '\U0001d6fa'), ('\U0001d6fc', '\U0001d714'), - ('\U0001d716', '\U0001d734'), ('\U0001d736', '\U0001d74e'), - ('\U0001d750', '\U0001d76e'), ('\U0001d770', '\U0001d788'), - ('\U0001d78a', '\U0001d7a8'), ('\U0001d7aa', '\U0001d7c2'), - ('\U0001d7c4', '\U0001d7cb'), ('\U0001d7ce', '\U0001d7ff'), - ('\U0001ee00', '\U0001ee03'), ('\U0001ee05', '\U0001ee1f'), - ('\U0001ee21', '\U0001ee22'), ('\U0001ee24', '\U0001ee24'), - ('\U0001ee27', '\U0001ee27'), ('\U0001ee29', '\U0001ee32'), - ('\U0001ee34', '\U0001ee37'), ('\U0001ee39', '\U0001ee39'), - ('\U0001ee3b', '\U0001ee3b'), ('\U0001ee42', '\U0001ee42'), - ('\U0001ee47', '\U0001ee47'), ('\U0001ee49', '\U0001ee49'), - ('\U0001ee4b', '\U0001ee4b'), ('\U0001ee4d', '\U0001ee4f'), - ('\U0001ee51', '\U0001ee52'), ('\U0001ee54', '\U0001ee54'), - ('\U0001ee57', '\U0001ee57'), ('\U0001ee59', '\U0001ee59'), - ('\U0001ee5b', '\U0001ee5b'), ('\U0001ee5d', '\U0001ee5d'), - ('\U0001ee5f', '\U0001ee5f'), ('\U0001ee61', '\U0001ee62'), - ('\U0001ee64', '\U0001ee64'), ('\U0001ee67', '\U0001ee6a'), - ('\U0001ee6c', '\U0001ee72'), ('\U0001ee74', '\U0001ee77'), - ('\U0001ee79', '\U0001ee7c'), ('\U0001ee7e', '\U0001ee7e'), - ('\U0001ee80', '\U0001ee89'), ('\U0001ee8b', '\U0001ee9b'), - ('\U0001eea1', '\U0001eea3'), ('\U0001eea5', '\U0001eea9'), - ('\U0001eeab', '\U0001eebb'), ('\U00020000', '\U0002a6d6'), - ('\U0002a700', '\U0002b734'), ('\U0002b740', '\U0002b81d'), - ('\U0002f800', '\U0002fa1d'), ('\U000e0100', '\U000e01ef') - ]; - - pub fn XID_Continue(c: char) -> bool { - bsearch_range_table(c, XID_Continue_table) - } - - static XID_Start_table : &'static [(char,char)] = &[ - ('\x41', '\x5a'), ('\x61', '\x7a'), - ('\xaa', '\xaa'), ('\xb5', '\xb5'), - ('\xba', '\xba'), ('\xc0', '\xd6'), - ('\xd8', '\xf6'), ('\xf8', '\u01ba'), - ('\u01bb', '\u01bb'), ('\u01bc', '\u01bf'), - ('\u01c0', '\u01c3'), ('\u01c4', '\u0293'), - ('\u0294', '\u0294'), ('\u0295', '\u02af'), - ('\u02b0', '\u02c1'), ('\u02c6', '\u02d1'), - ('\u02e0', '\u02e4'), ('\u02ec', '\u02ec'), - ('\u02ee', '\u02ee'), ('\u0370', '\u0373'), - ('\u0374', '\u0374'), ('\u0376', '\u0377'), - ('\u037b', '\u037d'), ('\u0386', '\u0386'), - ('\u0388', '\u038a'), ('\u038c', '\u038c'), - ('\u038e', '\u03a1'), ('\u03a3', '\u03f5'), - ('\u03f7', '\u0481'), ('\u048a', '\u0527'), - ('\u0531', '\u0556'), ('\u0559', '\u0559'), - ('\u0561', '\u0587'), ('\u05d0', '\u05ea'), - ('\u05f0', '\u05f2'), ('\u0620', '\u063f'), - ('\u0640', '\u0640'), ('\u0641', '\u064a'), - ('\u066e', '\u066f'), ('\u0671', '\u06d3'), - ('\u06d5', '\u06d5'), ('\u06e5', '\u06e6'), - ('\u06ee', '\u06ef'), ('\u06fa', '\u06fc'), - ('\u06ff', '\u06ff'), ('\u0710', '\u0710'), - ('\u0712', '\u072f'), ('\u074d', '\u07a5'), - ('\u07b1', '\u07b1'), ('\u07ca', '\u07ea'), - ('\u07f4', '\u07f5'), ('\u07fa', '\u07fa'), - ('\u0800', '\u0815'), ('\u081a', '\u081a'), - ('\u0824', '\u0824'), ('\u0828', '\u0828'), - ('\u0840', '\u0858'), ('\u08a0', '\u08a0'), - ('\u08a2', '\u08ac'), ('\u0904', '\u0939'), - ('\u093d', '\u093d'), ('\u0950', '\u0950'), - ('\u0958', '\u0961'), ('\u0971', '\u0971'), - ('\u0972', '\u0977'), ('\u0979', '\u097f'), - ('\u0985', '\u098c'), ('\u098f', '\u0990'), - ('\u0993', '\u09a8'), ('\u09aa', '\u09b0'), - ('\u09b2', '\u09b2'), ('\u09b6', '\u09b9'), - ('\u09bd', '\u09bd'), ('\u09ce', '\u09ce'), - ('\u09dc', '\u09dd'), ('\u09df', '\u09e1'), - ('\u09f0', '\u09f1'), ('\u0a05', '\u0a0a'), - ('\u0a0f', '\u0a10'), ('\u0a13', '\u0a28'), - ('\u0a2a', '\u0a30'), ('\u0a32', '\u0a33'), - ('\u0a35', '\u0a36'), ('\u0a38', '\u0a39'), - ('\u0a59', '\u0a5c'), ('\u0a5e', '\u0a5e'), - ('\u0a72', '\u0a74'), ('\u0a85', '\u0a8d'), - ('\u0a8f', '\u0a91'), ('\u0a93', '\u0aa8'), - ('\u0aaa', '\u0ab0'), ('\u0ab2', '\u0ab3'), - ('\u0ab5', '\u0ab9'), ('\u0abd', '\u0abd'), - ('\u0ad0', '\u0ad0'), ('\u0ae0', '\u0ae1'), - ('\u0b05', '\u0b0c'), ('\u0b0f', '\u0b10'), - ('\u0b13', '\u0b28'), ('\u0b2a', '\u0b30'), - ('\u0b32', '\u0b33'), ('\u0b35', '\u0b39'), - ('\u0b3d', '\u0b3d'), ('\u0b5c', '\u0b5d'), - ('\u0b5f', '\u0b61'), ('\u0b71', '\u0b71'), - ('\u0b83', '\u0b83'), ('\u0b85', '\u0b8a'), - ('\u0b8e', '\u0b90'), ('\u0b92', '\u0b95'), - ('\u0b99', '\u0b9a'), ('\u0b9c', '\u0b9c'), - ('\u0b9e', '\u0b9f'), ('\u0ba3', '\u0ba4'), - ('\u0ba8', '\u0baa'), ('\u0bae', '\u0bb9'), - ('\u0bd0', '\u0bd0'), ('\u0c05', '\u0c0c'), - ('\u0c0e', '\u0c10'), ('\u0c12', '\u0c28'), - ('\u0c2a', '\u0c33'), ('\u0c35', '\u0c39'), - ('\u0c3d', '\u0c3d'), ('\u0c58', '\u0c59'), - ('\u0c60', '\u0c61'), ('\u0c85', '\u0c8c'), - ('\u0c8e', '\u0c90'), ('\u0c92', '\u0ca8'), - ('\u0caa', '\u0cb3'), ('\u0cb5', '\u0cb9'), - ('\u0cbd', '\u0cbd'), ('\u0cde', '\u0cde'), - ('\u0ce0', '\u0ce1'), ('\u0cf1', '\u0cf2'), - ('\u0d05', '\u0d0c'), ('\u0d0e', '\u0d10'), - ('\u0d12', '\u0d3a'), ('\u0d3d', '\u0d3d'), - ('\u0d4e', '\u0d4e'), ('\u0d60', '\u0d61'), - ('\u0d7a', '\u0d7f'), ('\u0d85', '\u0d96'), - ('\u0d9a', '\u0db1'), ('\u0db3', '\u0dbb'), - ('\u0dbd', '\u0dbd'), ('\u0dc0', '\u0dc6'), - ('\u0e01', '\u0e30'), ('\u0e32', '\u0e32'), - ('\u0e40', '\u0e45'), ('\u0e46', '\u0e46'), - ('\u0e81', '\u0e82'), ('\u0e84', '\u0e84'), - ('\u0e87', '\u0e88'), ('\u0e8a', '\u0e8a'), - ('\u0e8d', '\u0e8d'), ('\u0e94', '\u0e97'), - ('\u0e99', '\u0e9f'), ('\u0ea1', '\u0ea3'), - ('\u0ea5', '\u0ea5'), ('\u0ea7', '\u0ea7'), - ('\u0eaa', '\u0eab'), ('\u0ead', '\u0eb0'), - ('\u0eb2', '\u0eb2'), ('\u0ebd', '\u0ebd'), - ('\u0ec0', '\u0ec4'), ('\u0ec6', '\u0ec6'), - ('\u0edc', '\u0edf'), ('\u0f00', '\u0f00'), - ('\u0f40', '\u0f47'), ('\u0f49', '\u0f6c'), - ('\u0f88', '\u0f8c'), ('\u1000', '\u102a'), - ('\u103f', '\u103f'), ('\u1050', '\u1055'), - ('\u105a', '\u105d'), ('\u1061', '\u1061'), - ('\u1065', '\u1066'), ('\u106e', '\u1070'), - ('\u1075', '\u1081'), ('\u108e', '\u108e'), - ('\u10a0', '\u10c5'), ('\u10c7', '\u10c7'), - ('\u10cd', '\u10cd'), ('\u10d0', '\u10fa'), - ('\u10fc', '\u10fc'), ('\u10fd', '\u1248'), - ('\u124a', '\u124d'), ('\u1250', '\u1256'), - ('\u1258', '\u1258'), ('\u125a', '\u125d'), - ('\u1260', '\u1288'), ('\u128a', '\u128d'), - ('\u1290', '\u12b0'), ('\u12b2', '\u12b5'), - ('\u12b8', '\u12be'), ('\u12c0', '\u12c0'), - ('\u12c2', '\u12c5'), ('\u12c8', '\u12d6'), - ('\u12d8', '\u1310'), ('\u1312', '\u1315'), - ('\u1318', '\u135a'), ('\u1380', '\u138f'), - ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), - ('\u166f', '\u167f'), ('\u1681', '\u169a'), - ('\u16a0', '\u16ea'), ('\u16ee', '\u16f0'), - ('\u1700', '\u170c'), ('\u170e', '\u1711'), - ('\u1720', '\u1731'), ('\u1740', '\u1751'), - ('\u1760', '\u176c'), ('\u176e', '\u1770'), - ('\u1780', '\u17b3'), ('\u17d7', '\u17d7'), - ('\u17dc', '\u17dc'), ('\u1820', '\u1842'), - ('\u1843', '\u1843'), ('\u1844', '\u1877'), - ('\u1880', '\u18a8'), ('\u18aa', '\u18aa'), - ('\u18b0', '\u18f5'), ('\u1900', '\u191c'), - ('\u1950', '\u196d'), ('\u1970', '\u1974'), - ('\u1980', '\u19ab'), ('\u19c1', '\u19c7'), - ('\u1a00', '\u1a16'), ('\u1a20', '\u1a54'), - ('\u1aa7', '\u1aa7'), ('\u1b05', '\u1b33'), - ('\u1b45', '\u1b4b'), ('\u1b83', '\u1ba0'), - ('\u1bae', '\u1baf'), ('\u1bba', '\u1be5'), - ('\u1c00', '\u1c23'), ('\u1c4d', '\u1c4f'), - ('\u1c5a', '\u1c77'), ('\u1c78', '\u1c7d'), - ('\u1ce9', '\u1cec'), ('\u1cee', '\u1cf1'), - ('\u1cf5', '\u1cf6'), ('\u1d00', '\u1d2b'), - ('\u1d2c', '\u1d6a'), ('\u1d6b', '\u1d77'), - ('\u1d78', '\u1d78'), ('\u1d79', '\u1d9a'), - ('\u1d9b', '\u1dbf'), ('\u1e00', '\u1f15'), - ('\u1f18', '\u1f1d'), ('\u1f20', '\u1f45'), - ('\u1f48', '\u1f4d'), ('\u1f50', '\u1f57'), - ('\u1f59', '\u1f59'), ('\u1f5b', '\u1f5b'), - ('\u1f5d', '\u1f5d'), ('\u1f5f', '\u1f7d'), - ('\u1f80', '\u1fb4'), ('\u1fb6', '\u1fbc'), - ('\u1fbe', '\u1fbe'), ('\u1fc2', '\u1fc4'), - ('\u1fc6', '\u1fcc'), ('\u1fd0', '\u1fd3'), - ('\u1fd6', '\u1fdb'), ('\u1fe0', '\u1fec'), - ('\u1ff2', '\u1ff4'), ('\u1ff6', '\u1ffc'), - ('\u2071', '\u2071'), ('\u207f', '\u207f'), - ('\u2090', '\u209c'), ('\u2102', '\u2102'), - ('\u2107', '\u2107'), ('\u210a', '\u2113'), - ('\u2115', '\u2115'), ('\u2118', '\u2118'), - ('\u2119', '\u211d'), ('\u2124', '\u2124'), - ('\u2126', '\u2126'), ('\u2128', '\u2128'), - ('\u212a', '\u212d'), ('\u212e', '\u212e'), - ('\u212f', '\u2134'), ('\u2135', '\u2138'), - ('\u2139', '\u2139'), ('\u213c', '\u213f'), - ('\u2145', '\u2149'), ('\u214e', '\u214e'), - ('\u2160', '\u2182'), ('\u2183', '\u2184'), - ('\u2185', '\u2188'), ('\u2c00', '\u2c2e'), - ('\u2c30', '\u2c5e'), ('\u2c60', '\u2c7b'), - ('\u2c7c', '\u2c7d'), ('\u2c7e', '\u2ce4'), - ('\u2ceb', '\u2cee'), ('\u2cf2', '\u2cf3'), - ('\u2d00', '\u2d25'), ('\u2d27', '\u2d27'), - ('\u2d2d', '\u2d2d'), ('\u2d30', '\u2d67'), - ('\u2d6f', '\u2d6f'), ('\u2d80', '\u2d96'), - ('\u2da0', '\u2da6'), ('\u2da8', '\u2dae'), - ('\u2db0', '\u2db6'), ('\u2db8', '\u2dbe'), - ('\u2dc0', '\u2dc6'), ('\u2dc8', '\u2dce'), - ('\u2dd0', '\u2dd6'), ('\u2dd8', '\u2dde'), - ('\u3005', '\u3005'), ('\u3006', '\u3006'), - ('\u3007', '\u3007'), ('\u3021', '\u3029'), - ('\u3031', '\u3035'), ('\u3038', '\u303a'), - ('\u303b', '\u303b'), ('\u303c', '\u303c'), - ('\u3041', '\u3096'), ('\u309d', '\u309e'), - ('\u309f', '\u309f'), ('\u30a1', '\u30fa'), - ('\u30fc', '\u30fe'), ('\u30ff', '\u30ff'), - ('\u3105', '\u312d'), ('\u3131', '\u318e'), - ('\u31a0', '\u31ba'), ('\u31f0', '\u31ff'), - ('\u3400', '\u4db5'), ('\u4e00', '\u9fcc'), - ('\ua000', '\ua014'), ('\ua015', '\ua015'), - ('\ua016', '\ua48c'), ('\ua4d0', '\ua4f7'), - ('\ua4f8', '\ua4fd'), ('\ua500', '\ua60b'), - ('\ua60c', '\ua60c'), ('\ua610', '\ua61f'), - ('\ua62a', '\ua62b'), ('\ua640', '\ua66d'), - ('\ua66e', '\ua66e'), ('\ua67f', '\ua67f'), - ('\ua680', '\ua697'), ('\ua6a0', '\ua6e5'), - ('\ua6e6', '\ua6ef'), ('\ua717', '\ua71f'), - ('\ua722', '\ua76f'), ('\ua770', '\ua770'), - ('\ua771', '\ua787'), ('\ua788', '\ua788'), - ('\ua78b', '\ua78e'), ('\ua790', '\ua793'), - ('\ua7a0', '\ua7aa'), ('\ua7f8', '\ua7f9'), - ('\ua7fa', '\ua7fa'), ('\ua7fb', '\ua801'), - ('\ua803', '\ua805'), ('\ua807', '\ua80a'), - ('\ua80c', '\ua822'), ('\ua840', '\ua873'), - ('\ua882', '\ua8b3'), ('\ua8f2', '\ua8f7'), - ('\ua8fb', '\ua8fb'), ('\ua90a', '\ua925'), - ('\ua930', '\ua946'), ('\ua960', '\ua97c'), - ('\ua984', '\ua9b2'), ('\ua9cf', '\ua9cf'), - ('\uaa00', '\uaa28'), ('\uaa40', '\uaa42'), - ('\uaa44', '\uaa4b'), ('\uaa60', '\uaa6f'), - ('\uaa70', '\uaa70'), ('\uaa71', '\uaa76'), - ('\uaa7a', '\uaa7a'), ('\uaa80', '\uaaaf'), - ('\uaab1', '\uaab1'), ('\uaab5', '\uaab6'), - ('\uaab9', '\uaabd'), ('\uaac0', '\uaac0'), - ('\uaac2', '\uaac2'), ('\uaadb', '\uaadc'), - ('\uaadd', '\uaadd'), ('\uaae0', '\uaaea'), - ('\uaaf2', '\uaaf2'), ('\uaaf3', '\uaaf4'), - ('\uab01', '\uab06'), ('\uab09', '\uab0e'), - ('\uab11', '\uab16'), ('\uab20', '\uab26'), - ('\uab28', '\uab2e'), ('\uabc0', '\uabe2'), - ('\uac00', '\ud7a3'), ('\ud7b0', '\ud7c6'), - ('\ud7cb', '\ud7fb'), ('\uf900', '\ufa6d'), - ('\ufa70', '\ufad9'), ('\ufb00', '\ufb06'), - ('\ufb13', '\ufb17'), ('\ufb1d', '\ufb1d'), - ('\ufb1f', '\ufb28'), ('\ufb2a', '\ufb36'), - ('\ufb38', '\ufb3c'), ('\ufb3e', '\ufb3e'), - ('\ufb40', '\ufb41'), ('\ufb43', '\ufb44'), - ('\ufb46', '\ufbb1'), ('\ufbd3', '\ufc5d'), - ('\ufc64', '\ufd3d'), ('\ufd50', '\ufd8f'), - ('\ufd92', '\ufdc7'), ('\ufdf0', '\ufdf9'), - ('\ufe71', '\ufe71'), ('\ufe73', '\ufe73'), - ('\ufe77', '\ufe77'), ('\ufe79', '\ufe79'), - ('\ufe7b', '\ufe7b'), ('\ufe7d', '\ufe7d'), - ('\ufe7f', '\ufefc'), ('\uff21', '\uff3a'), - ('\uff41', '\uff5a'), ('\uff66', '\uff6f'), - ('\uff70', '\uff70'), ('\uff71', '\uff9d'), - ('\uffa0', '\uffbe'), ('\uffc2', '\uffc7'), - ('\uffca', '\uffcf'), ('\uffd2', '\uffd7'), - ('\uffda', '\uffdc'), ('\U00010000', '\U0001000b'), - ('\U0001000d', '\U00010026'), ('\U00010028', '\U0001003a'), - ('\U0001003c', '\U0001003d'), ('\U0001003f', '\U0001004d'), - ('\U00010050', '\U0001005d'), ('\U00010080', '\U000100fa'), - ('\U00010140', '\U00010174'), ('\U00010280', '\U0001029c'), - ('\U000102a0', '\U000102d0'), ('\U00010300', '\U0001031e'), - ('\U00010330', '\U00010340'), ('\U00010341', '\U00010341'), - ('\U00010342', '\U00010349'), ('\U0001034a', '\U0001034a'), - ('\U00010380', '\U0001039d'), ('\U000103a0', '\U000103c3'), - ('\U000103c8', '\U000103cf'), ('\U000103d1', '\U000103d5'), - ('\U00010400', '\U0001044f'), ('\U00010450', '\U0001049d'), - ('\U00010800', '\U00010805'), ('\U00010808', '\U00010808'), - ('\U0001080a', '\U00010835'), ('\U00010837', '\U00010838'), - ('\U0001083c', '\U0001083c'), ('\U0001083f', '\U00010855'), - ('\U00010900', '\U00010915'), ('\U00010920', '\U00010939'), - ('\U00010980', '\U000109b7'), ('\U000109be', '\U000109bf'), - ('\U00010a00', '\U00010a00'), ('\U00010a10', '\U00010a13'), - ('\U00010a15', '\U00010a17'), ('\U00010a19', '\U00010a33'), - ('\U00010a60', '\U00010a7c'), ('\U00010b00', '\U00010b35'), - ('\U00010b40', '\U00010b55'), ('\U00010b60', '\U00010b72'), - ('\U00010c00', '\U00010c48'), ('\U00011003', '\U00011037'), - ('\U00011083', '\U000110af'), ('\U000110d0', '\U000110e8'), - ('\U00011103', '\U00011126'), ('\U00011183', '\U000111b2'), - ('\U000111c1', '\U000111c4'), ('\U00011680', '\U000116aa'), - ('\U00012000', '\U0001236e'), ('\U00012400', '\U00012462'), - ('\U00013000', '\U0001342e'), ('\U00016800', '\U00016a38'), - ('\U00016f00', '\U00016f44'), ('\U00016f50', '\U00016f50'), - ('\U00016f93', '\U00016f9f'), ('\U0001b000', '\U0001b001'), - ('\U0001d400', '\U0001d454'), ('\U0001d456', '\U0001d49c'), - ('\U0001d49e', '\U0001d49f'), ('\U0001d4a2', '\U0001d4a2'), - ('\U0001d4a5', '\U0001d4a6'), ('\U0001d4a9', '\U0001d4ac'), - ('\U0001d4ae', '\U0001d4b9'), ('\U0001d4bb', '\U0001d4bb'), - ('\U0001d4bd', '\U0001d4c3'), ('\U0001d4c5', '\U0001d505'), - ('\U0001d507', '\U0001d50a'), ('\U0001d50d', '\U0001d514'), - ('\U0001d516', '\U0001d51c'), ('\U0001d51e', '\U0001d539'), - ('\U0001d53b', '\U0001d53e'), ('\U0001d540', '\U0001d544'), - ('\U0001d546', '\U0001d546'), ('\U0001d54a', '\U0001d550'), - ('\U0001d552', '\U0001d6a5'), ('\U0001d6a8', '\U0001d6c0'), - ('\U0001d6c2', '\U0001d6da'), ('\U0001d6dc', '\U0001d6fa'), - ('\U0001d6fc', '\U0001d714'), ('\U0001d716', '\U0001d734'), - ('\U0001d736', '\U0001d74e'), ('\U0001d750', '\U0001d76e'), - ('\U0001d770', '\U0001d788'), ('\U0001d78a', '\U0001d7a8'), - ('\U0001d7aa', '\U0001d7c2'), ('\U0001d7c4', '\U0001d7cb'), - ('\U0001ee00', '\U0001ee03'), ('\U0001ee05', '\U0001ee1f'), - ('\U0001ee21', '\U0001ee22'), ('\U0001ee24', '\U0001ee24'), - ('\U0001ee27', '\U0001ee27'), ('\U0001ee29', '\U0001ee32'), - ('\U0001ee34', '\U0001ee37'), ('\U0001ee39', '\U0001ee39'), - ('\U0001ee3b', '\U0001ee3b'), ('\U0001ee42', '\U0001ee42'), - ('\U0001ee47', '\U0001ee47'), ('\U0001ee49', '\U0001ee49'), - ('\U0001ee4b', '\U0001ee4b'), ('\U0001ee4d', '\U0001ee4f'), - ('\U0001ee51', '\U0001ee52'), ('\U0001ee54', '\U0001ee54'), - ('\U0001ee57', '\U0001ee57'), ('\U0001ee59', '\U0001ee59'), - ('\U0001ee5b', '\U0001ee5b'), ('\U0001ee5d', '\U0001ee5d'), - ('\U0001ee5f', '\U0001ee5f'), ('\U0001ee61', '\U0001ee62'), - ('\U0001ee64', '\U0001ee64'), ('\U0001ee67', '\U0001ee6a'), - ('\U0001ee6c', '\U0001ee72'), ('\U0001ee74', '\U0001ee77'), - ('\U0001ee79', '\U0001ee7c'), ('\U0001ee7e', '\U0001ee7e'), - ('\U0001ee80', '\U0001ee89'), ('\U0001ee8b', '\U0001ee9b'), - ('\U0001eea1', '\U0001eea3'), ('\U0001eea5', '\U0001eea9'), - ('\U0001eeab', '\U0001eebb'), ('\U00020000', '\U0002a6d6'), - ('\U0002a700', '\U0002b734'), ('\U0002b740', '\U0002b81d'), - ('\U0002f800', '\U0002fa1d') - ]; - - pub fn XID_Start(c: char) -> bool { - bsearch_range_table(c, XID_Start_table) - } -} diff --git a/src/libcore/unstable/at_exit.rs b/src/libcore/unstable/at_exit.rs deleted file mode 100644 index d214b509dfb..00000000000 --- a/src/libcore/unstable/at_exit.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cast; -use libc::size_t; -use rand::RngUtil; -use rand; -use sys; -use task; -use vec; - -#[cfg(test)] use uint; - -/** -Register a function to be run during runtime shutdown. - -After all non-weak tasks have exited, registered exit functions will -execute, in random order, on the primary scheduler. Each function runs -in its own unsupervised task. -*/ -pub fn at_exit(f: ~fn()) { - unsafe { - let runner: &fn(*ExitFunctions) = exit_runner; - let runner_pair: sys::Closure = cast::transmute(runner); - let runner_ptr = runner_pair.code; - let runner_ptr = cast::transmute(runner_ptr); - rustrt::rust_register_exit_function(runner_ptr, ~f); - } -} - -// NB: The double pointer indirection here is because ~fn() is a fat -// pointer and due to FFI problems I am more comfortable making the -// interface use a normal pointer -mod rustrt { - use libc::c_void; - - pub extern { - fn rust_register_exit_function(runner: *c_void, f: ~~fn()); - } -} - -struct ExitFunctions { - // The number of exit functions - count: size_t, - // The buffer of exit functions - start: *~~fn() -} - -fn exit_runner(exit_fns: *ExitFunctions) { - let exit_fns = unsafe { &*exit_fns }; - let count = (*exit_fns).count; - let start = (*exit_fns).start; - - // NB: from_buf memcpys from the source, which will - // give us ownership of the array of functions - let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) }; - // Let's not make any promises about execution order - let mut rng = rand::rng(); - rng.shuffle_mut(exit_fns_vec); - - debug!("running %u exit functions", exit_fns_vec.len()); - - while !exit_fns_vec.is_empty() { - match exit_fns_vec.pop() { - ~f => { - let mut task = task::task(); - task.supervised(); - task.spawn(f); - } - } - } -} - -#[test] -fn test_at_exit() { - let i = 10; - do at_exit { - debug!("at_exit1"); - assert_eq!(i, 10); - } -} - -#[test] -fn test_at_exit_many() { - let i = 10; - for uint::range(20, 100) |j| { - do at_exit { - debug!("at_exit2"); - assert_eq!(i, 10); - assert!(j > i); - } - } -} diff --git a/src/libcore/unstable/extfmt.rs b/src/libcore/unstable/extfmt.rs deleted file mode 100644 index 8da378fdc97..00000000000 --- a/src/libcore/unstable/extfmt.rs +++ /dev/null @@ -1,690 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Support for fmt! expressions. -//! -//! The syntax is close to that of Posix format strings: -//! -//! ~~~~~~ -//! Format := '%' Parameter? Flag* Width? Precision? Type -//! Parameter := [0-9]+ '$' -//! Flag := [ 0#+-] -//! Width := Parameter | [0-9]+ -//! Precision := '.' [0-9]+ -//! Type := [bcdfiostuxX?] -//! ~~~~~~ -//! -//! * Parameter is the 1-based argument to apply the format to. Currently not -//! implemented. -//! * Flag 0 causes leading zeros to be used for padding when converting -//! numbers. -//! * Flag # causes the conversion to be done in an *alternative* manner. -//! Currently not implemented. -//! * Flag + causes signed numbers to always be prepended with a sign -//! character. -//! * Flag - left justifies the result -//! * Width specifies the minimum field width of the result. By default -//! leading spaces are added. -//! * Precision specifies the minimum number of digits for integral types -//! and the minimum number -//! of decimal places for float. -//! -//! The types currently supported are: -//! -//! * b - bool -//! * c - char -//! * d - int -//! * f - float -//! * i - int (same as d) -//! * o - uint as octal -//! * t - uint as binary -//! * u - uint -//! * x - uint as lower-case hexadecimal -//! * X - uint as upper-case hexadecimal -//! * s - str (any flavor) -//! * ? - arbitrary type (does not use the to_str trait) - -/* -Syntax Extension: fmt - -Format a string - -The 'fmt' extension is modeled on the posix printf system. - -A posix conversion ostensibly looks like this - -> %~[parameter]~[flags]~[width]~[.precision]~[length]type - -Given the different numeric type bestiary we have, we omit the 'length' -parameter and support slightly different conversions for 'type' - -> %~[parameter]~[flags]~[width]~[.precision]type - -we also only support translating-to-rust a tiny subset of the possible -combinations at the moment. - -Example: - -debug!("hello, %s!", "world"); - -*/ - -use cmp::Eq; -use prelude::*; - -/* - * We have a 'ct' (compile-time) module that parses format strings into a - * sequence of conversions. From those conversions AST fragments are built - * that call into properly-typed functions in the 'rt' (run-time) module. - * Each of those run-time conversion functions accepts another conversion - * description that specifies how to format its output. - * - * The building of the AST is currently done in a module inside the compiler, - * but should migrate over here as the plugin interface is defined. - */ - -// Functions used by the fmt extension at compile time -#[doc(hidden)] -pub mod ct { - use char; - use prelude::*; - use str; - - #[deriving(Eq)] - pub enum Signedness { Signed, Unsigned, } - - #[deriving(Eq)] - pub enum Caseness { CaseUpper, CaseLower, } - - #[deriving(Eq)] - pub enum Ty { - TyBool, - TyStr, - TyChar, - TyInt(Signedness), - TyBits, - TyHex(Caseness), - TyOctal, - TyFloat, - TyPoly, - } - - #[deriving(Eq)] - pub enum Flag { - FlagLeftJustify, - FlagLeftZeroPad, - FlagSpaceForSign, - FlagSignAlways, - FlagAlternate, - } - - #[deriving(Eq)] - pub enum Count { - CountIs(uint), - CountIsParam(uint), - CountIsNextParam, - CountImplied, - } - - #[deriving(Eq)] - struct Parsed<T> { - val: T, - next: uint - } - - pub impl<T> Parsed<T> { - fn new(val: T, next: uint) -> Parsed<T> { - Parsed {val: val, next: next} - } - } - - // A formatted conversion from an expression to a string - #[deriving(Eq)] - pub struct Conv { - param: Option<uint>, - flags: ~[Flag], - width: Count, - precision: Count, - ty: Ty - } - - // A fragment of the output sequence - #[deriving(Eq)] - pub enum Piece { PieceString(~str), PieceConv(Conv), } - - pub type ErrorFn = @fn(&str) -> !; - - pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] { - fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) { - if to > from { - ps.push(PieceString(s.slice(from, to).to_owned())); - } - } - - let lim = s.len(); - let mut h = 0; - let mut i = 0; - let mut pieces = ~[]; - - while i < lim { - if s[i] == '%' as u8 { - i += 1; - - if i >= lim { - err("unterminated conversion at end of string"); - } else if s[i] == '%' as u8 { - push_slice(&mut pieces, s, h, i); - i += 1; - } else { - push_slice(&mut pieces, s, h, i - 1); - let Parsed {val, next} = parse_conversion(s, i, lim, err); - pieces.push(val); - i = next; - } - - h = i; - } else { - i += str::utf8_char_width(s[i]); - } - } - - push_slice(&mut pieces, s, h, i); - pieces - } - - pub fn peek_num(s: &str, i: uint, lim: uint) -> Option<Parsed<uint>> { - let mut i = i; - let mut accum = 0; - let mut found = false; - - while i < lim { - match char::to_digit(s[i] as char, 10) { - Some(x) => { - found = true; - accum *= 10; - accum += x; - i += 1; - } - None => break - } - } - - if found { - Some(Parsed::new(accum, i)) - } else { - None - } - } - - pub fn parse_conversion(s: &str, i: uint, lim: uint, err: ErrorFn) -> - Parsed<Piece> { - let param = parse_parameter(s, i, lim); - // avoid copying ~[Flag] by destructuring - let Parsed {val: flags_val, next: flags_next} = parse_flags(s, - param.next, lim); - let width = parse_count(s, flags_next, lim); - let prec = parse_precision(s, width.next, lim); - let ty = parse_type(s, prec.next, lim, err); - - Parsed::new(PieceConv(Conv { - param: param.val, - flags: flags_val, - width: width.val, - precision: prec.val, - ty: ty.val}), ty.next) - } - - pub fn parse_parameter(s: &str, i: uint, lim: uint) -> - Parsed<Option<uint>> { - if i >= lim { return Parsed::new(None, i); } - - match peek_num(s, i, lim) { - Some(num) if num.next < lim && s[num.next] == '$' as u8 => - Parsed::new(Some(num.val), num.next + 1), - _ => Parsed::new(None, i) - } - } - - pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> { - let mut i = i; - let mut flags = ~[]; - - while i < lim { - let f = match s[i] as char { - '-' => FlagLeftJustify, - '0' => FlagLeftZeroPad, - ' ' => FlagSpaceForSign, - '+' => FlagSignAlways, - '#' => FlagAlternate, - _ => break - }; - - flags.push(f); - i += 1; - } - - Parsed::new(flags, i) - } - - pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed<Count> { - if i >= lim { - Parsed::new(CountImplied, i) - } else if s[i] == '*' as u8 { - let param = parse_parameter(s, i + 1, lim); - let j = param.next; - - match param.val { - None => Parsed::new(CountIsNextParam, j), - Some(n) => Parsed::new(CountIsParam(n), j) - } - } else { - match peek_num(s, i, lim) { - None => Parsed::new(CountImplied, i), - Some(num) => Parsed::new(CountIs(num.val), num.next) - } - } - } - - pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed<Count> { - if i < lim && s[i] == '.' as u8 { - let count = parse_count(s, i + 1, lim); - - // If there were no digits specified, i.e. the precision - // was ".", then the precision is 0 - match count.val { - CountImplied => Parsed::new(CountIs(0), count.next), - _ => count - } - } else { - Parsed::new(CountImplied, i) - } - } - - pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) -> - Parsed<Ty> { - if i >= lim { err("missing type in conversion"); } - - // FIXME (#2249): Do we really want two signed types here? - // How important is it to be printf compatible? - let t = match s[i] as char { - 'b' => TyBool, - 's' => TyStr, - 'c' => TyChar, - 'd' | 'i' => TyInt(Signed), - 'u' => TyInt(Unsigned), - 'x' => TyHex(CaseLower), - 'X' => TyHex(CaseUpper), - 't' => TyBits, - 'o' => TyOctal, - 'f' => TyFloat, - '?' => TyPoly, - _ => err(~"unknown type in conversion: " + s.substr(i, 1)) - }; - - Parsed::new(t, i + 1) - } - - #[cfg(test)] - fn die(s: &str) -> ! { fail!(s.to_owned()) } - - #[test] - fn test_parse_count() { - fn test(s: &str, count: Count, next: uint) -> bool { - parse_count(s, 0, s.len()) == Parsed::new(count, next) - } - - assert!(test("", CountImplied, 0)); - assert!(test("*", CountIsNextParam, 1)); - assert!(test("*1", CountIsNextParam, 1)); - assert!(test("*1$", CountIsParam(1), 3)); - assert!(test("123", CountIs(123), 3)); - } - - #[test] - fn test_parse_flags() { - fn pack(fs: &[Flag]) -> uint { - fs.foldl(0, |&p, &f| p | (1 << f as uint)) - } - - fn test(s: &str, flags: &[Flag], next: uint) { - let f = parse_flags(s, 0, s.len()); - assert_eq!(pack(f.val), pack(flags)); - assert_eq!(f.next, next); - } - - test("", [], 0); - test("!#-+ 0", [], 0); - test("#-+", [FlagAlternate, FlagLeftJustify, FlagSignAlways], 3); - test(" 0", [FlagSpaceForSign, FlagLeftZeroPad], 2); - } - - #[test] - fn test_parse_fmt_string() { - assert!(parse_fmt_string("foo %s bar", die) == ~[ - PieceString(~"foo "), - PieceConv(Conv { - param: None, - flags: ~[], - width: CountImplied, - precision: CountImplied, - ty: TyStr, - }), - PieceString(~" bar")]); - - assert!(parse_fmt_string("%s", die) == ~[ - PieceConv(Conv { - param: None, - flags: ~[], - width: CountImplied, - precision: CountImplied, - ty: TyStr, - })]); - - assert!(parse_fmt_string("%%%%", die) == ~[ - PieceString(~"%"), PieceString(~"%")]); - } - - #[test] - fn test_parse_parameter() { - fn test(s: &str, param: Option<uint>, next: uint) -> bool { - parse_parameter(s, 0, s.len()) == Parsed::new(param, next) - } - - assert!(test("", None, 0)); - assert!(test("foo", None, 0)); - assert!(test("123", None, 0)); - assert!(test("123$", Some(123), 4)); - } - - #[test] - fn test_parse_precision() { - fn test(s: &str, count: Count, next: uint) -> bool { - parse_precision(s, 0, s.len()) == Parsed::new(count, next) - } - - assert!(test("", CountImplied, 0)); - assert!(test(".", CountIs(0), 1)); - assert!(test(".*", CountIsNextParam, 2)); - assert!(test(".*1", CountIsNextParam, 2)); - assert!(test(".*1$", CountIsParam(1), 4)); - assert!(test(".123", CountIs(123), 4)); - } - - #[test] - fn test_parse_type() { - fn test(s: &str, ty: Ty) -> bool { - parse_type(s, 0, s.len(), die) == Parsed::new(ty, 1) - } - - assert!(test("b", TyBool)); - assert!(test("c", TyChar)); - assert!(test("d", TyInt(Signed))); - assert!(test("f", TyFloat)); - assert!(test("i", TyInt(Signed))); - assert!(test("o", TyOctal)); - assert!(test("s", TyStr)); - assert!(test("t", TyBits)); - assert!(test("x", TyHex(CaseLower))); - assert!(test("X", TyHex(CaseUpper))); - assert!(test("?", TyPoly)); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_parse_type_missing() { - parse_type("", 0, 0, die); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_parse_type_unknown() { - parse_type("!", 0, 1, die); - } - - #[test] - fn test_peek_num() { - let s1 = ""; - assert!(peek_num(s1, 0, s1.len()).is_none()); - - let s2 = "foo"; - assert!(peek_num(s2, 0, s2.len()).is_none()); - - let s3 = "123"; - assert_eq!(peek_num(s3, 0, s3.len()), Some(Parsed::new(123, 3))); - - let s4 = "123foo"; - assert_eq!(peek_num(s4, 0, s4.len()), Some(Parsed::new(123, 3))); - } -} - -// Functions used by the fmt extension at runtime. For now there are a lot of -// decisions made a runtime. If it proves worthwhile then some of these -// conditions can be evaluated at compile-time. For now though it's cleaner to -// implement it this way, I think. -#[doc(hidden)] -pub mod rt { - use float; - use str; - use sys; - use int; - use uint; - use vec; - use option::{Some, None, Option}; - - pub static flag_none : u32 = 0u32; - pub static flag_left_justify : u32 = 0b00000000000001u32; - pub static flag_left_zero_pad : u32 = 0b00000000000010u32; - pub static flag_space_for_sign : u32 = 0b00000000000100u32; - pub static flag_sign_always : u32 = 0b00000000001000u32; - pub static flag_alternate : u32 = 0b00000000010000u32; - - pub enum Count { CountIs(uint), CountImplied, } - - pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, } - - pub struct Conv { - flags: u32, - width: Count, - precision: Count, - ty: Ty, - } - - pub fn conv_int(cv: Conv, i: int, buf: &mut ~str) { - let radix = 10; - let prec = get_int_precision(cv); - let s : ~str = uint_to_str_prec(int::abs(i) as uint, radix, prec); - - let head = if i >= 0 { - if have_flag(cv.flags, flag_sign_always) { - Some('+') - } else if have_flag(cv.flags, flag_space_for_sign) { - Some(' ') - } else { - None - } - } else { Some('-') }; - pad(cv, s, head, PadSigned, buf); - } - pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) { - let prec = get_int_precision(cv); - let rs = - match cv.ty { - TyDefault => uint_to_str_prec(u, 10, prec), - TyHexLower => uint_to_str_prec(u, 16, prec), - - // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_consume and to_str_consume to not do a unnecessary copy. - TyHexUpper => { - let s = uint_to_str_prec(u, 16, prec); - s.to_ascii().to_upper().to_str_ascii() - } - TyBits => uint_to_str_prec(u, 2, prec), - TyOctal => uint_to_str_prec(u, 8, prec) - }; - pad(cv, rs, None, PadUnsigned, buf); - } - pub fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) { - let s = if b { "true" } else { "false" }; - // run the boolean conversion through the string conversion logic, - // giving it the same rules for precision, etc. - conv_str(cv, s, buf); - } - pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) { - pad(cv, "", Some(c), PadNozero, buf); - } - pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) { - // For strings, precision is the maximum characters - // 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) - } else { - s - } - }; - pad(cv, unpadded, None, PadNozero, buf); - } - pub fn conv_float(cv: Conv, f: float, buf: &mut ~str) { - let (to_str, digits) = match cv.precision { - CountIs(c) => (float::to_str_exact, c as uint), - CountImplied => (float::to_str_digits, 6u) - }; - let s = to_str(f, digits); - let head = if 0.0 <= f { - if have_flag(cv.flags, flag_sign_always) { - Some('+') - } else if have_flag(cv.flags, flag_space_for_sign) { - Some(' ') - } else { - None - } - } else { None }; - pad(cv, s, head, PadFloat, buf); - } - pub fn conv_poly<T>(cv: Conv, v: &T, buf: &mut ~str) { - let s = sys::log_str(v); - conv_str(cv, s, buf); - } - - // Convert a uint to string with a minimum number of digits. If precision - // is 0 and num is 0 then the result is the empty string. Could move this - // to uint: but it doesn't seem all that useful. - pub fn uint_to_str_prec(num: uint, radix: uint, prec: uint) -> ~str { - return if prec == 0u && num == 0u { - ~"" - } else { - let s = uint::to_str_radix(num, radix); - let len = str::char_len(s); - if len < prec { - let diff = prec - len; - let pad = str::from_chars(vec::from_elem(diff, '0')); - pad + s - } else { s } - }; - } - pub fn get_int_precision(cv: Conv) -> uint { - return match cv.precision { - CountIs(c) => c as uint, - CountImplied => 1u - }; - } - - #[deriving(Eq)] - pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat } - - pub fn pad(cv: Conv, s: &str, head: Option<char>, mode: PadMode, - buf: &mut ~str) { - let headsize = match head { Some(_) => 1, _ => 0 }; - let uwidth : uint = match cv.width { - CountImplied => { - for head.each |&c| { - buf.push_char(c); - } - return buf.push_str(s); - } - CountIs(width) => { width as uint } - }; - let strlen = str::char_len(s) + headsize; - if uwidth <= strlen { - for head.each |&c| { - buf.push_char(c); - } - return buf.push_str(s); - } - let mut padchar = ' '; - let diff = uwidth - strlen; - if have_flag(cv.flags, flag_left_justify) { - for head.each |&c| { - buf.push_char(c); - } - buf.push_str(s); - for diff.times { - buf.push_char(padchar); - } - return; - } - let (might_zero_pad, signed) = match mode { - PadNozero => (false, true), - PadSigned => (true, true), - PadFloat => (true, true), - PadUnsigned => (true, false) - }; - fn have_precision(cv: Conv) -> bool { - return match cv.precision { CountImplied => false, _ => true }; - } - let zero_padding = { - if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) && - (!have_precision(cv) || mode == PadFloat) { - padchar = '0'; - true - } else { - false - } - }; - let padstr = str::from_chars(vec::from_elem(diff, padchar)); - // This is completely heinous. If we have a signed value then - // potentially rip apart the intermediate result and insert some - // zeros. It may make sense to convert zero padding to a precision - // instead. - - if signed && zero_padding { - for head.each |&head| { - if head == '+' || head == '-' || head == ' ' { - buf.push_char(head); - buf.push_str(padstr); - buf.push_str(s); - return; - } - } - } - buf.push_str(padstr); - for head.each |&c| { - buf.push_char(c); - } - buf.push_str(s); - } - #[inline(always)] - pub fn have_flag(flags: u32, f: u32) -> bool { - flags & f != 0 - } -} - -// Bulk of the tests are in src/test/run-pass/syntax-extension-fmt.rs -#[cfg(test)] -mod test { - #[test] - fn fmt_slice() { - let s = "abc"; - let _s = fmt!("%s", s); - } -} diff --git a/src/libcore/unstable/finally.rs b/src/libcore/unstable/finally.rs deleted file mode 100644 index 5001fb421cd..00000000000 --- a/src/libcore/unstable/finally.rs +++ /dev/null @@ -1,139 +0,0 @@ -// 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 Finally trait provides a method, `finally` on -stack closures that emulates Java-style try/finally blocks. - -# Example - -~~~ -do || { - ... -}.finally { - alway_run_this(); -} -~~~ -*/ - -use ops::Drop; - -#[cfg(test)] use task::{failing, spawn}; - -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)() - } -} - -impl<T> Finally<T> for ~fn() -> T { - fn finally(&self, dtor: &fn()) -> T { - let _d = Finallyalizer { - dtor: dtor - }; - - (*self)() - } -} - -impl<T> Finally<T> for @fn() -> T { - fn finally(&self, dtor: &fn()) -> T { - let _d = Finallyalizer { - dtor: dtor - }; - - (*self)() - } -} - -struct Finallyalizer<'self> { - dtor: &'self fn() -} - -#[unsafe_destructor] -impl<'self> Drop for Finallyalizer<'self> { - fn finalize(&self) { - (self.dtor)(); - } -} - -#[test] -fn test_success() { - let mut i = 0; - do (|| { - i = 10; - }).finally { - assert!(!failing()); - assert_eq!(i, 10); - i = 20; - } - assert_eq!(i, 20); -} - -#[test] -#[ignore(cfg(windows))] -#[should_fail] -fn test_fail() { - let mut i = 0; - do (|| { - i = 10; - fail!(); - }).finally { - assert!(failing()); - assert_eq!(i, 10); - } -} - -#[test] -fn test_retval() { - let closure: &fn() -> int = || 10; - let i = do closure.finally { }; - assert_eq!(i, 10); -} - -#[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 but_always_run_this_function() { } - do_some_fallible_work.finally( - but_always_run_this_function); -} - -#[test] -fn test_owned() { - fn spawn_with_finalizer(f: ~fn()) { - do spawn { do f.finally { } } - } - let owned: ~fn() = || { }; - spawn_with_finalizer(owned); -} - -#[test] -fn test_managed() { - let i = @mut 10; - let managed: @fn() -> int = || { - let r = *i; - *i += 10; - r - }; - assert_eq!(do managed.finally {}, 10); - assert_eq!(*i, 20); -} \ No newline at end of file diff --git a/src/libcore/unstable/global.rs b/src/libcore/unstable/global.rs deleted file mode 100644 index 96549a83a8c..00000000000 --- a/src/libcore/unstable/global.rs +++ /dev/null @@ -1,281 +0,0 @@ -// 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. - -/*! -Global data - -An interface for creating and retrieving values with global -(per-runtime) scope. - -Global values are stored in a map and protected by a single global -mutex. Operations are provided for accessing and cloning the value -under the mutex. - -Because all globals go through a single mutex, they should be used -sparingly. The interface is intended to be used with clonable, -atomically reference counted synchronization types, like ARCs, in -which case the value should be cached locally whenever possible to -avoid hitting the mutex. -*/ - -use cast::{transmute}; -use clone::Clone; -use kinds::Owned; -use libc::{c_void}; -use option::{Option, Some, None}; -use ops::Drop; -use unstable::sync::{Exclusive, exclusive}; -use unstable::at_exit::at_exit; -use unstable::intrinsics::atomic_cxchg; -use hashmap::HashMap; -use sys::Closure; - -#[cfg(test)] use unstable::sync::{UnsafeAtomicRcBox}; -#[cfg(test)] use task::spawn; -#[cfg(test)] use uint; - -pub type GlobalDataKey<'self,T> = &'self fn(v: T); - -pub unsafe fn global_data_clone_create<T:Owned + Clone>( - key: GlobalDataKey<T>, create: &fn() -> ~T) -> T { - /*! - * Clone a global value or, if it has not been created, - * first construct the value then return a clone. - * - * # Safety note - * - * Both the clone operation and the constructor are - * called while the global lock is held. Recursive - * use of the global interface in either of these - * operations will result in deadlock. - */ - global_data_clone_create_(key_ptr(key), create) -} - -unsafe fn global_data_clone_create_<T:Owned + Clone>( - key: uint, create: &fn() -> ~T) -> T { - - let mut clone_value: Option<T> = None; - do global_data_modify_(key) |value: Option<~T>| { - match value { - None => { - let value = create(); - clone_value = Some((*value).clone()); - Some(value) - } - Some(value) => { - clone_value = Some((*value).clone()); - Some(value) - } - } - } - return clone_value.unwrap(); -} - -unsafe fn global_data_modify<T:Owned>( - key: GlobalDataKey<T>, op: &fn(Option<~T>) -> Option<~T>) { - - global_data_modify_(key_ptr(key), op) -} - -unsafe fn global_data_modify_<T:Owned>( - key: uint, op: &fn(Option<~T>) -> Option<~T>) { - - let mut old_dtor = None; - do get_global_state().with |gs| { - let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) { - Some((ptr, dtor)) => { - let value: ~T = transmute(ptr); - (op(Some(value)), Some(dtor)) - } - None => { - (op(None), None) - } - }; - match maybe_new_value { - Some(value) => { - let data: *c_void = transmute(value); - let dtor: ~fn() = match maybe_dtor { - Some(dtor) => dtor, - None => { - let dtor: ~fn() = || unsafe { - let _destroy_value: ~T = transmute(data); - }; - dtor - } - }; - let value = (data, dtor); - gs.map.insert(key, value); - } - None => { - match maybe_dtor { - Some(dtor) => old_dtor = Some(dtor), - None => () - } - } - } - } -} - -pub unsafe fn global_data_clone<T:Owned + Clone>( - key: GlobalDataKey<T>) -> Option<T> { - let mut maybe_clone: Option<T> = None; - do global_data_modify(key) |current| { - match ¤t { - &Some(~ref value) => { - maybe_clone = Some(value.clone()); - } - &None => () - } - current - } - return maybe_clone; -} - -// GlobalState is a map from keys to unique pointers and a -// destructor. Keys are pointers derived from the type of the -// global value. There is a single GlobalState instance per runtime. -struct GlobalState { - map: HashMap<uint, (*c_void, ~fn())> -} - -impl Drop for GlobalState { - fn finalize(&self) { - for self.map.each_value |v| { - match v { - &(_, ref dtor) => (*dtor)() - } - } - } -} - -fn get_global_state() -> Exclusive<GlobalState> { - - static POISON: int = -1; - - // FIXME #4728: Doing atomic_cxchg to initialize the global state - // lazily, which wouldn't be necessary with a runtime written - // in Rust - let global_ptr = unsafe { rust_get_global_data_ptr() }; - - if unsafe { *global_ptr } == 0 { - // Global state doesn't exist yet, probably - - // The global state object - let state = GlobalState { - map: HashMap::new() - }; - - // It's under a reference-counted mutex - let state = ~exclusive(state); - - // Convert it to an integer - let state_i: int = unsafe { - let state_ptr: &Exclusive<GlobalState> = state; - transmute(state_ptr) - }; - - // Swap our structure into the global pointer - let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) }; - - // Sanity check that we're not trying to reinitialize after shutdown - assert!(prev_i != POISON); - - if prev_i == 0 { - // Successfully installed the global pointer - - // Take a handle to return - let clone = (*state).clone(); - - // Install a runtime exit function to destroy the global object - do at_exit { - // Poison the global pointer - let prev_i = unsafe { - atomic_cxchg(&mut *global_ptr, state_i, POISON) - }; - assert_eq!(prev_i, state_i); - - // Capture the global state object in the at_exit closure - // so that it is destroyed at the right time - let _capture_global_state = &state; - }; - return clone; - } else { - // Somebody else initialized the globals first - let state: &Exclusive<GlobalState> = unsafe { transmute(prev_i) }; - return state.clone(); - } - } else { - let state: &Exclusive<GlobalState> = unsafe { - transmute(*global_ptr) - }; - return state.clone(); - } -} - -fn key_ptr<T:Owned>(key: GlobalDataKey<T>) -> uint { - unsafe { - let closure: Closure = transmute(key); - return transmute(closure.code); - } -} - -extern { - fn rust_get_global_data_ptr() -> *mut int; -} - -#[test] -fn test_clone_rc() { - fn key(_v: UnsafeAtomicRcBox<int>) { } - - for uint::range(0, 100) |_| { - do spawn { - unsafe { - let val = do global_data_clone_create(key) { - ~UnsafeAtomicRcBox::new(10) - }; - - assert!(val.get() == &10); - } - } - } -} - -#[test] -fn test_modify() { - fn key(_v: UnsafeAtomicRcBox<int>) { } - - unsafe { - do global_data_modify(key) |v| { - match v { - None => { Some(~UnsafeAtomicRcBox::new(10)) } - _ => fail!() - } - } - - do global_data_modify(key) |v| { - match v { - Some(sms) => { - let v = sms.get(); - assert!(*v == 10); - None - }, - _ => fail!() - } - } - - do global_data_modify(key) |v| { - match v { - None => { Some(~UnsafeAtomicRcBox::new(10)) } - _ => fail!() - } - } - } -} diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs deleted file mode 100644 index d476822819e..00000000000 --- a/src/libcore/unstable/intrinsics.rs +++ /dev/null @@ -1,211 +0,0 @@ -// 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. - -/*! rustc compiler intrinsics. - -The corresponding definitions are in librustc/middle/trans/foreign.rs. - -# Atomics - -The atomic intrinsics provide common atomic operations on machine -words, with multiple possible memory orderings. They obey the same -semantics as C++0x. See the LLVM documentation on [[atomics]]. - -[atomics]: http://llvm.org/docs/Atomics.html - -A quick refresher on memory ordering: - -* Acquire - a barrier for aquiring a lock. Subsequent reads and writes - take place after the barrier. -* Release - a barrier for releasing a lock. Preceding reads and writes - take place before the barrier. -* Sequentially consistent - sequentially consistent operations are - guaranteed to happen in order. This is the standard mode for working - with atomic types and is equivalent to Java's `volatile`. - -*/ - -#[abi = "rust-intrinsic"] -pub extern "rust-intrinsic" { - - /// Atomic compare and exchange, sequentially consistent. - pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int; - /// Atomic compare and exchange, acquire ordering. - pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int; - /// Atomic compare and exchange, release ordering. - pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int; - - /// Atomic load, sequentially consistent. - pub fn atomic_load(src: &int) -> int; - /// Atomic load, acquire ordering. - pub fn atomic_load_acq(src: &int) -> int; - - /// Atomic store, sequentially consistent. - pub fn atomic_store(dst: &mut int, val: int); - /// Atomic store, release ordering. - pub fn atomic_store_rel(dst: &mut int, val: int); - - /// Atomic exchange, sequentially consistent. - pub fn atomic_xchg(dst: &mut int, src: int) -> int; - /// Atomic exchange, acquire ordering. - pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int; - /// Atomic exchange, release ordering. - pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int; - - /// Atomic addition, sequentially consistent. - pub fn atomic_xadd(dst: &mut int, src: int) -> int; - /// Atomic addition, acquire ordering. - pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int; - /// Atomic addition, release ordering. - pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int; - - /// Atomic subtraction, sequentially consistent. - pub fn atomic_xsub(dst: &mut int, src: int) -> int; - /// Atomic subtraction, acquire ordering. - pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int; - /// Atomic subtraction, release ordering. - pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int; - - /// The size of a type in bytes. - /// - /// This is the exact number of bytes in memory taken up by a - /// value of the given type. In other words, a memset of this size - /// would *exactly* overwrite a value. When laid out in vectors - /// and structures there may be additional padding between - /// elements. - pub fn size_of<T>() -> uint; - - /// Move a value to a memory location containing a value. - /// - /// Drop glue is run on the destination, which must contain a - /// valid Rust value. - pub fn move_val<T>(dst: &mut T, src: T); - - /// Move a value to an uninitialized memory location. - /// - /// Drop glue is not run on the destination. - pub fn move_val_init<T>(dst: &mut T, src: T); - - pub fn min_align_of<T>() -> uint; - pub fn pref_align_of<T>() -> uint; - - /// Get a static pointer to a type descriptor. - pub fn get_tydesc<T>() -> *(); - - /// Create a value initialized to zero. - /// - /// `init` is unsafe because it returns a zeroed-out datum, - /// which is unsafe unless T is POD. We don't have a POD - /// kind yet. (See #4074). - pub unsafe fn init<T>() -> T; - - /// Create an uninitialized value. - pub unsafe fn uninit<T>() -> T; - - /// Move a value out of scope without running drop glue. - /// - /// `forget` is unsafe because the caller is responsible for - /// ensuring the argument is deallocated already. - pub unsafe fn forget<T>(_: T) -> (); - pub fn transmute<T,U>(e: T) -> U; - - /// Returns `true` if a type requires drop glue. - pub fn needs_drop<T>() -> bool; - - // XXX: intrinsic uses legacy modes and has reference to TyDesc - // and TyVisitor which are in librustc - //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> (); - - pub fn frame_address(f: &once fn(*u8)); - - /// Get the address of the `__morestack` stack growth function. - pub fn morestack_addr() -> *(); - - /// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic. - pub fn memmove32(dst: *mut u8, src: *u8, size: u32); - /// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic. - pub fn memmove64(dst: *mut u8, src: *u8, size: u64); - - pub fn sqrtf32(x: f32) -> f32; - pub fn sqrtf64(x: f64) -> f64; - - pub fn powif32(a: f32, x: i32) -> f32; - pub fn powif64(a: f64, x: i32) -> f64; - - // the following kill the stack canary without - // `fixed_stack_segment`. This possibly only affects the f64 - // variants, but it's hard to be sure since it seems to only - // occur with fairly specific arguments. - #[fixed_stack_segment] - pub fn sinf32(x: f32) -> f32; - #[fixed_stack_segment] - pub fn sinf64(x: f64) -> f64; - - #[fixed_stack_segment] - pub fn cosf32(x: f32) -> f32; - #[fixed_stack_segment] - pub fn cosf64(x: f64) -> f64; - - #[fixed_stack_segment] - pub fn powf32(a: f32, x: f32) -> f32; - #[fixed_stack_segment] - pub fn powf64(a: f64, x: f64) -> f64; - - #[fixed_stack_segment] - pub fn expf32(x: f32) -> f32; - #[fixed_stack_segment] - pub fn expf64(x: f64) -> f64; - - pub fn exp2f32(x: f32) -> f32; - pub fn exp2f64(x: f64) -> f64; - - pub fn logf32(x: f32) -> f32; - pub fn logf64(x: f64) -> f64; - - pub fn log10f32(x: f32) -> f32; - pub fn log10f64(x: f64) -> f64; - - pub fn log2f32(x: f32) -> f32; - pub fn log2f64(x: f64) -> f64; - - pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; - pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; - - pub fn fabsf32(x: f32) -> f32; - pub fn fabsf64(x: f64) -> f64; - - pub fn floorf32(x: f32) -> f32; - pub fn floorf64(x: f64) -> f64; - - pub fn ceilf32(x: f32) -> f32; - pub fn ceilf64(x: f64) -> f64; - - pub fn truncf32(x: f32) -> f32; - pub fn truncf64(x: f64) -> f64; - - pub fn ctpop8(x: i8) -> i8; - pub fn ctpop16(x: i16) -> i16; - pub fn ctpop32(x: i32) -> i32; - pub fn ctpop64(x: i64) -> i64; - - pub fn ctlz8(x: i8) -> i8; - pub fn ctlz16(x: i16) -> i16; - pub fn ctlz32(x: i32) -> i32; - pub fn ctlz64(x: i64) -> i64; - - pub fn cttz8(x: i8) -> i8; - pub fn cttz16(x: i16) -> i16; - pub fn cttz32(x: i32) -> i32; - pub fn cttz64(x: i64) -> i64; - - pub fn bswap16(x: i16) -> i16; - pub fn bswap32(x: i32) -> i32; - pub fn bswap64(x: i64) -> i64; -} diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs deleted file mode 100644 index 350b18d4541..00000000000 --- a/src/libcore/unstable/lang.rs +++ /dev/null @@ -1,420 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Runtime calls emitted by the compiler. - -use uint; -use cast::transmute; -use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO}; -use managed::raw::BoxRepr; -use str; -use sys; -use rt::{context, OldTaskContext}; -use rt::task::Task; -use rt::local::Local; -use option::{Option, Some, None}; -use io; -use rt::global_heap; - -#[allow(non_camel_case_types)] -pub type rust_task = c_void; - -pub static FROZEN_BIT: uint = 1 << (uint::bits - 1); -pub static MUT_BIT: uint = 1 << (uint::bits - 2); -static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; - -pub mod rustrt { - use unstable::lang::rust_task; - use libc::{c_void, c_char, uintptr_t}; - - pub extern { - #[rust_stack] - unsafe fn rust_upcall_malloc(td: *c_char, size: uintptr_t) -> *c_char; - - #[rust_stack] - unsafe fn rust_upcall_free(ptr: *c_char); - - #[fast_ffi] - unsafe fn rust_upcall_malloc_noswitch(td: *c_char, - size: uintptr_t) - -> *c_char; - - #[fast_ffi] - unsafe fn rust_upcall_free_noswitch(ptr: *c_char); - - #[rust_stack] - fn rust_take_task_borrow_list(task: *rust_task) -> *c_void; - - #[rust_stack] - fn rust_set_task_borrow_list(task: *rust_task, map: *c_void); - - #[rust_stack] - fn rust_try_get_task() -> *rust_task; - - fn rust_dbg_breakpoint(); - } -} - -#[lang="fail_"] -pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { - sys::begin_unwind_(expr, file, line); -} - -#[lang="fail_bounds_check"] -pub fn fail_bounds_check(file: *c_char, line: size_t, - index: size_t, len: size_t) { - let msg = fmt!("index out of bounds: the len is %d but the index is %d", - len as int, index as int); - do str::as_buf(msg) |p, _len| { - fail_(p as *c_char, file, line); - } -} - -#[deriving(Eq)] -struct BorrowRecord { - box: *mut BoxRepr, - file: *c_char, - line: size_t -} - -fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { - unsafe { - let cur_task: *rust_task = rustrt::rust_try_get_task(); - if cur_task.is_not_null() { - let ptr = rustrt::rust_take_task_borrow_list(cur_task); - if ptr.is_null() { - None - } else { - let v: ~[BorrowRecord] = transmute(ptr); - Some(v) - } - } else { - None - } - } -} - -fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { - unsafe { - let cur_task: *rust_task = rustrt::rust_try_get_task(); - if cur_task.is_not_null() { - let mut borrow_list: ~[BorrowRecord] = { - let ptr = rustrt::rust_take_task_borrow_list(cur_task); - if ptr.is_null() { ~[] } else { transmute(ptr) } - }; - borrow_list = f(borrow_list); - rustrt::rust_set_task_borrow_list(cur_task, transmute(borrow_list)); - } - } -} - -pub unsafe fn clear_task_borrow_list() { - // pub because it is used by the box annihilator. - let _ = try_take_task_borrow_list(); -} - -unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { - debug_borrow("fail_borrowed: ", box, 0, 0, file, line); - - match try_take_task_borrow_list() { - None => { // not recording borrows - let msg = "borrowed"; - do str::as_buf(msg) |msg_p, _| { - fail_(msg_p as *c_char, file, line); - } - } - Some(borrow_list) => { // recording borrows - let mut msg = ~"borrowed"; - let mut sep = " at "; - for borrow_list.each_reverse |entry| { - if entry.box == box { - str::push_str(&mut msg, 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)); - sep = " and at "; - } - } - do str::as_buf(msg) |msg_p, _| { - fail_(msg_p as *c_char, file, line) - } - } - } -} - -// FIXME #4942: Make these signatures agree with exchange_alloc's signatures -#[lang="exchange_malloc"] -#[inline(always)] -pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { - transmute(global_heap::malloc(transmute(td), transmute(size))) -} - -/// Because this code is so perf. sensitive, use a static constant so that -/// debug printouts are compiled out most of the time. -static ENABLE_DEBUG: bool = false; - -#[inline] -unsafe fn debug_borrow<T>(tag: &'static str, - p: *const T, - old_bits: uint, - new_bits: uint, - filename: *c_char, - line: size_t) { - //! A useful debugging function that prints a pointer + tag + newline - //! without allocating memory. - - if ENABLE_DEBUG && ::rt::env::get().debug_borrow { - debug_borrow_slow(tag, p, old_bits, new_bits, filename, line); - } - - unsafe fn debug_borrow_slow<T>(tag: &'static str, - p: *const T, - old_bits: uint, - new_bits: uint, - filename: *c_char, - line: size_t) { - let dbg = STDERR_FILENO as io::fd_t; - dbg.write_str(tag); - dbg.write_hex(p as uint); - dbg.write_str(" "); - dbg.write_hex(old_bits); - dbg.write_str(" "); - dbg.write_hex(new_bits); - dbg.write_str(" "); - dbg.write_cstr(filename); - dbg.write_str(":"); - dbg.write_hex(line as uint); - dbg.write_str("\n"); - } -} - -trait DebugPrints { - fn write_hex(&self, val: uint); - unsafe fn write_cstr(&self, str: *c_char); -} - -impl DebugPrints for io::fd_t { - fn write_hex(&self, mut i: uint) { - let letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'a', 'b', 'c', 'd', 'e', 'f']; - static uint_nibbles: uint = ::uint::bytes << 1; - let mut buffer = [0_u8, ..uint_nibbles+1]; - let mut c = uint_nibbles; - while c > 0 { - c -= 1; - buffer[c] = letters[i & 0xF] as u8; - i >>= 4; - } - self.write(buffer.slice(0, uint_nibbles)); - } - - unsafe fn write_cstr(&self, p: *c_char) { - use libc::strlen; - use vec; - - let len = strlen(p); - let p: *u8 = transmute(p); - do vec::raw::buf_as_slice(p, len as uint) |s| { - self.write(s); - } - } -} - -// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from -// inside a landing pad may corrupt the state of the exception handler. If a -// problem occurs, call exit instead. -#[lang="exchange_free"] -#[inline(always)] -pub unsafe fn exchange_free(ptr: *c_char) { - global_heap::free(transmute(ptr)) -} - -#[lang="malloc"] -pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - match context() { - OldTaskContext => { - return rustrt::rust_upcall_malloc_noswitch(td, size); - } - _ => { - let mut alloc = ::ptr::null(); - do Local::borrow::<Task> |task| { - alloc = task.heap.alloc(td as *c_void, size as uint) as *c_char; - } - return alloc; - } - } -} - -// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from -// inside a landing pad may corrupt the state of the exception handler. If a -// problem occurs, call exit instead. -#[lang="free"] -pub unsafe fn local_free(ptr: *c_char) { - match context() { - OldTaskContext => { - rustrt::rust_upcall_free_noswitch(ptr); - } - _ => { - do Local::borrow::<Task> |task| { - task.heap.free(ptr as *c_void); - } - } - } -} - -#[lang="borrow_as_imm"] -#[inline(always)] -pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; - let new_ref_count = old_ref_count | FROZEN_BIT; - - debug_borrow("borrow_as_imm:", a, old_ref_count, new_ref_count, file, line); - - if (old_ref_count & MUT_BIT) != 0 { - fail_borrowed(a, file, line); - } - - (*a).header.ref_count = new_ref_count; - - old_ref_count -} - -#[lang="borrow_as_mut"] -#[inline(always)] -pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; - let new_ref_count = old_ref_count | MUT_BIT | FROZEN_BIT; - - debug_borrow("borrow_as_mut:", a, old_ref_count, new_ref_count, file, line); - - if (old_ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { - fail_borrowed(a, file, line); - } - - (*a).header.ref_count = new_ref_count; - - old_ref_count -} - - -#[lang="record_borrow"] -pub unsafe fn record_borrow(a: *u8, old_ref_count: uint, - file: *c_char, line: size_t) { - if (old_ref_count & ALL_BITS) == 0 { - // was not borrowed before - let a: *mut BoxRepr = transmute(a); - debug_borrow("record_borrow:", a, old_ref_count, 0, file, line); - do swap_task_borrow_list |borrow_list| { - let mut borrow_list = borrow_list; - borrow_list.push(BorrowRecord {box: a, file: file, line: line}); - borrow_list - } - } -} - -#[lang="unrecord_borrow"] -pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, - file: *c_char, line: size_t) { - if (old_ref_count & ALL_BITS) == 0 { - // was not borrowed before, so we should find the record at - // the end of the list - let a: *mut BoxRepr = transmute(a); - debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line); - do swap_task_borrow_list |borrow_list| { - let mut borrow_list = borrow_list; - assert!(!borrow_list.is_empty()); - let br = borrow_list.pop(); - if br.box != a || br.file != file || br.line != line { - let err = fmt!("wrong borrow found, br=%?", br); - do str::as_buf(err) |msg_p, _| { - fail_(msg_p as *c_char, file, line) - } - } - borrow_list - } - } -} - -#[lang="return_to_mut"] -#[inline(always)] -pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint, - file: *c_char, line: size_t) { - // Sometimes the box is null, if it is conditionally frozen. - // See e.g. #4904. - if !a.is_null() { - let a: *mut BoxRepr = transmute(a); - let old_ref_count = (*a).header.ref_count; - let new_ref_count = - (old_ref_count & !ALL_BITS) | (orig_ref_count & ALL_BITS); - - debug_borrow("return_to_mut:", - a, old_ref_count, new_ref_count, file, line); - - (*a).header.ref_count = new_ref_count; - } -} - -#[lang="check_not_borrowed"] -#[inline(always)] -pub unsafe fn check_not_borrowed(a: *u8, - file: *c_char, - line: size_t) { - let a: *mut BoxRepr = transmute(a); - let ref_count = (*a).header.ref_count; - debug_borrow("check_not_borrowed:", a, ref_count, 0, file, line); - if (ref_count & FROZEN_BIT) != 0 { - fail_borrowed(a, file, line); - } -} - -#[lang="strdup_uniq"] -#[inline(always)] -pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str { - str::raw::from_buf_len(ptr, len) -} - -#[lang="start"] -pub fn start(main: *u8, argc: int, argv: **c_char, - crate_map: *u8) -> int { - use rt; - use sys::Closure; - use ptr; - use cast; - use os; - - unsafe { - let use_old_rt = os::getenv("RUST_NEWRT").is_none(); - if use_old_rt { - return rust_start(main as *c_void, argc as c_int, argv, - crate_map as *c_void) as int; - } else { - return do rt::start(argc, argv as **u8, crate_map) { - unsafe { - // `main` is an `fn() -> ()` that doesn't take an environment - // XXX: Could also call this as an `extern "Rust" fn` once they work - let main = Closure { - code: main as *(), - env: ptr::null(), - }; - let mainfn: &fn() = cast::transmute(main); - - mainfn(); - } - }; - } - } - - extern { - fn rust_start(main: *c_void, argc: c_int, argv: **c_char, - crate_map: *c_void) -> c_int; - } -} diff --git a/src/libcore/unstable/mod.rs b/src/libcore/unstable/mod.rs deleted file mode 100644 index 9681a3f36fc..00000000000 --- a/src/libcore/unstable/mod.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; - -use libc; -use comm::{GenericChan, GenericPort}; -use prelude::*; -use task; - -pub mod at_exit; -pub mod global; -pub mod finally; -pub mod weak_task; -pub mod intrinsics; -pub mod simd; -pub mod extfmt; -#[cfg(not(test))] -pub mod lang; -pub mod sync; - -/** - -Start a new thread outside of the current runtime context and wait -for it to terminate. - -The executing thread has no access to a task pointer and will be using -a normal large stack. -*/ -pub fn run_in_bare_thread(f: ~fn()) { - let (port, chan) = comm::stream(); - // FIXME #4525: Unfortunate that this creates an extra scheduler but it's - // necessary since rust_raw_thread_join_delete is blocking - do task::spawn_sched(task::SingleThreaded) { - unsafe { - let closure: &fn() = || { - f() - }; - let thread = rust_raw_thread_start(&closure); - rust_raw_thread_join_delete(thread); - chan.send(()); - } - } - port.recv(); -} - -#[test] -fn test_run_in_bare_thread() { - let i = 100; - do run_in_bare_thread { - assert_eq!(i, 100); - } -} - -#[test] -fn test_run_in_bare_thread_exchange() { - // Does the exchange heap work without the runtime? - let i = ~100; - do run_in_bare_thread { - assert!(i == ~100); - } -} - -#[allow(non_camel_case_types)] // runtime type -pub type raw_thread = libc::c_void; - -extern { - fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; - fn rust_raw_thread_join_delete(thread: *raw_thread); -} diff --git a/src/libcore/unstable/simd.rs b/src/libcore/unstable/simd.rs deleted file mode 100644 index a05f6e8af5a..00000000000 --- a/src/libcore/unstable/simd.rs +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -//! SIMD vectors - -#[allow(non_camel_case_types)]; - -#[simd] -pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8); - -#[simd] -pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); - -#[simd] -pub struct i32x4(i32, i32, i32, i32); - -#[simd] -pub struct i64x2(i64, i64); - -#[simd] -pub struct u8x16(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8); - -#[simd] -pub struct u16x8(u16, u16, u16, u16, u16, u16, u16, u16); - -#[simd] -pub struct u32x4(u32, u32, u32, u32); - -#[simd] -pub struct u64x2(u64, u64); - -#[simd] -pub struct f32x4(f32, f32, f32, f32); - -#[simd] -pub struct f64x2(f64, f64); diff --git a/src/libcore/unstable/sync.rs b/src/libcore/unstable/sync.rs deleted file mode 100644 index 734368c70c4..00000000000 --- a/src/libcore/unstable/sync.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use cast; -use libc; -use option::*; -use task; -use task::atomically; -use unstable::finally::Finally; -use unstable::intrinsics; -use ops::Drop; -use clone::Clone; -use kinds::Owned; - -/// An atomically reference counted pointer. -/// -/// Enforces no shared-memory safety. -pub struct UnsafeAtomicRcBox<T> { - data: *mut libc::c_void, -} - -struct AtomicRcBoxData<T> { - count: int, - data: Option<T>, -} - -impl<T: Owned> UnsafeAtomicRcBox<T> { - pub fn new(data: T) -> UnsafeAtomicRcBox<T> { - unsafe { - let data = ~AtomicRcBoxData { count: 1, data: Some(data) }; - let ptr = cast::transmute(data); - return UnsafeAtomicRcBox { data: ptr }; - } - } - - #[inline(always)] - pub unsafe fn get(&self) -> *mut T - { - let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data); - assert!(data.count > 0); - let r: *mut T = data.data.get_mut_ref(); - cast::forget(data); - return r; - } - - #[inline(always)] - pub unsafe fn get_immut(&self) -> *T - { - let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data); - assert!(data.count > 0); - let r: *T = cast::transmute_immut(data.data.get_mut_ref()); - cast::forget(data); - return r; - } -} - -impl<T: Owned> Clone for UnsafeAtomicRcBox<T> { - fn clone(&self) -> UnsafeAtomicRcBox<T> { - unsafe { - let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data); - let new_count = intrinsics::atomic_xadd(&mut data.count, 1) + 1; - assert!(new_count >= 2); - cast::forget(data); - return UnsafeAtomicRcBox { data: self.data }; - } - } -} - -#[unsafe_destructor] -impl<T> Drop for UnsafeAtomicRcBox<T>{ - fn finalize(&self) { - unsafe { - do task::unkillable { - let mut data: ~AtomicRcBoxData<T> = cast::transmute(self.data); - let new_count = intrinsics::atomic_xsub(&mut data.count, 1) - 1; - assert!(new_count >= 0); - if new_count == 0 { - // drop glue takes over. - } else { - cast::forget(data); - } - } - } - } -} - - -/****************************************************************************/ - -#[allow(non_camel_case_types)] // runtime type -pub type rust_little_lock = *libc::c_void; - -struct LittleLock { - l: rust_little_lock, -} - -impl Drop for LittleLock { - fn finalize(&self) { - unsafe { - rust_destroy_little_lock(self.l); - } - } -} - -fn LittleLock() -> LittleLock { - unsafe { - LittleLock { - l: rust_create_little_lock() - } - } -} - -pub impl LittleLock { - #[inline(always)] - unsafe fn lock<T>(&self, f: &fn() -> T) -> T { - do atomically { - rust_lock_little_lock(self.l); - do (|| { - f() - }).finally { - rust_unlock_little_lock(self.l); - } - } - } -} - -struct ExData<T> { - lock: LittleLock, - failed: bool, - data: T, -} - -/** - * An arc over mutable data that is protected by a lock. For library use only. - */ -pub struct Exclusive<T> { - x: UnsafeAtomicRcBox<ExData<T>> -} - -pub fn exclusive<T:Owned>(user_data: T) -> Exclusive<T> { - let data = ExData { - lock: LittleLock(), - failed: false, - data: user_data - }; - Exclusive { - x: UnsafeAtomicRcBox::new(data) - } -} - -impl<T:Owned> Clone for Exclusive<T> { - // Duplicate an exclusive ARC, as std::arc::clone. - fn clone(&self) -> Exclusive<T> { - Exclusive { x: self.x.clone() } - } -} - -pub 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. - // - // Currently, scheduling operations (i.e., yielding, receiving on a pipe, - // 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 { - let rec = self.x.get(); - do (*rec).lock.lock { - if (*rec).failed { - fail!("Poisoned exclusive - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&mut (*rec).data); - (*rec).failed = false; - result - } - } - - #[inline(always)] - unsafe fn with_imm<U>(&self, f: &fn(x: &T) -> U) -> U { - do self.with |x| { - f(cast::transmute_immut(x)) - } - } -} - -fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { - unsafe { - let old = intrinsics::atomic_cxchg(address, oldval, newval); - old == oldval - } -} - -extern { - fn rust_create_little_lock() -> rust_little_lock; - fn rust_destroy_little_lock(lock: rust_little_lock); - fn rust_lock_little_lock(lock: rust_little_lock); - fn rust_unlock_little_lock(lock: rust_little_lock); -} - -#[cfg(test)] -mod tests { - use comm; - use super::exclusive; - use task; - use uint; - - #[test] - fn exclusive_arc() { - let mut futures = ~[]; - - let num_tasks = 10; - let count = 10; - - let total = exclusive(~0); - - 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; - } - } - chan.send(()); - } - }; - - for futures.each |f| { f.recv() } - - 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); - } - }; - do x.with |one| { - assert_eq!(*one, 1); - } - } -} diff --git a/src/libcore/unstable/weak_task.rs b/src/libcore/unstable/weak_task.rs deleted file mode 100644 index d5c5230cef8..00000000000 --- a/src/libcore/unstable/weak_task.rs +++ /dev/null @@ -1,211 +0,0 @@ -// 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. - -/*! -Weak tasks - -Weak tasks are a runtime feature for building global services that -do not keep the runtime alive. Normally the runtime exits when all -tasks exits, but if a task is weak then the runtime may exit while -it is running, sending a notification to the task that the runtime -is trying to shut down. -*/ - -use cell::Cell; -use comm::{GenericSmartChan, stream}; -use comm::{Port, Chan, SharedChan, GenericChan, GenericPort}; -use hashmap::HashMap; -use option::{Some, None}; -use unstable::at_exit::at_exit; -use unstable::finally::Finally; -use unstable::global::global_data_clone_create; -use task::rt::{task_id, get_task_id}; -use task::task; - -#[cfg(test)] use task::spawn; - -type ShutdownMsg = (); - -// FIXME #4729: This could be a PortOne but I've experienced bugginess -// with oneshot pipes and try_send -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 task = get_task_id(); - // Expect the weak task service to be alive - assert!(service.try_send(RegisterWeakTask(task, shutdown_chan))); - rust_dec_kernel_live_count(); - do (|| { - f(shutdown_port.take()) - }).finally || { - rust_inc_kernel_live_count(); - // Service my have already exited - service.send(UnregisterWeakTask(task)); - } -} - -type WeakTaskService = SharedChan<ServiceMsg>; -type TaskHandle = task_id; - -fn global_data_key(_v: WeakTaskService) { } - -enum ServiceMsg { - RegisterWeakTask(TaskHandle, Chan<ShutdownMsg>), - UnregisterWeakTask(TaskHandle), - Shutdown -} - -fn create_global_service() -> ~WeakTaskService { - - debug!("creating global weak task service"); - let (port, chan) = stream::<ServiceMsg>(); - let port = Cell(port); - let chan = SharedChan::new(chan); - let chan_clone = chan.clone(); - - let mut task = task(); - task.unlinked(); - do task.spawn { - debug!("running global weak task service"); - let port = Cell(port.take()); - do (|| { - let port = port.take(); - // The weak task service is itself a weak task - debug!("weakening the weak service task"); - unsafe { rust_dec_kernel_live_count(); } - run_weak_task_service(port); - }).finally { - debug!("unweakening the weak service task"); - unsafe { rust_inc_kernel_live_count(); } - } - } - - do at_exit { - debug!("shutting down weak task service"); - chan.send(Shutdown); - } - - return ~chan_clone; -} - -fn run_weak_task_service(port: Port<ServiceMsg>) { - - let mut shutdown_map = HashMap::new(); - - loop { - match port.recv() { - RegisterWeakTask(task, shutdown_chan) => { - let previously_unregistered = - shutdown_map.insert(task, shutdown_chan); - assert!(previously_unregistered); - } - UnregisterWeakTask(task) => { - match shutdown_map.pop(&task) { - Some(shutdown_chan) => { - // Oneshot pipes must send, even though - // nobody will receive this - shutdown_chan.send(()); - } - None => fail!() - } - } - Shutdown => break - } - } - - do shutdown_map.consume |_, shutdown_chan| { - // Weak task may have already exited - shutdown_chan.send(()); - } -} - -extern { - unsafe fn rust_inc_kernel_live_count(); - unsafe fn rust_dec_kernel_live_count(); -} - -#[test] -fn test_simple() { - let (port, chan) = stream(); - do spawn { - unsafe { - do weaken_task |_signal| { - } - } - chan.send(()); - } - port.recv(); -} - -#[test] -fn test_weak_weak() { - let (port, chan) = stream(); - do spawn { - unsafe { - do weaken_task |_signal| { - } - do weaken_task |_signal| { - } - } - chan.send(()); - } - port.recv(); -} - -#[test] -fn test_wait_for_signal() { - do spawn { - unsafe { - do weaken_task |signal| { - signal.recv(); - } - } - } -} - -#[test] -fn test_wait_for_signal_many() { - use uint; - for uint::range(0, 100) |_| { - do spawn { - unsafe { - do weaken_task |signal| { - signal.recv(); - } - } - } - } -} - -#[test] -fn test_select_stream_and_oneshot() { - use comm::select2i; - use either::{Left, Right}; - - let (port, chan) = stream(); - let port = Cell(port); - let (waitport, waitchan) = stream(); - do spawn { - unsafe { - do weaken_task |mut signal| { - let mut port = port.take(); - match select2i(&mut port, &mut signal) { - Left(*) => (), - Right(*) => fail!() - } - } - } - waitchan.send(()); - } - chan.send(()); - waitport.recv(); -} diff --git a/src/libcore/util.rs b/src/libcore/util.rs deleted file mode 100644 index e2b91594d12..00000000000 --- a/src/libcore/util.rs +++ /dev/null @@ -1,190 +0,0 @@ -// 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. - -/*! - -Miscellaneous helpers for common patterns. - -*/ - -use prelude::*; -use unstable::intrinsics; - -/// The identity function. -#[inline(always)] -pub fn id<T>(x: T) -> T { x } - -/// Ignores a value. -#[inline(always)] -pub fn ignore<T>(_x: T) { } - -/// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the -/// original value of `*ptr`. -/// -/// NB: This function accepts `@mut T` and not `&mut T` to avoid -/// an obvious borrowck hazard. Typically passing in `&mut T` will -/// cause borrow check errors because it freezes whatever location -/// that `&mut T` is stored in (either statically or dynamically). -#[inline(always)] -pub fn with<T,R>( - ptr: @mut T, - value: T, - op: &fn() -> R) -> R -{ - let prev = replace(ptr, value); - let result = op(); - *ptr = prev; - return result; -} - -/** - * Swap the values at two mutable locations of the same type, without - * deinitialising or copying either one. - */ -#[inline(always)] -pub fn swap<T>(x: &mut T, y: &mut T) { - unsafe { - swap_ptr(ptr::to_mut_unsafe_ptr(x), ptr::to_mut_unsafe_ptr(y)); - } -} - -/** - * 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) { - if x == y { return } - - // Give ourselves some scratch space to work with - let mut tmp: T = intrinsics::uninit(); - let t = ptr::to_mut_unsafe_ptr(&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 t - // 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. - */ -#[inline(always)] -pub fn replace<T>(dest: &mut T, mut src: T) -> T { - swap(dest, &mut src); - 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: (), -} - -impl Drop for NonCopyable { - fn finalize(&self) { } -} - -pub fn NonCopyable() -> NonCopyable { NonCopyable { i: () } } - - -/// A type with no inhabitants -pub enum Void { } - -pub impl Void { - /// A utility function for ignoring this uninhabited type - fn uninhabited(self) -> ! { - match self { - // Nothing to match on - } - } -} - - -/** -A utility function for indicating unreachable code. It will fail if -executed. This is occasionally useful to put after loops that never -terminate normally, but instead directly return from a function. - -# Example - -~~~ -fn choose_weighted_item(v: &[Item]) -> Item { - assert!(!v.is_empty()); - let mut so_far = 0u; - for v.each |item| { - so_far += item.weight; - if so_far > 100 { - return item; - } - } - // The above loop always returns, so we must hint to the - // type checker that it isn't possible to get down here - util::unreachable(); -} -~~~ - -*/ -pub fn unreachable() -> ! { - fail!("internal error: entered unreachable code"); -} - -#[cfg(test)] -mod tests { - use option::{None, Some}; - use util::{Void, NonCopyable, id, replace, swap}; - use either::{Either, Left, Right}; - - #[test] - pub fn identity_crisis() { - // Writing a test for the identity function. How did it come to this? - let x = ~[(5, false)]; - //FIXME #3387 assert!(x.eq(id(copy x))); - let y = copy x; - assert!(x.eq(&id(y))); - } - #[test] - pub fn test_swap() { - let mut x = 31337; - let mut y = 42; - swap(&mut x, &mut y); - assert_eq!(x, 42); - assert_eq!(y, 31337); - } - #[test] - pub fn test_replace() { - let mut x = Some(NonCopyable()); - let y = replace(&mut x, None); - assert!(x.is_none()); - assert!(y.is_some()); - } - #[test] - pub fn test_uninhabited() { - let could_only_be_coin : Either <Void, ()> = Right (()); - match could_only_be_coin { - Right (coin) => coin, - Left (is_void) => is_void.uninhabited () - } - } -} diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs deleted file mode 100644 index 65f8dab25a5..00000000000 --- a/src/libcore/vec.rs +++ /dev/null @@ -1,4615 +0,0 @@ -// 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. - -//! Vectors - -#[warn(non_camel_case_types)]; - -use cast::transmute; -use cast; -use container::{Container, Mutable}; -use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; -use clone::Clone; -use old_iter::BaseIter; -use old_iter; -use iterator::Iterator; -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 sys; -use uint; -use unstable::intrinsics; -use vec; -use util; - -#[cfg(not(test))] use cmp::Equiv; - -pub mod rustrt { - use libc; - use sys; - use vec::raw; - - #[abi = "cdecl"] - pub extern { - // These names are terrible. reserve_shared applies - // to ~[] and reserve_shared_actual applies to @[]. - #[fast_ffi] - unsafe fn vec_reserve_shared(t: *sys::TypeDesc, - v: **raw::VecRepr, - n: libc::size_t); - #[fast_ffi] - unsafe fn vec_reserve_shared_actual(t: *sys::TypeDesc, - v: **raw::VecRepr, - n: libc::size_t); - } -} - -/// 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() -} - -/** - * Reserves capacity for exactly `n` elements in the given vector. - * - * If the capacity for `v` is already equal to or greater than the requested - * capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ -#[inline] -pub fn reserve<T>(v: &mut ~[T], n: uint) { - // Only make the (slow) call into the runtime if we have to - use managed; - if capacity(v) < n { - unsafe { - let ptr: **raw::VecRepr = cast::transmute(v); - let td = sys::get_type_desc::<T>(); - if ((**ptr).box_header.ref_count == - managed::raw::RC_MANAGED_UNIQUE) { - rustrt::vec_reserve_shared_actual(td, ptr, n as libc::size_t); - } else { - rustrt::vec_reserve_shared(td, ptr, n as libc::size_t); - } - } - } -} - -/** - * Reserves capacity for at least `n` elements in the given vector. - * - * 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 `v` is already equal to or greater than the requested - * capacity, then no action is taken. - * - * # Arguments - * - * * v - A vector - * * n - The number of elements to reserve space for - */ -pub fn reserve_at_least<T>(v: &mut ~[T], n: uint) { - reserve(v, uint::next_power_of_two(n)); -} - -/// Returns the number of elements the vector can hold without reallocating -#[inline(always)] -pub fn capacity<T>(v: &const ~[T]) -> uint { - unsafe { - let repr: **raw::VecRepr = transmute(v); - (**repr).unboxed.alloc / sys::nonzero_size_of::<T>() - } -} - -/// 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. -pub fn uniq_len<T>(v: &const ~[T]) -> uint { - unsafe { - let v: &~[T] = transmute(v); - as_const_buf(*v, |_p, len| len) - } -} - -/** - * Creates and initializes an owned vector. - * - * Creates an owned vector of size `n_elts` and initializes the elements - * to the value returned by the function `op`. - */ -pub fn from_fn<T>(n_elts: uint, op: old_iter::InitOp<T>) -> ~[T] { - unsafe { - let mut v = with_capacity(n_elts); - 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)); - i += 1u; - } - } - raw::set_len(&mut v, n_elts); - v - } -} - -/** - * Creates and initializes an owned vector. - * - * Creates an owned vector of size `n_elts` and initializes the elements - * to the value `t`. - */ -pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> ~[T] { - from_fn(n_elts, |_i| copy t) -} - -/// Creates a new unique vector with the same contents as the slice -pub fn to_owned<T:Copy>(t: &[T]) -> ~[T] { - from_fn(t.len(), |i| t[i]) -} - -/// Creates a new vector with a capacity of `capacity` -pub fn with_capacity<T>(capacity: uint) -> ~[T] { - let mut vec = ~[]; - reserve(&mut vec, capacity); - vec -} - -/** - * Builds a vector by calling a provided function with an argument - * function that pushes an element to the back of a vector. - * This version takes an initial capacity for the vector. - * - * # Arguments - * - * * size - An initial size of the vector to reserve - * * builder - A function that will construct the vector. It receives - * as an argument a function that will push an element - * onto the vector being constructed. - */ -#[inline(always)] -pub fn build_sized<A>(size: uint, builder: &fn(push: &fn(v: A))) -> ~[A] { - let mut vec = with_capacity(size); - builder(|x| vec.push(x)); - vec -} - -/** - * Builds a vector by calling a provided function with an argument - * function that pushes an element to the back of a vector. - * - * # Arguments - * - * * builder - A function that will construct the vector. It receives - * as an argument a function that will push an element - * onto the vector being constructed. - */ -#[inline(always)] -pub fn build<A>(builder: &fn(push: &fn(v: A))) -> ~[A] { - build_sized(4, builder) -} - -/** - * Builds a vector by calling a provided function with an argument - * function that pushes an element to the back of a vector. - * This version takes an initial size for the vector. - * - * # Arguments - * - * * size - An option, maybe containing initial size of the vector to reserve - * * builder - A function that will construct the vector. It receives - * as an argument a function that will push an element - * onto the vector being constructed. - */ -#[inline(always)] -pub fn build_sized_opt<A>(size: Option<uint>, - builder: &fn(push: &fn(v: A))) - -> ~[A] { - build_sized(size.get_or_default(4), builder) -} - -// Accessors - -/// Returns the first element of a vector -pub fn head<'r,T>(v: &'r [T]) -> &'r T { - if v.len() == 0 { fail!("head: empty vector") } - &v[0] -} - -/// Returns `Some(x)` where `x` is the first element of the slice `v`, -/// or `None` if the vector is empty. -pub fn head_opt<'r,T>(v: &'r [T]) -> Option<&'r T> { - if v.len() == 0 { None } else { Some(&v[0]) } -} - -/// Returns a vector containing all but the first element of a slice -pub fn tail<'r,T>(v: &'r [T]) -> &'r [T] { slice(v, 1, v.len()) } - -/// Returns a vector containing all but the first `n` elements of a slice -pub fn tailn<'r,T>(v: &'r [T], n: uint) -> &'r [T] { slice(v, n, v.len()) } - -/// Returns a vector containing all but the last element of a slice -pub fn init<'r,T>(v: &'r [T]) -> &'r [T] { slice(v, 0, v.len() - 1) } - -/// Returns a vector containing all but the last `n' elements of a slice -pub fn initn<'r,T>(v: &'r [T], n: uint) -> &'r [T] { - slice(v, 0, v.len() - n) -} - -/// Returns the last element of the slice `v`, failing if the slice is empty. -pub fn last<'r,T>(v: &'r [T]) -> &'r T { - if v.len() == 0 { fail!("last: empty vector") } - &v[v.len() - 1] -} - -/// Returns `Some(x)` where `x` is the last element of the slice `v`, or -/// `None` if the vector is empty. -pub fn last_opt<'r,T>(v: &'r [T]) -> Option<&'r T> { - if v.len() == 0 { None } else { Some(&v[v.len() - 1]) } -} - -/// Return a slice that points into another slice. -#[inline(always)] -pub fn slice<'r,T>(v: &'r [T], start: uint, end: uint) -> &'r [T] { - assert!(start <= end); - assert!(end <= len(v)); - do as_imm_buf(v) |p, _len| { - unsafe { - transmute((ptr::offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - -/// Return a slice that points into another slice. -#[inline(always)] -pub fn mut_slice<'r,T>(v: &'r mut [T], start: uint, end: uint) - -> &'r mut [T] { - assert!(start <= end); - assert!(end <= v.len()); - do as_mut_buf(v) |p, _len| { - unsafe { - transmute((ptr::mut_offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - -/// Return a slice that points into another slice. -#[inline(always)] -pub fn const_slice<'r,T>(v: &'r const [T], start: uint, end: uint) - -> &'r const [T] { - assert!(start <= end); - assert!(end <= len(v)); - do as_const_buf(v) |p, _len| { - unsafe { - transmute((ptr::const_offset(p, start), - (end - start) * sys::nonzero_size_of::<T>())) - } - } -} - -/// Copies - -/// 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); - if (ln == 0u) { return ~[] } - - let mut start = 0u; - let mut result = ~[]; - while start < ln { - match position_between(v, start, ln, f) { - None => break, - Some(i) => { - result.push(slice(v, start, i).to_vec()); - start = i + 1u; - } - } - } - result.push(slice(v, start, ln).to_vec()); - result -} - -/** - * Split the vector `v` by applying each element against the predicate `f` up - * to `n` times. - */ -pub fn splitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { - let ln = len(v); - if (ln == 0u) { return ~[] } - - let mut start = 0u; - let mut count = n; - let mut result = ~[]; - while start < ln && count > 0u { - match position_between(v, start, ln, f) { - None => break, - Some(i) => { - result.push(slice(v, start, i).to_vec()); - // Make sure to skip the separator. - start = i + 1u; - count -= 1u; - } - } - } - result.push(slice(v, start, ln).to_vec()); - result -} - -/** - * Reverse split the vector `v` by applying each element against the predicate - * `f`. - */ -pub fn rsplit<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[~[T]] { - let ln = len(v); - if (ln == 0) { return ~[] } - - let mut end = ln; - let mut result = ~[]; - while end > 0 { - match rposition_between(v, 0, end, f) { - None => break, - Some(i) => { - result.push(slice(v, i + 1, end).to_vec()); - end = i; - } - } - } - result.push(slice(v, 0u, end).to_vec()); - reverse(result); - result -} - -/** - * Reverse split the vector `v` by applying each element against the predicate - * `f` up to `n times. - */ -pub fn rsplitn<T:Copy>(v: &[T], n: uint, f: &fn(t: &T) -> bool) -> ~[~[T]] { - let ln = len(v); - if (ln == 0u) { return ~[] } - - let mut end = ln; - let mut count = n; - let mut result = ~[]; - while end > 0u && count > 0u { - match rposition_between(v, 0u, end, f) { - None => break, - Some(i) => { - result.push(slice(v, i + 1u, end).to_vec()); - // Make sure to skip the separator. - end = i; - count -= 1u; - } - } - } - result.push(slice(v, 0u, end).to_vec()); - reverse(result); - result -} - -/** - * Partitions a vector into two new vectors: those that satisfies the - * predicate, and those that do not. - */ -pub fn partition<T>(v: ~[T], f: &fn(&T) -> bool) -> (~[T], ~[T]) { - let mut lefts = ~[]; - let mut rights = ~[]; - - // FIXME (#4355 maybe): using v.consume here crashes - // do v.consume |_, elt| { - do consume(v) |_, elt| { - if f(&elt) { - lefts.push(elt); - } else { - rights.push(elt); - } - } - - (lefts, rights) -} - -/** - * Partitions a vector into two new vectors: those that satisfies the - * predicate, and those that do not. - */ -pub fn partitioned<T:Copy>(v: &[T], f: &fn(&T) -> bool) -> (~[T], ~[T]) { - let mut lefts = ~[]; - let mut rights = ~[]; - - for each(v) |elt| { - if f(elt) { - lefts.push(*elt); - } else { - rights.push(*elt); - } - } - - (lefts, rights) -} - -// Mutators - -/// Removes the first element from a vector and return it -pub fn shift<T>(v: &mut ~[T]) -> T { - unsafe { - assert!(!v.is_empty()); - - if v.len() == 1 { return v.pop() } - - if v.len() == 2 { - let last = v.pop(); - let first = v.pop(); - v.push(last); - return first; - } - - let ln = v.len(); - let next_ln = v.len() - 1; - - // Save the last element. We're going to overwrite its position - let work_elt = v.pop(); - // We still should have room to work where what last element was - assert!(capacity(v) >= ln); - // Pretend like we have the original length so we can use - // the vector copy_memory to overwrite the hole we just made - raw::set_len(&mut *v, ln); - - // Memcopy the head element (the one we want) to the location we just - // popped. For the moment it unsafely exists at both the head and last - // positions - { - let first_slice = slice(*v, 0, 1); - let last_slice = slice(*v, next_ln, ln); - raw::copy_memory(transmute(last_slice), first_slice, 1); - } - - // Memcopy everything to the left one element - { - let init_slice = slice(*v, 0, next_ln); - let tail_slice = slice(*v, 1, ln); - raw::copy_memory(transmute(init_slice), - tail_slice, - next_ln); - } - - // Set the new length. Now the vector is back to normal - raw::set_len(&mut *v, next_ln); - - // Swap out the element we want from the end - let vp = raw::to_mut_ptr(*v); - let vp = ptr::mut_offset(vp, next_ln - 1); - - util::replace_ptr(vp, work_elt) - } -} - -/// Prepend an element to the vector -pub fn unshift<T>(v: &mut ~[T], x: T) { - let vv = util::replace(v, ~[x]); - v.push_all_move(vv); -} - -/// Insert an element at position i within v, shifting all -/// elements after position i one position to the right. -pub fn insert<T>(v: &mut ~[T], i: uint, x: T) { - let len = v.len(); - assert!(i <= len); - - v.push(x); - let mut j = len; - while j > i { - swap(*v, j, j - 1); - j -= 1; - } -} - -/// Remove and return the element at position i within v, shifting -/// all elements after position i one position to the left. -pub fn remove<T>(v: &mut ~[T], i: uint) -> T { - let len = v.len(); - assert!(i < len); - - let mut j = i; - while j < len - 1 { - swap(*v, j, j + 1); - j += 1; - } - v.pop() -} - -pub fn consume<T>(mut v: ~[T], f: &fn(uint, v: T)) { - unsafe { - do as_mut_buf(v) |p, ln| { - for uint::range(0, ln) |i| { - // NB: This unsafe operation counts on init writing 0s to the - // holes we create in the vector. That ensures that, if the - // iterator fails then we won't try to clean up the consumed - // elements during unwinding - let x = intrinsics::init(); - let p = ptr::mut_offset(p, i); - f(i, util::replace_ptr(p, x)); - } - } - - raw::set_len(&mut v, 0); - } -} - -pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) { - unsafe { - do as_mut_buf(v) |p, ln| { - let mut i = ln; - while i > 0 { - i -= 1; - - // NB: This unsafe operation counts on init writing 0s to the - // holes we create in the vector. That ensures that, if the - // iterator fails then we won't try to clean up the consumed - // elements during unwinding - let x = intrinsics::init(); - let p = ptr::mut_offset(p, i); - f(i, util::replace_ptr(p, x)); - } - } - - raw::set_len(&mut v, 0); - } -} - -/// Remove the last element from a vector and return it -pub fn pop<T>(v: &mut ~[T]) -> T { - let ln = v.len(); - if ln == 0 { - fail!("sorry, cannot vec::pop an empty vector") - } - let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]); - unsafe { - let val = util::replace_ptr(valptr, intrinsics::init()); - raw::set_len(v, ln - 1u); - val - } -} - -/** - * Remove an element from anywhere in the vector and return it, replacing it - * with the last element. This does not preserve ordering, but is O(1). - * - * Fails if index >= length. - */ -pub fn swap_remove<T>(v: &mut ~[T], index: uint) -> T { - let ln = v.len(); - if index >= ln { - fail!("vec::swap_remove - index %u >= length %u", index, ln); - } - if index < ln - 1 { - swap(*v, index, ln - 1); - } - v.pop() -} - -/// Append an element to a vector -#[inline(always)] -pub fn push<T>(v: &mut ~[T], initval: T) { - unsafe { - let repr: **raw::VecRepr = transmute(&mut *v); - let fill = (**repr).unboxed.fill; - if (**repr).unboxed.alloc > fill { - push_fast(v, initval); - } - else { - push_slow(v, initval); - } - } -} - -// This doesn't bother to make sure we have space. -#[inline(always)] // really pretty please -unsafe fn push_fast<T>(v: &mut ~[T], initval: T) { - let repr: **mut raw::VecRepr = transmute(v); - let fill = (**repr).unboxed.fill; - (**repr).unboxed.fill += sys::nonzero_size_of::<T>(); - let p = to_unsafe_ptr(&((**repr).unboxed.data)); - let p = ptr::offset(p, fill) as *mut T; - intrinsics::move_val_init(&mut(*p), initval); -} - -#[inline(never)] -fn push_slow<T>(v: &mut ~[T], initval: T) { - let new_len = v.len() + 1; - reserve_at_least(&mut *v, new_len); - unsafe { push_fast(v, initval) } -} - -#[inline(always)] -pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) { - let new_len = v.len() + rhs.len(); - reserve(&mut *v, new_len); - - for uint::range(0u, rhs.len()) |i| { - push(&mut *v, unsafe { raw::get(rhs, i) }) - } -} - -#[inline(always)] -pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) { - let new_len = v.len() + rhs.len(); - reserve(&mut *v, new_len); - 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()); - push(&mut *v, x); - } - } - raw::set_len(&mut rhs, 0); - } -} - -/// Shorten a vector, dropping excess elements. -pub fn truncate<T>(v: &mut ~[T], newlen: uint) { - do as_mut_buf(*v) |p, oldlen| { - assert!(newlen <= oldlen); - 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()); - } - } - } - unsafe { raw::set_len(&mut *v, newlen); } -} - -/** - * Remove consecutive repeated elements from a vector; if the vector is - * sorted, this removes all duplicates. - */ -pub fn dedup<T:Eq>(v: &mut ~[T]) { - unsafe { - if v.len() < 1 { return; } - let mut last_written = 0, next_to_read = 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) - let p = p as *mut T; - // last_written < next_to_read <= ln - while next_to_read < ln { - // 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()); - } 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)); - } - } - // last_written <= next_to_read < ln - next_to_read += 1; - // last_written < next_to_read <= ln - } - } - // last_written < next_to_read == ln - raw::set_len(v, last_written + 1); - } -} - -// Appending -#[inline(always)] -pub fn append<T:Copy>(lhs: ~[T], rhs: &const [T]) -> ~[T] { - let mut v = lhs; - v.push_all(rhs); - v -} - -#[inline(always)] -pub fn append_one<T>(lhs: ~[T], x: T) -> ~[T] { - let mut v = lhs; - v.push(x); - v -} - -/** - * Expands a vector in place, initializing the new elements to a given value - * - * # Arguments - * - * * v - The vector to grow - * * n - The number of elements to add - * * initval - The value for the new elements - */ -pub fn grow<T:Copy>(v: &mut ~[T], n: uint, initval: &T) { - let new_len = v.len() + n; - reserve_at_least(&mut *v, new_len); - let mut i: uint = 0u; - - while i < n { - v.push(*initval); - i += 1u; - } -} - -/** - * Expands a vector in place, initializing the new elements to the result of - * a function - * - * Function `init_op` is called `n` times with the values [0..`n`) - * - * # Arguments - * - * * v - The vector to grow - * * n - The number of elements to add - * * init_op - A function to call to retreive each appended element's - * value - */ -pub fn grow_fn<T>(v: &mut ~[T], n: uint, op: old_iter::InitOp<T>) { - let new_len = v.len() + n; - reserve_at_least(&mut *v, new_len); - let mut i: uint = 0u; - while i < n { - v.push(op(i)); - i += 1u; - } -} - -/** - * Sets the value of a vector element at a given index, growing the vector as - * needed - * - * Sets the element at position `index` to `val`. If `index` is past the end - * of the vector, expands the vector by replicating `initval` to fill the - * intervening space. - */ -pub fn grow_set<T:Copy>(v: &mut ~[T], index: uint, initval: &T, val: T) { - let l = v.len(); - if index >= l { grow(&mut *v, index - l + 1u, initval); } - v[index] = val; -} - -// Functional utilities - -/// 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)); - for each(v) |elem| { - result.push(f(elem)); - } - result -} - -pub fn map_consume<T, U>(v: ~[T], f: &fn(v: T) -> U) -> ~[U] { - let mut result = ~[]; - do consume(v) |_i, x| { - result.push(f(x)); - } - result -} - -/// Apply a function to each element of a vector and return the results -pub fn mapi<T, U>(v: &[T], f: &fn(uint, t: &T) -> U) -> ~[U] { - let mut i = 0; - do map(v) |e| { - i += 1; - f(i - 1, e) - } -} - -/** - * Apply a function to each element of a vector and return a concatenation - * of each result vector - */ -pub fn flat_map<T, U>(v: &[T], f: &fn(t: &T) -> ~[U]) -> ~[U] { - let mut result = ~[]; - for each(v) |elem| { result.push_all_move(f(elem)); } - result -} - -/** - * Apply a function to each pair of elements and return the results. - * Equivalent to `map(zip(v0, v1), f)`. - */ -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 mut u: ~[V] = ~[]; - let mut i = 0u; - while i < v0_len { - u.push(f(&v0[i], &v1[i])); - i += 1u; - } - u -} - -pub fn filter_map<T, U>( - v: ~[T], - f: &fn(t: T) -> Option<U>) -> ~[U] -{ - /*! - * - * Apply a function to each element of a vector and return the results. - * Consumes the input vector. If function `f` returns `None` then that - * element is excluded from the resulting vector. - */ - - let mut result = ~[]; - do consume(v) |_, elem| { - match f(elem) { - None => {} - Some(result_elem) => { result.push(result_elem); } - } - } - result -} - -pub fn filter_mapped<T, U: Copy>( - v: &[T], - f: &fn(t: &T) -> Option<U>) -> ~[U] -{ - /*! - * - * Like `filter_map()`, but operates on a borrowed slice - * and does not consume the input. - */ - - let mut result = ~[]; - for each(v) |elem| { - match f(elem) { - None => {/* no-op */ } - Some(result_elem) => { result.push(result_elem); } - } - } - result -} - -/** - * Construct a new vector from the elements of a vector for which some - * predicate holds. - * - * Apply function `f` to each element of `v` and return a vector containing - * only those elements for which `f` returned true. - */ -pub fn filter<T>(v: ~[T], f: &fn(t: &T) -> bool) -> ~[T] { - let mut result = ~[]; - // FIXME (#4355 maybe): using v.consume here crashes - // do v.consume |_, elem| { - do consume(v) |_, elem| { - if f(&elem) { result.push(elem); } - } - result -} - -/** - * Construct a new vector from the elements of a vector for which some - * predicate holds. - * - * Apply function `f` to each element of `v` and return a vector containing - * only those elements for which `f` returned true. - */ -pub fn filtered<T:Copy>(v: &[T], f: &fn(t: &T) -> bool) -> ~[T] { - let mut result = ~[]; - for each(v) |elem| { - if f(elem) { result.push(*elem); } - } - result -} - -/** - * Like `filter()`, but in place. Preserves order of `v`. Linear time. - */ -pub fn retain<T>(v: &mut ~[T], f: &fn(t: &T) -> bool) { - let len = v.len(); - let mut deleted: uint = 0; - - for uint::range(0, len) |i| { - if !f(&v[i]) { - deleted += 1; - } else if deleted > 0 { - swap(*v, i - deleted, i); - } - } - - if deleted > 0 { - v.truncate(len - deleted); - } -} - -/** - * 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 -} - -/// 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 -} - -/** - * 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]: - * - * ~~~ - * 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 -} - -/** - * 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]: - * - * ~~~ - * 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; -} - -/** - * 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 -} - -/** - * 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; - } - 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 -} - -/** - * 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 -} - -/** - * 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 -} - -/// Return true if a vector contains an element with the given value -pub fn contains<T:Eq>(v: &[T], x: &T) -> bool { - for each(v) |elt| { if *x == *elt { return true; } } - 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 - * - * Apply function `f` to each element of `v`, starting from the first. - * When function `f` returns true then an option containing the element - * 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) -} - -/** - * Search for the first element that matches a given predicate within a range - * - * Apply function `f` to each element of `v` within the range - * [`start`, `end`). When function `f` returns true then an option containing - * the element is returned. If `f` matches no elements then none is returned. - */ -pub fn find_between<T:Copy>(v: &[T], start: uint, end: uint, - f: &fn(t: &T) -> bool) -> Option<T> { - position_between(v, start, end, f).map(|i| v[*i]) -} - -/** - * Search for the last element that matches a given predicate - * - * Apply function `f` to each element of `v` in reverse order. When function - * `f` returns true then an option containing the element is returned. If `f` - * 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) -} - -/** - * Search for the last element that matches a given predicate within a range - * - * Apply function `f` to each element of `v` in reverse order within the range - * [`start`, `end`). When function `f` returns true then an option containing - * the element is returned. If `f` matches no elements then none is return. - */ -pub fn rfind_between<T:Copy>(v: &[T], - start: uint, - end: uint, - f: &fn(t: &T) -> bool) - -> Option<T> { - rposition_between(v, start, end, f).map(|i| v[*i]) -} - -/// Find the first index containing a matching value -pub fn position_elem<T:Eq>(v: &[T], x: &T) -> Option<uint> { - position(v, |y| *x == *y) -} - -/** - * Find the first index matching some predicate - * - * Apply function `f` to each element of `v`. When function `f` returns true - * then an option containing the index is returned. If `f` matches no elements - * then none is returned. - */ -pub fn position<T>(v: &[T], f: &fn(t: &T) -> bool) -> Option<uint> { - position_between(v, 0u, len(v), f) -} - -/** - * Find the first index matching some predicate within a range - * - * Apply function `f` to each element of `v` between the range - * [`start`, `end`). When function `f` returns true then an option containing - * the index is returned. If `f` matches no elements then none is returned. - */ -pub fn position_between<T>(v: &[T], - start: uint, - end: uint, - f: &fn(t: &T) -> bool) - -> Option<uint> { - assert!(start <= end); - assert!(end <= len(v)); - let mut i = start; - while i < end { if f(&v[i]) { return Some::<uint>(i); } i += 1u; } - None -} - -/// Find the last index containing a matching value -pub fn rposition_elem<T:Eq>(v: &[T], x: &T) -> Option<uint> { - rposition(v, |y| *x == *y) -} - -/** - * Find the last index matching some predicate - * - * Apply function `f` to each element of `v` in reverse order. When function - * `f` returns true then an option containing the index is returned. If `f` - * 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) -} - -/** - * Find the last index matching some predicate within a range - * - * Apply function `f` to each element of `v` in reverse order between the - * range [`start`, `end`). When function `f` returns true then an option - * containing the index is returned. If `f` matches no elements then none is - * returned. - */ -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)); - let mut i = end; - while i > start { - if f(&v[i - 1u]) { return Some::<uint>(i - 1u); } - i -= 1u; - } - None -} - - - -/** - * Binary search a sorted vector with a comparator function. - * - * The comparator should implement an order consistent with the sort - * order of the underlying vector, returning an order code that indicates - * whether its argument is `Less`, `Equal` or `Greater` the desired target. - * - * Returns the index where the comparator returned `Equal`, or `None` if - * not found. - */ -pub fn bsearch<T>(v: &[T], f: &fn(&T) -> Ordering) -> Option<uint> { - let mut base : uint = 0; - let mut lim : uint = v.len(); - - while lim != 0 { - let ix = base + (lim >> 1); - match f(&v[ix]) { - Equal => return Some(ix), - Less => { - base = ix + 1; - lim -= 1; - } - Greater => () - } - lim >>= 1; - } - return None; -} - -/** - * Binary search a sorted vector for a given element. - * - * Returns the index of the element or None if not found. - */ -pub fn bsearch_elem<T:TotalOrd>(v: &[T], x: &T) -> Option<uint> { - bsearch(v, |p| p.cmp(x)) -} - -// FIXME: if issue #586 gets implemented, could have a postcondition -// saying the two result lists have the same length -- or, could -// return a nominal record with a constraint saying that, instead of -// returning a tuple (contingent on issue #869) -/** - * 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 = ~[]; - for each(v) |p| { - let (t, u) = *p; - ts.push(t); - us.push(u); - } - (ts, us) -} - -/** - * Convert a vector of pairs into a pair of vectors. - * - * Returns a tuple containing two vectors where the i-th element of the first - * vector contains the first element of the i-th tuple of the input vector, - * and the i-th element of the second vector contains the second element - * of the i-th tuple of the input vector. - */ -pub fn unzip<T,U>(v: ~[(T, U)]) -> (~[T], ~[U]) { - let mut ts = ~[], us = ~[]; - do consume(v) |_i, p| { - let (t, u) = p; - ts.push(t); - us.push(u); - } - (ts, us) -} - -/** - * Convert two vectors to a vector of pairs, by reference. As zip(). - */ -pub fn zip_slice<T:Copy,U:Copy>(v: &const [T], u: &const [U]) - -> ~[(T, U)] { - let mut zipped = ~[]; - let sz = len(v); - let mut i = 0u; - assert_eq!(sz, len(u)); - while i < sz { - zipped.push((v[i], u[i])); - i += 1u; - } - zipped -} - -/** - * Convert two vectors to a vector of pairs. - * - * Returns a vector of tuples, where the i-th tuple contains 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 w = with_capacity(i); - while i > 0 { - w.push((v.pop(),u.pop())); - i -= 1; - } - reverse(w); - w -} - -/** - * Swaps two elements in a vector - * - * # Arguments - * - * * v The input vector - * * a - The index of the first element - * * b - The index of the second element - */ -#[inline(always)] -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); - } -} - -/// 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); - while i < ln / 2 { - swap(v, i, ln - i - 1); - i += 1; - } -} - -/** - * Reverse part of a vector in place. - * - * Reverse the elements in the vector between `start` and `end - 1`. - * - * If either start or end do not represent valid positions in the vector, the - * vector is returned unchanged. - * - * # Arguments - * - * * `v` - The mutable vector to be modified - * - * * `start` - Index of the first element of the slice - * - * * `end` - Index one past the final element to be reversed. - * - * # Example - * - * Assume a mutable vector `v` contains `[1,2,3,4,5]`. After the call: - * - * ~~~ - * - * reverse_part(v, 1, 4); - * - * ~~~ - * - * `v` now contains `[1,4,3,2,5]`. - */ -pub fn reverse_part<T>(v: &mut [T], start: uint, end : uint) { - let sz = v.len(); - if start >= sz || end > sz { return; } - let mut i = start; - let mut j = end - 1; - while i < j { - vec::swap(v, i, j); - i += 1; - j -= 1; - } -} - -/// 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); - if i == 0 { return (rs); } else { i -= 1; } - while i != 0 { rs.push(v[i]); i -= 1; } - rs.push(v[0]); - rs -} - -/** - * Iterates over a vector, yielding each element to a closure. - * - * # Arguments - * - * * `v` - A vector, to be iterated over - * * `f` - A closure to do the iterating. Within this closure, return true to - * * continue iterating, false to break. - * - * # Examples - * ~~~ - * [1,2,3].each(|&i| { - * io::println(int::str(i)); - * true - * }); - * ~~~ - * - * ~~~ - * [1,2,3,4,5].each(|&i| { - * if i < 4 { - * io::println(int::str(i)); - * true - * } - * else { - * false - * } - * }); - * ~~~ - * - * You probably will want to use each with a `for`/`do` expression, depending - * on your iteration needs: - * - * ~~~ - * for [1,2,3].each |&i| { - * io::println(int::str(i)); - * } - * ~~~ - */ -#[inline(always)] -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. - - let mut broke = false; - do as_imm_buf(v) |p, n| { - let mut n = n; - let mut p = p; - while n > 0u { - unsafe { - let q = cast::copy_lifetime_vec(v, &*p); - if !f(q) { break; } - p = ptr::offset(p, 1u); - } - n -= 1u; - } - 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) -} - -/// 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 { - let mut i = 0; - let n = v.len(); - while i < n { - if !f(&const v[i]) { - return false; - } - i += 1; - } - 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 { - let mut i = 0; - for each(v) |p| { - if !f(i, p) { return false; } - i += 1; - } - 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`. - * - * Permutations are produced in lexicographic order with respect to the order - * 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 - * repeated elements, then some permutations are repeated. - * - * See [Algorithms to generate - * permutations](http://en.wikipedia.org/wiki/Permutation). - * - * # Arguments - * - * * `values` - A vector of values from which the permutations are - * chosen - * - * * `fun` - The function to iterate over the combinations - */ -pub fn each_permutation<T:Copy>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> bool { - let length = values.len(); - let mut permutation = vec::from_fn(length, |i| values[i]); - if length <= 1 { - fun(permutation); - return true; - } - let mut indices = vec::from_fn(length, |i| i); - loop { - if !fun(permutation) { return true; } - // find largest k such that indices[k] < indices[k+1] - // if no such k exists, all permutations have been generated - let mut k = length - 2; - while k > 0 && indices[k] >= indices[k+1] { - k -= 1; - } - if k == 0 && indices[0] > indices[1] { return true; } - // find largest l such that indices[k] < indices[l] - // k+1 is guaranteed to be such - let mut l = length - 1; - while indices[k] >= indices[l] { - l -= 1; - } - // swap indices[k] and indices[l]; sort indices[k+1..] - // (they're just reversed) - vec::swap(indices, k, l); - reverse_part(indices, k+1, length); - // fixup permutation based on indices - for uint::range(k, length) |i| { - permutation[i] = values[indices[i]]; - } - } -} - -/** - * Iterate over all contiguous windows of length `n` of the vector `v`. - * - * # Example - * - * Print the adjacent pairs of a vector (i.e. `[1,2]`, `[2,3]`, `[3,4]`) - * - * ~~~ - * for windowed(2, &[1,2,3,4]) |v| { - * io::println(fmt!("%?", v)); - * } - * ~~~ - * - */ -pub fn windowed<'r, T>(n: uint, v: &'r [T], it: &fn(&'r [T]) -> bool) -> bool { - assert!(1u <= n); - if n > v.len() { return true; } - for uint::range(0, v.len() - n + 1) |i| { - if !it(v.slice(i, i + n)) { return false; } - } - return true; -} - -/** - * Work with the buffer of a vector. - * - * Allows for unsafe manipulation of vector contents, which is useful for - * foreign interop. - */ -#[inline(always)] -pub fn as_imm_buf<T,U>(s: &[T], - /* NB---this CANNOT be const, see below */ - f: &fn(*T, uint) -> U) -> U { - - // NB---Do not change the type of s to `&const [T]`. This is - // unsound. The reason is that we are going to create immutable pointers - // into `s` and pass them to `f()`, but in fact they are potentially - // pointing at *mutable memory*. Use `as_const_buf` or `as_mut_buf` - // instead! - - unsafe { - let v : *(*T,uint) = transmute(&s); - let (buf,len) = *v; - f(buf, len / sys::nonzero_size_of::<T>()) - } -} - -/// Similar to `as_imm_buf` but passing a `*const T` -#[inline(always)] -pub fn as_const_buf<T,U>(s: &const [T], f: &fn(*const T, uint) -> U) -> U { - unsafe { - let v : *(*const T,uint) = transmute(&s); - let (buf,len) = *v; - f(buf, len / sys::nonzero_size_of::<T>()) - } -} - -/// Similar to `as_imm_buf` but passing a `*mut T` -#[inline(always)] -pub fn as_mut_buf<T,U>(s: &mut [T], f: &fn(*mut T, uint) -> U) -> U { - unsafe { - let v : *(*mut T,uint) = transmute(&s); - let (buf,len) = *v; - f(buf, len / sys::nonzero_size_of::<T>()) - } -} - -// Equality - -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; } - - let mut i = 0; - while i < a_len { - if a[i] != b[i] { return false; } - i += 1; - } - true -} - -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; } - - let mut i = 0; - while i < a_len { - if !a[i].equals(&b[i]) { return false; } - i += 1; - } - true -} - -#[cfg(not(test))] -impl<'self,T:Eq> Eq for &'self [T] { - #[inline(always)] - fn eq(&self, other: & &'self [T]) -> bool { eq(*self, *other) } - #[inline(always)] - fn ne(&self, other: & &'self [T]) -> bool { !self.eq(other) } -} - -#[cfg(not(test))] -impl<T:Eq> Eq for ~[T] { - #[inline(always)] - fn eq(&self, other: &~[T]) -> bool { eq(*self, *other) } - #[inline(always)] - fn ne(&self, other: &~[T]) -> bool { !self.eq(other) } -} - -#[cfg(not(test))] -impl<T:Eq> Eq for @[T] { - #[inline(always)] - fn eq(&self, other: &@[T]) -> bool { eq(*self, *other) } - #[inline(always)] - fn ne(&self, other: &@[T]) -> bool { !self.eq(other) } -} - -#[cfg(not(test))] -impl<'self,T:TotalEq> TotalEq for &'self [T] { - #[inline(always)] - fn equals(&self, other: & &'self [T]) -> bool { equals(*self, *other) } -} - -#[cfg(not(test))] -impl<T:TotalEq> TotalEq for ~[T] { - #[inline(always)] - fn equals(&self, other: &~[T]) -> bool { equals(*self, *other) } -} - -#[cfg(not(test))] -impl<T:TotalEq> TotalEq for @[T] { - #[inline(always)] - fn equals(&self, other: &@[T]) -> bool { equals(*self, *other) } -} - -#[cfg(not(test))] -impl<'self,T:Eq> Equiv<~[T]> for &'self [T] { - #[inline(always)] - fn equiv(&self, other: &~[T]) -> bool { eq(*self, *other) } -} - -// Lexicographical comparison - -fn cmp<T: TotalOrd>(a: &[T], b: &[T]) -> Ordering { - let low = uint::min(a.len(), b.len()); - - for uint::range(0, low) |idx| { - match a[idx].cmp(&b[idx]) { - Greater => return Greater, - Less => return Less, - Equal => () - } - } - - a.len().cmp(&b.len()) -} - -#[cfg(not(test))] -impl<'self,T:TotalOrd> TotalOrd for &'self [T] { - #[inline(always)] - fn cmp(&self, other: & &'self [T]) -> Ordering { cmp(*self, *other) } -} - -#[cfg(not(test))] -impl<T: TotalOrd> TotalOrd for ~[T] { - #[inline(always)] - fn cmp(&self, other: &~[T]) -> Ordering { cmp(*self, *other) } -} - -#[cfg(not(test))] -impl<T: TotalOrd> TotalOrd for @[T] { - #[inline(always)] - fn cmp(&self, other: &@[T]) -> Ordering { cmp(*self, *other) } -} - -fn lt<T:Ord>(a: &[T], b: &[T]) -> bool { - let (a_len, b_len) = (a.len(), b.len()); - let end = uint::min(a_len, b_len); - - let mut i = 0; - while i < end { - let (c_a, c_b) = (&a[i], &b[i]); - if *c_a < *c_b { return true; } - if *c_a > *c_b { return false; } - i += 1; - } - - a_len < b_len -} - -fn le<T:Ord>(a: &[T], b: &[T]) -> bool { !lt(b, a) } -fn ge<T:Ord>(a: &[T], b: &[T]) -> bool { !lt(a, b) } -fn gt<T:Ord>(a: &[T], b: &[T]) -> bool { lt(b, a) } - -#[cfg(not(test))] -impl<'self,T:Ord> Ord for &'self [T] { - #[inline(always)] - fn lt(&self, other: & &'self [T]) -> bool { lt((*self), (*other)) } - #[inline(always)] - fn le(&self, other: & &'self [T]) -> bool { le((*self), (*other)) } - #[inline(always)] - fn ge(&self, other: & &'self [T]) -> bool { ge((*self), (*other)) } - #[inline(always)] - fn gt(&self, other: & &'self [T]) -> bool { gt((*self), (*other)) } -} - -#[cfg(not(test))] -impl<T:Ord> Ord for ~[T] { - #[inline(always)] - fn lt(&self, other: &~[T]) -> bool { lt((*self), (*other)) } - #[inline(always)] - fn le(&self, other: &~[T]) -> bool { le((*self), (*other)) } - #[inline(always)] - fn ge(&self, other: &~[T]) -> bool { ge((*self), (*other)) } - #[inline(always)] - fn gt(&self, other: &~[T]) -> bool { gt((*self), (*other)) } -} - -#[cfg(not(test))] -impl<T:Ord> Ord for @[T] { - #[inline(always)] - fn lt(&self, other: &@[T]) -> bool { lt((*self), (*other)) } - #[inline(always)] - fn le(&self, other: &@[T]) -> bool { le((*self), (*other)) } - #[inline(always)] - fn ge(&self, other: &@[T]) -> bool { ge((*self), (*other)) } - #[inline(always)] - fn gt(&self, other: &@[T]) -> bool { gt((*self), (*other)) } -} - -#[cfg(not(test))] -pub mod traits { - use kinds::Copy; - use ops::Add; - use vec::append; - - impl<'self,T:Copy> Add<&'self const [T],~[T]> for ~[T] { - #[inline(always)] - fn add(&self, rhs: & &'self const [T]) -> ~[T] { - append(copy *self, (*rhs)) - } - } -} - -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) } - - /// Returns the length of a vector - #[inline] - fn len(&const self) -> uint { len(*self) } -} - -pub trait CopyableVector<T> { - fn to_owned(&self) -> ~[T]; -} - -/// Extension methods for vectors -impl<'self,T:Copy> CopyableVector<T> for &'self [T] { - /// Returns a copy of `v`. - #[inline] - fn to_owned(&self) -> ~[T] { - let mut result = ~[]; - reserve(&mut result, self.len()); - for self.each |e| { - result.push(copy *e); - } - result - - } -} - -pub trait ImmutableVector<'self, T> { - fn slice(&self, start: uint, end: uint) -> &'self [T]; - fn iter(self) -> VecIterator<'self, T>; - fn head(&self) -> &'self T; - fn head_opt(&self) -> Option<&'self T>; - fn tail(&self) -> &'self [T]; - fn tailn(&self, n: uint) -> &'self [T]; - fn init(&self) -> &'self [T]; - fn initn(&self, n: uint) -> &'self [T]; - fn last(&self) -> &'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; -} - -/// Extension methods for vectors -impl<'self,T> ImmutableVector<'self, T> for &'self [T] { - /// Return a slice that points into another slice. - #[inline] - fn slice(&self, start: uint, end: uint) -> &'self [T] { - slice(*self, start, end) - } - - #[inline] - fn iter(self) -> VecIterator<'self, T> { - unsafe { - let p = vec::raw::to_ptr(self); - VecIterator{ptr: p, end: p.offset(self.len()), - lifetime: cast::transmute(p)} - } - } - - /// Returns the first element of a vector, failing if the vector is empty. - #[inline] - fn head(&self) -> &'self T { head(*self) } - - /// Returns the first element of a vector - #[inline] - fn head_opt(&self) -> Option<&'self T> { head_opt(*self) } - - /// Returns all but the first element of a vector - #[inline] - fn tail(&self) -> &'self [T] { tail(*self) } - - /// Returns all but the first `n' elements of a vector - #[inline] - fn tailn(&self, n: uint) -> &'self [T] { tailn(*self, n) } - - /// Returns all but the last elemnt of a vector - #[inline] - fn init(&self) -> &'self [T] { init(*self) } - - /// Returns all but the last `n' elemnts of a vector - #[inline] - fn initn(&self, n: uint) -> &'self [T] { initn(*self, n) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last(&self) -> &'self T { last(*self) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last_opt(&self) -> Option<&'self T> { last_opt(*self) } - - /** - * Find the first index matching some predicate - * - * Apply function `f` to each element of `v`. When function `f` returns - * true then an option containing the index is returned. If `f` matches no - * elements then none is returned. - */ - #[inline] - fn position(&self, f: &fn(t: &T) -> bool) -> Option<uint> { - position(*self, f) - } - - /** - * Find the last index matching some predicate - * - * Apply function `f` to each element of `v` in reverse order. When - * function `f` returns true then an option containing the index is - * returned. If `f` matches no elements then none is returned. - */ - #[inline] - fn rposition(&self, f: &fn(t: &T) -> bool) -> Option<uint> { - 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) } - - /** - * Apply a function to the index and value of each element in the vector - * and return the results - */ - fn mapi<U>(&self, f: &fn(uint, t: &T) -> U) -> ~[U] { - mapi(*self, f) - } - - #[inline] - fn map_r<U>(&self, f: &fn(x: &T) -> U) -> ~[U] { - let mut r = ~[]; - let mut i = 0; - while i < self.len() { - r.push(f(&self[i])); - i += 1; - } - r - } - - /** - * 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 - */ - #[inline] - fn flat_map<U>(&self, f: &fn(t: &T) -> ~[U]) -> ~[U] { - flat_map(*self, f) - } - /** - * Apply a function to each element of a vector and return the results - * - * If function `f` returns `none` then that element is excluded from - * the resulting vector. - */ - #[inline] - fn filter_mapped<U:Copy>(&self, f: &fn(t: &T) -> Option<U>) -> ~[U] { - filter_mapped(*self, f) - } - - /// Returns a pointer to the element at the given index, without doing - /// bounds checking. - #[inline(always)] - unsafe fn unsafe_ref(&self, index: uint) -> *T { - let (ptr, _): (*T, uint) = transmute(*self); - ptr.offset(index) - } -} - -pub trait ImmutableEqVector<T:Eq> { - fn position_elem(&self, t: &T) -> Option<uint>; - fn rposition_elem(&self, t: &T) -> Option<uint>; -} - -impl<'self,T:Eq> ImmutableEqVector<T> for &'self [T] { - /// Find the first index containing a matching value - #[inline] - fn position_elem(&self, x: &T) -> Option<uint> { - position_elem(*self, x) - } - - /// Find the last index containing a matching value - #[inline] - fn rposition_elem(&self, t: &T) -> Option<uint> { - rposition_elem(*self, t) - } -} - -pub trait ImmutableCopyableVector<T> { - fn filtered(&self, f: &fn(&T) -> bool) -> ~[T]; - fn rfind(&self, f: &fn(t: &T) -> bool) -> Option<T>; - fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]); - unsafe fn unsafe_get(&self, elem: uint) -> T; -} - -/// Extension methods for vectors -impl<'self,T:Copy> ImmutableCopyableVector<T> for &'self [T] { - /** - * Construct a new vector from the elements of a vector for which some - * predicate holds. - * - * Apply function `f` to each element of `v` and return a vector - * containing only those elements for which `f` returned true. - */ - #[inline] - fn filtered(&self, f: &fn(t: &T) -> bool) -> ~[T] { - filtered(*self, f) - } - - /** - * Search for the last element that matches a given predicate - * - * Apply function `f` to each element of `v` in reverse order. When - * function `f` returns true then an option containing the element is - * returned. If `f` matches no elements then none is returned. - */ - #[inline] - fn rfind(&self, f: &fn(t: &T) -> bool) -> Option<T> { - rfind(*self, f) - } - - /** - * Partitions the vector into those that satisfies the predicate, and - * those that do not. - */ - #[inline] - fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]) { - partitioned(*self, f) - } - - /// Returns the element at the given index, without doing bounds checking. - #[inline(always)] - unsafe fn unsafe_get(&self, index: uint) -> T { - *self.unsafe_ref(index) - } -} - -pub trait OwnedVector<T> { - fn push(&mut self, t: T); - fn push_all_move(&mut self, rhs: ~[T]); - fn pop(&mut self) -> T; - fn shift(&mut self) -> T; - fn unshift(&mut self, x: T); - fn insert(&mut self, i: uint, x:T); - fn remove(&mut self, i: uint) -> T; - fn swap_remove(&mut self, index: uint) -> T; - fn truncate(&mut self, newlen: uint); - fn retain(&mut self, f: &fn(t: &T) -> bool); - fn consume(self, f: &fn(uint, v: T)); - fn consume_reverse(self, f: &fn(uint, v: T)); - fn filter(self, f: &fn(t: &T) -> bool) -> ~[T]; - fn partition(self, f: &fn(&T) -> bool) -> (~[T], ~[T]); - fn grow_fn(&mut self, n: uint, op: old_iter::InitOp<T>); -} - -impl<T> OwnedVector<T> for ~[T] { - #[inline] - fn push(&mut self, t: T) { - push(self, t); - } - - #[inline] - fn push_all_move(&mut self, rhs: ~[T]) { - push_all_move(self, rhs); - } - - #[inline] - fn pop(&mut self) -> T { - pop(self) - } - - #[inline] - fn shift(&mut self) -> T { - shift(self) - } - - #[inline] - fn unshift(&mut self, x: T) { - unshift(self, x) - } - - #[inline] - fn insert(&mut self, i: uint, x:T) { - insert(self, i, x) - } - - #[inline] - fn remove(&mut self, i: uint) -> T { - remove(self, i) - } - - #[inline] - fn swap_remove(&mut self, index: uint) -> T { - swap_remove(self, index) - } - - #[inline] - fn truncate(&mut self, newlen: uint) { - truncate(self, newlen); - } - - #[inline] - fn retain(&mut self, f: &fn(t: &T) -> bool) { - retain(self, f); - } - - #[inline] - fn consume(self, f: &fn(uint, v: T)) { - consume(self, f) - } - - #[inline] - fn consume_reverse(self, f: &fn(uint, v: T)) { - consume_reverse(self, f) - } - - #[inline] - fn filter(self, f: &fn(&T) -> bool) -> ~[T] { - filter(self, f) - } - - /** - * Partitions the vector into those that satisfies the predicate, and - * those that do not. - */ - #[inline] - fn partition(self, f: &fn(&T) -> bool) -> (~[T], ~[T]) { - partition(self, f) - } - - #[inline] - fn grow_fn(&mut self, n: uint, op: old_iter::InitOp<T>) { - grow_fn(self, n, op); - } -} - -impl<T> Mutable for ~[T] { - /// Clear the vector, removing all values. - fn clear(&mut self) { self.truncate(0) } -} - -pub trait OwnedCopyableVector<T:Copy> { - fn push_all(&mut self, rhs: &const [T]); - fn grow(&mut self, n: uint, initval: &T); - fn grow_set(&mut self, index: uint, initval: &T, val: T); -} - -impl<T:Copy> OwnedCopyableVector<T> for ~[T] { - #[inline] - fn push_all(&mut self, rhs: &const [T]) { - push_all(self, rhs); - } - - #[inline] - fn grow(&mut self, n: uint, initval: &T) { - grow(self, n, initval); - } - - #[inline] - fn grow_set(&mut self, index: uint, initval: &T, val: T) { - grow_set(self, index, initval, val); - } -} - -trait OwnedEqVector<T:Eq> { - fn dedup(&mut self); -} - -impl<T:Eq> OwnedEqVector<T> for ~[T] { - #[inline] - fn dedup(&mut self) { - dedup(self) - } -} - -pub trait MutableVector<T> { - unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T; - unsafe fn unsafe_set(&self, index: uint, val: T); -} - -impl<'self,T> MutableVector<T> for &'self mut [T] { - #[inline(always)] - unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T { - let pair_ptr: &(*mut T, uint) = transmute(self); - let (ptr, _) = *pair_ptr; - ptr.offset(index) - } - - #[inline(always)] - unsafe fn unsafe_set(&self, index: uint, val: T) { - *self.unsafe_mut_ref(index) = val; - } -} - -/** -* Constructs a vector from an unsafe pointer to a buffer -* -* # Arguments -* -* * ptr - An unsafe pointer to a buffer of `T` -* * elts - The number of elements in the buffer -*/ -// Wrapper for fn in raw: needs to be called by net_tcp::on_tcp_read_cb -pub unsafe fn from_buf<T>(ptr: *T, elts: uint) -> ~[T] { - raw::from_buf_raw(ptr, elts) -} - -/// The internal 'unboxed' representation of a vector -pub struct UnboxedVecRepr { - fill: uint, - alloc: uint, - data: u8 -} - -/// Unsafe operations -pub mod raw { - use cast::transmute; - use kinds::Copy; - use managed; - use option::{None, Some}; - use ptr; - use sys; - use unstable::intrinsics; - use vec::{UnboxedVecRepr, as_const_buf, as_mut_buf, len, with_capacity}; - use util; - - /// The internal representation of a (boxed) vector - pub struct VecRepr { - box_header: managed::raw::BoxHeaderRepr, - unboxed: UnboxedVecRepr - } - - pub struct SliceRepr { - data: *u8, - len: uint - } - - /** - * Sets the length of a vector - * - * This will explicitly set the size of the vector, without actually - * modifing its buffers, so it is up to the caller to ensure that - * the vector is actually the specified size. - */ - #[inline(always)] - pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) { - let repr: **mut VecRepr = transmute(v); - (**repr).unboxed.fill = new_len * sys::nonzero_size_of::<T>(); - } - - /** - * Returns an unsafe pointer to the vector's buffer - * - * The caller must ensure that the vector outlives the pointer this - * function returns, or else it will end up pointing to garbage. - * - * Modifying the vector may cause its buffer to be reallocated, which - * would also make any pointers to it invalid. - */ - #[inline(always)] - pub fn to_ptr<T>(v: &[T]) -> *T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } - } - - /** see `to_ptr()` */ - #[inline(always)] - pub fn to_const_ptr<T>(v: &const [T]) -> *const T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } - } - - /** see `to_ptr()` */ - #[inline(always)] - pub fn to_mut_ptr<T>(v: &mut [T]) -> *mut T { - unsafe { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) - } - } - - /** - * Form a slice from a pointer and length (as a number of units, - * not bytes). - */ - #[inline(always)] - pub unsafe fn buf_as_slice<T,U>(p: *T, - len: uint, - f: &fn(v: &[T]) -> U) -> U { - let pair = (p, len * sys::nonzero_size_of::<T>()); - let v : *(&'blk [T]) = transmute(&pair); - f(*v) - } - - /** - * Form a slice from a pointer and length (as a number of units, - * not bytes). - */ - #[inline(always)] - pub unsafe fn mut_buf_as_slice<T,U>(p: *mut T, - len: uint, - f: &fn(v: &mut [T]) -> U) -> U { - let pair = (p, len * sys::nonzero_size_of::<T>()); - let v : *(&'blk mut [T]) = transmute(&pair); - f(*v) - } - - /** - * Unchecked vector indexing. - */ - #[inline(always)] - pub unsafe fn get<T:Copy>(v: &const [T], i: uint) -> T { - as_const_buf(v, |p, _len| *ptr::const_offset(p, i)) - } - - /** - * Unchecked vector index assignment. Does not drop the - * old value and hence is only suitable when the vector - * is newly allocated. - */ - #[inline(always)] - pub unsafe fn init_elem<T>(v: &mut [T], i: uint, val: T) { - let mut box = Some(val); - do as_mut_buf(v) |p, _len| { - let box2 = util::replace(&mut box, None); - intrinsics::move_val_init(&mut(*ptr::mut_offset(p, i)), - box2.unwrap()); - } - } - - /** - * Constructs a vector from an unsafe pointer to a buffer - * - * # Arguments - * - * * ptr - An unsafe pointer to a buffer of `T` - * * elts - The number of elements in the buffer - */ - // Was in raw, but needs to be called by net_tcp::on_tcp_read_cb - #[inline(always)] - pub unsafe fn from_buf_raw<T>(ptr: *T, elts: uint) -> ~[T] { - let mut dst = with_capacity(elts); - set_len(&mut dst, elts); - as_mut_buf(dst, |p_dst, _len_dst| ptr::copy_memory(p_dst, ptr, elts)); - dst - } - - /** - * Copies data from one vector to another. - * - * Copies `count` bytes from `src` to `dst`. The source and destination - * may overlap. - */ - #[inline(always)] - pub unsafe fn copy_memory<T>(dst: &mut [T], src: &const [T], - count: uint) { - assert!(dst.len() >= count); - assert!(src.len() >= count); - - do as_mut_buf(dst) |p_dst, _len_dst| { - do as_const_buf(src) |p_src, _len_src| { - ptr::copy_memory(p_dst, p_src, count) - } - } - } -} - -/// Operations on `[u8]` -pub mod bytes { - use libc; - use uint; - use vec::raw; - use vec; - - /// Bytewise string comparison - pub fn memcmp(a: &~[u8], b: &~[u8]) -> int { - let a_len = a.len(); - let b_len = b.len(); - let n = uint::min(a_len, b_len) as libc::size_t; - let r = unsafe { - libc::memcmp(raw::to_ptr(*a) as *libc::c_void, - raw::to_ptr(*b) as *libc::c_void, n) as int - }; - - if r != 0 { r } else { - if a_len == b_len { - 0 - } else if a_len < b_len { - -1 - } else { - 1 - } - } - } - - /// Bytewise less than or equal - pub fn lt(a: &~[u8], b: &~[u8]) -> bool { memcmp(a, b) < 0 } - - /// Bytewise less than or equal - pub fn le(a: &~[u8], b: &~[u8]) -> bool { memcmp(a, b) <= 0 } - - /// Bytewise equality - pub fn eq(a: &~[u8], b: &~[u8]) -> bool { memcmp(a, b) == 0 } - - /// Bytewise inequality - pub fn ne(a: &~[u8], b: &~[u8]) -> bool { memcmp(a, b) != 0 } - - /// Bytewise greater than or equal - pub fn ge(a: &~[u8], b: &~[u8]) -> bool { memcmp(a, b) >= 0 } - - /// Bytewise greater than - pub fn gt(a: &~[u8], b: &~[u8]) -> bool { memcmp(a, b) > 0 } - - /** - * Copies data from one vector to another. - * - * Copies `count` bytes from `src` to `dst`. The source and destination - * may overlap. - */ - #[inline(always)] - pub fn copy_memory(dst: &mut [u8], src: &const [u8], count: uint) { - // Bound checks are done at vec::raw::copy_memory. - unsafe { vec::raw::copy_memory(dst, src, count) } - } -} - -// ___________________________________________________________________________ -// ITERATION TRAIT METHODS - -impl<'self,A> old_iter::BaseIter<A> for &'self [A] { - #[inline(always)] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { - each(*self, blk) - } - #[inline(always)] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::BaseIter<A> for ~[A] { - #[inline(always)] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { - each(*self, blk) - } - #[inline(always)] - fn size_hint(&self) -> Option<uint> { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -impl<A> old_iter::BaseIter<A> for @[A] { - #[inline(always)] - fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) -> bool { - each(*self, blk) - } - #[inline(always)] - 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) - } - 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) - } -} - -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 { - 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) - } -} - -// 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 { - 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) - } -} - -impl<'self,A:Eq> old_iter::EqIter<A> for &'self [A] { - pub fn contains(&self, x: &A) -> bool { old_iter::contains(self, x) } - pub fn count(&self, x: &A) -> uint { old_iter::count(self, x) } -} - -// FIXME(#4148): This should be redundant -impl<A:Eq> old_iter::EqIter<A> for ~[A] { - pub fn contains(&self, x: &A) -> bool { old_iter::contains(self, x) } - pub fn count(&self, x: &A) -> uint { old_iter::count(self, x) } -} - -// FIXME(#4148): This should be redundant -impl<A:Eq> old_iter::EqIter<A> for @[A] { - pub fn contains(&self, x: &A) -> bool { old_iter::contains(self, x) } - pub fn count(&self, x: &A) -> uint { old_iter::count(self, x) } -} - -impl<'self,A:Copy> old_iter::CopyableIter<A> for &'self [A] { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A] { - old_iter::filter_to_vec(self, pred) - } - fn to_vec(&self) -> ~[A] { old_iter::to_vec(self) } - pub fn find(&self, f: &fn(&A) -> bool) -> Option<A> { - old_iter::find(self, f) - } -} - -// FIXME(#4148): This should be redundant -impl<A:Copy> old_iter::CopyableIter<A> for ~[A] { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A] { - old_iter::filter_to_vec(self, pred) - } - fn to_vec(&self) -> ~[A] { old_iter::to_vec(self) } - pub fn find(&self, f: &fn(&A) -> bool) -> Option<A> { - old_iter::find(self, f) - } -} - -// FIXME(#4148): This should be redundant -impl<A:Copy> old_iter::CopyableIter<A> for @[A] { - fn filter_to_vec(&self, pred: &fn(&A) -> bool) -> ~[A] { - old_iter::filter_to_vec(self, pred) - } - fn to_vec(&self) -> ~[A] { old_iter::to_vec(self) } - pub fn find(&self, f: &fn(&A) -> bool) -> Option<A> { - old_iter::find(self, f) - } -} - -impl<'self,A:Copy + Ord> old_iter::CopyableOrderedIter<A> for &'self [A] { - fn min(&self) -> A { old_iter::min(self) } - fn max(&self) -> A { old_iter::max(self) } -} - -// FIXME(#4148): This should be redundant -impl<A:Copy + Ord> old_iter::CopyableOrderedIter<A> for ~[A] { - fn min(&self) -> A { old_iter::min(self) } - fn max(&self) -> A { old_iter::max(self) } -} - -// FIXME(#4148): This should be redundant -impl<A:Copy + Ord> old_iter::CopyableOrderedIter<A> for @[A] { - fn min(&self) -> A { old_iter::min(self) } - 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; - } -} - -// 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; - } - 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; - } - return true; - } -} - -impl<A:Clone> Clone for ~[A] { - #[inline] - fn clone(&self) -> ~[A] { - self.map(|item| item.clone()) - } -} - -// could be implemented with &[T] with .slice(), but this avoids bounds checks -pub struct VecIterator<'self, T> { - priv ptr: *T, - priv end: *T, - priv lifetime: &'self T // FIXME: #5922 -} - -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)) - } - } - } -} - -#[cfg(test)] -mod tests { - use option::{None, Option, Some}; - use sys; - use vec::*; - use cmp::*; - - fn square(n: uint) -> uint { n * n } - - fn square_ref(n: &uint) -> uint { square(*n) } - - fn is_three(n: &uint) -> bool { *n == 3u } - - fn is_odd(n: &uint) -> bool { *n % 2u == 1u } - - fn is_equal(x: &uint, y:&uint) -> bool { *x == *y } - - fn square_if_odd_r(n: &uint) -> Option<uint> { - if *n % 2u == 1u { Some(*n * *n) } else { None } - } - - fn square_if_odd_v(n: uint) -> Option<uint> { - if n % 2u == 1u { Some(n * n) } else { None } - } - - fn add(x: uint, y: &uint) -> uint { x + *y } - - #[test] - fn test_unsafe_ptrs() { - unsafe { - // Test on-stack copy-from-buf. - let a = ~[1, 2, 3]; - let mut ptr = raw::to_ptr(a); - let b = from_buf(ptr, 3u); - assert_eq!(b.len(), 3u); - assert_eq!(b[0], 1); - assert_eq!(b[1], 2); - assert_eq!(b[2], 3); - - // Test on-heap copy-from-buf. - let c = ~[1, 2, 3, 4, 5]; - ptr = raw::to_ptr(c); - let d = from_buf(ptr, 5u); - assert_eq!(d.len(), 5u); - assert_eq!(d[0], 1); - assert_eq!(d[1], 2); - assert_eq!(d[2], 3); - assert_eq!(d[3], 4); - assert_eq!(d[4], 5); - } - } - - #[test] - fn test_from_fn() { - // Test on-stack from_fn. - let mut v = from_fn(3u, square); - assert_eq!(v.len(), 3u); - assert_eq!(v[0], 0u); - assert_eq!(v[1], 1u); - assert_eq!(v[2], 4u); - - // Test on-heap from_fn. - v = from_fn(5u, square); - assert_eq!(v.len(), 5u); - assert_eq!(v[0], 0u); - assert_eq!(v[1], 1u); - assert_eq!(v[2], 4u); - assert_eq!(v[3], 9u); - assert_eq!(v[4], 16u); - } - - #[test] - fn test_from_elem() { - // Test on-stack from_elem. - let mut v = from_elem(2u, 10u); - assert_eq!(v.len(), 2u); - assert_eq!(v[0], 10u); - assert_eq!(v[1], 10u); - - // Test on-heap from_elem. - v = from_elem(6u, 20u); - assert_eq!(v[0], 20u); - assert_eq!(v[1], 20u); - assert_eq!(v[2], 20u); - assert_eq!(v[3], 20u); - assert_eq!(v[4], 20u); - assert_eq!(v[5], 20u); - } - - #[test] - fn test_is_empty() { - assert!(is_empty::<int>(~[])); - assert!(!is_empty(~[0])); - } - - #[test] - fn test_len_divzero() { - type Z = [i8, ..0]; - let v0 : &[Z] = &[]; - let v1 : &[Z] = &[[]]; - let v2 : &[Z] = &[[], []]; - assert_eq!(sys::size_of::<Z>(), 0); - assert_eq!(v0.len(), 0); - assert_eq!(v1.len(), 1); - assert_eq!(v2.len(), 2); - } - - #[test] - fn test_head() { - let mut a = ~[11]; - assert_eq!(a.head(), &11); - a = ~[11, 12]; - assert_eq!(a.head(), &11); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_head_empty() { - let a: ~[int] = ~[]; - a.head(); - } - - #[test] - fn test_head_opt() { - let mut a = ~[]; - assert_eq!(a.head_opt(), None); - a = ~[11]; - assert_eq!(a.head_opt().unwrap(), &11); - a = ~[11, 12]; - assert_eq!(a.head_opt().unwrap(), &11); - } - - #[test] - fn test_tail() { - let mut a = ~[11]; - assert_eq!(a.tail(), &[]); - a = ~[11, 12]; - assert_eq!(a.tail(), &[12]); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_tail_empty() { - let a: ~[int] = ~[]; - a.tail(); - } - - #[test] - fn test_tailn() { - let mut a = ~[11, 12, 13]; - assert_eq!(a.tailn(0), &[11, 12, 13]); - a = ~[11, 12, 13]; - assert_eq!(a.tailn(2), &[13]); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_tailn_empty() { - let a: ~[int] = ~[]; - a.tailn(2); - } - - #[test] - fn test_init() { - let mut a = ~[11]; - assert_eq!(a.init(), &[]); - a = ~[11, 12]; - assert_eq!(a.init(), &[11]); - } - - #[init] - #[should_fail] - #[ignore(cfg(windows))] - fn test_init_empty() { - let a: ~[int] = ~[]; - a.init(); - } - - #[test] - fn test_initn() { - let mut a = ~[11, 12, 13]; - assert_eq!(a.initn(0), &[11, 12, 13]); - a = ~[11, 12, 13]; - assert_eq!(a.initn(2), &[11]); - } - - #[init] - #[should_fail] - #[ignore(cfg(windows))] - fn test_initn_empty() { - let a: ~[int] = ~[]; - a.initn(2); - } - - #[test] - fn test_last() { - let mut a = ~[11]; - assert_eq!(a.last(), &11); - a = ~[11, 12]; - assert_eq!(a.last(), &12); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_last_empty() { - let a: ~[int] = ~[]; - a.last(); - } - - #[test] - fn test_last_opt() { - let mut a = ~[]; - assert_eq!(a.last_opt(), None); - a = ~[11]; - assert_eq!(a.last_opt().unwrap(), &11); - a = ~[11, 12]; - assert_eq!(a.last_opt().unwrap(), &12); - } - - #[test] - fn test_slice() { - // Test fixed length vector. - let vec_fixed = [1, 2, 3, 4]; - let v_a = slice(vec_fixed, 1u, vec_fixed.len()).to_vec(); - assert_eq!(v_a.len(), 3u); - assert_eq!(v_a[0], 2); - assert_eq!(v_a[1], 3); - assert_eq!(v_a[2], 4); - - // Test on stack. - let vec_stack = &[1, 2, 3]; - let v_b = slice(vec_stack, 1u, 3u).to_vec(); - assert_eq!(v_b.len(), 2u); - assert_eq!(v_b[0], 2); - assert_eq!(v_b[1], 3); - - // Test on managed heap. - let vec_managed = @[1, 2, 3, 4, 5]; - let v_c = slice(vec_managed, 0u, 3u).to_vec(); - assert_eq!(v_c.len(), 3u); - assert_eq!(v_c[0], 1); - assert_eq!(v_c[1], 2); - assert_eq!(v_c[2], 3); - - // Test on exchange heap. - let vec_unique = ~[1, 2, 3, 4, 5, 6]; - let v_d = slice(vec_unique, 1u, 6u).to_vec(); - assert_eq!(v_d.len(), 5u); - assert_eq!(v_d[0], 2); - assert_eq!(v_d[1], 3); - assert_eq!(v_d[2], 4); - assert_eq!(v_d[3], 5); - assert_eq!(v_d[4], 6); - } - - #[test] - fn test_pop() { - // Test on-heap pop. - let mut v = ~[1, 2, 3, 4, 5]; - let e = v.pop(); - assert_eq!(v.len(), 4u); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(e, 5); - } - - #[test] - fn test_swap_remove() { - let mut v = ~[1, 2, 3, 4, 5]; - let mut e = v.swap_remove(0); - assert_eq!(v.len(), 4); - assert_eq!(e, 1); - assert_eq!(v[0], 5); - e = v.swap_remove(3); - assert_eq!(v.len(), 3); - assert_eq!(e, 4); - assert_eq!(v[0], 5); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - } - - #[test] - fn test_swap_remove_noncopyable() { - // Tests that we don't accidentally run destructors twice. - let mut v = ~[::unstable::sync::exclusive(()), - ::unstable::sync::exclusive(()), - ::unstable::sync::exclusive(())]; - let mut _e = v.swap_remove(0); - assert_eq!(v.len(), 2); - _e = v.swap_remove(1); - assert_eq!(v.len(), 1); - _e = v.swap_remove(0); - assert_eq!(v.len(), 0); - } - - #[test] - fn test_push() { - // Test on-stack push(). - let mut v = ~[]; - v.push(1); - assert_eq!(v.len(), 1u); - assert_eq!(v[0], 1); - - // Test on-heap push(). - v.push(2); - assert_eq!(v.len(), 2u); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - } - - #[test] - fn test_grow() { - // Test on-stack grow(). - let mut v = ~[]; - v.grow(2u, &1); - assert_eq!(v.len(), 2u); - assert_eq!(v[0], 1); - assert_eq!(v[1], 1); - - // Test on-heap grow(). - v.grow(3u, &2); - assert_eq!(v.len(), 5u); - assert_eq!(v[0], 1); - assert_eq!(v[1], 1); - assert_eq!(v[2], 2); - assert_eq!(v[3], 2); - assert_eq!(v[4], 2); - } - - #[test] - fn test_grow_fn() { - let mut v = ~[]; - v.grow_fn(3u, square); - assert_eq!(v.len(), 3u); - assert_eq!(v[0], 0u); - assert_eq!(v[1], 1u); - assert_eq!(v[2], 4u); - } - - #[test] - fn test_grow_set() { - let mut v = ~[1, 2, 3]; - v.grow_set(4u, &4, 5); - assert_eq!(v.len(), 5u); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(v[4], 5); - } - - #[test] - fn test_truncate() { - let mut v = ~[@6,@5,@4]; - v.truncate(1); - assert_eq!(v.len(), 1); - assert_eq!(*(v[0]), 6); - // If the unsafe block didn't drop things properly, we blow up here. - } - - #[test] - fn test_clear() { - let mut v = ~[@6,@5,@4]; - v.clear(); - assert_eq!(v.len(), 0); - // If the unsafe block didn't drop things properly, we blow up here. - } - - #[test] - fn test_dedup() { - fn case(a: ~[uint], b: ~[uint]) { - let mut v = a; - v.dedup(); - assert_eq!(v, b); - } - case(~[], ~[]); - case(~[1], ~[1]); - case(~[1,1], ~[1]); - case(~[1,2,3], ~[1,2,3]); - case(~[1,1,2,3], ~[1,2,3]); - case(~[1,2,2,3], ~[1,2,3]); - case(~[1,2,3,3], ~[1,2,3]); - case(~[1,1,2,2,2,3,3], ~[1,2,3]); - } - - #[test] - fn test_dedup_unique() { - let mut v0 = ~[~1, ~1, ~2, ~3]; - v0.dedup(); - let mut v1 = ~[~1, ~2, ~2, ~3]; - v1.dedup(); - let mut v2 = ~[~1, ~2, ~3, ~3]; - v2.dedup(); - /* - * If the ~pointers were leaked or otherwise misused, valgrind and/or - * rustrt should raise errors. - */ - } - - #[test] - fn test_dedup_shared() { - let mut v0 = ~[@1, @1, @2, @3]; - v0.dedup(); - let mut v1 = ~[@1, @2, @2, @3]; - v1.dedup(); - let mut v2 = ~[@1, @2, @3, @3]; - v2.dedup(); - /* - * If the @pointers were leaked or otherwise misused, valgrind and/or - * rustrt should raise errors. - */ - } - - #[test] - fn test_map() { - // Test on-stack map. - let mut v = ~[1u, 2u, 3u]; - let mut w = map(v, square_ref); - assert_eq!(w.len(), 3u); - assert_eq!(w[0], 1u); - assert_eq!(w[1], 4u); - assert_eq!(w[2], 9u); - - // Test on-heap map. - v = ~[1u, 2u, 3u, 4u, 5u]; - w = map(v, square_ref); - assert_eq!(w.len(), 5u); - assert_eq!(w[0], 1u); - assert_eq!(w[1], 4u); - assert_eq!(w[2], 9u); - assert_eq!(w[3], 16u); - assert_eq!(w[4], 25u); - } - - #[test] - fn test_map_zip() { - fn times(x: &int, y: &int) -> int { *x * *y } - let f = times; - let v0 = ~[1, 2, 3, 4, 5]; - let v1 = ~[5, 4, 3, 2, 1]; - let u = map_zip::<int, int, int>(v0, v1, f); - let mut i = 0; - while i < 5 { assert!(v0[i] * v1[i] == u[i]); i += 1; } - } - - #[test] - fn test_filter_mapped() { - // Test on-stack filter-map. - let mut v = ~[1u, 2u, 3u]; - let mut w = filter_mapped(v, square_if_odd_r); - assert_eq!(w.len(), 2u); - assert_eq!(w[0], 1u); - assert_eq!(w[1], 9u); - - // Test on-heap filter-map. - v = ~[1u, 2u, 3u, 4u, 5u]; - w = filter_mapped(v, square_if_odd_r); - assert_eq!(w.len(), 3u); - assert_eq!(w[0], 1u); - assert_eq!(w[1], 9u); - assert_eq!(w[2], 25u); - - fn halve(i: &int) -> Option<int> { - if *i % 2 == 0 { - Some::<int>(*i / 2) - } else { - None::<int> - } - } - fn halve_for_sure(i: &int) -> int { *i / 2 } - let all_even: ~[int] = ~[0, 2, 8, 6]; - let all_odd1: ~[int] = ~[1, 7, 3]; - let all_odd2: ~[int] = ~[]; - let mix: ~[int] = ~[9, 2, 6, 7, 1, 0, 0, 3]; - let mix_dest: ~[int] = ~[1, 3, 0, 0]; - assert!(filter_mapped(all_even, halve) == - map(all_even, halve_for_sure)); - assert_eq!(filter_mapped(all_odd1, halve), ~[]); - assert_eq!(filter_mapped(all_odd2, halve), ~[]); - assert_eq!(filter_mapped(mix, halve), mix_dest); - } - - #[test] - fn test_filter_map() { - // Test on-stack filter-map. - let mut v = ~[1u, 2u, 3u]; - let mut w = filter_map(v, square_if_odd_v); - assert_eq!(w.len(), 2u); - assert_eq!(w[0], 1u); - assert_eq!(w[1], 9u); - - // Test on-heap filter-map. - v = ~[1u, 2u, 3u, 4u, 5u]; - w = filter_map(v, square_if_odd_v); - assert_eq!(w.len(), 3u); - assert_eq!(w[0], 1u); - assert_eq!(w[1], 9u); - assert_eq!(w[2], 25u); - - fn halve(i: int) -> Option<int> { - if i % 2 == 0 { - Some::<int>(i / 2) - } else { - None::<int> - } - } - fn halve_for_sure(i: &int) -> int { *i / 2 } - let all_even: ~[int] = ~[0, 2, 8, 6]; - let all_even0: ~[int] = copy all_even; - let all_odd1: ~[int] = ~[1, 7, 3]; - let all_odd2: ~[int] = ~[]; - let mix: ~[int] = ~[9, 2, 6, 7, 1, 0, 0, 3]; - let mix_dest: ~[int] = ~[1, 3, 0, 0]; - assert!(filter_map(all_even, halve) == - map(all_even0, halve_for_sure)); - assert_eq!(filter_map(all_odd1, halve), ~[]); - assert_eq!(filter_map(all_odd2, halve), ~[]); - assert_eq!(filter_map(mix, halve), mix_dest); - } - - #[test] - fn test_filter() { - assert_eq!(filter(~[1u, 2u, 3u], is_odd), ~[1u, 3u]); - assert_eq!(filter(~[1u, 2u, 4u, 8u, 16u], is_three), ~[]); - } - - #[test] - fn test_retain() { - let mut v = ~[1, 2, 3, 4, 5]; - v.retain(is_odd); - assert_eq!(v, ~[1, 3, 5]); - } - - #[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 - } - } - - #[test] - fn test_each_nonempty() { - let mut i = 0; - for each(~[1, 2, 3]) |v| { - i += *v; - } - assert_eq!(i, 6); - } - - #[test] - fn test_eachi() { - let mut i = 0; - for eachi(~[1, 2, 3]) |j, v| { - if i == 0 { assert!(*v == 1); } - assert_eq!(j + 1u, *v as uint); - i += *v; - } - assert_eq!(i, 6); - } - - #[test] - fn test_each_reverse_empty() { - let v: ~[int] = ~[]; - for v.each_reverse |_v| { - fail!(); // should never execute - } - } - - #[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); - } - - #[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() { - let mut results: ~[~[int]]; - - results = ~[]; - for each_permutation(~[]) |v| { results.push(to_owned(v)); } - assert_eq!(results, ~[~[]]); - - results = ~[]; - for each_permutation(~[7]) |v| { results.push(to_owned(v)); } - assert_eq!(results, ~[~[7]]); - - results = ~[]; - for each_permutation(~[1,1]) |v| { results.push(to_owned(v)); } - assert_eq!(results, ~[~[1,1],~[1,1]]); - - results = ~[]; - for each_permutation(~[5,2,0]) |v| { results.push(to_owned(v)); } - assert!(results == - ~[~[5,2,0],~[5,0,2],~[2,5,0],~[2,0,5],~[0,5,2],~[0,2,5]]); - } - - #[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]; - - let z1 = zip(v1, v2); - - assert_eq!((1, 4), z1[0]); - assert_eq!((2, 5), z1[1]); - assert_eq!((3, 6), z1[2]); - - let (left, right) = unzip(z1); - - assert_eq!((1, 4), (left[0], right[0])); - assert_eq!((2, 5), (left[1], right[1])); - assert_eq!((3, 6), (left[2], right[2])); - } - - #[test] - fn test_position_elem() { - assert!(position_elem(~[], &1).is_none()); - - let v1 = ~[1, 2, 3, 3, 2, 5]; - assert_eq!(position_elem(v1, &1), Some(0u)); - assert_eq!(position_elem(v1, &2), Some(1u)); - assert_eq!(position_elem(v1, &5), Some(5u)); - assert!(position_elem(v1, &4).is_none()); - } - - #[test] - fn test_position() { - fn less_than_three(i: &int) -> bool { *i < 3 } - fn is_eighteen(i: &int) -> bool { *i == 18 } - - assert!(position(~[], less_than_three).is_none()); - - let v1 = ~[5, 4, 3, 2, 1]; - assert_eq!(position(v1, less_than_three), Some(3u)); - assert!(position(v1, is_eighteen).is_none()); - } - - #[test] - fn test_position_between() { - assert!(position_between(~[], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(position_between(v, 0u, 0u, f).is_none()); - assert!(position_between(v, 0u, 1u, f).is_none()); - assert_eq!(position_between(v, 0u, 2u, f), Some(1u)); - assert_eq!(position_between(v, 0u, 3u, f), Some(1u)); - assert_eq!(position_between(v, 0u, 4u, f), Some(1u)); - - assert!(position_between(v, 1u, 1u, f).is_none()); - assert_eq!(position_between(v, 1u, 2u, f), Some(1u)); - assert_eq!(position_between(v, 1u, 3u, f), Some(1u)); - assert_eq!(position_between(v, 1u, 4u, f), Some(1u)); - - assert!(position_between(v, 2u, 2u, f).is_none()); - assert!(position_between(v, 2u, 3u, f).is_none()); - assert_eq!(position_between(v, 2u, 4u, f), Some(3u)); - - assert!(position_between(v, 3u, 3u, f).is_none()); - assert_eq!(position_between(v, 3u, 4u, f), Some(3u)); - - assert!(position_between(v, 4u, 4u, f).is_none()); - } - - #[test] - fn test_find() { - assert!(find(~[], f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(find(v, f), Some((1, 'b'))); - assert!(find(v, g).is_none()); - } - - #[test] - fn test_find_between() { - assert!(find_between(~[], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(find_between(v, 0u, 0u, f).is_none()); - assert!(find_between(v, 0u, 1u, f).is_none()); - assert_eq!(find_between(v, 0u, 2u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 0u, 3u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 0u, 4u, f), Some((1, 'b'))); - - assert!(find_between(v, 1u, 1u, f).is_none()); - assert_eq!(find_between(v, 1u, 2u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 1u, 3u, f), Some((1, 'b'))); - assert_eq!(find_between(v, 1u, 4u, f), Some((1, 'b'))); - - assert!(find_between(v, 2u, 2u, f).is_none()); - assert!(find_between(v, 2u, 3u, f).is_none()); - assert_eq!(find_between(v, 2u, 4u, f), Some((3, 'b'))); - - assert!(find_between(v, 3u, 3u, f).is_none()); - assert_eq!(find_between(v, 3u, 4u, f), Some((3, 'b'))); - - assert!(find_between(v, 4u, 4u, f).is_none()); - } - - #[test] - fn test_rposition() { - assert!(find(~[], f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(position(v, f), Some(1u)); - assert!(position(v, g).is_none()); - } - - #[test] - fn test_rposition_between() { - assert!(rposition_between(~[], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(rposition_between(v, 0u, 0u, f).is_none()); - assert!(rposition_between(v, 0u, 1u, f).is_none()); - assert_eq!(rposition_between(v, 0u, 2u, f), Some(1u)); - assert_eq!(rposition_between(v, 0u, 3u, f), Some(1u)); - assert_eq!(rposition_between(v, 0u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 1u, 1u, f).is_none()); - assert_eq!(rposition_between(v, 1u, 2u, f), Some(1u)); - assert_eq!(rposition_between(v, 1u, 3u, f), Some(1u)); - assert_eq!(rposition_between(v, 1u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 2u, 2u, f).is_none()); - assert!(rposition_between(v, 2u, 3u, f).is_none()); - assert_eq!(rposition_between(v, 2u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 3u, 3u, f).is_none()); - assert_eq!(rposition_between(v, 3u, 4u, f), Some(3u)); - - assert!(rposition_between(v, 4u, 4u, f).is_none()); - } - - #[test] - fn test_rfind() { - assert!(rfind(~[], f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(rfind(v, f), Some((3, 'b'))); - assert!(rfind(v, g).is_none()); - } - - #[test] - fn test_rfind_between() { - assert!(rfind_between(~[], 0u, 0u, f).is_none()); - - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert!(rfind_between(v, 0u, 0u, f).is_none()); - assert!(rfind_between(v, 0u, 1u, f).is_none()); - assert_eq!(rfind_between(v, 0u, 2u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 0u, 3u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 0u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 1u, 1u, f).is_none()); - assert_eq!(rfind_between(v, 1u, 2u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 1u, 3u, f), Some((1, 'b'))); - assert_eq!(rfind_between(v, 1u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 2u, 2u, f).is_none()); - assert!(rfind_between(v, 2u, 3u, f).is_none()); - assert_eq!(rfind_between(v, 2u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 3u, 3u, f).is_none()); - assert_eq!(rfind_between(v, 3u, 4u, f), Some((3, 'b'))); - - assert!(rfind_between(v, 4u, 4u, f).is_none()); - } - - #[test] - fn test_bsearch_elem() { - assert_eq!(bsearch_elem([1,2,3,4,5], &5), Some(4)); - assert_eq!(bsearch_elem([1,2,3,4,5], &4), Some(3)); - assert_eq!(bsearch_elem([1,2,3,4,5], &3), Some(2)); - assert_eq!(bsearch_elem([1,2,3,4,5], &2), Some(1)); - assert_eq!(bsearch_elem([1,2,3,4,5], &1), Some(0)); - - assert_eq!(bsearch_elem([2,4,6,8,10], &1), None); - assert_eq!(bsearch_elem([2,4,6,8,10], &5), None); - assert_eq!(bsearch_elem([2,4,6,8,10], &4), Some(1)); - assert_eq!(bsearch_elem([2,4,6,8,10], &10), Some(4)); - - assert_eq!(bsearch_elem([2,4,6,8], &1), None); - assert_eq!(bsearch_elem([2,4,6,8], &5), None); - assert_eq!(bsearch_elem([2,4,6,8], &4), Some(1)); - assert_eq!(bsearch_elem([2,4,6,8], &8), Some(3)); - - assert_eq!(bsearch_elem([2,4,6], &1), None); - assert_eq!(bsearch_elem([2,4,6], &5), None); - assert_eq!(bsearch_elem([2,4,6], &4), Some(1)); - assert_eq!(bsearch_elem([2,4,6], &6), Some(2)); - - assert_eq!(bsearch_elem([2,4], &1), None); - assert_eq!(bsearch_elem([2,4], &5), None); - assert_eq!(bsearch_elem([2,4], &2), Some(0)); - assert_eq!(bsearch_elem([2,4], &4), Some(1)); - - assert_eq!(bsearch_elem([2], &1), None); - assert_eq!(bsearch_elem([2], &5), None); - assert_eq!(bsearch_elem([2], &2), Some(0)); - - assert_eq!(bsearch_elem([], &1), None); - assert_eq!(bsearch_elem([], &5), None); - - assert!(bsearch_elem([1,1,1,1,1], &1) != None); - assert!(bsearch_elem([1,1,1,1,2], &1) != None); - assert!(bsearch_elem([1,1,1,2,2], &1) != None); - assert!(bsearch_elem([1,1,2,2,2], &1) != None); - assert_eq!(bsearch_elem([1,2,2,2,2], &1), Some(0)); - - assert_eq!(bsearch_elem([1,2,3,4,5], &6), None); - assert_eq!(bsearch_elem([1,2,3,4,5], &0), None); - } - - #[test] - fn reverse_and_reversed() { - let mut v: ~[int] = ~[10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - reverse(v); - assert_eq!(v[0], 20); - assert_eq!(v[1], 10); - let v2 = reversed::<int>(~[10, 20]); - assert_eq!(v2[0], 20); - assert_eq!(v2[1], 10); - v[0] = 30; - assert_eq!(v2[0], 20); - // Make sure they work with 0-length vectors too. - - let v4 = reversed::<int>(~[]); - assert_eq!(v4, ~[]); - let mut v3: ~[int] = ~[]; - reverse::<int>(v3); - } - - #[test] - fn reversed_mut() { - let v2 = reversed::<int>(~[10, 20]); - assert_eq!(v2[0], 20); - assert_eq!(v2[1], 10); - } - - #[test] - fn test_split() { - fn f(x: &int) -> bool { *x == 3 } - - assert_eq!(split(~[], f), ~[]); - assert_eq!(split(~[1, 2], f), ~[~[1, 2]]); - assert_eq!(split(~[3, 1, 2], f), ~[~[], ~[1, 2]]); - assert_eq!(split(~[1, 2, 3], f), ~[~[1, 2], ~[]]); - assert_eq!(split(~[1, 2, 3, 4, 3, 5], f), ~[~[1, 2], ~[4], ~[5]]); - } - - #[test] - fn test_splitn() { - fn f(x: &int) -> bool { *x == 3 } - - assert_eq!(splitn(~[], 1u, f), ~[]); - assert_eq!(splitn(~[1, 2], 1u, f), ~[~[1, 2]]); - assert_eq!(splitn(~[3, 1, 2], 1u, f), ~[~[], ~[1, 2]]); - assert_eq!(splitn(~[1, 2, 3], 1u, f), ~[~[1, 2], ~[]]); - assert!(splitn(~[1, 2, 3, 4, 3, 5], 1u, f) == - ~[~[1, 2], ~[4, 3, 5]]); - } - - #[test] - fn test_rsplit() { - fn f(x: &int) -> bool { *x == 3 } - - assert_eq!(rsplit(~[], f), ~[]); - assert_eq!(rsplit(~[1, 2], f), ~[~[1, 2]]); - assert_eq!(rsplit(~[1, 2, 3], f), ~[~[1, 2], ~[]]); - assert!(rsplit(~[1, 2, 3, 4, 3, 5], f) == - ~[~[1, 2], ~[4], ~[5]]); - } - - #[test] - fn test_rsplitn() { - fn f(x: &int) -> bool { *x == 3 } - - assert_eq!(rsplitn(~[], 1u, f), ~[]); - assert_eq!(rsplitn(~[1, 2], 1u, f), ~[~[1, 2]]); - assert_eq!(rsplitn(~[1, 2, 3], 1u, f), ~[~[1, 2], ~[]]); - assert!(rsplitn(~[1, 2, 3, 4, 3, 5], 1u, f) == - ~[~[1, 2, 3, 4], ~[5]]); - } - - #[test] - fn test_partition() { - // FIXME (#4355 maybe): using v.partition here crashes - assert_eq!(partition(~[], |x: &int| *x < 3), (~[], ~[])); - assert!(partition(~[1, 2, 3], |x: &int| *x < 4) == - (~[1, 2, 3], ~[])); - assert!(partition(~[1, 2, 3], |x: &int| *x < 2) == - (~[1], ~[2, 3])); - assert!(partition(~[1, 2, 3], |x: &int| *x < 0) == - (~[], ~[1, 2, 3])); - } - - #[test] - fn test_partitioned() { - assert_eq!((~[]).partitioned(|x: &int| *x < 3), (~[], ~[])) - assert!((~[1, 2, 3]).partitioned(|x: &int| *x < 4) == - (~[1, 2, 3], ~[])); - assert!((~[1, 2, 3]).partitioned(|x: &int| *x < 2) == - (~[1], ~[2, 3])); - assert!((~[1, 2, 3]).partitioned(|x: &int| *x < 0) == - (~[], ~[1, 2, 3])); - } - - #[test] - fn test_concat() { - assert_eq!(concat(~[~[1], ~[2,3]]), ~[1, 2, 3]); - } - - #[test] - fn test_connect() { - 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]); - } - - #[test] - fn test_windowed () { - fn t(n: uint, expected: &[&[int]]) { - let mut i = 0; - for windowed(n, ~[1,2,3,4,5,6]) |v| { - assert_eq!(v, expected[i]); - i += 1; - } - - // check that we actually iterated the right number of times - assert_eq!(i, expected.len()); - } - t(3, &[&[1,2,3],&[2,3,4],&[3,4,5],&[4,5,6]]); - t(4, &[&[1,2,3,4],&[2,3,4,5],&[3,4,5,6]]); - t(7, &[]); - t(8, &[]); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_windowed_() { - for windowed (0u, ~[1u,2u,3u,4u,5u,6u]) |_v| {} - } - - #[test] - fn test_unshift() { - let mut x = ~[1, 2, 3]; - x.unshift(0); - assert_eq!(x, ~[0, 1, 2, 3]); - } - - #[test] - fn test_insert() { - let mut a = ~[1, 2, 4]; - a.insert(2, 3); - assert_eq!(a, ~[1, 2, 3, 4]); - - let mut a = ~[1, 2, 3]; - a.insert(0, 0); - assert_eq!(a, ~[0, 1, 2, 3]); - - let mut a = ~[1, 2, 3]; - a.insert(3, 4); - assert_eq!(a, ~[1, 2, 3, 4]); - - let mut a = ~[]; - a.insert(0, 1); - assert_eq!(a, ~[1]); - } - - #[test] - #[ignore(cfg(windows))] - #[should_fail] - fn test_insert_oob() { - let mut a = ~[1, 2, 3]; - a.insert(4, 5); - } - - #[test] - fn test_remove() { - let mut a = ~[1, 2, 3, 4]; - a.remove(2); - assert_eq!(a, ~[1, 2, 4]); - - let mut a = ~[1, 2, 3]; - a.remove(0); - assert_eq!(a, ~[2, 3]); - - let mut a = ~[1]; - a.remove(0); - assert_eq!(a, ~[]); - } - - #[test] - #[ignore(cfg(windows))] - #[should_fail] - fn test_remove_oob() { - let mut a = ~[1, 2, 3]; - a.remove(3); - } - - #[test] - fn test_capacity() { - let mut v = ~[0u64]; - reserve(&mut v, 10u); - assert_eq!(capacity(&v), 10u); - let mut v = ~[0u32]; - reserve(&mut v, 10u); - assert_eq!(capacity(&v), 10u); - } - - #[test] - fn test_slice_2() { - let v = ~[1, 2, 3, 4, 5]; - let v = v.slice(1u, 3u); - assert_eq!(v.len(), 2u); - assert_eq!(v[0], 2); - assert_eq!(v[1], 3); - } - - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_from_fn_fail() { - do from_fn(100) |v| { - if v == 50 { fail!() } - (~0, @0) - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_build_fail() { - do build |push| { - push((~0, @0)); - push((~0, @0)); - push((~0, @0)); - push((~0, @0)); - fail!(); - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_split_fail_ret_true() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do split(v) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - true - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_split_fail_ret_false() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do split(v) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_splitn_fail_ret_true() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do splitn(v, 100) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - true - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_splitn_fail_ret_false() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do split(v) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_rsplit_fail_ret_true() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do rsplit(v) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - true - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_rsplit_fail_ret_false() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do rsplit(v) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_rsplitn_fail_ret_true() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do rsplitn(v, 100) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - true - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_rsplitn_fail_ret_false() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do rsplitn(v, 100) |_elt| { - if i == 2 { - fail!() - } - i += 1; - - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_consume_fail() { - let v = ~[(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do consume(v) |_i, _elt| { - if i == 2 { - fail!() - } - i += 1; - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_grow_fn_fail() { - let mut v = ~[]; - do v.grow_fn(100) |i| { - if i == 50 { - fail!() - } - (~0, @0) - } - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_map_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do map(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - ~[(~0, @0)] - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_map_consume_fail() { - let v = ~[(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do map_consume(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - ~[(~0, @0)] - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_mapi_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do mapi(v) |_i, _elt| { - if i == 2 { - fail!() - } - i += 0; - ~[(~0, @0)] - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_flat_map_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do map(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - ~[(~0, @0)] - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_map_zip_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do map_zip(v, v) |_elt1, _elt2| { - if i == 2 { - fail!() - } - i += 0; - ~[(~0, @0)] - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_filter_mapped_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do filter_mapped(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - Some((~0, @0)) - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_filter_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do v.filtered |_elt| { - if i == 2 { - fail!() - } - i += 0; - true - }; - } - - #[test] - #[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; - do find(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_position_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do position(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_rposition_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do rposition(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_each_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do each(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_eachi_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do eachi(v) |_i, _elt| { - if i == 2 { - fail!() - } - i += 0; - false - }; - } - - #[test] - #[ignore(windows)] - #[should_fail] - #[allow(non_implicitly_copyable_typarams)] - fn test_permute_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - for each_permutation(v) |_elt| { - if i == 2 { - fail!() - } - i += 0; - } - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_as_imm_buf_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - do as_imm_buf(v) |_buf, _i| { - fail!() - } - } - - #[test] - #[ignore(windows)] - #[should_fail] - fn test_as_const_buf_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - do as_const_buf(v) |_buf, _i| { - fail!() - } - } - - #[test] - #[ignore(cfg(windows))] - #[should_fail] - fn test_as_mut_buf_fail() { - let mut v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - do as_mut_buf(v) |_buf, _i| { - fail!() - } - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_copy_memory_oob() { - unsafe { - let mut a = [1, 2, 3, 4]; - let b = [1, 2, 3, 4, 5]; - raw::copy_memory(a, b, 5); - } - } - - #[test] - fn test_total_ord() { - [1, 2, 3, 4].cmp(& &[1, 2, 3]) == Greater; - [1, 2, 3].cmp(& &[1, 2, 3, 4]) == Less; - [1, 2, 3, 4].cmp(& &[1, 2, 3, 4]) == Equal; - [1, 2, 3, 4, 5, 5, 5, 5].cmp(& &[1, 2, 3, 4, 5, 6]) == Less; - [2, 2].cmp(& &[1, 2, 3, 4]) == Greater; - } - - #[test] - fn test_iterator() { - use iterator::*; - let xs = [1, 2, 5, 10, 11]; - let ys = [1, 2, 5, 10, 11, 19]; - let mut it = xs.iter(); - let mut i = 0; - for it.advance |&x| { - assert_eq!(x, ys[i]); - i += 1; - } - } - - #[test] - fn test_reverse_part() { - let mut values = [1,2,3,4,5]; - reverse_part(values,1,4); - assert_eq!(values, [1,4,3,2,5]); - } - - #[test] - fn test_permutations0() { - let values = []; - let mut v : ~[~[int]] = ~[]; - for each_permutation(values) |p| { - v.push(p.to_owned()); - } - assert_eq!(v, ~[~[]]); - } - - #[test] - fn test_permutations1() { - let values = [1]; - let mut v : ~[~[int]] = ~[]; - for each_permutation(values) |p| { - v.push(p.to_owned()); - } - assert_eq!(v, ~[~[1]]); - } - - #[test] - fn test_permutations2() { - let values = [1,2]; - let mut v : ~[~[int]] = ~[]; - for each_permutation(values) |p| { - v.push(p.to_owned()); - } - assert_eq!(v, ~[~[1,2],~[2,1]]); - } - - #[test] - fn test_permutations3() { - let values = [1,2,3]; - let mut v : ~[~[int]] = ~[]; - for each_permutation(values) |p| { - v.push(p.to_owned()); - } - 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); - } -} |
