Skip to content
Open
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
14 changes: 12 additions & 2 deletions src/integer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use core::num::ParseIntError;

use core::num::{NonZero, ParseIntError, TryFromIntError};
use crate::{PrimitiveError, PrimitiveNumber, PrimitiveNumberRef};

/// Trait for all primitive [integer types], including the supertrait [`PrimitiveNumber`].
Expand Down Expand Up @@ -517,6 +516,15 @@ pub trait PrimitiveInteger:
/// This results in undefined behavior when `self - rhs > Self::MAX` or `self - rhs <
/// Self::MIN`, i.e. when [`checked_sub`][Self::checked_sub] would return `None`.
unsafe fn unchecked_sub(self, rhs: Self) -> Self;

/// The NonZero struct for this integer
type NonZero:
core::convert::TryFrom<Self, Error = TryFromIntError>
+ core::ops::BitOr<Self, Output = Self::NonZero>
+ core::ops::BitOr<Self::NonZero, Output = Self::NonZero>
+ core::ops::BitOrAssign<Self>
+ core::ops::BitOrAssign<Self::NonZero>
+ Into<Self>;
}

/// Trait for references to primitive integer types ([`PrimitiveInteger`]).
Expand Down Expand Up @@ -690,6 +698,8 @@ macro_rules! impl_integer {
unsafe fn unchecked_shr(self, rhs: u32) -> Self;
unsafe fn unchecked_sub(self, rhs: Self) -> Self;
}

type NonZero = NonZero<Self>;
}

impl PrimitiveIntegerRef<$Integer> for &$Integer {}
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ mod integer;
mod number;
mod signed;
mod unsigned;
mod nonzero;

