Skip to content

Commit

Permalink
Merge #153
Browse files Browse the repository at this point in the history
153: Add WrappingNeg trait r=cuviper a=ocstl

Closes #10 

A quick search turned up that the [extprim](https://github.com/kennytm/extprim) implements `PrimInt` for its `u128` and `i128`, but, since both have their own `wrapping_neg` method, it's a non-issue.

That being said, I don't know for certain that it is the only project that implements `PrimInt`, so it might be wise to wait for a larger version bump before merging this.

Co-authored-by: Olivier Chassé St-Laurent <[email protected]>
Co-authored-by: Josh Stone <[email protected]>
  • Loading branch information
3 people authored Mar 6, 2020
2 parents ea2ff8d + e1ecc9d commit 1eb80e1
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ pub use ops::checked::{
pub use ops::inv::Inv;
pub use ops::mul_add::{MulAdd, MulAddAssign};
pub use ops::saturating::Saturating;
pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingShl, WrappingShr, WrappingSub};
pub use ops::wrapping::{
WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
};
pub use pow::{checked_pow, pow, Pow};
pub use sign::{abs, abs_sub, signum, Signed, Unsigned};

Expand Down
67 changes: 66 additions & 1 deletion src/ops/wrapping.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::num::Wrapping;
use core::ops::{Add, Mul, Shl, Shr, Sub};
use core::ops::{Add, Mul, Neg, Shl, Shr, Sub};

macro_rules! wrapping_impl {
($trait_name:ident, $method:ident, $t:ty) => {
Expand Down Expand Up @@ -89,6 +89,54 @@ wrapping_impl!(WrappingMul, wrapping_mul, isize);
#[cfg(has_i128)]
wrapping_impl!(WrappingMul, wrapping_mul, i128);

macro_rules! wrapping_unary_impl {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
#[inline]
fn $method(&self) -> $t {
<$t>::$method(*self)
}
}
};
}

/// Performs a negation that does not panic.
pub trait WrappingNeg: Sized {
/// Wrapping (modular) negation. Computes `-self`,
/// wrapping around at the boundary of the type.
///
/// Since unsigned types do not have negative equivalents
/// all applications of this function will wrap (except for `-0`).
/// For values smaller than the corresponding signed type's maximum
/// the result is the same as casting the corresponding signed value.
/// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where
/// `MAX` is the corresponding signed type's maximum.
///
/// ```
/// use num_traits::WrappingNeg;
///
/// assert_eq!(100i8.wrapping_neg(), -100);
/// assert_eq!((-100i8).wrapping_neg(), 100);
/// assert_eq!((-128i8).wrapping_neg(), -128); // wrapped!
/// ```
fn wrapping_neg(&self) -> Self;
}

wrapping_unary_impl!(WrappingNeg, wrapping_neg, u8);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, u16);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, u32);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, u64);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, usize);
#[cfg(has_i128)]
wrapping_unary_impl!(WrappingNeg, wrapping_neg, u128);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i8);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i16);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i32);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i64);
wrapping_unary_impl!(WrappingNeg, wrapping_neg, isize);
#[cfg(has_i128)]
wrapping_unary_impl!(WrappingNeg, wrapping_neg, i128);

macro_rules! wrapping_shift_impl {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
Expand Down Expand Up @@ -195,6 +243,14 @@ where
Wrapping(self.0.wrapping_mul(&v.0))
}
}
impl<T: WrappingNeg> WrappingNeg for Wrapping<T>
where
Wrapping<T>: Neg<Output = Wrapping<T>>,
{
fn wrapping_neg(&self) -> Self {
Wrapping(self.0.wrapping_neg())
}
}
impl<T: WrappingShl> WrappingShl for Wrapping<T>
where
Wrapping<T>: Shl<usize, Output = Wrapping<T>>,
Expand Down Expand Up @@ -223,6 +279,9 @@ fn test_wrapping_traits() {
fn wrapping_mul<T: WrappingMul>(a: T, b: T) -> T {
a.wrapping_mul(&b)
}
fn wrapping_neg<T: WrappingNeg>(a: T) -> T {
a.wrapping_neg()
}
fn wrapping_shl<T: WrappingShl>(a: T, b: u32) -> T {
a.wrapping_shl(b)
}
Expand All @@ -232,11 +291,14 @@ 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_neg(255), 1u8);
assert_eq!(wrapping_shl(255, 8), 255u8);
assert_eq!(wrapping_shr(255, 8), 255u8);
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);
// TODO: Test for Wrapping::Neg. Not possible yet since core::ops::Neg was
// only added to core::num::Wrapping<_> in Rust 1.10.
assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0);
assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0);
}
Expand All @@ -259,6 +321,9 @@ fn wrapping_is_wrappingmul() {
require_wrappingmul(&Wrapping(42));
}

// TODO: Test for Wrapping::Neg. Not possible yet since core::ops::Neg was
// only added to core::num::Wrapping<_> in Rust 1.10.

#[test]
fn wrapping_is_wrappingshl() {
fn require_wrappingshl<T: WrappingShl>(_: &T) {}
Expand Down

0 comments on commit 1eb80e1

Please sign in to comment.