Browse Source

Merge #153

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]>
bors[bot] 5 years ago
parent
commit
1eb80e123b
2 changed files with 69 additions and 2 deletions
  1. 3 1
      src/lib.rs
  2. 66 1
      src/ops/wrapping.rs

+ 3 - 1
src/lib.rs

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

+ 66 - 1
src/ops/wrapping.rs

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