From d25f53056df12880a82d7db29b4e339619ce2982 Mon Sep 17 00:00:00 2001 From: nwin Date: Sun, 22 Jan 2017 09:45:35 +0100 Subject: [PATCH 1/4] Added traits for wrapping arithmetics. Added `Wrapping` traits for the most common operations. Similar to the already present `Checked` traits. --- traits/src/lib.rs | 1 + traits/src/ops/mod.rs | 1 + traits/src/ops/wrapping.rs | 153 +++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 traits/src/ops/wrapping.rs diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 2cd85d4..26efd0a 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -20,6 +20,7 @@ pub use bounds::Bounded; pub use float::{Float, FloatConst}; pub use identities::{Zero, One, zero, one}; pub use ops::checked::*; +pub use ops::wrapping::*; pub use ops::saturating::Saturating; pub use sign::{Signed, Unsigned, abs, abs_sub, signum}; pub use cast::*; diff --git a/traits/src/ops/mod.rs b/traits/src/ops/mod.rs index 2632a0f..ec9edeb 100644 --- a/traits/src/ops/mod.rs +++ b/traits/src/ops/mod.rs @@ -1,2 +1,3 @@ pub mod saturating; pub mod checked; +pub mod wrapping; diff --git a/traits/src/ops/wrapping.rs b/traits/src/ops/wrapping.rs new file mode 100644 index 0000000..419c8dc --- /dev/null +++ b/traits/src/ops/wrapping.rs @@ -0,0 +1,153 @@ +use std::ops::{Add, Sub, Mul, Div, Shl, Shr}; + +macro_rules! wrapping_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + #[inline] + fn $method(&self, v: &Self) -> Self { + <$t>::$method(*self, *v) + } + } + }; + ($trait_name:ident, $method:ident, $t:ty, $rhs:ty) => { + impl $trait_name<$rhs> for $t { + #[inline] + fn $method(&self, v: &$rhs) -> Self { + <$t>::$method(*self, *v) + } + } + } +} + +/// Performs addition that wrapps around on overflow. +pub trait WrappingAdd: Sized + Add { + /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of + /// the type. + fn wrapping_add(&self, v: &Self) -> Self; +} + +wrapping_impl!(WrappingAdd, wrapping_add, u8); +wrapping_impl!(WrappingAdd, wrapping_add, u16); +wrapping_impl!(WrappingAdd, wrapping_add, u32); +wrapping_impl!(WrappingAdd, wrapping_add, u64); +wrapping_impl!(WrappingAdd, wrapping_add, usize); + +wrapping_impl!(WrappingAdd, wrapping_add, i8); +wrapping_impl!(WrappingAdd, wrapping_add, i16); +wrapping_impl!(WrappingAdd, wrapping_add, i32); +wrapping_impl!(WrappingAdd, wrapping_add, i64); +wrapping_impl!(WrappingAdd, wrapping_add, isize); + +/// Performs subtraction that wrapps around on overflow. +pub trait WrappingSub: Sized + Sub { + /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary + /// of the type. + fn wrapping_sub(&self, v: &Self) -> Self; +} + +wrapping_impl!(WrappingSub, wrapping_sub, u8); +wrapping_impl!(WrappingSub, wrapping_sub, u16); +wrapping_impl!(WrappingSub, wrapping_sub, u32); +wrapping_impl!(WrappingSub, wrapping_sub, u64); +wrapping_impl!(WrappingSub, wrapping_sub, usize); + +wrapping_impl!(WrappingSub, wrapping_sub, i8); +wrapping_impl!(WrappingSub, wrapping_sub, i16); +wrapping_impl!(WrappingSub, wrapping_sub, i32); +wrapping_impl!(WrappingSub, wrapping_sub, i64); +wrapping_impl!(WrappingSub, wrapping_sub, isize); + +/// Performs multiplication that wrapps around on overflow. +pub trait WrappingMul: Sized + Mul { + /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary + /// of the type. + fn wrapping_mul(&self, v: &Self) -> Self; +} + +wrapping_impl!(WrappingMul, wrapping_mul, u8); +wrapping_impl!(WrappingMul, wrapping_mul, u16); +wrapping_impl!(WrappingMul, wrapping_mul, u32); +wrapping_impl!(WrappingMul, wrapping_mul, u64); +wrapping_impl!(WrappingMul, wrapping_mul, usize); + +wrapping_impl!(WrappingMul, wrapping_mul, i8); +wrapping_impl!(WrappingMul, wrapping_mul, i16); +wrapping_impl!(WrappingMul, wrapping_mul, i32); +wrapping_impl!(WrappingMul, wrapping_mul, i64); +wrapping_impl!(WrappingMul, wrapping_mul, isize); + +/// Performs division that wrapps around on overflow. +pub trait WrappingDiv: Sized + Div { + /// Wrapping (modular) division. Computes `self / other`, wrapping around at the boundary of + /// the type. + /// + /// The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type + /// (where `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a + /// positive value that is too large to represent in the type. In such a case, this function + /// returns `MIN` itself. + /// + /// # Panics + /// + /// This function will panic if rhs is 0. + fn wrapping_div(&self, v: &Self) -> Self; +} + +wrapping_impl!(WrappingDiv, wrapping_div, u8); +wrapping_impl!(WrappingDiv, wrapping_div, u16); +wrapping_impl!(WrappingDiv, wrapping_div, u32); +wrapping_impl!(WrappingDiv, wrapping_div, u64); +wrapping_impl!(WrappingDiv, wrapping_div, usize); + +wrapping_impl!(WrappingDiv, wrapping_div, i8); +wrapping_impl!(WrappingDiv, wrapping_div, i16); +wrapping_impl!(WrappingDiv, wrapping_div, i32); +wrapping_impl!(WrappingDiv, wrapping_div, i64); +wrapping_impl!(WrappingDiv, wrapping_div, isize); + +/// Performs bitwise shift left that wrapps around on overflow. +pub trait WrappingShl: Sized + Shl { + /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes any + /// high-order bits of rhs that would cause the shift to exceed the bitwidth of the type. + /// + /// Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is + /// restricted to the range of the type, rather than the bits shifted out of the LHS being + /// returned to the other end. The primitive integer types all implement a `rotate_left` + /// function, which may be what you want instead. + fn wrapping_shl(&self, v: &RHS) -> Self; +} + +wrapping_impl!(WrappingShl, wrapping_shl, u8, u32); +wrapping_impl!(WrappingShl, wrapping_shl, u16, u32); +wrapping_impl!(WrappingShl, wrapping_shl, u32, u32); +wrapping_impl!(WrappingShl, wrapping_shl, u64, u32); +wrapping_impl!(WrappingShl, wrapping_shl, usize, u32); + +wrapping_impl!(WrappingShl, wrapping_shl, i8, u32); +wrapping_impl!(WrappingShl, wrapping_shl, i16, u32); +wrapping_impl!(WrappingShl, wrapping_shl, i32, u32); +wrapping_impl!(WrappingShl, wrapping_shl, i64, u32); +wrapping_impl!(WrappingShl, wrapping_shl, isize, u32); + +/// Performs bitwise shift right that wrapps around on overflow. +pub trait WrappingShr: Sized + Shr { + /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` removes any + /// high-order bits of rhs that would cause the shift to exceed the bitwidth of the type. + /// + /// Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is + /// restricted to the range of the type, rather than the bits shifted out of the LHS being + /// returned to the other end. The primitive integer types all implement a `rotate_right` + /// function, which may be what you want instead. + fn wrapping_shr(&self, v: &RHS) -> Self; +} + +wrapping_impl!(WrappingShr, wrapping_shr, u8, u32); +wrapping_impl!(WrappingShr, wrapping_shr, u16, u32); +wrapping_impl!(WrappingShr, wrapping_shr, u32, u32); +wrapping_impl!(WrappingShr, wrapping_shr, u64, u32); +wrapping_impl!(WrappingShr, wrapping_shr, usize, u32); + +wrapping_impl!(WrappingShr, wrapping_shr, i8, u32); +wrapping_impl!(WrappingShr, wrapping_shr, i16, u32); +wrapping_impl!(WrappingShr, wrapping_shr, i32, u32); +wrapping_impl!(WrappingShr, wrapping_shr, i64, u32); +wrapping_impl!(WrappingShr, wrapping_shr, isize, u32); From ee9d474243d15d6f061f93fddce14edd8d53cb9f Mon Sep 17 00:00:00 2001 From: nwin Date: Sun, 22 Jan 2017 10:13:50 +0100 Subject: [PATCH 2/4] Ensure compatibility with Rust 1.0.0. --- traits/src/ops/wrapping.rs | 78 +------------------------------------- 1 file changed, 1 insertion(+), 77 deletions(-) diff --git a/traits/src/ops/wrapping.rs b/traits/src/ops/wrapping.rs index 419c8dc..a1bcb0d 100644 --- a/traits/src/ops/wrapping.rs +++ b/traits/src/ops/wrapping.rs @@ -1,4 +1,4 @@ -use std::ops::{Add, Sub, Mul, Div, Shl, Shr}; +use std::ops::{Add, Sub, Mul}; macro_rules! wrapping_impl { ($trait_name:ident, $method:ident, $t:ty) => { @@ -75,79 +75,3 @@ wrapping_impl!(WrappingMul, wrapping_mul, i16); wrapping_impl!(WrappingMul, wrapping_mul, i32); wrapping_impl!(WrappingMul, wrapping_mul, i64); wrapping_impl!(WrappingMul, wrapping_mul, isize); - -/// Performs division that wrapps around on overflow. -pub trait WrappingDiv: Sized + Div { - /// Wrapping (modular) division. Computes `self / other`, wrapping around at the boundary of - /// the type. - /// - /// The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type - /// (where `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a - /// positive value that is too large to represent in the type. In such a case, this function - /// returns `MIN` itself. - /// - /// # Panics - /// - /// This function will panic if rhs is 0. - fn wrapping_div(&self, v: &Self) -> Self; -} - -wrapping_impl!(WrappingDiv, wrapping_div, u8); -wrapping_impl!(WrappingDiv, wrapping_div, u16); -wrapping_impl!(WrappingDiv, wrapping_div, u32); -wrapping_impl!(WrappingDiv, wrapping_div, u64); -wrapping_impl!(WrappingDiv, wrapping_div, usize); - -wrapping_impl!(WrappingDiv, wrapping_div, i8); -wrapping_impl!(WrappingDiv, wrapping_div, i16); -wrapping_impl!(WrappingDiv, wrapping_div, i32); -wrapping_impl!(WrappingDiv, wrapping_div, i64); -wrapping_impl!(WrappingDiv, wrapping_div, isize); - -/// Performs bitwise shift left that wrapps around on overflow. -pub trait WrappingShl: Sized + Shl { - /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes any - /// high-order bits of rhs that would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is - /// restricted to the range of the type, rather than the bits shifted out of the LHS being - /// returned to the other end. The primitive integer types all implement a `rotate_left` - /// function, which may be what you want instead. - fn wrapping_shl(&self, v: &RHS) -> Self; -} - -wrapping_impl!(WrappingShl, wrapping_shl, u8, u32); -wrapping_impl!(WrappingShl, wrapping_shl, u16, u32); -wrapping_impl!(WrappingShl, wrapping_shl, u32, u32); -wrapping_impl!(WrappingShl, wrapping_shl, u64, u32); -wrapping_impl!(WrappingShl, wrapping_shl, usize, u32); - -wrapping_impl!(WrappingShl, wrapping_shl, i8, u32); -wrapping_impl!(WrappingShl, wrapping_shl, i16, u32); -wrapping_impl!(WrappingShl, wrapping_shl, i32, u32); -wrapping_impl!(WrappingShl, wrapping_shl, i64, u32); -wrapping_impl!(WrappingShl, wrapping_shl, isize, u32); - -/// Performs bitwise shift right that wrapps around on overflow. -pub trait WrappingShr: Sized + Shr { - /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` removes any - /// high-order bits of rhs that would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is - /// restricted to the range of the type, rather than the bits shifted out of the LHS being - /// returned to the other end. The primitive integer types all implement a `rotate_right` - /// function, which may be what you want instead. - fn wrapping_shr(&self, v: &RHS) -> Self; -} - -wrapping_impl!(WrappingShr, wrapping_shr, u8, u32); -wrapping_impl!(WrappingShr, wrapping_shr, u16, u32); -wrapping_impl!(WrappingShr, wrapping_shr, u32, u32); -wrapping_impl!(WrappingShr, wrapping_shr, u64, u32); -wrapping_impl!(WrappingShr, wrapping_shr, usize, u32); - -wrapping_impl!(WrappingShr, wrapping_shr, i8, u32); -wrapping_impl!(WrappingShr, wrapping_shr, i16, u32); -wrapping_impl!(WrappingShr, wrapping_shr, i32, u32); -wrapping_impl!(WrappingShr, wrapping_shr, i64, u32); -wrapping_impl!(WrappingShr, wrapping_shr, isize, u32); From 450c0e2760d2e6ea790e38ad50a4ffa53d8a004f Mon Sep 17 00:00:00 2001 From: nwin Date: Thu, 26 Jan 2017 21:12:27 +0100 Subject: [PATCH 3/4] Correct typos. --- traits/src/ops/wrapping.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/traits/src/ops/wrapping.rs b/traits/src/ops/wrapping.rs index a1bcb0d..699405d 100644 --- a/traits/src/ops/wrapping.rs +++ b/traits/src/ops/wrapping.rs @@ -19,7 +19,7 @@ macro_rules! wrapping_impl { } } -/// Performs addition that wrapps around on overflow. +/// Performs addition that wraps around on overflow. pub trait WrappingAdd: Sized + Add { /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of /// the type. @@ -38,7 +38,7 @@ wrapping_impl!(WrappingAdd, wrapping_add, i32); wrapping_impl!(WrappingAdd, wrapping_add, i64); wrapping_impl!(WrappingAdd, wrapping_add, isize); -/// Performs subtraction that wrapps around on overflow. +/// Performs subtraction that wraps around on overflow. pub trait WrappingSub: Sized + Sub { /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary /// of the type. @@ -57,7 +57,7 @@ wrapping_impl!(WrappingSub, wrapping_sub, i32); wrapping_impl!(WrappingSub, wrapping_sub, i64); wrapping_impl!(WrappingSub, wrapping_sub, isize); -/// Performs multiplication that wrapps around on overflow. +/// Performs multiplication that wraps around on overflow. pub trait WrappingMul: Sized + Mul { /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary /// of the type. From 58b7da46d2051ba27846f2eaedda9a899696bdea Mon Sep 17 00:00:00 2001 From: nwin Date: Sat, 4 Feb 2017 10:42:12 +0100 Subject: [PATCH 4/4] Added tests. --- traits/src/ops/wrapping.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/traits/src/ops/wrapping.rs b/traits/src/ops/wrapping.rs index 699405d..40b266d 100644 --- a/traits/src/ops/wrapping.rs +++ b/traits/src/ops/wrapping.rs @@ -75,3 +75,14 @@ wrapping_impl!(WrappingMul, wrapping_mul, i16); wrapping_impl!(WrappingMul, wrapping_mul, i32); wrapping_impl!(WrappingMul, wrapping_mul, i64); wrapping_impl!(WrappingMul, wrapping_mul, isize); + + +#[test] +fn test_wrapping_traits() { + fn wrapping_add(a: T, b: T) -> T { a.wrapping_add(&b) } + fn wrapping_sub(a: T, b: T) -> T { a.wrapping_sub(&b) } + fn wrapping_mul(a: T, b: T) -> T { a.wrapping_mul(&b) } + assert_eq!(wrapping_add(255, 1), 0u8); + assert_eq!(wrapping_sub(0, 1), 255u8); + assert_eq!(wrapping_mul(255, 2), 254u8); +}