Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "num-primitive"
version = "0.3.7"
version = "0.3.8"
description = "Traits for primitive numeric types"
repository = "https://github.com/rust-num/num-primitive"
license = "MIT OR Apache-2.0"
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Each trait includes supertraits for everything implemented in common by these
types, as well as associated constants and methods matching their inherent
items. `PrimitiveFloat` also adds the contents of `core::{float}::consts`.

`NonZero` integer wrappers are similarly supported by `NonZeroPrimitiveInteger`,
`NonZeroPrimitiveSigned`, and `NonZeroPrimitiveUnsigned`.

It is not a goal of this crate to *add* any functionality to the primitive
types, only to expose what is already available in the standard library in a
more generic way. The traits are also [sealed] against downstream
Expand Down
6 changes: 6 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Release 0.3.8 (2026-07-09)

- Added traits for `NonZero`-wrapped primitive integers: `NonZeroPrimitiveInteger`,
`NonZeroPrimitiveSigned`, and `NonZeroPrimitiveUnsigned`.
- Extended `PrimitiveInteger` and `PrimitiveUnsigned` for `NonZero` interactions.

# Release 0.3.7 (2026-03-15)

- Updated to MSRV 1.94.
Expand Down
172 changes: 171 additions & 1 deletion src/integer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use core::num::ParseIntError;
use core::num::{NonZero, ParseIntError, TryFromIntError};

use crate::{PrimitiveError, PrimitiveNumber, PrimitiveNumberRef};

trait NonZeroSealed {}

