diff --git a/Cargo.toml b/Cargo.toml index 226d416..f384480 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 98b06be..5950182 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/bounds.rs b/src/bounds.rs index acc990e..61427c5 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/int.rs b/src/int.rs index c6284bf..9af2f81 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 553b28b..7913c4f 100644 --- a/src/ops/checked.rs +++ b/src/ops/checked.rs @@ -1,15 +1,29 @@ 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; } +/// 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; +} + + 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) @@ -18,6 +32,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 +52,17 @@ checked_impl!(CheckedAdd, checked_add, u64); checked_impl!(CheckedAdd, checked_add, usize); checked_impl!(CheckedAdd, 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); checked_impl!(CheckedAdd, checked_add, i32); @@ -46,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); @@ -54,12 +96,25 @@ 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 +#[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; } +/// 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; +} + + checked_impl!(CheckedMul, checked_mul, u8); checked_impl!(CheckedMul, checked_mul, u16); checked_impl!(CheckedMul, checked_mul, u32); @@ -67,6 +122,16 @@ checked_impl!(CheckedMul, checked_mul, u64); checked_impl!(CheckedMul, checked_mul, usize); checked_impl!(CheckedMul, 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); checked_impl!(CheckedMul, checked_mul, i32); diff --git a/src/ops/mul_add.rs b/src/ops/mul_add.rs index 51beb55..6f5eeb4 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 16a0045..f4449f8 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 a0d6b0f..ed28345 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