diff options
Diffstat (limited to 'src/libstd/num/mod.rs')
| -rw-r--r-- | src/libstd/num/mod.rs | 1596 |
1 files changed, 1596 insertions, 0 deletions
diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs new file mode 100644 index 00000000000..3097a8e138e --- /dev/null +++ b/src/libstd/num/mod.rs @@ -0,0 +1,1596 @@ +// 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. + +//! Numeric traits and functions for generic mathematics. +//! +//! These are implemented for the primitive numeric types in `std::{u8, u16, +//! u32, u64, uint, i8, i16, i32, i64, int, f32, f64, float}`. + +#[allow(missing_doc)]; + +use clone::{Clone, DeepClone}; +use cmp::{Eq, ApproxEq, Ord}; +use ops::{Add, Sub, Mul, Div, Rem, Neg}; +use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; +use option::{Option, Some, None}; + +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 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; +} + +/// Return the smaller number. +#[inline(always)] pub fn min<T: Orderable>(x: T, y: T) -> T { x.min(&y) } +/// Return the larger number. +#[inline(always)] pub fn max<T: Orderable>(x: T, y: T) -> T { x.max(&y) } +/// 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 + fn is_zero(&self) -> bool; +} + +/// Returns `0` of appropriate type. +#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() } + +pub trait One { + fn one() -> Self; // FIXME (#5527): This should be an associated constant +} + +/// Returns `1` of appropriate type. +#[inline(always)] pub fn one<T: One>() -> T { One::one() } + +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; +} + +/// Computes the absolute value. +/// +/// For float, f32, and f64, `NaN` will be returned if the number is `NaN` +#[inline(always)] pub fn abs<T: Signed>(value: T) -> T { value.abs() } +/// The positive difference of two numbers. +/// +/// Returns `zero` if the number is less than or equal to `other`, +/// otherwise the difference between `self` and `other` is returned. +#[inline(always)] pub fn abs_sub<T: Signed>(x: T, y: T) -> T { x.abs_sub(&y) } +/// Returns the sign of the number. +/// +/// For float, f32, f64: +/// - `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` +/// +/// For int: +/// - `0` if the number is zero +/// - `1` if the number is positive +/// - `-1` if the number is negative +#[inline(always)] pub fn signum<T: Signed>(value: T) -> T { value.signum() } + +pub trait Unsigned: Num {} + +/// Times trait +/// +/// ```rust +/// use num::Times; +/// let ten = 10 as uint; +/// let mut accum = 0; +/// do ten.times { accum += 1; } +/// ``` +/// +pub trait Times { + fn times(&self, it: &fn()); +} + +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; +} + +/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. +/// +/// The result is always positive. +#[inline(always)] pub fn gcd<T: Integer>(x: T, y: T) -> T { x.gcd(&y) } +/// Calculates the Lowest Common Multiple (LCM) of the number and `other`. +#[inline(always)] pub fn lcm<T: Integer>(x: T, y: T) -> T { x.lcm(&y) } + +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; +} + +/// Raise a number to a power. +/// +/// # Example +/// +/// ```rust +/// let sixteen: float = num::pow(2.0, 4.0); +/// assert_eq!(sixteen, 16.0); +/// ``` +#[inline(always)] pub fn pow<T: Algebraic>(value: T, n: T) -> T { value.pow(&n) } +/// Take the squre root of a number. +#[inline(always)] pub fn sqrt<T: Algebraic>(value: T) -> T { value.sqrt() } +/// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. +#[inline(always)] pub fn rsqrt<T: Algebraic>(value: T) -> T { value.rsqrt() } +/// Take the cubic root of a number. +#[inline(always)] pub fn cbrt<T: Algebraic>(value: T) -> T { value.cbrt() } +/// Calculate the length of the hypotenuse of a right-angle triangle given legs of length `x` and +/// `y`. +#[inline(always)] pub fn hypot<T: Algebraic>(x: T, y: T) -> T { x.hypot(&y) } + +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); +} + +/// Sine function. +#[inline(always)] pub fn sin<T: Trigonometric>(value: T) -> T { value.sin() } +/// Cosine function. +#[inline(always)] pub fn cos<T: Trigonometric>(value: T) -> T { value.cos() } +/// Tangent function. +#[inline(always)] pub fn tan<T: Trigonometric>(value: T) -> T { value.tan() } + +/// Compute the arcsine of the number. +#[inline(always)] pub fn asin<T: Trigonometric>(value: T) -> T { value.asin() } +/// Compute the arccosine of the number. +#[inline(always)] pub fn acos<T: Trigonometric>(value: T) -> T { value.acos() } +/// Compute the arctangent of the number. +#[inline(always)] pub fn atan<T: Trigonometric>(value: T) -> T { value.atan() } + +/// Compute the arctangent with 2 arguments. +#[inline(always)] pub fn atan2<T: Trigonometric>(x: T, y: T) -> T { x.atan2(&y) } +/// Simultaneously computes the sine and cosine of the number. +#[inline(always)] pub fn sin_cos<T: Trigonometric>(value: T) -> (T, T) { value.sin_cos() } + +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; +} + +/// Returns `e^(value)`, (the exponential function). +#[inline(always)] pub fn exp<T: Exponential>(value: T) -> T { value.exp() } +/// Returns 2 raised to the power of the number, `2^(value)`. +#[inline(always)] pub fn exp2<T: Exponential>(value: T) -> T { value.exp2() } + +/// Returns the natural logarithm of the number. +#[inline(always)] pub fn ln<T: Exponential>(value: T) -> T { value.ln() } +/// Returns the logarithm of the number with respect to an arbitrary base. +#[inline(always)] pub fn log<T: Exponential>(value: T, base: T) -> T { value.log(&base) } +/// Returns the base 2 logarithm of the number. +#[inline(always)] pub fn log2<T: Exponential>(value: T) -> T { value.log2() } +/// Returns the base 10 logarithm of the number. +#[inline(always)] pub fn log10<T: Exponential>(value: T) -> T { value.log10() } + +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; +} + +/// Hyperbolic cosine function. +#[inline(always)] pub fn sinh<T: Hyperbolic>(value: T) -> T { value.sinh() } +/// Hyperbolic sine function. +#[inline(always)] pub fn cosh<T: Hyperbolic>(value: T) -> T { value.cosh() } +/// Hyperbolic tangent function. +#[inline(always)] pub fn tanh<T: Hyperbolic>(value: T) -> T { value.tanh() } + +/// Inverse hyperbolic sine function. +#[inline(always)] pub fn asinh<T: Hyperbolic>(value: T) -> T { value.asinh() } +/// Inverse hyperbolic cosine function. +#[inline(always)] pub fn acosh<T: Hyperbolic>(value: T) -> T { value.acosh() } +/// Inverse hyperbolic tangent function. +#[inline(always)] pub fn atanh<T: Hyperbolic>(value: T) -> T { value.atanh() } + +/// 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: Clone + + DeepClone + + Num + + NumCast + + Orderable + + 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 + // FIXME (#8888): Removing `unused_self` requires #8888 to be fixed. + fn bits(unused_self: Option<Self>) -> uint; + fn bytes(unused_self: Option<Self>) -> uint; + fn is_signed(unused_self: Option<Self>) -> bool; +} + +/// 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; + + // FIXME (#8888): Removing `unused_self` requires #8888 to be fixed. + fn mantissa_digits(unused_self: Option<Self>) -> uint; + fn digits(unused_self: Option<Self>) -> uint; + fn epsilon() -> Self; + fn min_exp(unused_self: Option<Self>) -> int; + fn max_exp(unused_self: Option<Self>) -> int; + fn min_10_exp(unused_self: Option<Self>) -> int; + fn max_10_exp(unused_self: Option<Self>) -> 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; +} + +/// Returns the exponential of the number, minus `1`, `exp(n) - 1`, in a way +/// that is accurate even if the number is close to zero. +#[inline(always)] pub fn exp_m1<T: Float>(value: T) -> T { value.exp_m1() } +/// Returns the natural logarithm of the number plus `1`, `ln(n + 1)`, more +/// accurately than if the operations were performed separately. +#[inline(always)] pub fn ln_1p<T: Float>(value: T) -> T { value.ln_1p() } +/// Fused multiply-add. Computes `(a * b) + c` with only one rounding error. +/// +/// This produces a more accurate result with better performance (on some +/// architectures) than a separate multiplication operation followed by an add. +#[inline(always)] pub fn mul_add<T: Float>(a: T, b: T, c: T) -> T { a.mul_add(b, c) } + +/// A generic trait for converting a value to a number. +pub trait ToPrimitive { + /// Converts the value of `self` to an `int`. + #[inline] + fn to_int(&self) -> Option<int> { + self.to_i64().and_then(|x| x.to_int()) + } + + /// Converts the value of `self` to an `i8`. + #[inline] + fn to_i8(&self) -> Option<i8> { + self.to_i64().and_then(|x| x.to_i8()) + } + + /// Converts the value of `self` to an `i16`. + #[inline] + fn to_i16(&self) -> Option<i16> { + self.to_i64().and_then(|x| x.to_i16()) + } + + /// Converts the value of `self` to an `i32`. + #[inline] + fn to_i32(&self) -> Option<i32> { + self.to_i64().and_then(|x| x.to_i32()) + } + + /// Converts the value of `self` to an `i64`. + fn to_i64(&self) -> Option<i64>; + + /// Converts the value of `self` to an `uint`. + #[inline] + fn to_uint(&self) -> Option<uint> { + self.to_u64().and_then(|x| x.to_uint()) + } + + /// Converts the value of `self` to an `u8`. + #[inline] + fn to_u8(&self) -> Option<u8> { + self.to_u64().and_then(|x| x.to_u8()) + } + + /// Converts the value of `self` to an `u16`. + #[inline] + fn to_u16(&self) -> Option<u16> { + self.to_u64().and_then(|x| x.to_u16()) + } + + /// Converts the value of `self` to an `u32`. + #[inline] + fn to_u32(&self) -> Option<u32> { + self.to_u64().and_then(|x| x.to_u32()) + } + + /// Converts the value of `self` to an `u64`. + #[inline] + fn to_u64(&self) -> Option<u64>; + + /// Converts the value of `self` to an `f32`. + #[inline] + fn to_f32(&self) -> Option<f32> { + self.to_f64().and_then(|x| x.to_f32()) + } + + /// Converts the value of `self` to an `f64`. + #[inline] + fn to_f64(&self) -> Option<f64> { + self.to_i64().and_then(|x| x.to_f64()) + } +} + +macro_rules! impl_to_primitive_int_to_int( + ($SrcT:ty, $DstT:ty) => ( + { + if Primitive::bits(None::<$SrcT>) <= Primitive::bits(None::<$DstT>) { + Some(*self as $DstT) + } else { + let n = *self as i64; + let min_value: $DstT = Bounded::min_value(); + let max_value: $DstT = Bounded::max_value(); + if min_value as i64 <= n && n <= max_value as i64 { + Some(*self as $DstT) + } else { + None + } + } + } + ) +) + +macro_rules! impl_to_primitive_int_to_uint( + ($SrcT:ty, $DstT:ty) => ( + { + let zero: $SrcT = Zero::zero(); + let max_value: $DstT = Bounded::max_value(); + if zero <= *self && *self as u64 <= max_value as u64 { + Some(*self as $DstT) + } else { + None + } + } + ) +) + +macro_rules! impl_to_primitive_int( + ($T:ty) => ( + impl ToPrimitive for $T { + #[inline] + fn to_int(&self) -> Option<int> { impl_to_primitive_int_to_int!($T, int) } + #[inline] + fn to_i8(&self) -> Option<i8> { impl_to_primitive_int_to_int!($T, i8) } + #[inline] + fn to_i16(&self) -> Option<i16> { impl_to_primitive_int_to_int!($T, i16) } + #[inline] + fn to_i32(&self) -> Option<i32> { impl_to_primitive_int_to_int!($T, i32) } + #[inline] + fn to_i64(&self) -> Option<i64> { impl_to_primitive_int_to_int!($T, i64) } + + #[inline] + fn to_uint(&self) -> Option<uint> { impl_to_primitive_int_to_uint!($T, uint) } + #[inline] + fn to_u8(&self) -> Option<u8> { impl_to_primitive_int_to_uint!($T, u8) } + #[inline] + fn to_u16(&self) -> Option<u16> { impl_to_primitive_int_to_uint!($T, u16) } + #[inline] + fn to_u32(&self) -> Option<u32> { impl_to_primitive_int_to_uint!($T, u32) } + #[inline] + fn to_u64(&self) -> Option<u64> { impl_to_primitive_int_to_uint!($T, u64) } + + #[inline] + fn to_f32(&self) -> Option<f32> { Some(*self as f32) } + #[inline] + fn to_f64(&self) -> Option<f64> { Some(*self as f64) } + } + ) +) + +impl_to_primitive_int!(int) +impl_to_primitive_int!(i8) +impl_to_primitive_int!(i16) +impl_to_primitive_int!(i32) +impl_to_primitive_int!(i64) + +macro_rules! impl_to_primitive_uint_to_int( + ($DstT:ty) => ( + { + let max_value: $DstT = Bounded::max_value(); + if *self as u64 <= max_value as u64 { + Some(*self as $DstT) + } else { + None + } + } + ) +) + +macro_rules! impl_to_primitive_uint_to_uint( + ($SrcT:ty, $DstT:ty) => ( + { + if Primitive::bits(None::<$SrcT>) <= Primitive::bits(None::<$DstT>) { + Some(*self as $DstT) + } else { + let zero: $SrcT = Zero::zero(); + let max_value: $DstT = Bounded::max_value(); + if zero <= *self && *self as u64 <= max_value as u64 { + Some(*self as $DstT) + } else { + None + } + } + } + ) +) + +macro_rules! impl_to_primitive_uint( + ($T:ty) => ( + impl ToPrimitive for $T { + #[inline] + fn to_int(&self) -> Option<int> { impl_to_primitive_uint_to_int!(int) } + #[inline] + fn to_i8(&self) -> Option<i8> { impl_to_primitive_uint_to_int!(i8) } + #[inline] + fn to_i16(&self) -> Option<i16> { impl_to_primitive_uint_to_int!(i16) } + #[inline] + fn to_i32(&self) -> Option<i32> { impl_to_primitive_uint_to_int!(i32) } + #[inline] + fn to_i64(&self) -> Option<i64> { impl_to_primitive_uint_to_int!(i64) } + + #[inline] + fn to_uint(&self) -> Option<uint> { impl_to_primitive_uint_to_uint!($T, uint) } + #[inline] + fn to_u8(&self) -> Option<u8> { impl_to_primitive_uint_to_uint!($T, u8) } + #[inline] + fn to_u16(&self) -> Option<u16> { impl_to_primitive_uint_to_uint!($T, u16) } + #[inline] + fn to_u32(&self) -> Option<u32> { impl_to_primitive_uint_to_uint!($T, u32) } + #[inline] + fn to_u64(&self) -> Option<u64> { impl_to_primitive_uint_to_uint!($T, u64) } + + #[inline] + fn to_f32(&self) -> Option<f32> { Some(*self as f32) } + #[inline] + fn to_f64(&self) -> Option<f64> { Some(*self as f64) } + } + ) +) + +impl_to_primitive_uint!(uint) +impl_to_primitive_uint!(u8) +impl_to_primitive_uint!(u16) +impl_to_primitive_uint!(u32) +impl_to_primitive_uint!(u64) + +macro_rules! impl_to_primitive_float_to_float( + ($SrcT:ty, $DstT:ty) => ( + if Primitive::bits(None::<$SrcT>) <= Primitive::bits(None::<$DstT>) { + Some(*self as $DstT) + } else { + let n = *self as f64; + let max_value: $SrcT = Bounded::max_value(); + if -max_value as f64 <= n && n <= max_value as f64 { + Some(*self as $DstT) + } else { + None + } + } + ) +) + +macro_rules! impl_to_primitive_float( + ($T:ty) => ( + impl ToPrimitive for $T { + #[inline] + fn to_int(&self) -> Option<int> { Some(*self as int) } + #[inline] + fn to_i8(&self) -> Option<i8> { Some(*self as i8) } + #[inline] + fn to_i16(&self) -> Option<i16> { Some(*self as i16) } + #[inline] + fn to_i32(&self) -> Option<i32> { Some(*self as i32) } + #[inline] + fn to_i64(&self) -> Option<i64> { Some(*self as i64) } + + #[inline] + fn to_uint(&self) -> Option<uint> { Some(*self as uint) } + #[inline] + fn to_u8(&self) -> Option<u8> { Some(*self as u8) } + #[inline] + fn to_u16(&self) -> Option<u16> { Some(*self as u16) } + #[inline] + fn to_u32(&self) -> Option<u32> { Some(*self as u32) } + #[inline] + fn to_u64(&self) -> Option<u64> { Some(*self as u64) } + + #[inline] + fn to_f32(&self) -> Option<f32> { impl_to_primitive_float_to_float!($T, f32) } + #[inline] + fn to_f64(&self) -> Option<f64> { impl_to_primitive_float_to_float!($T, f64) } + } + ) +) + +impl_to_primitive_float!(f32) +impl_to_primitive_float!(f64) + +/// A generic trait for converting a number to a value. +pub trait FromPrimitive { + /// Convert an `int` to return an optional value of this type. If the + /// value cannot be represented by this value, the `None` is returned. + #[inline] + fn from_int(n: int) -> Option<Self> { + FromPrimitive::from_i64(n as i64) + } + + /// Convert an `i8` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_i8(n: i8) -> Option<Self> { + FromPrimitive::from_i64(n as i64) + } + + /// Convert an `i16` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_i16(n: i16) -> Option<Self> { + FromPrimitive::from_i64(n as i64) + } + + /// Convert an `i32` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_i32(n: i32) -> Option<Self> { + FromPrimitive::from_i64(n as i64) + } + + /// Convert an `i64` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + fn from_i64(n: i64) -> Option<Self>; + + /// Convert an `uint` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_uint(n: uint) -> Option<Self> { + FromPrimitive::from_u64(n as u64) + } + + /// Convert an `u8` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_u8(n: u8) -> Option<Self> { + FromPrimitive::from_u64(n as u64) + } + + /// Convert an `u16` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_u16(n: u16) -> Option<Self> { + FromPrimitive::from_u64(n as u64) + } + + /// Convert an `u32` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_u32(n: u32) -> Option<Self> { + FromPrimitive::from_u64(n as u64) + } + + /// Convert an `u64` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + fn from_u64(n: u64) -> Option<Self>; + + /// Convert a `f32` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_f32(n: f32) -> Option<Self> { + FromPrimitive::from_f64(n as f64) + } + + /// Convert a `f64` to return an optional value of this type. If the + /// type cannot be represented by this value, the `None` is returned. + #[inline] + fn from_f64(n: f64) -> Option<Self> { + FromPrimitive::from_i64(n as i64) + } +} + +/// A utility function that just calls `FromPrimitive::from_int`. +pub fn from_int<A: FromPrimitive>(n: int) -> Option<A> { + FromPrimitive::from_int(n) +} + +/// A utility function that just calls `FromPrimitive::from_i8`. +pub fn from_i8<A: FromPrimitive>(n: i8) -> Option<A> { + FromPrimitive::from_i8(n) +} + +/// A utility function that just calls `FromPrimitive::from_i16`. +pub fn from_i16<A: FromPrimitive>(n: i16) -> Option<A> { + FromPrimitive::from_i16(n) +} + +/// A utility function that just calls `FromPrimitive::from_i32`. +pub fn from_i32<A: FromPrimitive>(n: i32) -> Option<A> { + FromPrimitive::from_i32(n) +} + +/// A utility function that just calls `FromPrimitive::from_i64`. +pub fn from_i64<A: FromPrimitive>(n: i64) -> Option<A> { + FromPrimitive::from_i64(n) +} + +/// A utility function that just calls `FromPrimitive::from_uint`. +pub fn from_uint<A: FromPrimitive>(n: uint) -> Option<A> { + FromPrimitive::from_uint(n) +} + +/// A utility function that just calls `FromPrimitive::from_u8`. +pub fn from_u8<A: FromPrimitive>(n: u8) -> Option<A> { + FromPrimitive::from_u8(n) +} + +/// A utility function that just calls `FromPrimitive::from_u16`. +pub fn from_u16<A: FromPrimitive>(n: u16) -> Option<A> { + FromPrimitive::from_u16(n) +} + +/// A utility function that just calls `FromPrimitive::from_u32`. +pub fn from_u32<A: FromPrimitive>(n: u32) -> Option<A> { + FromPrimitive::from_u32(n) +} + +/// A utility function that just calls `FromPrimitive::from_u64`. +pub fn from_u64<A: FromPrimitive>(n: u64) -> Option<A> { + FromPrimitive::from_u64(n) +} + +/// A utility function that just calls `FromPrimitive::from_f32`. +pub fn from_f32<A: FromPrimitive>(n: f32) -> Option<A> { + FromPrimitive::from_f32(n) +} + +/// A utility function that just calls `FromPrimitive::from_f64`. +pub fn from_f64<A: FromPrimitive>(n: f64) -> Option<A> { + FromPrimitive::from_f64(n) +} + +macro_rules! impl_from_primitive( + ($T:ty, $to_ty:expr) => ( + impl FromPrimitive for $T { + #[inline] fn from_int(n: int) -> Option<$T> { $to_ty } + #[inline] fn from_i8(n: i8) -> Option<$T> { $to_ty } + #[inline] fn from_i16(n: i16) -> Option<$T> { $to_ty } + #[inline] fn from_i32(n: i32) -> Option<$T> { $to_ty } + #[inline] fn from_i64(n: i64) -> Option<$T> { $to_ty } + + #[inline] fn from_uint(n: uint) -> Option<$T> { $to_ty } + #[inline] fn from_u8(n: u8) -> Option<$T> { $to_ty } + #[inline] fn from_u16(n: u16) -> Option<$T> { $to_ty } + #[inline] fn from_u32(n: u32) -> Option<$T> { $to_ty } + #[inline] fn from_u64(n: u64) -> Option<$T> { $to_ty } + + #[inline] fn from_f32(n: f32) -> Option<$T> { $to_ty } + #[inline] fn from_f64(n: f64) -> Option<$T> { $to_ty } + } + ) +) + +impl_from_primitive!(int, n.to_int()) +impl_from_primitive!(i8, n.to_i8()) +impl_from_primitive!(i16, n.to_i16()) +impl_from_primitive!(i32, n.to_i32()) +impl_from_primitive!(i64, n.to_i64()) +impl_from_primitive!(uint, n.to_uint()) +impl_from_primitive!(u8, n.to_u8()) +impl_from_primitive!(u16, n.to_u16()) +impl_from_primitive!(u32, n.to_u32()) +impl_from_primitive!(u64, n.to_u64()) +impl_from_primitive!(f32, n.to_f32()) +impl_from_primitive!(f64, n.to_f64()) + +/// Cast from one machine scalar to another. +/// +/// # Example +/// +/// ``` +/// let twenty: f32 = num::cast(0x14).unwrap(); +/// assert_eq!(twenty, 20f32); +/// ``` +/// +#[inline] +pub fn cast<T: NumCast,U: NumCast>(n: T) -> Option<U> { + NumCast::from(n) +} + +/// An interface for casting between machine scalars +pub trait NumCast: ToPrimitive { + fn from<T: ToPrimitive>(n: T) -> Option<Self>; +} + +macro_rules! impl_num_cast( + ($T:ty, $conv:ident) => ( + impl NumCast for $T { + #[inline] + fn from<N: ToPrimitive>(n: N) -> Option<$T> { + // `$conv` could be generated using `concat_idents!`, but that + // macro seems to be broken at the moment + n.$conv() + } + } + ) +) + +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) + +pub trait ToStrRadix { + fn to_str_radix(&self, radix: uint) -> ~str; +} + +pub trait FromStrRadix { + fn from_str_radix(str: &str, radix: uint) -> Option<Self>; +} + +/// A utility function that just calls FromStrRadix::from_str_radix. +pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> { + FromStrRadix::from_str_radix(str, radix) +} + +/// 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+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).unwrap(); + while (my_pow > 0u) { + if my_pow % 2u == 1u { + total = total * multiplier; + } + my_pow = my_pow / 2u; + multiplier = multiplier * multiplier; + } + total +} + +impl<T: Zero + 'static> Zero for @mut T { + fn zero() -> @mut T { @mut Zero::zero() } + fn is_zero(&self) -> bool { (**self).is_zero() } +} + +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. + /// Returns a+b, saturating at the numeric bounds instead of overflowing. + fn saturating_add(self, v: Self) -> Self; + + /// Saturating subtraction operator. + /// Returns a-b, saturating at the numeric bounds instead of overflowing. + fn saturating_sub(self, v: Self) -> Self; +} + +impl<T: CheckedAdd + CheckedSub + Zero + Ord + Bounded> Saturating for T { + #[inline] + fn saturating_add(self, v: T) -> T { + match self.checked_add(&v) { + Some(x) => x, + None => if v >= Zero::zero() { + Bounded::max_value() + } else { + Bounded::min_value() + } + } + } + + #[inline] + fn saturating_sub(self, v: T) -> T { + match self.checked_sub(&v) { + Some(x) => x, + None => if v >= Zero::zero() { + Bounded::min_value() + } else { + Bounded::max_value() + } + } + } +} + +pub trait CheckedAdd: Add<Self, Self> { + fn checked_add(&self, v: &Self) -> Option<Self>; +} + +pub trait CheckedSub: Sub<Self, Self> { + fn checked_sub(&self, v: &Self) -> Option<Self>; +} + +pub trait CheckedMul: Mul<Self, Self> { + fn checked_mul(&self, v: &Self) -> Option<Self>; +} + +pub trait CheckedDiv: Div<Self, Self> { + fn checked_div(&self, v: &Self) -> Option<Self>; +} + +/// 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).unwrap()); + assert_eq!(ten.sub(&two), cast(8).unwrap()); + assert_eq!(ten.mul(&two), cast(20).unwrap()); + assert_eq!(ten.div(&two), cast(5).unwrap()); + assert_eq!(ten.rem(&two), cast(0).unwrap()); + + 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); +} + +#[cfg(test)] +mod tests { + use prelude::*; + use super::*; + use i8; + use i16; + use i32; + use i64; + use int; + use u8; + use u16; + use u32; + use u64; + use uint; + + macro_rules! test_cast_20( + ($_20:expr) => ({ + let _20 = $_20; + + assert_eq!(20u, _20.to_uint().unwrap()); + assert_eq!(20u8, _20.to_u8().unwrap()); + assert_eq!(20u16, _20.to_u16().unwrap()); + assert_eq!(20u32, _20.to_u32().unwrap()); + assert_eq!(20u64, _20.to_u64().unwrap()); + assert_eq!(20i, _20.to_int().unwrap()); + assert_eq!(20i8, _20.to_i8().unwrap()); + assert_eq!(20i16, _20.to_i16().unwrap()); + assert_eq!(20i32, _20.to_i32().unwrap()); + assert_eq!(20i64, _20.to_i64().unwrap()); + assert_eq!(20f32, _20.to_f32().unwrap()); + assert_eq!(20f64, _20.to_f64().unwrap()); + + assert_eq!(_20, NumCast::from(20u).unwrap()); + assert_eq!(_20, NumCast::from(20u8).unwrap()); + assert_eq!(_20, NumCast::from(20u16).unwrap()); + assert_eq!(_20, NumCast::from(20u32).unwrap()); + assert_eq!(_20, NumCast::from(20u64).unwrap()); + assert_eq!(_20, NumCast::from(20i).unwrap()); + assert_eq!(_20, NumCast::from(20i8).unwrap()); + assert_eq!(_20, NumCast::from(20i16).unwrap()); + assert_eq!(_20, NumCast::from(20i32).unwrap()); + assert_eq!(_20, NumCast::from(20i64).unwrap()); + assert_eq!(_20, NumCast::from(20f32).unwrap()); + assert_eq!(_20, NumCast::from(20f64).unwrap()); + + assert_eq!(_20, cast(20u).unwrap()); + assert_eq!(_20, cast(20u8).unwrap()); + assert_eq!(_20, cast(20u16).unwrap()); + assert_eq!(_20, cast(20u32).unwrap()); + assert_eq!(_20, cast(20u64).unwrap()); + assert_eq!(_20, cast(20i).unwrap()); + assert_eq!(_20, cast(20i8).unwrap()); + assert_eq!(_20, cast(20i16).unwrap()); + assert_eq!(_20, cast(20i32).unwrap()); + assert_eq!(_20, cast(20i64).unwrap()); + assert_eq!(_20, cast(20f32).unwrap()); + assert_eq!(_20, cast(20f64).unwrap()); + }) + ) + + #[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_cast_range_int_min() { + assert_eq!(int::min_value.to_int(), Some(int::min_value as int)); + assert_eq!(int::min_value.to_i8(), None); + assert_eq!(int::min_value.to_i16(), None); + // int::min_value.to_i32() is word-size specific + assert_eq!(int::min_value.to_i64(), Some(int::min_value as i64)); + assert_eq!(int::min_value.to_uint(), None); + assert_eq!(int::min_value.to_u8(), None); + assert_eq!(int::min_value.to_u16(), None); + assert_eq!(int::min_value.to_u32(), None); + assert_eq!(int::min_value.to_u64(), None); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(int::min_value.to_i32(), Some(int::min_value as i32)); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(int::min_value.to_i32(), None); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_i8_min() { + assert_eq!(i8::min_value.to_int(), Some(i8::min_value as int)); + assert_eq!(i8::min_value.to_i8(), Some(i8::min_value as i8)); + assert_eq!(i8::min_value.to_i16(), Some(i8::min_value as i16)); + assert_eq!(i8::min_value.to_i32(), Some(i8::min_value as i32)); + assert_eq!(i8::min_value.to_i64(), Some(i8::min_value as i64)); + assert_eq!(i8::min_value.to_uint(), None); + assert_eq!(i8::min_value.to_u8(), None); + assert_eq!(i8::min_value.to_u16(), None); + assert_eq!(i8::min_value.to_u32(), None); + assert_eq!(i8::min_value.to_u64(), None); + } + + #[test] + fn test_cast_range_i16_min() { + assert_eq!(i16::min_value.to_int(), Some(i16::min_value as int)); + assert_eq!(i16::min_value.to_i8(), None); + assert_eq!(i16::min_value.to_i16(), Some(i16::min_value as i16)); + assert_eq!(i16::min_value.to_i32(), Some(i16::min_value as i32)); + assert_eq!(i16::min_value.to_i64(), Some(i16::min_value as i64)); + assert_eq!(i16::min_value.to_uint(), None); + assert_eq!(i16::min_value.to_u8(), None); + assert_eq!(i16::min_value.to_u16(), None); + assert_eq!(i16::min_value.to_u32(), None); + assert_eq!(i16::min_value.to_u64(), None); + } + + #[test] + fn test_cast_range_i32_min() { + assert_eq!(i32::min_value.to_int(), Some(i32::min_value as int)); + assert_eq!(i32::min_value.to_i8(), None); + assert_eq!(i32::min_value.to_i16(), None); + assert_eq!(i32::min_value.to_i32(), Some(i32::min_value as i32)); + assert_eq!(i32::min_value.to_i64(), Some(i32::min_value as i64)); + assert_eq!(i32::min_value.to_uint(), None); + assert_eq!(i32::min_value.to_u8(), None); + assert_eq!(i32::min_value.to_u16(), None); + assert_eq!(i32::min_value.to_u32(), None); + assert_eq!(i32::min_value.to_u64(), None); + } + + #[test] + fn test_cast_range_i64_min() { + // i64::min_value.to_int() is word-size specific + assert_eq!(i64::min_value.to_i8(), None); + assert_eq!(i64::min_value.to_i16(), None); + assert_eq!(i64::min_value.to_i32(), None); + assert_eq!(i64::min_value.to_i64(), Some(i64::min_value as i64)); + assert_eq!(i64::min_value.to_uint(), None); + assert_eq!(i64::min_value.to_u8(), None); + assert_eq!(i64::min_value.to_u16(), None); + assert_eq!(i64::min_value.to_u32(), None); + assert_eq!(i64::min_value.to_u64(), None); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(i64::min_value.to_int(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(i64::min_value.to_int(), Some(i64::min_value as int)); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_int_max() { + assert_eq!(int::max_value.to_int(), Some(int::max_value as int)); + assert_eq!(int::max_value.to_i8(), None); + assert_eq!(int::max_value.to_i16(), None); + // int::max_value.to_i32() is word-size specific + assert_eq!(int::max_value.to_i64(), Some(int::max_value as i64)); + assert_eq!(int::max_value.to_u8(), None); + assert_eq!(int::max_value.to_u16(), None); + // int::max_value.to_u32() is word-size specific + assert_eq!(int::max_value.to_u64(), Some(int::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(int::max_value.to_i32(), Some(int::max_value as i32)); + assert_eq!(int::max_value.to_u32(), Some(int::max_value as u32)); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(int::max_value.to_i32(), None); + assert_eq!(int::max_value.to_u32(), None); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_i8_max() { + assert_eq!(i8::max_value.to_int(), Some(i8::max_value as int)); + assert_eq!(i8::max_value.to_i8(), Some(i8::max_value as i8)); + assert_eq!(i8::max_value.to_i16(), Some(i8::max_value as i16)); + assert_eq!(i8::max_value.to_i32(), Some(i8::max_value as i32)); + assert_eq!(i8::max_value.to_i64(), Some(i8::max_value as i64)); + assert_eq!(i8::max_value.to_uint(), Some(i8::max_value as uint)); + assert_eq!(i8::max_value.to_u8(), Some(i8::max_value as u8)); + assert_eq!(i8::max_value.to_u16(), Some(i8::max_value as u16)); + assert_eq!(i8::max_value.to_u32(), Some(i8::max_value as u32)); + assert_eq!(i8::max_value.to_u64(), Some(i8::max_value as u64)); + } + + #[test] + fn test_cast_range_i16_max() { + assert_eq!(i16::max_value.to_int(), Some(i16::max_value as int)); + assert_eq!(i16::max_value.to_i8(), None); + assert_eq!(i16::max_value.to_i16(), Some(i16::max_value as i16)); + assert_eq!(i16::max_value.to_i32(), Some(i16::max_value as i32)); + assert_eq!(i16::max_value.to_i64(), Some(i16::max_value as i64)); + assert_eq!(i16::max_value.to_uint(), Some(i16::max_value as uint)); + assert_eq!(i16::max_value.to_u8(), None); + assert_eq!(i16::max_value.to_u16(), Some(i16::max_value as u16)); + assert_eq!(i16::max_value.to_u32(), Some(i16::max_value as u32)); + assert_eq!(i16::max_value.to_u64(), Some(i16::max_value as u64)); + } + + #[test] + fn test_cast_range_i32_max() { + assert_eq!(i32::max_value.to_int(), Some(i32::max_value as int)); + assert_eq!(i32::max_value.to_i8(), None); + assert_eq!(i32::max_value.to_i16(), None); + assert_eq!(i32::max_value.to_i32(), Some(i32::max_value as i32)); + assert_eq!(i32::max_value.to_i64(), Some(i32::max_value as i64)); + assert_eq!(i32::max_value.to_uint(), Some(i32::max_value as uint)); + assert_eq!(i32::max_value.to_u8(), None); + assert_eq!(i32::max_value.to_u16(), None); + assert_eq!(i32::max_value.to_u32(), Some(i32::max_value as u32)); + assert_eq!(i32::max_value.to_u64(), Some(i32::max_value as u64)); + } + + #[test] + fn test_cast_range_i64_max() { + // i64::max_value.to_int() is word-size specific + assert_eq!(i64::max_value.to_i8(), None); + assert_eq!(i64::max_value.to_i16(), None); + assert_eq!(i64::max_value.to_i32(), None); + assert_eq!(i64::max_value.to_i64(), Some(i64::max_value as i64)); + // i64::max_value.to_uint() is word-size specific + assert_eq!(i64::max_value.to_u8(), None); + assert_eq!(i64::max_value.to_u16(), None); + assert_eq!(i64::max_value.to_u32(), None); + assert_eq!(i64::max_value.to_u64(), Some(i64::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(i64::max_value.to_int(), None); + assert_eq!(i64::max_value.to_uint(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(i64::max_value.to_int(), Some(i64::max_value as int)); + assert_eq!(i64::max_value.to_uint(), Some(i64::max_value as uint)); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_uint_min() { + assert_eq!(uint::min_value.to_int(), Some(uint::min_value as int)); + assert_eq!(uint::min_value.to_i8(), Some(uint::min_value as i8)); + assert_eq!(uint::min_value.to_i16(), Some(uint::min_value as i16)); + assert_eq!(uint::min_value.to_i32(), Some(uint::min_value as i32)); + assert_eq!(uint::min_value.to_i64(), Some(uint::min_value as i64)); + assert_eq!(uint::min_value.to_uint(), Some(uint::min_value as uint)); + assert_eq!(uint::min_value.to_u8(), Some(uint::min_value as u8)); + assert_eq!(uint::min_value.to_u16(), Some(uint::min_value as u16)); + assert_eq!(uint::min_value.to_u32(), Some(uint::min_value as u32)); + assert_eq!(uint::min_value.to_u64(), Some(uint::min_value as u64)); + } + + #[test] + fn test_cast_range_u8_min() { + assert_eq!(u8::min_value.to_int(), Some(u8::min_value as int)); + assert_eq!(u8::min_value.to_i8(), Some(u8::min_value as i8)); + assert_eq!(u8::min_value.to_i16(), Some(u8::min_value as i16)); + assert_eq!(u8::min_value.to_i32(), Some(u8::min_value as i32)); + assert_eq!(u8::min_value.to_i64(), Some(u8::min_value as i64)); + assert_eq!(u8::min_value.to_uint(), Some(u8::min_value as uint)); + assert_eq!(u8::min_value.to_u8(), Some(u8::min_value as u8)); + assert_eq!(u8::min_value.to_u16(), Some(u8::min_value as u16)); + assert_eq!(u8::min_value.to_u32(), Some(u8::min_value as u32)); + assert_eq!(u8::min_value.to_u64(), Some(u8::min_value as u64)); + } + + #[test] + fn test_cast_range_u16_min() { + assert_eq!(u16::min_value.to_int(), Some(u16::min_value as int)); + assert_eq!(u16::min_value.to_i8(), Some(u16::min_value as i8)); + assert_eq!(u16::min_value.to_i16(), Some(u16::min_value as i16)); + assert_eq!(u16::min_value.to_i32(), Some(u16::min_value as i32)); + assert_eq!(u16::min_value.to_i64(), Some(u16::min_value as i64)); + assert_eq!(u16::min_value.to_uint(), Some(u16::min_value as uint)); + assert_eq!(u16::min_value.to_u8(), Some(u16::min_value as u8)); + assert_eq!(u16::min_value.to_u16(), Some(u16::min_value as u16)); + assert_eq!(u16::min_value.to_u32(), Some(u16::min_value as u32)); + assert_eq!(u16::min_value.to_u64(), Some(u16::min_value as u64)); + } + + #[test] + fn test_cast_range_u32_min() { + assert_eq!(u32::min_value.to_int(), Some(u32::min_value as int)); + assert_eq!(u32::min_value.to_i8(), Some(u32::min_value as i8)); + assert_eq!(u32::min_value.to_i16(), Some(u32::min_value as i16)); + assert_eq!(u32::min_value.to_i32(), Some(u32::min_value as i32)); + assert_eq!(u32::min_value.to_i64(), Some(u32::min_value as i64)); + assert_eq!(u32::min_value.to_uint(), Some(u32::min_value as uint)); + assert_eq!(u32::min_value.to_u8(), Some(u32::min_value as u8)); + assert_eq!(u32::min_value.to_u16(), Some(u32::min_value as u16)); + assert_eq!(u32::min_value.to_u32(), Some(u32::min_value as u32)); + assert_eq!(u32::min_value.to_u64(), Some(u32::min_value as u64)); + } + + #[test] + fn test_cast_range_u64_min() { + assert_eq!(u64::min_value.to_int(), Some(u64::min_value as int)); + assert_eq!(u64::min_value.to_i8(), Some(u64::min_value as i8)); + assert_eq!(u64::min_value.to_i16(), Some(u64::min_value as i16)); + assert_eq!(u64::min_value.to_i32(), Some(u64::min_value as i32)); + assert_eq!(u64::min_value.to_i64(), Some(u64::min_value as i64)); + assert_eq!(u64::min_value.to_uint(), Some(u64::min_value as uint)); + assert_eq!(u64::min_value.to_u8(), Some(u64::min_value as u8)); + assert_eq!(u64::min_value.to_u16(), Some(u64::min_value as u16)); + assert_eq!(u64::min_value.to_u32(), Some(u64::min_value as u32)); + assert_eq!(u64::min_value.to_u64(), Some(u64::min_value as u64)); + } + + #[test] + fn test_cast_range_uint_max() { + assert_eq!(uint::max_value.to_int(), None); + assert_eq!(uint::max_value.to_i8(), None); + assert_eq!(uint::max_value.to_i16(), None); + assert_eq!(uint::max_value.to_i32(), None); + // uint::max_value.to_i64() is word-size specific + assert_eq!(uint::max_value.to_u8(), None); + assert_eq!(uint::max_value.to_u16(), None); + // uint::max_value.to_u32() is word-size specific + assert_eq!(uint::max_value.to_u64(), Some(uint::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(uint::max_value.to_u32(), Some(uint::max_value as u32)); + assert_eq!(uint::max_value.to_i64(), Some(uint::max_value as i64)); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(uint::max_value.to_u32(), None); + assert_eq!(uint::max_value.to_i64(), None); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_u8_max() { + assert_eq!(u8::max_value.to_int(), Some(u8::max_value as int)); + assert_eq!(u8::max_value.to_i8(), None); + assert_eq!(u8::max_value.to_i16(), Some(u8::max_value as i16)); + assert_eq!(u8::max_value.to_i32(), Some(u8::max_value as i32)); + assert_eq!(u8::max_value.to_i64(), Some(u8::max_value as i64)); + assert_eq!(u8::max_value.to_uint(), Some(u8::max_value as uint)); + assert_eq!(u8::max_value.to_u8(), Some(u8::max_value as u8)); + assert_eq!(u8::max_value.to_u16(), Some(u8::max_value as u16)); + assert_eq!(u8::max_value.to_u32(), Some(u8::max_value as u32)); + assert_eq!(u8::max_value.to_u64(), Some(u8::max_value as u64)); + } + + #[test] + fn test_cast_range_u16_max() { + assert_eq!(u16::max_value.to_int(), Some(u16::max_value as int)); + assert_eq!(u16::max_value.to_i8(), None); + assert_eq!(u16::max_value.to_i16(), None); + assert_eq!(u16::max_value.to_i32(), Some(u16::max_value as i32)); + assert_eq!(u16::max_value.to_i64(), Some(u16::max_value as i64)); + assert_eq!(u16::max_value.to_uint(), Some(u16::max_value as uint)); + assert_eq!(u16::max_value.to_u8(), None); + assert_eq!(u16::max_value.to_u16(), Some(u16::max_value as u16)); + assert_eq!(u16::max_value.to_u32(), Some(u16::max_value as u32)); + assert_eq!(u16::max_value.to_u64(), Some(u16::max_value as u64)); + } + + #[test] + fn test_cast_range_u32_max() { + // u32::max_value.to_int() is word-size specific + assert_eq!(u32::max_value.to_i8(), None); + assert_eq!(u32::max_value.to_i16(), None); + assert_eq!(u32::max_value.to_i32(), None); + assert_eq!(u32::max_value.to_i64(), Some(u32::max_value as i64)); + assert_eq!(u32::max_value.to_uint(), Some(u32::max_value as uint)); + assert_eq!(u32::max_value.to_u8(), None); + assert_eq!(u32::max_value.to_u16(), None); + assert_eq!(u32::max_value.to_u32(), Some(u32::max_value as u32)); + assert_eq!(u32::max_value.to_u64(), Some(u32::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(u32::max_value.to_int(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(u32::max_value.to_int(), Some(u32::max_value as int)); + } + + check_word_size(); + } + + #[test] + fn test_cast_range_u64_max() { + assert_eq!(u64::max_value.to_int(), None); + assert_eq!(u64::max_value.to_i8(), None); + assert_eq!(u64::max_value.to_i16(), None); + assert_eq!(u64::max_value.to_i32(), None); + assert_eq!(u64::max_value.to_i64(), None); + // u64::max_value.to_uint() is word-size specific + assert_eq!(u64::max_value.to_u8(), None); + assert_eq!(u64::max_value.to_u16(), None); + assert_eq!(u64::max_value.to_u32(), None); + assert_eq!(u64::max_value.to_u64(), Some(u64::max_value as u64)); + + #[cfg(target_word_size = "32")] + fn check_word_size() { + assert_eq!(u64::max_value.to_uint(), None); + } + + #[cfg(target_word_size = "64")] + fn check_word_size() { + assert_eq!(u64::max_value.to_uint(), Some(u64::max_value as uint)); + } + + check_word_size(); + } + + #[test] + fn test_saturating_add_uint() { + use uint::max_value; + assert_eq!(3u.saturating_add(5u), 8u); + assert_eq!(3u.saturating_add(max_value-1), max_value); + assert_eq!(max_value.saturating_add(max_value), max_value); + assert_eq!((max_value-2).saturating_add(1), max_value-1); + } + + #[test] + fn test_saturating_sub_uint() { + use uint::max_value; + assert_eq!(5u.saturating_sub(3u), 2u); + assert_eq!(3u.saturating_sub(5u), 0u); + assert_eq!(0u.saturating_sub(1u), 0u); + assert_eq!((max_value-1).saturating_sub(max_value), 0); + } + + #[test] + fn test_saturating_add_int() { + use int::{min_value,max_value}; + assert_eq!(3i.saturating_add(5i), 8i); + assert_eq!(3i.saturating_add(max_value-1), max_value); + assert_eq!(max_value.saturating_add(max_value), max_value); + assert_eq!((max_value-2).saturating_add(1), max_value-1); + assert_eq!(3i.saturating_add(-5i), -2i); + assert_eq!(min_value.saturating_add(-1i), min_value); + assert_eq!((-2i).saturating_add(-max_value), min_value); + } + + #[test] + fn test_saturating_sub_int() { + use int::{min_value,max_value}; + assert_eq!(3i.saturating_sub(5i), -2i); + assert_eq!(min_value.saturating_sub(1i), min_value); + assert_eq!((-2i).saturating_sub(max_value), min_value); + assert_eq!(3i.saturating_sub(-5i), 8i); + assert_eq!(3i.saturating_sub(-(max_value-1)), max_value); + assert_eq!(max_value.saturating_sub(-max_value), max_value); + assert_eq!((max_value-2).saturating_sub(-1), max_value-1); + } + + #[test] + fn test_checked_add() { + let five_less = uint::max_value - 5; + assert_eq!(five_less.checked_add(&0), Some(uint::max_value - 5)); + assert_eq!(five_less.checked_add(&1), Some(uint::max_value - 4)); + assert_eq!(five_less.checked_add(&2), Some(uint::max_value - 3)); + assert_eq!(five_less.checked_add(&3), Some(uint::max_value - 2)); + assert_eq!(five_less.checked_add(&4), Some(uint::max_value - 1)); + assert_eq!(five_less.checked_add(&5), Some(uint::max_value)); + assert_eq!(five_less.checked_add(&6), None); + assert_eq!(five_less.checked_add(&7), None); + } + + #[test] + fn test_checked_sub() { + assert_eq!(5u.checked_sub(&0), Some(5)); + assert_eq!(5u.checked_sub(&1), Some(4)); + assert_eq!(5u.checked_sub(&2), Some(3)); + assert_eq!(5u.checked_sub(&3), Some(2)); + assert_eq!(5u.checked_sub(&4), Some(1)); + assert_eq!(5u.checked_sub(&5), Some(0)); + assert_eq!(5u.checked_sub(&6), None); + assert_eq!(5u.checked_sub(&7), None); + } + + #[test] + fn test_checked_mul() { + let third = uint::max_value / 3; + assert_eq!(third.checked_mul(&0), Some(0)); + assert_eq!(third.checked_mul(&1), Some(third)); + assert_eq!(third.checked_mul(&2), Some(third * 2)); + assert_eq!(third.checked_mul(&3), Some(third * 3)); + assert_eq!(third.checked_mul(&4), None); + } + + + #[deriving(Eq)] + struct Value { x: int } + + impl ToPrimitive for Value { + fn to_i64(&self) -> Option<i64> { self.x.to_i64() } + fn to_u64(&self) -> Option<u64> { self.x.to_u64() } + } + + impl FromPrimitive for Value { + fn from_i64(n: i64) -> Option<Value> { Some(Value { x: n as int }) } + fn from_u64(n: u64) -> Option<Value> { Some(Value { x: n as int }) } + } + + #[test] + fn test_to_primitive() { + let value = Value { x: 5 }; + assert_eq!(value.to_int(), Some(5)); + assert_eq!(value.to_i8(), Some(5)); + assert_eq!(value.to_i16(), Some(5)); + assert_eq!(value.to_i32(), Some(5)); + assert_eq!(value.to_i64(), Some(5)); + assert_eq!(value.to_uint(), Some(5)); + assert_eq!(value.to_u8(), Some(5)); + assert_eq!(value.to_u16(), Some(5)); + assert_eq!(value.to_u32(), Some(5)); + assert_eq!(value.to_u64(), Some(5)); + assert_eq!(value.to_f32(), Some(5f32)); + assert_eq!(value.to_f64(), Some(5f64)); + } + + #[test] + fn test_from_primitive() { + assert_eq!(from_int(5), Some(Value { x: 5 })); + assert_eq!(from_i8(5), Some(Value { x: 5 })); + assert_eq!(from_i16(5), Some(Value { x: 5 })); + assert_eq!(from_i32(5), Some(Value { x: 5 })); + assert_eq!(from_i64(5), Some(Value { x: 5 })); + assert_eq!(from_uint(5), Some(Value { x: 5 })); + assert_eq!(from_u8(5), Some(Value { x: 5 })); + assert_eq!(from_u16(5), Some(Value { x: 5 })); + assert_eq!(from_u32(5), Some(Value { x: 5 })); + assert_eq!(from_u64(5), Some(Value { x: 5 })); + assert_eq!(from_f32(5f32), Some(Value { x: 5 })); + assert_eq!(from_f64(5f64), Some(Value { x: 5 })); + } +} |
