diff --git a/Cargo.toml b/Cargo.toml index 525089032..9d19d42c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ rand_core = { version = "0.6.4", optional = true } rlp = { version = "0.5", optional = true, default-features = false } serdect = { version = "0.2", optional = true, default-features = false } zeroize = { version = "1", optional = true, default-features = false } +num-traits = { version = "0.2", optional = true } [dev-dependencies] bincode = "1" diff --git a/src/wrapping.rs b/src/wrapping.rs index 77e1b78f8..f97e9ce1d 100644 --- a/src/wrapping.rs +++ b/src/wrapping.rs @@ -4,6 +4,13 @@ use crate::Zero; use core::fmt; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; +#[cfg(feature = "num-traits")] +use crate::{Integer, NonZero}; +#[cfg(feature = "num-traits")] +use core::ops::{Add, Div, Mul, Rem, Sub}; +#[cfg(feature = "num-traits")] +use num_traits::Num; + #[cfg(feature = "rand_core")] use {crate::Random, rand_core::CryptoRngCore}; @@ -63,6 +70,70 @@ impl ConstantTimeEq for Wrapping { } } +#[cfg(feature = "num-traits")] +impl num_traits::Zero for Wrapping +where + Wrapping: Add, Output = Wrapping> + PartialEq>, +{ + fn zero() -> Self { + Self::ZERO + } + + fn is_zero(&self) -> bool { + self == &Self::ZERO + } +} + +#[cfg(feature = "num-traits")] +impl num_traits::One for Wrapping +where + Wrapping: Add, Output = Wrapping> + Mul, Output = Wrapping>, +{ + fn one() -> Self { + Wrapping(T::ONE) + } +} + +#[cfg(feature = "num-traits")] +impl Div> for Wrapping +where + Wrapping: Div, Output = Wrapping>, +{ + type Output = Wrapping; + + fn div(self, rhs: Wrapping) -> Self::Output { + self / NonZero::new(rhs.0).unwrap() + } +} + +#[cfg(feature = "num-traits")] +impl Rem> for Wrapping +where + Wrapping: Rem, Output = Wrapping>, +{ + type Output = Wrapping; + + fn rem(self, rhs: Wrapping) -> Self::Output { + self % NonZero::new(rhs.0).unwrap() + } +} + +#[cfg(feature = "num-traits")] +impl Num for Wrapping +where + Wrapping: Add, Output = Wrapping> + + Sub, Output = Wrapping> + + Mul, Output = Wrapping> + + Div, Output = Wrapping> + + Rem, Output = Wrapping>, +{ + type FromStrRadixErr = (); + + fn from_str_radix(str: &str, radix: u32) -> Result { + todo!() + } +} + #[cfg(feature = "rand_core")] impl Random for Wrapping { fn random(rng: &mut impl CryptoRngCore) -> Self { @@ -90,6 +161,24 @@ impl Serialize for Wrapping { } } +#[cfg(all(test, feature = "num-traits"))] +mod tests { + use crate::{Integer, NonZero}; + use core::ops::{Add, Div, Mul, Rem, Sub}; + use num_traits::{Num, NumOps, One, Zero}; + + use crate::{Wrapping, U64}; + + fn assures_num(x: T) {} + + #[test] + fn num_traits() { + const TEST: Wrapping = Wrapping(U64::from_u64(0x0011223344556677)); + + assures_num(TEST) + } +} + #[cfg(all(test, feature = "serde"))] mod tests { use crate::{Wrapping, U64};