Skip to content

Commit ef08fe2

Browse files
committed
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.
2 parents 51e9555 + 9115df6 commit ef08fe2

File tree

7 files changed

+221
-0
lines changed

7 files changed

+221
-0
lines changed

traits/src/bounds.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{usize, u8, u16, u32, u64};
22
use std::{isize, i8, i16, i32, i64};
33
use std::{f32, f64};
4+
use std::num::Wrapping;
45

56
/// Numbers which have upper and lower bounds
67
pub trait Bounded {
@@ -35,6 +36,11 @@ bounded_impl!(i16, i16::MIN, i16::MAX);
3536
bounded_impl!(i32, i32::MIN, i32::MAX);
3637
bounded_impl!(i64, i64::MIN, i64::MAX);
3738

39+
impl<T: Bounded> Bounded for Wrapping<T> {
40+
fn min_value() -> Self { Wrapping(T::min_value()) }
41+
fn max_value() -> Self { Wrapping(T::max_value()) }
42+
}
43+
3844
bounded_impl!(f32, f32::MIN, f32::MAX);
3945

4046
macro_rules! for_each_tuple_ {
@@ -69,3 +75,25 @@ macro_rules! bounded_tuple {
6975

7076
for_each_tuple!(bounded_tuple);
7177
bounded_impl!(f64, f64::MIN, f64::MAX);
78+
79+
80+
macro_rules! test_wrapping_bounded {
81+
($($t:ty)+) => {
82+
$(
83+
assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value());
84+
assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value());
85+
)+
86+
};
87+
}
88+
89+
#[test]
90+
fn wrapping_bounded() {
91+
test_wrapping_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
92+
}
93+
94+
#[test]
95+
fn wrapping_is_bounded() {
96+
fn require_bounded<T: Bounded>(_: &T) {}
97+
require_bounded(&Wrapping(42_u32));
98+
require_bounded(&Wrapping(-42));
99+
}

traits/src/cast.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::mem::size_of;
2+
use std::num::Wrapping;
23

34
use identities::Zero;
45
use bounds::Bounded;
@@ -385,6 +386,17 @@ impl_from_primitive!(u64, to_u64);
385386
impl_from_primitive!(f32, to_f32);
386387
impl_from_primitive!(f64, to_f64);
387388

389+
390+
impl<T: ToPrimitive> ToPrimitive for Wrapping<T> {
391+
fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
392+
fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
393+
}
394+
impl<T: FromPrimitive> FromPrimitive for Wrapping<T> {
395+
fn from_u64(n: u64) -> Option<Self> { T::from_u64(n).map(Wrapping) }
396+
fn from_i64(n: i64) -> Option<Self> { T::from_i64(n).map(Wrapping) }
397+
}
398+
399+
388400
/// Cast from one machine scalar to another.
389401
///
390402
/// # Examples
@@ -434,6 +446,11 @@ impl_num_cast!(isize, to_isize);
434446
impl_num_cast!(f32, to_f32);
435447
impl_num_cast!(f64, to_f64);
436448

449+
impl<T: NumCast> NumCast for Wrapping<T> {
450+
fn from<U: ToPrimitive>(n: U) -> Option<Self> {
451+
T::from(n).map(Wrapping)
452+
}
453+
}
437454

438455
#[test]
439456
fn to_primitive_float() {
@@ -448,3 +465,47 @@ fn to_primitive_float() {
448465
assert_eq!((f64::NEG_INFINITY).to_f32(), Some(f32::NEG_INFINITY));
449466
assert!((f64::NAN).to_f32().map_or(false, |f| f.is_nan()));
450467
}
468+
469+
macro_rules! test_wrapping_to_primitive {
470+
($($t:ty)+) => {
471+
$({
472+
let i: $t = 0;
473+
let w = Wrapping(i);
474+
assert_eq!(i.to_u8(), w.to_u8());
475+
assert_eq!(i.to_u16(), w.to_u16());
476+
assert_eq!(i.to_u32(), w.to_u32());
477+
assert_eq!(i.to_u64(), w.to_u64());
478+
assert_eq!(i.to_usize(), w.to_usize());
479+
assert_eq!(i.to_i8(), w.to_i8());
480+
assert_eq!(i.to_i16(), w.to_i16());
481+
assert_eq!(i.to_i32(), w.to_i32());
482+
assert_eq!(i.to_i64(), w.to_i64());
483+
assert_eq!(i.to_isize(), w.to_isize());
484+
assert_eq!(i.to_f32(), w.to_f32());
485+
assert_eq!(i.to_f64(), w.to_f64());
486+
})+
487+
};
488+
}
489+
490+
#[test]
491+
fn wrapping_to_primitive() {
492+
test_wrapping_to_primitive!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
493+
}
494+
495+
#[test]
496+
fn wrapping_is_toprimitive() {
497+
fn require_toprimitive<T: ToPrimitive>(_: &T) {}
498+
require_toprimitive(&Wrapping(42));
499+
}
500+
501+
#[test]
502+
fn wrapping_is_fromprimitive() {
503+
fn require_fromprimitive<T: FromPrimitive>(_: &T) {}
504+
require_fromprimitive(&Wrapping(42));
505+
}
506+
507+
#[test]
508+
fn wrapping_is_numcast() {
509+
fn require_numcast<T: NumCast>(_: &T) {}
510+
require_numcast(&Wrapping(42));
511+
}

traits/src/identities.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,31 @@ impl<T: One> One for Wrapping<T> where Wrapping<T>: Mul<Output=Wrapping<T>> {
118118

119119
/// Returns the multiplicative identity, `1`.
120120
#[inline(always)] pub fn one<T: One>() -> T { One::one() }
121+
122+
123+
macro_rules! test_wrapping_identities {
124+
($($t:ty)+) => {
125+
$(
126+
assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
127+
assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
128+
assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
129+
assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
130+
)+
131+
};
132+
}
133+
134+
#[test]
135+
fn wrapping_identities() {
136+
test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
137+
}
138+
139+
#[test]
140+
fn wrapping_is_zero() {
141+
fn require_zero<T: Zero>(_: &T) {}
142+
require_zero(&Wrapping(42));
143+
}
144+
#[test]
145+
fn wrapping_is_one() {
146+
fn require_one<T: One>(_: &T) {}
147+
require_one(&Wrapping(42));
148+
}

traits/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,24 @@ fn from_str_radix_unwrap() {
294294
let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
295295
assert_eq!(f, 0.0);
296296
}
297+
298+
macro_rules! test_wrapping_from_str_radix {
299+
($($t:ty)+) => {
300+
$(
301+
for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
302+
let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0);
303+
assert_eq!(w, <$t as Num>::from_str_radix(s, r));
304+
}
305+
)+
306+
};
307+
}
308+
#[test]
309+
fn wrapping_is_num() {
310+
fn require_num<T: Num>(_: &T) {}
311+
require_num(&Wrapping(42_u32));
312+
require_num(&Wrapping(-42));
313+
}
314+
#[test]
315+
fn wrapping_from_str_radix() {
316+
test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
317+
}

traits/src/ops/checked.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,4 @@ checked_impl!(CheckedDiv, checked_div, i16);
8989
checked_impl!(CheckedDiv, checked_div, i32);
9090
checked_impl!(CheckedDiv, checked_div, i64);
9191
checked_impl!(CheckedDiv, checked_div, isize);
92+

traits/src/ops/wrapping.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::ops::{Add, Sub, Mul};
2+
use std::num::Wrapping;
23

34
macro_rules! wrapping_impl {
45
($trait_name:ident, $method:ident, $t:ty) => {
@@ -76,6 +77,23 @@ wrapping_impl!(WrappingMul, wrapping_mul, i32);
7677
wrapping_impl!(WrappingMul, wrapping_mul, i64);
7778
wrapping_impl!(WrappingMul, wrapping_mul, isize);
7879

80+
// Well this is a bit funny, but all the more appropriate.
81+
impl<T: WrappingAdd> WrappingAdd for Wrapping<T> where Wrapping<T>: Add<Output = Wrapping<T>> {
82+
fn wrapping_add(&self, v: &Self) -> Self {
83+
Wrapping(self.0.wrapping_add(&v.0))
84+
}
85+
}
86+
impl<T: WrappingSub> WrappingSub for Wrapping<T> where Wrapping<T>: Sub<Output = Wrapping<T>> {
87+
fn wrapping_sub(&self, v: &Self) -> Self {
88+
Wrapping(self.0.wrapping_sub(&v.0))
89+
}
90+
}
91+
impl<T: WrappingMul> WrappingMul for Wrapping<T> where Wrapping<T>: Mul<Output = Wrapping<T>> {
92+
fn wrapping_mul(&self, v: &Self) -> Self {
93+
Wrapping(self.0.wrapping_mul(&v.0))
94+
}
95+
}
96+
7997

8098
#[test]
8199
fn test_wrapping_traits() {
@@ -85,4 +103,25 @@ fn test_wrapping_traits() {
85103
assert_eq!(wrapping_add(255, 1), 0u8);
86104
assert_eq!(wrapping_sub(0, 1), 255u8);
87105
assert_eq!(wrapping_mul(255, 2), 254u8);
106+
assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0);
107+
assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0);
108+
assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0);
109+
}
110+
111+
#[test]
112+
fn wrapping_is_wrappingadd() {
113+
fn require_wrappingadd<T: WrappingAdd>(_: &T) {}
114+
require_wrappingadd(&Wrapping(42));
115+
}
116+
117+
#[test]
118+
fn wrapping_is_wrappingsub() {
119+
fn require_wrappingsub<T: WrappingSub>(_: &T) {}
120+
require_wrappingsub(&Wrapping(42));
121+
}
122+
123+
#[test]
124+
fn wrapping_is_wrappingmul() {
125+
fn require_wrappingmul<T: WrappingMul>(_: &T) {}
126+
require_wrappingmul(&Wrapping(42));
88127
}

traits/src/sign.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::ops::Neg;
22
use std::{f32, f64};
3+
use std::num::Wrapping;
34

45
use Num;
56

@@ -73,6 +74,30 @@ macro_rules! signed_impl {
7374

7475
signed_impl!(isize i8 i16 i32 i64);
7576

77+
impl<T: Signed> Signed for Wrapping<T> where Wrapping<T>: Num + Neg<Output=Wrapping<T>>
78+
{
79+
#[inline]
80+
fn abs(&self) -> Self {
81+
Wrapping(self.0.abs())
82+
}
83+
84+
#[inline]
85+
fn abs_sub(&self, other: &Self) -> Self {
86+
Wrapping(self.0.abs_sub(&other.0))
87+
}
88+
89+
#[inline]
90+
fn signum(&self) -> Self {
91+
Wrapping(self.0.signum())
92+
}
93+
94+
#[inline]
95+
fn is_positive(&self) -> bool { self.0.is_positive() }
96+
97+
#[inline]
98+
fn is_negative(&self) -> bool { self.0.is_negative() }
99+
}
100+
76101
macro_rules! signed_float_impl {
77102
($t:ty, $nan:expr, $inf:expr, $neg_inf:expr) => {
78103
impl Signed for $t {
@@ -159,3 +184,21 @@ macro_rules! empty_trait_impl {
159184
}
160185

161186
empty_trait_impl!(Unsigned for usize u8 u16 u32 u64);
187+
188+
impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
189+
190+
#[test]
191+
fn unsigned_wrapping_is_unsigned() {
192+
fn require_unsigned<T: Unsigned>(_: &T) {}
193+
require_unsigned(&Wrapping(42_u32));
194+
}
195+
/*
196+
// Commenting this out since it doesn't compile on Rust 1.8,
197+
// because on this version Wrapping doesn't implement Neg and therefore can't
198+
// implement Signed.
199+
#[test]
200+
fn signed_wrapping_is_signed() {
201+
fn require_signed<T: Signed>(_: &T) {}
202+
require_signed(&Wrapping(-42));
203+
}
204+
*/

0 commit comments

Comments
 (0)