#[cfg(test)]
mod tests;
Expand All @@ -77,3 +78,4 @@ pub use self::integer::{PrimitiveInteger, PrimitiveIntegerRef};
pub use self::number::{PrimitiveNumber, PrimitiveNumberAs, PrimitiveNumberRef};
pub use self::signed::{PrimitiveSigned, PrimitiveSignedRef};
pub use self::unsigned::{PrimitiveUnsigned, PrimitiveUnsignedRef};
pub use self::nonzero::{NonZeroPrimitiveInteger, NonZeroPrimitiveSigned, NonZeroPrimitiveUnsigned};
8 changes: 8 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ macro_rules! forward {
Self::$method($( $arg ),* )
}
)*};
($(unsafe fn $method:ident ( $( $arg:ident : $ty:ty )* ) -> $ret:ty ; )*) => {$(
#[doc = forward_doc!($method)]
#[inline]
unsafe fn $method( $( $arg : $ty )* ) -> $ret {
// SAFETY: we're just passing through here!
unsafe { Self::$method( $( $arg ),* ) }
}
)*};
($(unsafe fn $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*) => {$(
#[doc = forward_doc!($method)]
#[inline]
Expand Down
69 changes: 69 additions & 0 deletions src/nonzero/implement.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use super::{NonZeroPrimitiveInteger, NonZeroPrimitiveUnsigned, NonZeroPrimitiveSigned};
use crate::PrimitiveUnsigned;
use core::num::NonZero;

macro_rules! impl_nonzero {
(@uint $($t:ty),+) => {
impl_nonzero!($($t, <$t as PrimitiveUnsigned>::Signed),+);
$(
impl NonZeroPrimitiveUnsigned for NonZero<$t> {
type Signed = NonZero<<$t as PrimitiveUnsigned>::Signed>;
forward!(
fn saturating_add(self, rhs: $t) -> Self;
fn checked_add(self, rhs: $t) -> Option<Self>;
fn cast_signed(self) -> Self::Signed;
fn ilog2(self) -> u32;
fn ilog10(self) -> u32;
fn isqrt(self) -> Self;
fn midpoint(self, rhs: Self) -> Self;
fn checked_next_power_of_two(self) -> Option<Self>;
fn is_power_of_two(self) -> bool;
);
}
impl NonZeroPrimitiveSigned for NonZero<<$t as PrimitiveUnsigned>::Signed> {
type Unsigned = NonZero<$t>;
forward!(
fn abs(self) -> Self;
fn checked_abs(self) -> Option<Self>;
fn saturating_abs(self) -> Self;
fn overflowing_abs(self) -> (Self, bool);
fn wrapping_abs(self) -> Self;
fn unsigned_abs(self) -> Self::Unsigned;
fn is_positive(self) -> bool;
fn is_negative(self) -> bool;
fn checked_neg(self) -> Option<Self>;
fn overflowing_neg(self) -> (Self, bool);
fn saturating_neg(self) -> Self;
fn cast_unsigned(self) -> Self::Unsigned;
);
}
)+
};
($($t:ty),+) => {$(
impl NonZeroPrimitiveInteger for NonZero<$t> {
type Zeroable = $t;
forward! {
fn new(n: Self::Zeroable) -> Option<Self>;
}
forward! {
fn get(self) -> Self::Zeroable;
fn leading_zeros(self) -> u32;
fn trailing_zeros(self) -> u32;
fn checked_mul(self, rhs: Self) -> Option<Self>;
fn checked_pow(self, exponent: u32) -> Option<Self>;
fn saturating_pow(self, exponent: u32) -> Self;
fn count_ones(self) -> NonZero<u32>;
}
forward! {
unsafe fn new_unchecked(n: Self::Zeroable) -> Self;
}
// not forwarding because core's docs are inaccurate
// It specifies that it can only saturate to `Self::MAX`
// even on signed types.
fn saturating_mul(self, rhs: Self) -> Self {
self.saturating_mul(rhs)
}
}
)+};
}
impl_nonzero!(@uint u8, u16, u32, u64, u128, usize);
129 changes: 129 additions & 0 deletions src/nonzero/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
mod signed_nonzero;
mod unsigned_nonzero;
mod implement;

pub use self::unsigned_nonzero::NonZeroPrimitiveUnsigned;
pub use self::signed_nonzero::NonZeroPrimitiveSigned;

use crate::{PrimitiveInteger, PrimitiveError};
use core::num::NonZero;


/// Trait for [`NonZero`].
///
/// This encapsulates trait implementations, constants, and inherent methods that are common among
/// all of the implementations of `NonZero<T>`.
///
/// See the corresponding items on the individual types for more documentation and examples.
///
/// This trait is sealed with a private trait to prevent downstream implementations, so we may
/// continue to expand along with the standard library without worrying about breaking changes for
/// implementors.
pub trait NonZeroPrimitiveInteger:
'static
+ core::cmp::Eq
+ core::cmp::PartialEq
+ core::cmp::Ord
+ core::cmp::PartialOrd
+ core::fmt::Debug
+ core::fmt::Display
+ core::fmt::LowerExp
+ core::fmt::UpperExp
+ core::fmt::Binary
+ core::fmt::LowerHex
+ core::fmt::Octal
+ core::fmt::UpperHex
+ core::hash::Hash
+ core::marker::Copy
+ core::marker::Send
+ core::marker::Sync
+ core::marker::Unpin
+ core::panic::RefUnwindSafe
+ core::panic::UnwindSafe
+ core::str::FromStr<Err: PrimitiveError>
+ core::convert::TryFrom<NonZero<i8>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<i16>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<i32>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<i64>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<i128>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<isize>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<u8>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<u16>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<u32>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<u64>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<u128>, Error: PrimitiveError>
+ core::convert::TryFrom<NonZero<usize>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<i8>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<i16>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<i32>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<i64>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<i128>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<isize>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<u8>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<u16>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<u32>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<u64>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<u128>, Error: PrimitiveError>
+ core::convert::TryInto<NonZero<usize>, Error: PrimitiveError>
+ core::ops::BitOr<Self, Output=Self>
+ core::ops::BitOr<Self::Zeroable, Output=Self>
+ core::ops::BitOrAssign<Self::Zeroable>
{
/// The integer type that this represents,
/// For a `NonZero<T>` this is `T`.
type Zeroable:
PrimitiveInteger<NonZero=Self>
+ core::ops::BitOr<Self, Output=Self>
+ From<Self>
+ TryInto<Self>;

/// The size of this non-zero integer type in bits, equal to `Self::Zeroable::BITS`
const BITS: u32 = Self::Zeroable::BITS;

/// The largest value that can be represented by this non-zero integer type, equal to `Self::Zeroable::MAX`.
const MAX: Self = unsafe { core::mem::transmute_copy::<Self::Zeroable, Self>(&Self::Zeroable::MAX) };

/// Creates a non-zero if the given value is not zero.
fn new(n: Self::Zeroable) -> Option<Self>;

/// Creates a non-zero without checking whether the value is non-zero.
/// This results in undefined behavior if the value is zero.
///
/// # Safety
/// The value must not be zero.
unsafe fn new_unchecked(n: Self::Zeroable) -> Self;

/// Returns the contained value as a primitive type.
fn get(self) -> Self::Zeroable;

/// Returns the number of leading zeros in the binary representation of `self`.
///
/// On many architectures, this function can perform better than `leading_zeros()`
/// on `Self::Zeroable`, as special handling of zero can be avoided.
fn leading_zeros(self) -> u32;

/// Returns the number of leading zeros in the binary representation of `self`.
///
/// On many architectures, this function can perform better than `trailing_zeros()`
/// on the `Self::Zeroable`, as special handling of zero can be avoided.
fn trailing_zeros(self) -> u32;

/// Returns the number of ones in the binary representation of `self`.
fn count_ones(self) -> NonZero<u32>;

/// Multiplies two non-zero integers together. Checks for overflow and returns `None`
/// if it occurs. As a consequence, the result cannot wrap to zero.
fn checked_mul(self, rhs: Self) -> Option<Self>;

/// Multiplies two non-zero integers together, saturating at the numeric upper and lower
/// bounds instead of overflowing. As a consequence, the result cannot wrap to zero.
fn saturating_mul(self, rhs: Self) -> Self;

/// Raise non-zero value to an integer power. Checks for overflow and returns `None` on
/// overflow. As a consequence, the result cannot wrap to zero.
fn checked_pow(self, exponent: u32) -> Option<Self>;

/// Raise non-zero value to an integer power. Return NonZero::<i8>::MIN or NonZero::<i8>::MAX
/// on overflow based on the sign of the exact result.
fn saturating_pow(self, exponent: u32) -> Self;
}
86 changes: 86 additions & 0 deletions src/nonzero/signed_nonzero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use core::convert::Infallible;
use core::num::NonZero;
use core::ops::{Neg, Div, DivAssign, Rem, RemAssign};

use crate::{NonZeroPrimitiveInteger, NonZeroPrimitiveUnsigned, PrimitiveSigned, PrimitiveUnsigned};

/// A trait for [`NonZero`] of a signed integer.
///
/// This encapsulates trait implementations, constants, and inherent methods that are common among
/// all of the implementations of `NonZero<T> where T: PrimitiveSigned`.
///
/// See the corresponding items on the individual types for more documentation and examples.
///
/// This trait is sealed with a private trait to prevent downstream implementations, so we may
/// continue to expand along with the standard library without worrying about breaking changes for
/// implementors.
///
///
pub trait NonZeroPrimitiveSigned:
NonZeroPrimitiveInteger<Zeroable: PrimitiveSigned>
+ TryFrom<NonZero<i8>, Error=Infallible>
+ Neg<Output=Self>
where Self::Zeroable: PrimitiveSigned,
<Self::Unsigned as NonZeroPrimitiveInteger>::Zeroable:
Div<Self::Unsigned, Output=<Self::Unsigned as NonZeroPrimitiveInteger>::Zeroable>
+ DivAssign<Self::Unsigned>
+ Rem<Self::Unsigned, Output=<Self::Unsigned as NonZeroPrimitiveInteger>::Zeroable>
+ RemAssign<Self::Unsigned>
+ PrimitiveUnsigned
{
/// The unsigned nonzero type with the same size as this.
type Unsigned: NonZeroPrimitiveUnsigned;

/// Computes the absolute value of `self`.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn abs(self) -> Self;

/// Checked absolute value. Computes the absolute value of `self`, returning `None`
/// if it overflows.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn checked_abs(self) -> Option<Self>;

/// Saturating absolute value. Computes the absolute value of `self`, saturating to
/// `Self::MAX` when it would overflow.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn saturating_abs(self) -> Self;

/// Overflowing absolute value. Computes the absolute value of `self`, returning a
/// tuple of the result and a bool indicating if the operation overflowed.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn overflowing_abs(self) -> (Self, bool);

/// Overflowing absolute value. Computes the absolute value of `self`, wrapping when
/// `self == Self::MIN`.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn wrapping_abs(self) -> Self;

/// Computes the absolute value of `Self` without any wrapping or panicking.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn unsigned_abs(self) -> Self::Unsigned;

/// Returns true if `self` is positive and `false` if it is negative.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn is_positive(self) -> bool;

/// Returns true if `self` is positive and `false` if it is negative.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn is_negative(self) -> bool;

/// Checked negation. Compute `-self`, returning `None` if it overflows.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn checked_neg(self) -> Option<Self>;

/// Checked negation. Compute `-self`, returning a tuple of the result and a bool
/// indicating if the operation overflowed.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn overflowing_neg(self) -> (Self, bool);

/// Checked negation. Compute `-self`, saturating to `Self::MAX` when it would overflow.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn saturating_neg(self) -> Self;

/// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size.
#[must_use = "this returns the result of the operation, without modifying the original"]
fn cast_unsigned(self) -> Self::Unsigned;
}
Loading