From 522635148bec4521631bd0ad81a405bd57a6bb22 Mon Sep 17 00:00:00 2001 From: rickwebiii Date: Wed, 13 Aug 2025 15:05:55 -0700 Subject: [PATCH 1/4] Generalize Wrapping traits --- src/ops/wrapping.rs | 89 +++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/src/ops/wrapping.rs b/src/ops/wrapping.rs index 3a8b3311..b39395ee 100644 --- a/src/ops/wrapping.rs +++ b/src/ops/wrapping.rs @@ -2,29 +2,24 @@ use core::num::Wrapping; use core::ops::{Add, Mul, Neg, Shl, Shr, Sub}; macro_rules! wrapping_impl { - ($trait_name:ident, $method:ident, $t:ty) => { - impl $trait_name for $t { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + type WrappingOutput = $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 wraps around on overflow. -pub trait WrappingAdd: Sized + Add { +pub trait WrappingAdd: Sized + Add { + type WrappingOutput; /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of /// the type. - fn wrapping_add(&self, v: &Self) -> Self; + fn wrapping_add(&self, v: &Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingAdd, wrapping_add, u8); @@ -42,10 +37,11 @@ wrapping_impl!(WrappingAdd, wrapping_add, isize); wrapping_impl!(WrappingAdd, wrapping_add, i128); /// Performs subtraction that wraps around on overflow. -pub trait WrappingSub: Sized + Sub { +pub trait WrappingSub: Sized + Sub { + type WrappingOutput; /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary /// of the type. - fn wrapping_sub(&self, v: &Self) -> Self; + fn wrapping_sub(&self, v: &Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingSub, wrapping_sub, u8); @@ -63,10 +59,11 @@ wrapping_impl!(WrappingSub, wrapping_sub, isize); wrapping_impl!(WrappingSub, wrapping_sub, i128); /// Performs multiplication that wraps around on overflow. -pub trait WrappingMul: Sized + Mul { +pub trait WrappingMul: Sized + Mul { + type WrappingOutput; /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary /// of the type. - fn wrapping_mul(&self, v: &Self) -> Self; + fn wrapping_mul(&self, v: &Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingMul, wrapping_mul, u8); @@ -86,8 +83,10 @@ wrapping_impl!(WrappingMul, wrapping_mul, i128); macro_rules! wrapping_unary_impl { ($trait_name:ident, $method:ident, $t:ty) => { impl $trait_name for $t { + type WrappingOutput = Self; + #[inline] - fn $method(&self) -> $t { + fn $method(&self) -> Self { <$t>::$method(*self) } } @@ -96,6 +95,8 @@ macro_rules! wrapping_unary_impl { /// Performs a negation that does not panic. pub trait WrappingNeg: Sized { + type WrappingOutput; + /// Wrapping (modular) negation. Computes `-self`, /// wrapping around at the boundary of the type. /// @@ -113,7 +114,7 @@ pub trait WrappingNeg: Sized { /// assert_eq!((-100i8).wrapping_neg(), 100); /// assert_eq!((-128i8).wrapping_neg(), -128); // wrapped! /// ``` - fn wrapping_neg(&self) -> Self; + fn wrapping_neg(&self) -> Self::WrappingOutput; } wrapping_unary_impl!(WrappingNeg, wrapping_neg, u8); @@ -132,8 +133,10 @@ wrapping_unary_impl!(WrappingNeg, wrapping_neg, i128); macro_rules! wrapping_shift_impl { ($trait_name:ident, $method:ident, $t:ty) => { impl $trait_name for $t { + type WrappingOutput = Self; + #[inline] - fn $method(&self, rhs: u32) -> $t { + fn $method(&self, rhs: u32) -> Self::WrappingOutput { <$t>::$method(*self, rhs) } } @@ -142,6 +145,8 @@ macro_rules! wrapping_shift_impl { /// Performs a left shift that does not panic. pub trait WrappingShl: Sized + Shl { + type WrappingOutput; + /// 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. @@ -156,7 +161,7 @@ pub trait WrappingShl: Sized + Shl { /// assert_eq!(WrappingShl::wrapping_shl(&x, 15), 0x8000); /// assert_eq!(WrappingShl::wrapping_shl(&x, 16), 0x0001); /// ``` - fn wrapping_shl(&self, rhs: u32) -> Self; + fn wrapping_shl(&self, rhs: u32) -> Self::WrappingOutput; } wrapping_shift_impl!(WrappingShl, wrapping_shl, u8); @@ -175,6 +180,8 @@ wrapping_shift_impl!(WrappingShl, wrapping_shl, i128); /// Performs a right shift that does not panic. pub trait WrappingShr: Sized + Shr { + type WrappingOutput; + /// 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. @@ -189,7 +196,7 @@ pub trait WrappingShr: Sized + Shr { /// assert_eq!(WrappingShr::wrapping_shr(&x, 15), 0x0001); /// assert_eq!(WrappingShr::wrapping_shr(&x, 16), 0x8000); /// ``` - fn wrapping_shr(&self, rhs: u32) -> Self; + fn wrapping_shr(&self, rhs: u32) -> Self::WrappingOutput; } wrapping_shift_impl!(WrappingShr, wrapping_shr, u8); @@ -207,50 +214,70 @@ wrapping_shift_impl!(WrappingShr, wrapping_shr, isize); wrapping_shift_impl!(WrappingShr, wrapping_shr, i128); // Well this is a bit funny, but all the more appropriate. -impl WrappingAdd for Wrapping +impl WrappingAdd for Wrapping where - Wrapping: Add>, + T: WrappingAdd, + Wrapping: Add, { + type WrappingOutput = Self; + fn wrapping_add(&self, v: &Self) -> Self { Wrapping(self.0.wrapping_add(&v.0)) } } -impl WrappingSub for Wrapping + +impl WrappingSub for Wrapping where + T: WrappingSub, Wrapping: Sub>, { + type WrappingOutput = Self; + fn wrapping_sub(&self, v: &Self) -> Self { Wrapping(self.0.wrapping_sub(&v.0)) } } -impl WrappingMul for Wrapping + +impl WrappingMul for Wrapping where + T: WrappingMul, Wrapping: Mul>, { + type WrappingOutput = Self; + fn wrapping_mul(&self, v: &Self) -> Self { Wrapping(self.0.wrapping_mul(&v.0)) } } impl WrappingNeg for Wrapping where + T: WrappingNeg, Wrapping: Neg>, { + type WrappingOutput = Self; + fn wrapping_neg(&self) -> Self { Wrapping(self.0.wrapping_neg()) } } impl WrappingShl for Wrapping where + T: WrappingShl, Wrapping: Shl>, { + type WrappingOutput = Self; + fn wrapping_shl(&self, rhs: u32) -> Self { Wrapping(self.0.wrapping_shl(rhs)) } } impl WrappingShr for Wrapping where + T: WrappingShr, Wrapping: Shr>, { + type WrappingOutput = Self; + fn wrapping_shr(&self, rhs: u32) -> Self { Wrapping(self.0.wrapping_shr(rhs)) } @@ -258,22 +285,22 @@ where #[test] fn test_wrapping_traits() { - fn wrapping_add(a: T, b: T) -> T { + fn wrapping_add>(a: T, b: T) -> T { a.wrapping_add(&b) } - fn wrapping_sub(a: T, b: T) -> T { + fn wrapping_sub>(a: T, b: T) -> T { a.wrapping_sub(&b) } - fn wrapping_mul(a: T, b: T) -> T { + fn wrapping_mul>(a: T, b: T) -> T { a.wrapping_mul(&b) } - fn wrapping_neg(a: T) -> T { + fn wrapping_neg>(a: T) -> T { a.wrapping_neg() } - fn wrapping_shl(a: T, b: u32) -> T { + fn wrapping_shl>(a: T, b: u32) -> T { a.wrapping_shl(b) } - fn wrapping_shr(a: T, b: u32) -> T { + fn wrapping_shr>(a: T, b: u32) -> T { a.wrapping_shr(b) } assert_eq!(wrapping_add(255, 1), 0u8); From e1256d84123afbcd96115597660612046ba40c5a Mon Sep 17 00:00:00 2001 From: rickwebiii Date: Wed, 13 Aug 2025 15:11:21 -0700 Subject: [PATCH 2/4] Bump crate version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b0ddbe27..af4c1e42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["algorithms", "science", "no-std"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-num/num-traits" name = "num-traits" -version = "0.2.19" +version = "0.3.0" readme = "README.md" build = "build.rs" exclude = ["/ci/*", "/.github/*"] From 2325da92ff5902ffea862e138cf78eb805c2fd77 Mon Sep 17 00:00:00 2001 From: rickwebiii Date: Wed, 13 Aug 2025 15:37:15 -0700 Subject: [PATCH 3/4] rhs shouldn't be a ref --- src/ops/wrapping.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ops/wrapping.rs b/src/ops/wrapping.rs index b39395ee..b1e7dc95 100644 --- a/src/ops/wrapping.rs +++ b/src/ops/wrapping.rs @@ -7,8 +7,8 @@ macro_rules! wrapping_impl { type WrappingOutput = $t; #[inline] - fn $method(&self, v: &Self) -> Self { - <$t>::$method(*self, *v) + fn $method(&self, v: Self) -> Self { + <$t>::$method(*self, v) } } }; @@ -19,7 +19,7 @@ pub trait WrappingAdd: Sized + Add type WrappingOutput; /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of /// the type. - fn wrapping_add(&self, v: &Rhs) -> Self::WrappingOutput; + fn wrapping_add(&self, v: Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingAdd, wrapping_add, u8); @@ -41,7 +41,7 @@ pub trait WrappingSub: Sized + Sub { type WrappingOutput; /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary /// of the type. - fn wrapping_sub(&self, v: &Rhs) -> Self::WrappingOutput; + fn wrapping_sub(&self, v: Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingSub, wrapping_sub, u8); @@ -63,7 +63,7 @@ pub trait WrappingMul: Sized + Mul { type WrappingOutput; /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary /// of the type. - fn wrapping_mul(&self, v: &Rhs) -> Self::WrappingOutput; + fn wrapping_mul(&self, v: Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingMul, wrapping_mul, u8); @@ -221,8 +221,8 @@ where { type WrappingOutput = Self; - fn wrapping_add(&self, v: &Self) -> Self { - Wrapping(self.0.wrapping_add(&v.0)) + fn wrapping_add(&self, v: Self) -> Self { + Wrapping(self.0.wrapping_add(v.0)) } } @@ -233,8 +233,8 @@ where { type WrappingOutput = Self; - fn wrapping_sub(&self, v: &Self) -> Self { - Wrapping(self.0.wrapping_sub(&v.0)) + fn wrapping_sub(&self, v: Self) -> Self { + Wrapping(self.0.wrapping_sub(v.0)) } } @@ -245,8 +245,8 @@ where { type WrappingOutput = Self; - fn wrapping_mul(&self, v: &Self) -> Self { - Wrapping(self.0.wrapping_mul(&v.0)) + fn wrapping_mul(&self, v: Self) -> Self { + Wrapping(self.0.wrapping_mul(v.0)) } } impl WrappingNeg for Wrapping @@ -286,13 +286,13 @@ where #[test] fn test_wrapping_traits() { fn wrapping_add>(a: T, b: T) -> T { - a.wrapping_add(&b) + a.wrapping_add(b) } fn wrapping_sub>(a: T, b: T) -> T { - a.wrapping_sub(&b) + a.wrapping_sub(b) } fn wrapping_mul>(a: T, b: T) -> T { - a.wrapping_mul(&b) + a.wrapping_mul(b) } fn wrapping_neg>(a: T) -> T { a.wrapping_neg() From dd98265e6a796c2d6a86035e0a9cdc81b28c25df Mon Sep 17 00:00:00 2001 From: rickwebiii Date: Wed, 13 Aug 2025 15:44:28 -0700 Subject: [PATCH 4/4] Remove LHS ref+fmt --- src/ops/wrapping.rs | 81 +++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/ops/wrapping.rs b/src/ops/wrapping.rs index b1e7dc95..0628399f 100644 --- a/src/ops/wrapping.rs +++ b/src/ops/wrapping.rs @@ -2,24 +2,26 @@ use core::num::Wrapping; use core::ops::{Add, Mul, Neg, Shl, Shr, Sub}; macro_rules! wrapping_impl { - ($trait_name:ident, $method:ident, $t:ty) => { + ($trait_name:ident, $method:ident, $t:ty) => { impl $trait_name for $t { type WrappingOutput = $t; #[inline] - fn $method(&self, v: Self) -> Self { - <$t>::$method(*self, v) + fn $method(self, v: Self) -> Self { + <$t>::$method(self, v) } } }; } /// Performs addition that wraps around on overflow. -pub trait WrappingAdd: Sized + Add { +pub trait WrappingAdd: Sized + Add { + /// The result type. type WrappingOutput; + /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of /// the type. - fn wrapping_add(&self, v: Rhs) -> Self::WrappingOutput; + fn wrapping_add(self, v: Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingAdd, wrapping_add, u8); @@ -37,11 +39,13 @@ wrapping_impl!(WrappingAdd, wrapping_add, isize); wrapping_impl!(WrappingAdd, wrapping_add, i128); /// Performs subtraction that wraps around on overflow. -pub trait WrappingSub: Sized + Sub { +pub trait WrappingSub: Sized + Sub { + /// The result type. type WrappingOutput; + /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary /// of the type. - fn wrapping_sub(&self, v: Rhs) -> Self::WrappingOutput; + fn wrapping_sub(self, v: Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingSub, wrapping_sub, u8); @@ -59,11 +63,13 @@ wrapping_impl!(WrappingSub, wrapping_sub, isize); wrapping_impl!(WrappingSub, wrapping_sub, i128); /// Performs multiplication that wraps around on overflow. -pub trait WrappingMul: Sized + Mul { +pub trait WrappingMul: Sized + Mul { + /// The result type. type WrappingOutput; + /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary /// of the type. - fn wrapping_mul(&self, v: Rhs) -> Self::WrappingOutput; + fn wrapping_mul(self, v: Rhs) -> Self::WrappingOutput; } wrapping_impl!(WrappingMul, wrapping_mul, u8); @@ -86,8 +92,8 @@ macro_rules! wrapping_unary_impl { type WrappingOutput = Self; #[inline] - fn $method(&self) -> Self { - <$t>::$method(*self) + fn $method(self) -> Self { + <$t>::$method(self) } } }; @@ -95,6 +101,7 @@ macro_rules! wrapping_unary_impl { /// Performs a negation that does not panic. pub trait WrappingNeg: Sized { + /// The result type. type WrappingOutput; /// Wrapping (modular) negation. Computes `-self`, @@ -114,7 +121,7 @@ pub trait WrappingNeg: Sized { /// assert_eq!((-100i8).wrapping_neg(), 100); /// assert_eq!((-128i8).wrapping_neg(), -128); // wrapped! /// ``` - fn wrapping_neg(&self) -> Self::WrappingOutput; + fn wrapping_neg(self) -> Self::WrappingOutput; } wrapping_unary_impl!(WrappingNeg, wrapping_neg, u8); @@ -136,8 +143,8 @@ macro_rules! wrapping_shift_impl { type WrappingOutput = Self; #[inline] - fn $method(&self, rhs: u32) -> Self::WrappingOutput { - <$t>::$method(*self, rhs) + fn $method(self, rhs: u32) -> Self::WrappingOutput { + <$t>::$method(self, rhs) } } }; @@ -145,6 +152,7 @@ macro_rules! wrapping_shift_impl { /// Performs a left shift that does not panic. pub trait WrappingShl: Sized + Shl { + /// The result type. type WrappingOutput; /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, @@ -156,12 +164,12 @@ pub trait WrappingShl: Sized + Shl { /// /// let x: u16 = 0x0001; /// - /// assert_eq!(WrappingShl::wrapping_shl(&x, 0), 0x0001); - /// assert_eq!(WrappingShl::wrapping_shl(&x, 1), 0x0002); - /// assert_eq!(WrappingShl::wrapping_shl(&x, 15), 0x8000); - /// assert_eq!(WrappingShl::wrapping_shl(&x, 16), 0x0001); + /// assert_eq!(WrappingShl::wrapping_shl(x, 0), 0x0001); + /// assert_eq!(WrappingShl::wrapping_shl(x, 1), 0x0002); + /// assert_eq!(WrappingShl::wrapping_shl(x, 15), 0x8000); + /// assert_eq!(WrappingShl::wrapping_shl(x, 16), 0x0001); /// ``` - fn wrapping_shl(&self, rhs: u32) -> Self::WrappingOutput; + fn wrapping_shl(self, rhs: u32) -> Self::WrappingOutput; } wrapping_shift_impl!(WrappingShl, wrapping_shl, u8); @@ -180,6 +188,7 @@ wrapping_shift_impl!(WrappingShl, wrapping_shl, i128); /// Performs a right shift that does not panic. pub trait WrappingShr: Sized + Shr { + /// The result type. type WrappingOutput; /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, @@ -191,12 +200,12 @@ pub trait WrappingShr: Sized + Shr { /// /// let x: u16 = 0x8000; /// - /// assert_eq!(WrappingShr::wrapping_shr(&x, 0), 0x8000); - /// assert_eq!(WrappingShr::wrapping_shr(&x, 1), 0x4000); - /// assert_eq!(WrappingShr::wrapping_shr(&x, 15), 0x0001); - /// assert_eq!(WrappingShr::wrapping_shr(&x, 16), 0x8000); + /// assert_eq!(WrappingShr::wrapping_shr(x, 0), 0x8000); + /// assert_eq!(WrappingShr::wrapping_shr(x, 1), 0x4000); + /// assert_eq!(WrappingShr::wrapping_shr(x, 15), 0x0001); + /// assert_eq!(WrappingShr::wrapping_shr(x, 16), 0x8000); /// ``` - fn wrapping_shr(&self, rhs: u32) -> Self::WrappingOutput; + fn wrapping_shr(self, rhs: u32) -> Self::WrappingOutput; } wrapping_shift_impl!(WrappingShr, wrapping_shr, u8); @@ -221,7 +230,7 @@ where { type WrappingOutput = Self; - fn wrapping_add(&self, v: Self) -> Self { + fn wrapping_add(self, v: Self) -> Self { Wrapping(self.0.wrapping_add(v.0)) } } @@ -233,7 +242,7 @@ where { type WrappingOutput = Self; - fn wrapping_sub(&self, v: Self) -> Self { + fn wrapping_sub(self, v: Self) -> Self { Wrapping(self.0.wrapping_sub(v.0)) } } @@ -245,7 +254,7 @@ where { type WrappingOutput = Self; - fn wrapping_mul(&self, v: Self) -> Self { + fn wrapping_mul(self, v: Self) -> Self { Wrapping(self.0.wrapping_mul(v.0)) } } @@ -256,7 +265,7 @@ where { type WrappingOutput = Self; - fn wrapping_neg(&self) -> Self { + fn wrapping_neg(self) -> Self { Wrapping(self.0.wrapping_neg()) } } @@ -267,7 +276,7 @@ where { type WrappingOutput = Self; - fn wrapping_shl(&self, rhs: u32) -> Self { + fn wrapping_shl(self, rhs: u32) -> Self { Wrapping(self.0.wrapping_shl(rhs)) } } @@ -278,29 +287,29 @@ where { type WrappingOutput = Self; - fn wrapping_shr(&self, rhs: u32) -> Self { + fn wrapping_shr(self, rhs: u32) -> Self { Wrapping(self.0.wrapping_shr(rhs)) } } #[test] fn test_wrapping_traits() { - fn wrapping_add>(a: T, b: T) -> T { + fn wrapping_add>(a: T, b: T) -> T { a.wrapping_add(b) } - fn wrapping_sub>(a: T, b: T) -> T { + fn wrapping_sub>(a: T, b: T) -> T { a.wrapping_sub(b) } - fn wrapping_mul>(a: T, b: T) -> T { + fn wrapping_mul>(a: T, b: T) -> T { a.wrapping_mul(b) } - fn wrapping_neg>(a: T) -> T { + fn wrapping_neg>(a: T) -> T { a.wrapping_neg() } - fn wrapping_shl>(a: T, b: u32) -> T { + fn wrapping_shl>(a: T, b: u32) -> T { a.wrapping_shl(b) } - fn wrapping_shr>(a: T, b: u32) -> T { + fn wrapping_shr>(a: T, b: u32) -> T { a.wrapping_shr(b) } assert_eq!(wrapping_add(255, 1), 0u8);