diff --git a/traits/src/bounds.rs b/traits/src/bounds.rs index 966296c..ea5c811 100644 --- a/traits/src/bounds.rs +++ b/traits/src/bounds.rs @@ -1,6 +1,7 @@ use std::{usize, u8, u16, u32, u64}; use std::{isize, i8, i16, i32, i64}; use std::{f32, f64}; +use std::num::Wrapping; /// Numbers which have upper and lower bounds pub trait Bounded { @@ -35,6 +36,11 @@ bounded_impl!(i16, i16::MIN, i16::MAX); bounded_impl!(i32, i32::MIN, i32::MAX); bounded_impl!(i64, i64::MIN, i64::MAX); +impl Bounded for Wrapping { + fn min_value() -> Self { Wrapping(T::min_value()) } + fn max_value() -> Self { Wrapping(T::max_value()) } +} + bounded_impl!(f32, f32::MIN, f32::MAX); macro_rules! for_each_tuple_ { @@ -69,3 +75,25 @@ macro_rules! bounded_tuple { for_each_tuple!(bounded_tuple); bounded_impl!(f64, f64::MIN, f64::MAX); + + +macro_rules! test_wrapping_bounded { + ($($t:ty)+) => { + $( + assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value()); + assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value()); + )+ + }; +} + +#[test] +fn wrapping_bounded() { + test_wrapping_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); +} + +#[test] +fn wrapping_is_bounded() { + fn require_bounded(_: &T) {} + require_bounded(&Wrapping(42_u32)); + require_bounded(&Wrapping(-42)); +} diff --git a/traits/src/cast.rs b/traits/src/cast.rs index 8ff03fd..8949834 100644 --- a/traits/src/cast.rs +++ b/traits/src/cast.rs @@ -1,4 +1,5 @@ use std::mem::size_of; +use std::num::Wrapping; use identities::Zero; use bounds::Bounded; @@ -385,6 +386,17 @@ impl_from_primitive!(u64, to_u64); impl_from_primitive!(f32, to_f32); impl_from_primitive!(f64, to_f64); + +impl ToPrimitive for Wrapping { + fn to_i64(&self) -> Option { self.0.to_i64() } + fn to_u64(&self) -> Option { self.0.to_u64() } +} +impl FromPrimitive for Wrapping { + fn from_u64(n: u64) -> Option { T::from_u64(n).map(Wrapping) } + fn from_i64(n: i64) -> Option { T::from_i64(n).map(Wrapping) } +} + + /// Cast from one machine scalar to another. /// /// # Examples @@ -434,6 +446,11 @@ impl_num_cast!(isize, to_isize); impl_num_cast!(f32, to_f32); impl_num_cast!(f64, to_f64); +impl NumCast for Wrapping { + fn from(n: U) -> Option { + T::from(n).map(Wrapping) + } +} #[test] fn to_primitive_float() { @@ -448,3 +465,47 @@ fn to_primitive_float() { assert_eq!((f64::NEG_INFINITY).to_f32(), Some(f32::NEG_INFINITY)); assert!((f64::NAN).to_f32().map_or(false, |f| f.is_nan())); } + +macro_rules! test_wrapping_to_primitive { + ($($t:ty)+) => { + $({ + let i: $t = 0; + let w = Wrapping(i); + assert_eq!(i.to_u8(), w.to_u8()); + assert_eq!(i.to_u16(), w.to_u16()); + assert_eq!(i.to_u32(), w.to_u32()); + assert_eq!(i.to_u64(), w.to_u64()); + assert_eq!(i.to_usize(), w.to_usize()); + assert_eq!(i.to_i8(), w.to_i8()); + assert_eq!(i.to_i16(), w.to_i16()); + assert_eq!(i.to_i32(), w.to_i32()); + assert_eq!(i.to_i64(), w.to_i64()); + assert_eq!(i.to_isize(), w.to_isize()); + assert_eq!(i.to_f32(), w.to_f32()); + assert_eq!(i.to_f64(), w.to_f64()); + })+ + }; +} + +#[test] +fn wrapping_to_primitive() { + test_wrapping_to_primitive!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); +} + +#[test] +fn wrapping_is_toprimitive() { + fn require_toprimitive(_: &T) {} + require_toprimitive(&Wrapping(42)); +} + +#[test] +fn wrapping_is_fromprimitive() { + fn require_fromprimitive(_: &T) {} + require_fromprimitive(&Wrapping(42)); +} + +#[test] +fn wrapping_is_numcast() { + fn require_numcast(_: &T) {} + require_numcast(&Wrapping(42)); +} diff --git a/traits/src/identities.rs b/traits/src/identities.rs index 889b11d..2f520e0 100644 --- a/traits/src/identities.rs +++ b/traits/src/identities.rs @@ -118,3 +118,31 @@ impl One for Wrapping where Wrapping: Mul> { /// Returns the multiplicative identity, `1`. #[inline(always)] pub fn one() -> T { One::one() } + + +macro_rules! test_wrapping_identities { + ($($t:ty)+) => { + $( + assert_eq!(zero::<$t>(), zero::>().0); + assert_eq!(one::<$t>(), one::>().0); + assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero()); + assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero()); + )+ + }; +} + +#[test] +fn wrapping_identities() { + test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64); +} + +#[test] +fn wrapping_is_zero() { + fn require_zero(_: &T) {} + require_zero(&Wrapping(42)); +} +#[test] +fn wrapping_is_one() { + fn require_one(_: &T) {} + require_one(&Wrapping(42)); +} diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 0cf7e34..083fe41 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -294,3 +294,24 @@ fn from_str_radix_unwrap() { let f: f32 = Num::from_str_radix("0.0", 10).unwrap(); assert_eq!(f, 0.0); } + +macro_rules! test_wrapping_from_str_radix { + ($($t:ty)+) => { + $( + for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] { + let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0); + assert_eq!(w, <$t as Num>::from_str_radix(s, r)); + } + )+ + }; +} +#[test] +fn wrapping_is_num() { + fn require_num(_: &T) {} + require_num(&Wrapping(42_u32)); + require_num(&Wrapping(-42)); +} +#[test] +fn wrapping_from_str_radix() { + test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); +} diff --git a/traits/src/ops/checked.rs b/traits/src/ops/checked.rs index b6bf0d6..45e6716 100644 --- a/traits/src/ops/checked.rs +++ b/traits/src/ops/checked.rs @@ -89,3 +89,4 @@ checked_impl!(CheckedDiv, checked_div, i16); checked_impl!(CheckedDiv, checked_div, i32); checked_impl!(CheckedDiv, checked_div, i64); checked_impl!(CheckedDiv, checked_div, isize); + diff --git a/traits/src/ops/wrapping.rs b/traits/src/ops/wrapping.rs index 40b266d..f989058 100644 --- a/traits/src/ops/wrapping.rs +++ b/traits/src/ops/wrapping.rs @@ -1,4 +1,5 @@ use std::ops::{Add, Sub, Mul}; +use std::num::Wrapping; macro_rules! wrapping_impl { ($trait_name:ident, $method:ident, $t:ty) => { @@ -76,6 +77,23 @@ wrapping_impl!(WrappingMul, wrapping_mul, i32); wrapping_impl!(WrappingMul, wrapping_mul, i64); wrapping_impl!(WrappingMul, wrapping_mul, isize); +// Well this is a bit funny, but all the more appropriate. +impl WrappingAdd for Wrapping where Wrapping: Add> { + fn wrapping_add(&self, v: &Self) -> Self { + Wrapping(self.0.wrapping_add(&v.0)) + } +} +impl WrappingSub for Wrapping where Wrapping: Sub> { + fn wrapping_sub(&self, v: &Self) -> Self { + Wrapping(self.0.wrapping_sub(&v.0)) + } +} +impl WrappingMul for Wrapping where Wrapping: Mul> { + fn wrapping_mul(&self, v: &Self) -> Self { + Wrapping(self.0.wrapping_mul(&v.0)) + } +} + #[test] fn test_wrapping_traits() { @@ -85,4 +103,25 @@ fn test_wrapping_traits() { assert_eq!(wrapping_add(255, 1), 0u8); assert_eq!(wrapping_sub(0, 1), 255u8); assert_eq!(wrapping_mul(255, 2), 254u8); + assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0); + assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0); + assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0); +} + +#[test] +fn wrapping_is_wrappingadd() { + fn require_wrappingadd(_: &T) {} + require_wrappingadd(&Wrapping(42)); +} + +#[test] +fn wrapping_is_wrappingsub() { + fn require_wrappingsub(_: &T) {} + require_wrappingsub(&Wrapping(42)); +} + +#[test] +fn wrapping_is_wrappingmul() { + fn require_wrappingmul(_: &T) {} + require_wrappingmul(&Wrapping(42)); } diff --git a/traits/src/sign.rs b/traits/src/sign.rs index c56ad25..4b43c89 100644 --- a/traits/src/sign.rs +++ b/traits/src/sign.rs @@ -1,5 +1,6 @@ use std::ops::Neg; use std::{f32, f64}; +use std::num::Wrapping; use Num; @@ -73,6 +74,30 @@ macro_rules! signed_impl { signed_impl!(isize i8 i16 i32 i64); +impl Signed for Wrapping where Wrapping: Num + Neg> +{ + #[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, $nan:expr, $inf:expr, $neg_inf:expr) => { impl Signed for $t { @@ -159,3 +184,21 @@ macro_rules! empty_trait_impl { } empty_trait_impl!(Unsigned for usize u8 u16 u32 u64); + +impl Unsigned for Wrapping where Wrapping: Num {} + +#[test] +fn unsigned_wrapping_is_unsigned() { + fn require_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) {} + require_signed(&Wrapping(-42)); +} +*/