diff --git a/src/libextra/uuid.rs b/src/libextra/uuid.rs index 2c48a7a4d3e5..02930dc9c4c6 100644 --- a/src/libextra/uuid.rs +++ b/src/libextra/uuid.rs @@ -57,7 +57,7 @@ Examples of string representations: use std::str; use std::vec; -use std::num::{FromStrRadix, Zero}; +use std::num::FromStrRadix; use std::char::Char; use std::container::Container; use std::to_str::ToStr; @@ -158,9 +158,8 @@ static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u]; /// UUID support impl Uuid { - /// Returns a nil or empty UUID (containing all zeroes) - pub fn new_nil() -> Uuid { + pub fn nil() -> Uuid { let uuid = Uuid{ bytes: [0, .. 16] }; uuid } @@ -423,24 +422,17 @@ impl Uuid { Ok(Uuid::from_bytes(ub).unwrap()) } + + /// Tests if the UUID is nil + pub fn is_nil(&self) -> bool { + return self.bytes.iter().all(|&b| b == 0); + } } impl Default for Uuid { /// Returns the nil UUID, which is all zeroes fn default() -> Uuid { - Uuid::new_nil() - } -} - -impl Zero for Uuid { - /// Returns the nil UUID, which is all zeroes - fn zero() -> Uuid { - Uuid::new_nil() - } - - /// Tests if the UUID is nil or all zeroes - fn is_zero(&self) -> bool { - return self.bytes.iter().all(|&b| b == 0); + Uuid::nil() } } @@ -521,24 +513,15 @@ mod test { use super::*; use std::str; use std::rand; - use std::num::Zero; use std::io::MemWriter; #[test] - fn test_new_nil() { - let nil = Uuid::new_nil(); - let nb = nil.to_bytes(); + fn test_nil() { + let nil = Uuid::nil(); + let not_nil = Uuid::new_v4(); - assert!(nb.iter().all(|&b| b == 0)); - } - - #[test] - fn test_zero() { - let uz: Uuid = Zero::zero(); - let nz = Uuid::new_v4(); - - assert!(uz.is_zero()); - assert!(! nz.is_zero()); + assert!(nil.is_nil()); + assert!(!not_nil.is_nil()); } #[test] @@ -619,7 +602,7 @@ mod test { assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok()); // Nil - let nil = Uuid::new_nil(); + let nil = Uuid::nil(); assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil); assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil); diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index d080262ccc77..af745f94fb51 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -40,7 +40,6 @@ use num::FromPrimitive; #[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering}; #[cfg(not(test))] use ops::{Not, BitAnd, BitOr, BitXor}; #[cfg(not(test))] use default::Default; -#[cfg(not(test))] use num::Zero; ///////////////////////////////////////////////////////////////////////////// // Freestanding functions @@ -309,12 +308,6 @@ impl Default for bool { fn default() -> bool { false } } -#[cfg(not(test))] -impl Zero for bool { - fn zero() -> bool { false } - fn is_zero(&self) -> bool { *self == false } -} - #[cfg(test)] mod tests { use prelude::*; diff --git a/src/libstd/char.rs b/src/libstd/char.rs index 4e9c72de6188..71a297d71765 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -22,7 +22,6 @@ use str; #[cfg(not(test))] use cmp::{Eq, Ord}; #[cfg(not(test))] use default::Default; -#[cfg(not(test))] use num::Zero; // UTF-8 ranges and tags for encoding characters static TAG_CONT: uint = 128u; @@ -449,15 +448,6 @@ impl Default for char { fn default() -> char { '\x00' } } -#[cfg(not(test))] -impl Zero for char { - #[inline] - fn zero() -> char { '\x00' } - - #[inline] - fn is_zero(&self) -> bool { *self == '\x00' } -} - #[test] fn test_is_lowercase() { assert!('a'.is_lowercase()); diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index fcf0f4f24443..8081c6ed8db5 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -2872,6 +2872,12 @@ mod tests { } } + impl Mul for Foo { + fn mul(&self, _: &Foo) -> Foo { + Foo + } + } + impl num::One for Foo { fn one() -> Foo { Foo diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index c374d6c21574..34dd313d4421 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -50,19 +50,59 @@ pub trait Orderable: Ord { /// Returns the number constrained within the range `mn <= self <= mx`. #[inline(always)] pub fn clamp(value: T, mn: T, mx: T) -> T { value.clamp(&mn, &mx) } -pub trait Zero { - fn zero() -> Self; // FIXME (#5527): This should be an associated constant +/// Defines an additive identity element for `Self`. +/// +/// # Deriving +/// +/// This trait can be automatically be derived using `#[deriving(Zero)]` +/// attribute. If you choose to use this, make sure that the laws outlined in +/// the documentation for `Zero::zero` still hold. +pub trait Zero: Add { + /// Returns the additive identity element of `Self`, `0`. + /// + /// # Laws + /// + /// ~~~ + /// a + 0 = a ∀ a ∈ Self + /// 0 + a = a ∀ a ∈ Self + /// ~~~ + /// + /// # Purity + /// + /// This function should return the same result at all times regardless of + /// external mutable state, for example values stored in TLS or in + /// `static mut`s. + // FIXME (#5527): This should be an associated constant + fn zero() -> Self; + + /// Returns `true` if `self` is equal to the additive identity. fn is_zero(&self) -> bool; } -/// Returns `0` of appropriate type. +/// Returns the additive identity, `0`. #[inline(always)] pub fn zero() -> T { Zero::zero() } -pub trait One { - fn one() -> Self; // FIXME (#5527): This should be an associated constant +/// Defines a multiplicative identity element for `Self`. +pub trait One: Mul { + /// Returns the multiplicative identity element of `Self`, `1`. + /// + /// # Laws + /// + /// ~~~ + /// a * 1 = a ∀ a ∈ Self + /// 1 * a = a ∀ a ∈ Self + /// ~~~ + /// + /// # Purity + /// + /// This function should return the same result at all times regardless of + /// external mutable state, for example values stored in TLS or in + /// `static mut`s. + // FIXME (#5527): This should be an associated constant + fn one() -> Self; } -/// Returns `1` of appropriate type. +/// Returns the multiplicative identity, `1`. #[inline(always)] pub fn one() -> T { One::one() } pub trait Signed: Num @@ -264,48 +304,29 @@ pub trait Real: Signed fn to_radians(&self) -> Self; } -/// Raises a value to the power of exp, using -/// exponentiation by squaring. +/// Raises a value to the power of exp, using exponentiation by squaring. /// /// # Example /// /// ```rust /// use std::num; /// -/// let sixteen = num::pow(2, 4u); -/// assert_eq!(sixteen, 16); +/// assert_eq!(num::pow(2, 4), 16); /// ``` #[inline] -pub fn pow>(num: T, exp: uint) -> T { - let one: uint = One::one(); - let num_one: T = One::one(); - - if exp.is_zero() { return num_one; } - if exp == one { return num.clone(); } - - let mut i: uint = exp; - let mut v: T; - let mut r: T = num_one; - - // This if is to avoid cloning self. - if (i & one) == one { - r = r * num; - i = i - one; - } - - i = i >> one; - v = num * num; - - while !i.is_zero() { - if (i & one) == one { - r = r * v; - i = i - one; +pub fn pow>(mut base: T, mut exp: uint) -> T { + if exp == 1 { base } + else { + let mut acc = one::(); + while exp > 0 { + if (exp & 1) == 1 { + acc = acc * base; + } + base = base * base; + exp = exp >> 1; } - i = i >> one; - v = v * v; + acc } - - r } /// Raise a number to a power. @@ -993,16 +1014,6 @@ pub fn from_str_radix(str: &str, radix: uint) -> Option { FromStrRadix::from_str_radix(str, radix) } -impl Zero for @T { - fn zero() -> @T { @Zero::zero() } - fn is_zero(&self) -> bool { (**self).is_zero() } -} - -impl Zero for ~T { - fn zero() -> ~T { ~Zero::zero() } - fn is_zero(&self) -> bool { (**self).is_zero() } -} - /// Saturating math operations pub trait Saturating { /// Saturating addition operator. @@ -1640,17 +1651,24 @@ mod tests { #[test] fn test_pow() { - fn assert_pow>(num: T, exp: uint) -> () { - assert_eq!(num::pow(num.clone(), exp), - range(1u, exp).fold(num.clone(), |acc, _| acc * num)); + fn naive_pow>(base: T, exp: uint) -> T { + range(0, exp).fold(one::(), |acc, _| acc * base) } - - assert_eq!(num::pow(3, 0), 1); - assert_eq!(num::pow(5, 1), 5); - assert_pow(-4, 2); - assert_pow(8, 3); - assert_pow(8, 5); - assert_pow(2u64, 50); + macro_rules! assert_pow( + (($num:expr, $exp:expr) => $expected:expr) => {{ + let result = pow($num, $exp); + assert_eq!(result, $expected); + assert_eq!(result, naive_pow($num, $exp)); + }} + ) + assert_pow!((3, 0 ) => 1); + assert_pow!((5, 1 ) => 5); + assert_pow!((-4, 2 ) => 16); + assert_pow!((0.5, 5 ) => 0.03125); + assert_pow!((8, 3 ) => 512); + assert_pow!((8.0, 5 ) => 32768.0); + assert_pow!((8.5, 5 ) => 44370.53125); + assert_pow!((2u64, 50) => 1125899906842624); } } diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 313fd9c79b46..8e278aeb2eab 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -15,7 +15,6 @@ use clone::Clone; #[cfg(not(test))] use cmp::*; #[cfg(not(test))] use default::Default; -#[cfg(not(test))] use num::Zero; /// Method extensions to pairs where both types satisfy the `Clone` bound pub trait CopyableTuple { @@ -177,18 +176,6 @@ macro_rules! tuple_impls { ($({ let x: $T = Default::default(); x},)+) } } - - #[cfg(not(test))] - impl<$($T:Zero),+> Zero for ($($T,)+) { - #[inline] - fn zero() -> ($($T,)+) { - ($({ let x: $T = Zero::zero(); x},)+) - } - #[inline] - fn is_zero(&self) -> bool { - $(self.$get_ref_fn().is_zero())&&+ - } - } )+ } } diff --git a/src/libstd/unit.rs b/src/libstd/unit.rs index c27f6e3d086b..786a7f42bb39 100644 --- a/src/libstd/unit.rs +++ b/src/libstd/unit.rs @@ -12,8 +12,6 @@ #[cfg(not(test))] use prelude::*; -#[cfg(not(test))] -use num::Zero; #[cfg(not(test))] impl Eq for () { @@ -46,11 +44,3 @@ impl Default for () { #[inline] fn default() -> () { () } } - -#[cfg(not(test))] -impl Zero for () { - #[inline] - fn zero() -> () { () } - #[inline] - fn is_zero(&self) -> bool { true } -} diff --git a/src/test/run-pass/deriving-zero.rs b/src/test/run-pass/deriving-zero.rs index d28e54d57ad4..9ae72038aa9d 100644 --- a/src/test/run-pass/deriving-zero.rs +++ b/src/test/run-pass/deriving-zero.rs @@ -10,32 +10,55 @@ #[feature(managed_boxes)]; -use std::util; use std::num::Zero; #[deriving(Zero)] -struct A; -#[deriving(Zero)] -struct B(int); -#[deriving(Zero)] -struct C(int, int); -#[deriving(Zero)] -struct D { a: int } -#[deriving(Zero)] -struct E { a: int, b: int } +struct Vector2(T, T); + +impl> Add, Vector2> for Vector2 { + fn add(&self, other: &Vector2) -> Vector2 { + match (self, other) { + (&Vector2(ref x0, ref y0), &Vector2(ref x1, ref y1)) => { + Vector2(*x0 + *x1, *y0 + *y1) + } + } + } +} #[deriving(Zero)] -struct Lots { - d: u8, - e: char, - f: f64, - g: (f32, char), - h: @(int, int), - i: bool, - j: (), +struct Vector3 { + x: T, y: T, z: T, +} + +impl> Add, Vector3> for Vector3 { + fn add(&self, other: &Vector3) -> Vector3 { + Vector3 { + x: self.x + other.x, + y: self.y + other.y, + z: self.z + other.z, + } + } +} + +#[deriving(Zero)] +struct Matrix3x2 { + x: Vector2, + y: Vector2, + z: Vector2, +} + +impl> Add, Matrix3x2> for Matrix3x2 { + fn add(&self, other: &Matrix3x2) -> Matrix3x2 { + Matrix3x2 { + x: self.x + other.x, + y: self.y + other.y, + z: self.z + other.z, + } + } } pub fn main() { - let lots: Lots = Zero::zero(); - assert!(lots.is_zero()); + let _: Vector2 = Zero::zero(); + let _: Vector3 = Zero::zero(); + let _: Matrix3x2 = Zero::zero(); } diff --git a/src/test/run-pass/issue-5554.rs b/src/test/run-pass/issue-5554.rs index e4ef20a3b0fc..25293c4dd1be 100644 --- a/src/test/run-pass/issue-5554.rs +++ b/src/test/run-pass/issue-5554.rs @@ -10,30 +10,25 @@ #[feature(macro_rules)]; -use std::num::Zero; +use std::default::Default; pub struct X { - a: T + a: T, } // reordering these bounds stops the ICE -impl - Zero for X { - fn zero() -> X { - X { a: Zero::zero() } - } - fn is_zero(&self) -> bool { - self.a.is_zero() +impl Default for X { + fn default() -> X { + X { a: Default::default() } } } macro_rules! constants { - () => { - let _0 : X = Zero::zero(); - } + () => { + let _ : X = Default::default(); + } } - pub fn main() { - constants!(); + constants!(); }