Add operator trait constraints to std::num::{Zero, One} and document their appropriate use
Zero and One have precise definitions in mathematics. Documentation has been added to describe the appropriate uses for these traits and the laws that they should satisfy. For more information regarding these identities, see the following wikipedia pages: - http://wikipedia.org/wiki/Additive_identity - http://wikipedia.org/wiki/Multiplicative_identity
This commit is contained in:
parent
764f2cb6f3
commit
cf56624a4a
@ -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);
|
||||
|
||||
|
@ -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::*;
|
||||
|
@ -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());
|
||||
|
@ -2872,6 +2872,12 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Foo, Foo> for Foo {
|
||||
fn mul(&self, _: &Foo) -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
impl num::One for Foo {
|
||||
fn one() -> Foo {
|
||||
Foo
|
||||
|
@ -50,19 +50,59 @@ pub trait Orderable: Ord {
|
||||
/// Returns the number constrained within the range `mn <= self <= mx`.
|
||||
#[inline(always)] pub fn clamp<T: Orderable>(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<Self, Self> {
|
||||
/// 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>() -> 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<Self, Self> {
|
||||
/// 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>() -> T { One::one() }
|
||||
|
||||
pub trait Signed: Num
|
||||
@ -993,16 +1033,6 @@ pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
|
||||
FromStrRadix::from_str_radix(str, radix)
|
||||
}
|
||||
|
||||
impl<T: Zero + 'static> Zero for @T {
|
||||
fn zero() -> @T { @Zero::zero() }
|
||||
fn is_zero(&self) -> bool { (**self).is_zero() }
|
||||
}
|
||||
|
||||
impl<T: Zero> 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.
|
||||
|
@ -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<T, U> {
|
||||
@ -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())&&+
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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, T);
|
||||
|
||||
impl<T: Add<T, T>> Add<Vector2<T>, Vector2<T>> for Vector2<T> {
|
||||
fn add(&self, other: &Vector2<T>) -> Vector2<T> {
|
||||
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<T> {
|
||||
x: T, y: T, z: T,
|
||||
}
|
||||
|
||||
impl<T: Add<T, T>> Add<Vector3<T>, Vector3<T>> for Vector3<T> {
|
||||
fn add(&self, other: &Vector3<T>) -> Vector3<T> {
|
||||
Vector3 {
|
||||
x: self.x + other.x,
|
||||
y: self.y + other.y,
|
||||
z: self.z + other.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Zero)]
|
||||
struct Matrix3x2<T> {
|
||||
x: Vector2<T>,
|
||||
y: Vector2<T>,
|
||||
z: Vector2<T>,
|
||||
}
|
||||
|
||||
impl<T: Add<T, T>> Add<Matrix3x2<T>, Matrix3x2<T>> for Matrix3x2<T> {
|
||||
fn add(&self, other: &Matrix3x2<T>) -> Matrix3x2<T> {
|
||||
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<int> = Zero::zero();
|
||||
let _: Vector3<f64> = Zero::zero();
|
||||
let _: Matrix3x2<u8> = Zero::zero();
|
||||
}
|
||||
|
@ -10,30 +10,25 @@
|
||||
|
||||
#[feature(macro_rules)];
|
||||
|
||||
use std::num::Zero;
|
||||
use std::default::Default;
|
||||
|
||||
pub struct X<T> {
|
||||
a: T
|
||||
a: T,
|
||||
}
|
||||
|
||||
// reordering these bounds stops the ICE
|
||||
impl<T: Zero + Eq + Zero>
|
||||
Zero for X<T> {
|
||||
fn zero() -> X<T> {
|
||||
X { a: Zero::zero() }
|
||||
}
|
||||
fn is_zero(&self) -> bool {
|
||||
self.a.is_zero()
|
||||
impl<T: Default + Eq + Default> Default for X<T> {
|
||||
fn default() -> X<T> {
|
||||
X { a: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! constants {
|
||||
() => {
|
||||
let _0 : X<int> = Zero::zero();
|
||||
}
|
||||
() => {
|
||||
let _ : X<int> = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn main() {
|
||||
constants!();
|
||||
constants!();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user