Skip to content

some set of generic based non zero support #346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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/*"]
Expand All @@ -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"
7 changes: 7 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}
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
3 changes: 2 additions & 1 deletion src/int.rs
Original file line number Diff line number Diff line change
@@ -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::*;
Expand Down Expand Up @@ -49,6 +49,7 @@ pub trait PrimInt:
+ CheckedAdd<Output = Self>
+ CheckedSub<Output = Self>
+ CheckedMul<Output = Self>
+ Mul<Output = Self>
+ CheckedDiv<Output = Self>
+ Saturating
{
Expand Down
65 changes: 65 additions & 0 deletions src/ops/checked.rs
Original file line number Diff line number Diff line change
@@ -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<Self, Output = Self> {
/// Adds two numbers, checking for overflow. If overflow happens, `None` is
/// returned.
fn checked_add(&self, v: &Self) -> Option<Self>;
}

/// 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<Self::Output>;
}


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)
Expand All @@ -18,13 +32,37 @@ 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);

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);
Expand All @@ -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);
Expand All @@ -54,19 +96,42 @@ 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<Self, Output = Self> {
/// Multiplies two numbers, checking for overflow. If overflow happens,
/// `None` is returned.
fn checked_mul(&self, v: &Self) -> Option<Self>;
}

/// 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<Self::Output>;
}


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);

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);
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
Loading