/// Trait for all primitive [integer types], including the supertrait [`PrimitiveNumber`].
///
/// This encapsulates trait implementations, constants, and inherent methods that are common among
Expand Down Expand Up @@ -40,6 +42,7 @@ pub trait PrimitiveInteger:
PrimitiveNumber
+ core::cmp::Eq
+ core::cmp::Ord
+ core::convert::From<Self::NonZero>
+ core::convert::TryFrom<i8, Error: PrimitiveError>
+ core::convert::TryFrom<i16, Error: PrimitiveError>
+ core::convert::TryFrom<i32, Error: PrimitiveError>
Expand All @@ -52,6 +55,7 @@ pub trait PrimitiveInteger:
+ core::convert::TryFrom<u64, Error: PrimitiveError>
+ core::convert::TryFrom<u128, Error: PrimitiveError>
+ core::convert::TryFrom<usize, Error: PrimitiveError>
+ core::convert::TryInto<Self::NonZero, Error = TryFromIntError>
+ core::convert::TryInto<i8, Error: PrimitiveError>
+ core::convert::TryInto<i16, Error: PrimitiveError>
+ core::convert::TryInto<i32, Error: PrimitiveError>
Expand All @@ -72,6 +76,7 @@ pub trait PrimitiveInteger:
+ core::ops::BitAnd<Self, Output = Self>
+ core::ops::BitAndAssign<Self>
+ core::ops::BitOr<Self, Output = Self>
+ core::ops::BitOr<Self::NonZero, Output = Self::NonZero>
+ core::ops::BitOrAssign<Self>
+ core::ops::BitXor<Self, Output = Self>
+ core::ops::BitXorAssign<Self>
Expand Down Expand Up @@ -188,6 +193,11 @@ pub trait PrimitiveInteger:
+ for<'a> core::ops::ShrAssign<&'a u128>
+ for<'a> core::ops::ShrAssign<&'a usize>
{
/// The non-zero integer type wrapping this primitive integer.
///
/// This is always `core::num::NonZero<Self>`.
type NonZero: NonZeroPrimitiveInteger<Integer = Self>;

/// The size of this integer type in bits.
const BITS: u32;

Expand Down Expand Up @@ -594,9 +604,140 @@ pub trait PrimitiveIntegerRef<T>:
{
}

/// Trait for [`NonZero`] primitive integers.
///
/// This encapsulates trait implementations, constants, and inherent methods that are common among
/// all of the implementations of `NonZero<T>`, where `T` is a [`PrimitiveInteger`].
///
/// 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.
///
/// # Examples
///
/// ```
/// use num_primitive::NonZeroPrimitiveInteger;
/// use core::num::NonZero;
///
/// fn bits_and_zeros<T: NonZeroPrimitiveInteger>(n: T) -> (u32, u32, u32) {
/// (T::BITS, n.leading_zeros(), n.trailing_zeros())
/// }
///
/// assert_eq!(bits_and_zeros(NonZero::new(0b0010_1000u8).unwrap()), (8, 2, 3));
/// assert_eq!(bits_and_zeros(NonZero::new(1i64).unwrap()), (64, 63, 0));
/// ```
#[expect(private_bounds)]
pub trait NonZeroPrimitiveInteger:
'static
+ NonZeroSealed
+ core::cmp::Eq
+ core::cmp::Ord
+ core::convert::Into<Self::Integer>
+ core::convert::TryFrom<Self::Integer, Error = TryFromIntError>
+ 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::fmt::Binary
+ core::fmt::Debug
+ core::fmt::Display
+ core::fmt::LowerExp
+ core::fmt::LowerHex
+ core::fmt::Octal
+ core::fmt::UpperExp
+ core::fmt::UpperHex
+ core::hash::Hash
+ core::marker::Copy
+ core::marker::Send
+ core::marker::Sync
+ core::marker::Unpin
+ core::ops::BitOr<Self, Output = Self>
+ core::ops::BitOr<Self::Integer, Output = Self>
+ core::ops::BitOrAssign<Self>
+ core::ops::BitOrAssign<Self::Integer>
+ core::panic::RefUnwindSafe
+ core::panic::UnwindSafe
+ core::str::FromStr<Err = ParseIntError>
{
/// The primitive integer type that this non-zero type wraps.
///
/// For `core::num::NonZero<T>`, this is `T`.
type Integer: PrimitiveInteger<NonZero = Self>;

/// The size of this non-zero integer type in bits.
const BITS: u32;

/// The largest value that can be represented by this non-zero integer type.
const MAX: Self;

/// The smallest value that can be represented by this non-zero integer type.
const MIN: Self;

/// Multiplies two non-zero integers together. Returns [`None`] on overflow.
fn checked_mul(self, other: Self) -> Option<Self>;

/// Raises non-zero value to an integer power. Returns [`None`] on overflow.
fn checked_pow(self, other: u32) -> Option<Self>;

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

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

/// Returns the number of leading zeros in the binary representation of `self`.
fn leading_zeros(self) -> u32;

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

/// Multiplies two non-zero integers together, saturating at the numeric bounds
/// instead of overflowing.
fn saturating_mul(self, other: Self) -> Self;

/// Raise non-zero value to an integer power, saturating at the numeric bounds
/// instead of overflowing.
fn saturating_pow(self, other: u32) -> Self;

/// Returns the number of trailing zeros in the binary representation of `self`.
fn trailing_zeros(self) -> u32;

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

macro_rules! impl_integer {
($($Integer:ident),*) => {$(
impl PrimitiveInteger for $Integer {
type NonZero = NonZero<Self>;

use_consts!(Self::{
BITS: u32,
MAX: Self,
Expand Down Expand Up @@ -693,6 +834,35 @@ macro_rules! impl_integer {
}

impl PrimitiveIntegerRef<$Integer> for &$Integer {}

impl NonZeroSealed for NonZero<$Integer> {}

impl NonZeroPrimitiveInteger for NonZero<$Integer> {
type Integer = $Integer;

use_consts!(Self::{
BITS: u32,
MAX: Self,
MIN: Self,
});

forward! {
fn new(n: Self::Integer) -> Option<Self>;
}
forward! {
fn checked_mul(self, other: Self) -> Option<Self>;
fn checked_pow(self, other: u32) -> Option<Self>;
fn count_ones(self) -> NonZero<u32>;
fn get(self) -> Self::Integer;
fn leading_zeros(self) -> u32;
fn saturating_mul(self, other: Self) -> Self;
fn saturating_pow(self, other: u32) -> Self;
fn trailing_zeros(self) -> u32;
}
forward! {
unsafe fn new_unchecked(n: Self::Integer) -> Self;
}
}
)*}
}

Expand Down
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
//! types, as well as associated constants and methods matching their inherent
//! items. `PrimitiveFloat` also adds the contents of `core::{float}::consts`.
//!
//! [`NonZero`][core::num::NonZero] integer wrappers are similarly supported by
//! [`NonZeroPrimitiveInteger`], [`NonZeroPrimitiveSigned`], and [`NonZeroPrimitiveUnsigned`].
//!
//! It is not a goal of this crate to *add* any functionality to the primitive
//! types, only to expose what is already available in the standard library in a
//! more generic way. The traits are also [sealed] against downstream
Expand Down Expand Up @@ -73,7 +76,7 @@ mod tests;
pub use self::bytes::PrimitiveBytes;
pub use self::error::PrimitiveError;
pub use self::float::{PrimitiveFloat, PrimitiveFloatRef, PrimitiveFloatToInt};
pub use self::integer::{PrimitiveInteger, PrimitiveIntegerRef};
pub use self::integer::{NonZeroPrimitiveInteger, PrimitiveInteger, PrimitiveIntegerRef};
pub use self::number::{PrimitiveNumber, PrimitiveNumberAs, PrimitiveNumberRef};
pub use self::signed::{PrimitiveSigned, PrimitiveSignedRef};
pub use self::unsigned::{PrimitiveUnsigned, PrimitiveUnsignedRef};
pub use self::signed::{NonZeroPrimitiveSigned, PrimitiveSigned, PrimitiveSignedRef};
pub use self::unsigned::{NonZeroPrimitiveUnsigned, PrimitiveUnsigned, PrimitiveUnsignedRef};
8 changes: 8 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ macro_rules! forward {
unsafe { Self::$method(self $( , $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 ),* ) }
}
)*};
}

/// A string suitable for method `#[doc = ...]`
Expand Down
Loading
Loading