From c45a4104eae4c715a8e2809cc07b378f25f41d18 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Fri, 31 Jan 2025 23:00:39 +0000 Subject: [PATCH 1/2] some set of non zero support --- src/bounds.rs | 15 +++++++++++++- src/ops/checked.rs | 41 +++++++++++++++++++++++++++++++++++++ src/ops/mul_add.rs | 26 ++++++++++++++++++++++++ src/ops/saturating.rs | 40 ++++++++++++++++++++++++++++++++++++ src/sign.rs | 47 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/src/bounds.rs b/src/bounds.rs index acc990ea..61427c5f 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -1,4 +1,4 @@ -use core::num::Wrapping; +use core::num::{NonZero, Wrapping}; use core::{f32, f64}; use core::{i128, i16, i32, i64, i8, isize}; use core::{u128, u16, u32, u64, u8, usize}; @@ -26,6 +26,7 @@ impl LowerBounded for T { } /// Numbers which have upper bounds +//ASDF pub trait UpperBounded { /// Returns the largest finite number this type can represent fn max_value() -> Self; @@ -61,6 +62,12 @@ bounded_impl!(u32, u32::MIN, u32::MAX); bounded_impl!(u64, u64::MIN, u64::MAX); bounded_impl!(u128, u128::MIN, u128::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); + bounded_impl!(isize, isize::MIN, isize::MAX); bounded_impl!(i8, i8::MIN, i8::MAX); bounded_impl!(i16, i16::MIN, i16::MAX); @@ -68,6 +75,12 @@ bounded_impl!(i32, i32::MIN, i32::MAX); bounded_impl!(i64, i64::MIN, i64::MAX); bounded_impl!(i128, i128::MIN, i128::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); +bounded_impl!(NonZero, NonZero::::MIN, NonZero::::MAX); + impl Bounded for Wrapping { fn min_value() -> Self { Wrapping(T::min_value()) diff --git a/src/ops/checked.rs b/src/ops/checked.rs index 553b28be..9776e669 100644 --- a/src/ops/checked.rs +++ b/src/ops/checked.rs @@ -1,12 +1,19 @@ use core::ops::{Add, Div, Mul, Rem, Shl, Shr, Sub}; /// Performs addition, returning `None` if overflow occurred. +// FIXME: With a major version bump, this should not require `Add` supertrait pub trait CheckedAdd: Sized + Add { /// Adds two numbers, checking for overflow. If overflow happens, `None` is /// returned. fn checked_add(&self, v: &Self) -> Option; } +pub trait BaseCheckedAdd: Sized { + /// Adds two numbers, checking for overflow. If overflow happens, `None` is + /// returned. + fn checked_add(&self, v: &Self) -> Option; +} + macro_rules! checked_impl { ($trait_name:ident, $method:ident, $t:ty) => { impl $trait_name for $t { @@ -18,6 +25,19 @@ macro_rules! checked_impl { }; } +macro_rules! nonzero_checked_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for core::num::NonZero<$t> { + #[inline] + fn $method(&self, v: &core::num::NonZero<$t>) -> Option> { + <$t>::$method((*self).get(), (*v).get()).map(|x| { + core::num::NonZero::new(x).expect("checked sum of non zero is never zero") + }) + } + } + }; +} + checked_impl!(CheckedAdd, checked_add, u8); checked_impl!(CheckedAdd, checked_add, u16); checked_impl!(CheckedAdd, checked_add, u32); @@ -25,6 +45,13 @@ checked_impl!(CheckedAdd, checked_add, u64); checked_impl!(CheckedAdd, checked_add, usize); checked_impl!(CheckedAdd, checked_add, u128); +nonzero_checked_impl!(BaseCheckedAdd, checked_add, u8); +nonzero_checked_impl!(BaseCheckedAdd, checked_add, u16); +nonzero_checked_impl!(BaseCheckedAdd, checked_add, u32); +nonzero_checked_impl!(BaseCheckedAdd, checked_add, u64); +nonzero_checked_impl!(BaseCheckedAdd, checked_add, usize); +nonzero_checked_impl!(BaseCheckedAdd, checked_add, u128); + checked_impl!(CheckedAdd, checked_add, i8); checked_impl!(CheckedAdd, checked_add, i16); checked_impl!(CheckedAdd, checked_add, i32); @@ -54,12 +81,19 @@ checked_impl!(CheckedSub, checked_sub, isize); checked_impl!(CheckedSub, checked_sub, i128); /// Performs multiplication, returning `None` if overflow occurred. +//FIXME: With a major version bump, this should not require `Mul` supertrait pub trait CheckedMul: Sized + Mul { /// Multiplies two numbers, checking for overflow. If overflow happens, /// `None` is returned. fn checked_mul(&self, v: &Self) -> Option; } +pub trait BaseCheckedMul: Sized { + /// Multiplies two numbers, checking for overflow. If overflow happens, + /// `None` is returned. + fn checked_mul(&self, v: &Self) -> Option; +} + checked_impl!(CheckedMul, checked_mul, u8); checked_impl!(CheckedMul, checked_mul, u16); checked_impl!(CheckedMul, checked_mul, u32); @@ -67,6 +101,13 @@ checked_impl!(CheckedMul, checked_mul, u64); checked_impl!(CheckedMul, checked_mul, usize); checked_impl!(CheckedMul, checked_mul, u128); +nonzero_checked_impl!(BaseCheckedMul, checked_mul, u8); +nonzero_checked_impl!(BaseCheckedMul, checked_mul, u16); +nonzero_checked_impl!(BaseCheckedMul, checked_mul, u32); +nonzero_checked_impl!(BaseCheckedMul, checked_mul, u64); +nonzero_checked_impl!(BaseCheckedMul, checked_mul, usize); +nonzero_checked_impl!(BaseCheckedMul, checked_mul, u128); + checked_impl!(CheckedMul, checked_mul, i8); checked_impl!(CheckedMul, checked_mul, i16); checked_impl!(CheckedMul, checked_mul, i32); diff --git a/src/ops/mul_add.rs b/src/ops/mul_add.rs index 51beb557..6f5eeb43 100644 --- a/src/ops/mul_add.rs +++ b/src/ops/mul_add.rs @@ -67,8 +67,22 @@ macro_rules! mul_add_impl { )*} } +macro_rules! nonzero_mul_add_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for core::num::NonZero<$t> { + type Output = Self; + + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self::Output { + core::num::NonZero::new((self.get() * a.get()) + b.get()).expect("non zero mul add is non zero") + } + } + )*} +} + mul_add_impl!(MulAdd for isize i8 i16 i32 i64 i128); mul_add_impl!(MulAdd for usize u8 u16 u32 u64 u128); +nonzero_mul_add_impl!(MulAdd for usize u8 u16 u32 u64 u128); #[cfg(any(feature = "std", feature = "libm"))] impl MulAddAssign for f32 { @@ -97,8 +111,20 @@ macro_rules! mul_add_assign_impl { )*} } +macro_rules! nonzero_mul_add_assign_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for core::num::NonZero<$t> { + #[inline] + fn mul_add_assign(&mut self, a: Self, b: Self) { + *self = core::num::NonZero::new((self.get() * a.get()) + b.get()).expect("non zero mul add assign is non zero") + } + } + )*} +} + mul_add_assign_impl!(MulAddAssign for isize i8 i16 i32 i64 i128); mul_add_assign_impl!(MulAddAssign for usize u8 u16 u32 u64 u128); +nonzero_mul_add_assign_impl!(MulAddAssign for usize u8 u16 u32 u64 u128); #[cfg(test)] mod tests { diff --git a/src/ops/saturating.rs b/src/ops/saturating.rs index 16a00457..f4449f83 100644 --- a/src/ops/saturating.rs +++ b/src/ops/saturating.rs @@ -42,13 +42,32 @@ macro_rules! saturating_impl { }; } +macro_rules! nonzero_saturating_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for core::num::NonZero<$t> { + #[inline] + fn $method(&self, v: &Self) -> Self { + core::num::NonZero::new(<$t>::$method((*self).get(), (*v).get())) + .expect("non zero saturating operation is non zero") + } + } + }; +} + /// Performs addition that saturates at the numeric bounds instead of overflowing. +// FIXME: With a major version bump, this should not require `Add` supertrait pub trait SaturatingAdd: Sized + Add { /// Saturating addition. Computes `self + other`, saturating at the relevant high or low boundary of /// the type. fn saturating_add(&self, v: &Self) -> Self; } +pub trait BaseSaturatingAdd: Sized { + /// Saturating addition. Computes `self + other`, saturating at the relevant high or low boundary of + /// the type. + fn saturating_add(&self, v: &Self) -> Self; +} + saturating_impl!(SaturatingAdd, saturating_add, u8); saturating_impl!(SaturatingAdd, saturating_add, u16); saturating_impl!(SaturatingAdd, saturating_add, u32); @@ -56,6 +75,13 @@ saturating_impl!(SaturatingAdd, saturating_add, u64); saturating_impl!(SaturatingAdd, saturating_add, usize); saturating_impl!(SaturatingAdd, saturating_add, u128); +nonzero_saturating_impl!(BaseSaturatingAdd, saturating_add, u8); +nonzero_saturating_impl!(BaseSaturatingAdd, saturating_add, u16); +nonzero_saturating_impl!(BaseSaturatingAdd, saturating_add, u32); +nonzero_saturating_impl!(BaseSaturatingAdd, saturating_add, u64); +nonzero_saturating_impl!(BaseSaturatingAdd, saturating_add, usize); +nonzero_saturating_impl!(BaseSaturatingAdd, saturating_add, u128); + saturating_impl!(SaturatingAdd, saturating_add, i8); saturating_impl!(SaturatingAdd, saturating_add, i16); saturating_impl!(SaturatingAdd, saturating_add, i32); @@ -85,12 +111,19 @@ saturating_impl!(SaturatingSub, saturating_sub, isize); saturating_impl!(SaturatingSub, saturating_sub, i128); /// Performs multiplication that saturates at the numeric bounds instead of overflowing. +//FIXME: With a major version bump, this should not require `Mul` supertrait pub trait SaturatingMul: Sized + Mul { /// Saturating multiplication. Computes `self * other`, saturating at the relevant high or low boundary of /// the type. fn saturating_mul(&self, v: &Self) -> Self; } +pub trait BaseSaturatingMul: Sized { + /// Saturating multiplication. Computes `self * other`, saturating at the relevant high or low boundary of + /// the type. + fn saturating_mul(&self, v: &Self) -> Self; +} + saturating_impl!(SaturatingMul, saturating_mul, u8); saturating_impl!(SaturatingMul, saturating_mul, u16); saturating_impl!(SaturatingMul, saturating_mul, u32); @@ -98,6 +131,13 @@ saturating_impl!(SaturatingMul, saturating_mul, u64); saturating_impl!(SaturatingMul, saturating_mul, usize); saturating_impl!(SaturatingMul, saturating_mul, u128); +nonzero_saturating_impl!(BaseSaturatingMul, saturating_mul, u8); +nonzero_saturating_impl!(BaseSaturatingMul, saturating_mul, u16); +nonzero_saturating_impl!(BaseSaturatingMul, saturating_mul, u32); +nonzero_saturating_impl!(BaseSaturatingMul, saturating_mul, u64); +nonzero_saturating_impl!(BaseSaturatingMul, saturating_mul, usize); +nonzero_saturating_impl!(BaseSaturatingMul, saturating_mul, u128); + saturating_impl!(SaturatingMul, saturating_mul, i8); saturating_impl!(SaturatingMul, saturating_mul, i16); saturating_impl!(SaturatingMul, saturating_mul, i32); diff --git a/src/sign.rs b/src/sign.rs index a0d6b0fd..ed283450 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -5,6 +5,7 @@ use crate::float::FloatCore; use crate::Num; /// Useful functions for signed numbers (i.e. numbers that can be negative). +// FIXME: With a major version bump, do not require `Zero` supertrait. pub trait Signed: Sized + Num + Neg { /// Computes the absolute value. /// @@ -41,6 +42,31 @@ pub trait Signed: Sized + Num + Neg { fn is_negative(&self) -> bool; } +pub trait BaseSigned { + /// Returns the sign of the number. + /// + /// For `f32` and `f64`: + /// + /// * `1.0` if the number is positive, `+0.0` or `INFINITY` + /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// * `NaN` if the number is `NaN` + /// + /// For signed integers: + /// + /// * `0` if the number is zero + /// * `1` if the number is positive + /// * `-1` if the number is negative + /// + /// For non zero numbers never returns zero. + fn signum(&self) -> Self; + + /// Returns true if the number is positive and false if the number is zero or negative. + fn is_positive(&self) -> bool; + + /// Returns true if the number is negative and false if the number is zero or positive. + fn is_negative(&self) -> bool; +} + macro_rules! signed_impl { ($($t:ty)*) => ($( impl Signed for $t { @@ -72,7 +98,28 @@ macro_rules! signed_impl { )*) } +macro_rules! nonzero_signed_impl{ + ($($t:ty)*) => ($( + impl BaseSigned for core::num::NonZero<$t> { + #[inline] + fn signum(&self) -> core::num::NonZero<$t> { + match (*self).get() { + n if n > 0 => core::num::NonZero::new(1).unwrap(), + _ => core::num::NonZero::new(-1).unwrap(), + } + } + + #[inline] + fn is_positive(&self) -> bool { (*self).get().is_positive() } + + #[inline] + fn is_negative(&self) -> bool { (*self).get().is_negative() } + } + )*) +} + signed_impl!(isize i8 i16 i32 i64 i128); +nonzero_signed_impl!(isize i8 i16 i32 i64 i128); impl Signed for Wrapping where From 8be8f12e1f9fc26622eba745e147a3ea2eb09e5f Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Sun, 2 Feb 2025 14:22:17 +0000 Subject: [PATCH 2/2] seems need bump for clear API incroporating nonzero --- Cargo.toml | 8 +++++-- build.rs | 7 ++++++ src/int.rs | 3 ++- src/ops/checked.rs | 56 +++++++++++++++++++++++++++++++++------------- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 226d4164..f384480e 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 = "1.2.19" readme = "README.md" build = "build.rs" exclude = ["/ci/*", "/.github/*"] @@ -21,14 +21,18 @@ rustdoc-args = ["--generate-link-to-definition"] [dependencies] libm = { version = "0.2.0", optional = true } +rustversion.version = "1" [features] -default = ["std"] +default = ["std", "unstable_1"] libm = ["dep:libm"] std = [] # vestigial features, now always in effect i128 = [] +unstable_1 = [] + [build-dependencies] autocfg = "1" +semver = "1" diff --git a/build.rs b/build.rs index 98b06bef..59501820 100644 --- a/build.rs +++ b/build.rs @@ -4,4 +4,11 @@ fn main() { ac.emit_expression_cfg("1f64.total_cmp(&2f64)", "has_total_cmp"); // 1.62 autocfg::rerun_path("build.rs"); + + let version: semver::Version = + std::env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION must be set").parse().expect("Cargo.toml of this crate to be correct version format"); + + if version.major >= 1 { + println!("cargo:rustc-cfg=unstable_1") + } } diff --git a/src/int.rs b/src/int.rs index c6284bf4..9af2f819 100644 --- a/src/int.rs +++ b/src/int.rs @@ -1,4 +1,4 @@ -use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; +use core::ops::{BitAnd, BitOr, BitXor, Mul, Not, Shl, Shr}; use crate::bounds::Bounded; use crate::ops::checked::*; @@ -49,6 +49,7 @@ pub trait PrimInt: + CheckedAdd + CheckedSub + CheckedMul + + Mul + CheckedDiv + Saturating { diff --git a/src/ops/checked.rs b/src/ops/checked.rs index 9776e669..7913c4fb 100644 --- a/src/ops/checked.rs +++ b/src/ops/checked.rs @@ -2,21 +2,28 @@ use core::ops::{Add, Div, Mul, Rem, Shl, Shr, Sub}; /// Performs addition, returning `None` if overflow occurred. // FIXME: With a major version bump, this should not require `Add` supertrait +#[cfg(not(feature = "unstable_1"))] pub trait CheckedAdd: Sized + Add { /// Adds two numbers, checking for overflow. If overflow happens, `None` is /// returned. fn checked_add(&self, v: &Self) -> Option; } -pub trait BaseCheckedAdd: Sized { +/// Performs addition, returning `None` if overflow occurred. +#[cfg(feature = "unstable_1")] +pub trait CheckedAdd: Sized { + type Output; /// Adds two numbers, checking for overflow. If overflow happens, `None` is /// returned. - fn checked_add(&self, v: &Self) -> Option; + fn checked_add(&self, v: &Self) -> Option; } + macro_rules! checked_impl { ($trait_name:ident, $method:ident, $t:ty) => { impl $trait_name for $t { + #[cfg(feature = "unstable_1")] + type Output = $t; #[inline] fn $method(&self, v: &$t) -> Option<$t> { <$t>::$method(*self, *v) @@ -45,12 +52,16 @@ checked_impl!(CheckedAdd, checked_add, u64); checked_impl!(CheckedAdd, checked_add, usize); checked_impl!(CheckedAdd, checked_add, u128); -nonzero_checked_impl!(BaseCheckedAdd, checked_add, u8); -nonzero_checked_impl!(BaseCheckedAdd, checked_add, u16); -nonzero_checked_impl!(BaseCheckedAdd, checked_add, u32); -nonzero_checked_impl!(BaseCheckedAdd, checked_add, u64); -nonzero_checked_impl!(BaseCheckedAdd, checked_add, usize); -nonzero_checked_impl!(BaseCheckedAdd, checked_add, u128); +mod non_zero { + use super::*; + nonzero_checked_impl!(CheckedAdd, checked_add, u8); + nonzero_checked_impl!(CheckedAdd, checked_add, u16); + nonzero_checked_impl!(CheckedAdd, checked_add, u32); + nonzero_checked_impl!(CheckedAdd, checked_add, u64); + nonzero_checked_impl!(CheckedAdd, checked_add, usize); + nonzero_checked_impl!(CheckedAdd, checked_add, u128); +} + checked_impl!(CheckedAdd, checked_add, i8); checked_impl!(CheckedAdd, checked_add, i16); @@ -73,6 +84,10 @@ checked_impl!(CheckedSub, checked_sub, u64); checked_impl!(CheckedSub, checked_sub, usize); checked_impl!(CheckedSub, checked_sub, u128); +mod nonzero { + +} + checked_impl!(CheckedSub, checked_sub, i8); checked_impl!(CheckedSub, checked_sub, i16); checked_impl!(CheckedSub, checked_sub, i32); @@ -82,18 +97,24 @@ checked_impl!(CheckedSub, checked_sub, i128); /// Performs multiplication, returning `None` if overflow occurred. //FIXME: With a major version bump, this should not require `Mul` supertrait +#[cfg(not(feature = "unstable_1"))] pub trait CheckedMul: Sized + Mul { /// Multiplies two numbers, checking for overflow. If overflow happens, /// `None` is returned. fn checked_mul(&self, v: &Self) -> Option; } -pub trait BaseCheckedMul: Sized { +/// Performs multiplication, returning `None` if overflow occurred. +//FIXME: With a major version bump, this should not require `Mul` supertrait +#[cfg(any(feature = "unstable_1"))] +pub trait CheckedMul: Sized { + type Output; /// Multiplies two numbers, checking for overflow. If overflow happens, /// `None` is returned. - fn checked_mul(&self, v: &Self) -> Option; + fn checked_mul(&self, v: &Self) -> Option; } + checked_impl!(CheckedMul, checked_mul, u8); checked_impl!(CheckedMul, checked_mul, u16); checked_impl!(CheckedMul, checked_mul, u32); @@ -101,12 +122,15 @@ checked_impl!(CheckedMul, checked_mul, u64); checked_impl!(CheckedMul, checked_mul, usize); checked_impl!(CheckedMul, checked_mul, u128); -nonzero_checked_impl!(BaseCheckedMul, checked_mul, u8); -nonzero_checked_impl!(BaseCheckedMul, checked_mul, u16); -nonzero_checked_impl!(BaseCheckedMul, checked_mul, u32); -nonzero_checked_impl!(BaseCheckedMul, checked_mul, u64); -nonzero_checked_impl!(BaseCheckedMul, checked_mul, usize); -nonzero_checked_impl!(BaseCheckedMul, checked_mul, u128); +mod nonzero { + use super::*; + nonzero_checked_impl!(CheckedMul, checked_mul, u8); + nonzero_checked_impl!(CheckedMul, checked_mul, u16); + nonzero_checked_impl!(CheckedMul, checked_mul, u32); + nonzero_checked_impl!(CheckedMul, checked_mul, u64); + nonzero_checked_impl!(CheckedMul, checked_mul, usize); + nonzero_checked_impl!(CheckedMul, checked_mul, u128); +} checked_impl!(CheckedMul, checked_mul, i8); checked_impl!(CheckedMul, checked_mul, i16);