Auto merge of #286 - yoanlcq:missing-impls-for-wrapping, r=cuviper

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

This is a (late) follow-up for [https://github.com/rust-num/num/pull/279](https://github.com/rust-num/num/pull/279) since I realized that implementing `Num` for `Wrapping<T>` was merely half of the work.

This PR makes `Wrapping<T>` implement the remaining appropriate traits, granting it the ability to really be used a complete substitute for its primitive integer counterparts.
Some benefits are :
- Less refactoring for users using `num`'s traits replacing some primitives by their `Wrapping` counterpart (same for the opposite);
- Since `Wrapping<T>` is from `std`, nobody except us can `impl` our traits for it, so people don't have to create their own.
This commit is contained in:
Homu 2017-05-07 13:26:44 +09:00
commit ef08fe2f96
7 changed files with 221 additions and 0 deletions

View File

@ -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<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_ {
@ -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));
}

View File

@ -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<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
@ -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() {
@ -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));
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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<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() {
@ -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));
}

View File

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