diff options
Diffstat (limited to 'third_party/rust/num-traits/src/sign.rs')
-rw-r--r-- | third_party/rust/num-traits/src/sign.rs | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/third_party/rust/num-traits/src/sign.rs b/third_party/rust/num-traits/src/sign.rs new file mode 100644 index 0000000000..5c32071c23 --- /dev/null +++ b/third_party/rust/num-traits/src/sign.rs @@ -0,0 +1,224 @@ +use core::num::Wrapping; +use core::ops::Neg; + +use float::FloatCore; +use Num; + +/// Useful functions for signed numbers (i.e. numbers that can be negative). +pub trait Signed: Sized + Num + Neg<Output = Self> { + /// Computes the absolute value. + /// + /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`. + /// + /// For signed integers, `::MIN` will be returned if the number is `::MIN`. + fn abs(&self) -> Self; + + /// 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. + fn abs_sub(&self, other: &Self) -> Self; + + /// Returns the sign of the number. + /// + /// For `f32` and `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 signed integers: + /// + /// * `0` if the number is zero + /// * `1` if the number is positive + /// * `-1` if the number is negative + fn signum(&self) -> Self; + + /// Returns true if the number is positive and false if the number is zero or negative. + fn is_positive(&self) -> bool; + + /// Returns true if the number is negative and false if the number is zero or positive. + fn is_negative(&self) -> bool; +} + +macro_rules! signed_impl { + ($($t:ty)*) => ($( + impl Signed for $t { + #[inline] + fn abs(&self) -> $t { + if self.is_negative() { -*self } else { *self } + } + + #[inline] + fn abs_sub(&self, other: &$t) -> $t { + if *self <= *other { 0 } else { *self - *other } + } + + #[inline] + fn signum(&self) -> $t { + match *self { + n if n > 0 => 1, + 0 => 0, + _ => -1, + } + } + + #[inline] + fn is_positive(&self) -> bool { *self > 0 } + + #[inline] + fn is_negative(&self) -> bool { *self < 0 } + } + )*) +} + +signed_impl!(isize i8 i16 i32 i64); + +#[cfg(has_i128)] +signed_impl!(i128); + +impl<T: Signed> Signed for Wrapping<T> +where + Wrapping<T>: Num + Neg<Output = Wrapping<T>>, +{ + #[inline] + fn abs(&self) -> Self { + Wrapping(self.0.abs()) + } + + #[inline] + fn abs_sub(&self, other: &Self) -> Self { + Wrapping(self.0.abs_sub(&other.0)) + } + + #[inline] + fn signum(&self) -> Self { + Wrapping(self.0.signum()) + } + + #[inline] + fn is_positive(&self) -> bool { + self.0.is_positive() + } + + #[inline] + fn is_negative(&self) -> bool { + self.0.is_negative() + } +} + +macro_rules! signed_float_impl { + ($t:ty) => { + impl Signed for $t { + /// Computes the absolute value. Returns `NAN` if the number is `NAN`. + #[inline] + fn abs(&self) -> $t { + FloatCore::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] + fn abs_sub(&self, other: &$t) -> $t { + if *self <= *other { + 0. + } else { + *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] + fn signum(&self) -> $t { + FloatCore::signum(*self) + } + + /// Returns `true` if the number is positive, including `+0.0` and `INFINITY` + #[inline] + fn is_positive(&self) -> bool { + FloatCore::is_sign_positive(*self) + } + + /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY` + #[inline] + fn is_negative(&self) -> bool { + FloatCore::is_sign_negative(*self) + } + } + }; +} + +signed_float_impl!(f32); +signed_float_impl!(f64); + +/// Computes the absolute value. +/// +/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN` +/// +/// For signed integers, `::MIN` will be returned if the number is `::MIN`. +#[inline(always)] +pub fn abs<T: Signed>(value: T) -> T { + value.abs() +} + +/// The positive difference of two numbers. +/// +/// Returns zero if `x` is less than or equal to `y`, otherwise the difference +/// between `x` and `y` 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 `f32` and `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 signed integers: +/// +/// * `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() +} + +/// A trait for values which cannot be negative +pub trait Unsigned: Num {} + +macro_rules! empty_trait_impl { + ($name:ident for $($t:ty)*) => ($( + impl $name for $t {} + )*) +} + +empty_trait_impl!(Unsigned for usize u8 u16 u32 u64); +#[cfg(has_i128)] +empty_trait_impl!(Unsigned for u128); + +impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {} + +#[test] +fn unsigned_wrapping_is_unsigned() { + fn require_unsigned<T: Unsigned>(_: &T) {} + require_unsigned(&Wrapping(42_u32)); +} + +// Commenting this out since it doesn't compile on Rust 1.8, +// because on this version Wrapping doesn't implement Neg and therefore can't +// implement Signed. +// #[test] +// fn signed_wrapping_is_signed() { +// fn require_signed<T: Signed>(_: &T) {} +// require_signed(&Wrapping(-42)); +// } |