Skip to content

impl remaining num-traits for std::num::Wrapping<T> #286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions traits/src/bounds.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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<T: Bounded> Bounded for Wrapping<T> {
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_ {
Expand Down Expand Up @@ -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: Bounded>(_: &T) {}
require_bounded(&Wrapping(42_u32));
require_bounded(&Wrapping(-42));
}
61 changes: 61 additions & 0 deletions traits/src/cast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::mem::size_of;
use std::num::Wrapping;

use identities::Zero;
use bounds::Bounded;
Expand Down Expand Up @@ -385,6 +386,17 @@ impl_from_primitive!(u64, to_u64);
impl_from_primitive!(f32, to_f32);
impl_from_primitive!(f64, to_f64);


impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
}
impl<T: FromPrimitive> FromPrimitive for Wrapping<T> {
fn from_u64(n: u64) -> Option<Self> { T::from_u64(n).map(Wrapping) }
fn from_i64(n: i64) -> Option<Self> { T::from_i64(n).map(Wrapping) }
}


/// Cast from one machine scalar to another.
///
/// # Examples
Expand Down Expand Up @@ -434,6 +446,11 @@ impl_num_cast!(isize, to_isize);
impl_num_cast!(f32, to_f32);
impl_num_cast!(f64, to_f64);

impl<T: NumCast> NumCast for Wrapping<T> {
fn from<U: ToPrimitive>(n: U) -> Option<Self> {
T::from(n).map(Wrapping)
}
}

#[test]
fn to_primitive_float() {
Expand All @@ -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: ToPrimitive>(_: &T) {}
require_toprimitive(&Wrapping(42));
}

#[test]
fn wrapping_is_fromprimitive() {
fn require_fromprimitive<T: FromPrimitive>(_: &T) {}
require_fromprimitive(&Wrapping(42));
}

#[test]
fn wrapping_is_numcast() {
fn require_numcast<T: NumCast>(_: &T) {}
require_numcast(&Wrapping(42));
}
28 changes: 28 additions & 0 deletions traits/src/identities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,31 @@ impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {

/// Returns the multiplicative identity, `1`.
#[inline(always)] pub fn one<T: One>() -> T { One::one() }


macro_rules! test_wrapping_identities {
($($t:ty)+) => {
$(
assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
assert_eq!(one::<$t>(), one::<Wrapping<$t>>().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: Zero>(_: &T) {}
require_zero(&Wrapping(42));
}
#[test]
fn wrapping_is_one() {
fn require_one<T: One>(_: &T) {}
require_one(&Wrapping(42));
}
21 changes: 21 additions & 0 deletions traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: 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);
}
1 change: 1 addition & 0 deletions traits/src/ops/checked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

39 changes: 39 additions & 0 deletions traits/src/ops/wrapping.rs
Original file line number Diff line number Diff line change
@@ -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) => {
Expand Down Expand Up @@ -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<T: WrappingAdd> WrappingAdd for Wrapping<T> where Wrapping<T>: Add<Output = Wrapping<T>> {
fn wrapping_add(&self, v: &Self) -> Self {
Wrapping(self.0.wrapping_add(&v.0))
}
}
impl<T: WrappingSub> WrappingSub for Wrapping<T> where Wrapping<T>: Sub<Output = Wrapping<T>> {
fn wrapping_sub(&self, v: &Self) -> Self {
Wrapping(self.0.wrapping_sub(&v.0))
}
}
impl<T: WrappingMul> WrappingMul for Wrapping<T> where Wrapping<T>: Mul<Output = Wrapping<T>> {
fn wrapping_mul(&self, v: &Self) -> Self {
Wrapping(self.0.wrapping_mul(&v.0))
}
}


#[test]
fn test_wrapping_traits() {
Expand All @@ -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: WrappingAdd>(_: &T) {}
require_wrappingadd(&Wrapping(42));
}

#[test]
fn wrapping_is_wrappingsub() {
fn require_wrappingsub<T: WrappingSub>(_: &T) {}
require_wrappingsub(&Wrapping(42));
}

#[test]
fn wrapping_is_wrappingmul() {
fn require_wrappingmul<T: WrappingMul>(_: &T) {}
require_wrappingmul(&Wrapping(42));
}
43 changes: 43 additions & 0 deletions traits/src/sign.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::ops::Neg;
use std::{f32, f64};
use std::num::Wrapping;

use Num;

Expand Down Expand Up @@ -73,6 +74,30 @@ macro_rules! signed_impl {

signed_impl!(isize i8 i16 i32 i64);

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, $nan:expr, $inf:expr, $neg_inf:expr) => {
impl Signed for $t {
Expand Down Expand Up @@ -159,3 +184,21 @@ macro_rules! empty_trait_impl {
}

empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);

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));
}
*/