Skip to content

Commit

Permalink
some set of non zero support
Browse files Browse the repository at this point in the history
  • Loading branch information
dzmitry-lahoda committed Jan 31, 2025
1 parent 022f250 commit c45a410
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/bounds.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -26,6 +26,7 @@ impl<T: Bounded> 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;
Expand Down Expand Up @@ -61,13 +62,25 @@ bounded_impl!(u32, u32::MIN, u32::MAX);
bounded_impl!(u64, u64::MIN, u64::MAX);
bounded_impl!(u128, u128::MIN, u128::MAX);

bounded_impl!(NonZero<u8>, NonZero::<u8>::MIN, NonZero::<u8>::MAX);
bounded_impl!(NonZero<u16>, NonZero::<u16>::MIN, NonZero::<u16>::MAX);
bounded_impl!(NonZero<u32>, NonZero::<u32>::MIN, NonZero::<u32>::MAX);
bounded_impl!(NonZero<u64>, NonZero::<u64>::MIN, NonZero::<u64>::MAX);
bounded_impl!(NonZero<u128>, NonZero::<u128>::MIN, NonZero::<u128>::MAX);

bounded_impl!(isize, isize::MIN, isize::MAX);
bounded_impl!(i8, i8::MIN, i8::MAX);
bounded_impl!(i16, i16::MIN, i16::MAX);
bounded_impl!(i32, i32::MIN, i32::MAX);
bounded_impl!(i64, i64::MIN, i64::MAX);
bounded_impl!(i128, i128::MIN, i128::MAX);

bounded_impl!(NonZero<i8>, NonZero::<i8>::MIN, NonZero::<i8>::MAX);
bounded_impl!(NonZero<i16>, NonZero::<i16>::MIN, NonZero::<i16>::MAX);
bounded_impl!(NonZero<i32>, NonZero::<i32>::MIN, NonZero::<i32>::MAX);
bounded_impl!(NonZero<i64>, NonZero::<i64>::MIN, NonZero::<i64>::MAX);
bounded_impl!(NonZero<i128>, NonZero::<i128>::MIN, NonZero::<i128>::MAX);

impl<T: Bounded> Bounded for Wrapping<T> {
fn min_value() -> Self {
Wrapping(T::min_value())
Expand Down
41 changes: 41 additions & 0 deletions src/ops/checked.rs
Original file line number Diff line number Diff line change
@@ -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<Self, Output = Self> {
/// Adds two numbers, checking for overflow. If overflow happens, `None` is
/// returned.
fn checked_add(&self, v: &Self) -> Option<Self>;
}

pub trait BaseCheckedAdd: Sized {
/// Adds two numbers, checking for overflow. If overflow happens, `None` is
/// returned.
fn checked_add(&self, v: &Self) -> Option<Self>;
}

macro_rules! checked_impl {
($trait_name:ident, $method:ident, $t:ty) => {
impl $trait_name for $t {
Expand All @@ -18,13 +25,33 @@ 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<core::num::NonZero<$t>> {
<$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);
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);
Expand Down Expand Up @@ -54,19 +81,33 @@ 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<Self, Output = Self> {
/// Multiplies two numbers, checking for overflow. If overflow happens,
/// `None` is returned.
fn checked_mul(&self, v: &Self) -> Option<Self>;
}

pub trait BaseCheckedMul: Sized {
/// Multiplies two numbers, checking for overflow. If overflow happens,
/// `None` is returned.
fn checked_mul(&self, v: &Self) -> Option<Self>;
}

checked_impl!(CheckedMul, checked_mul, u8);
checked_impl!(CheckedMul, checked_mul, u16);
checked_impl!(CheckedMul, checked_mul, u32);
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);
Expand Down
26 changes: 26 additions & 0 deletions src/ops/mul_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<f32, f32> for f32 {
Expand Down Expand Up @@ -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 {
Expand Down
40 changes: 40 additions & 0 deletions src/ops/saturating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,46 @@ 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<Self, Output = Self> {
/// 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);
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);
Expand Down Expand Up @@ -85,19 +111,33 @@ 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<Self, Output = Self> {
/// 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);
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);
Expand Down
47 changes: 47 additions & 0 deletions src/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Output = Self> {
/// Computes the absolute value.
///
Expand Down Expand Up @@ -41,6 +42,31 @@ pub trait Signed: Sized + Num + Neg<Output = Self> {
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 {
Expand Down Expand Up @@ -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<T: Signed> Signed for Wrapping<T>
where
Expand Down

0 comments on commit c45a410

Please sign in to comment.