#[rustfmt::skip]
macro_rules! uint_generate_inner {
($name:ident, $d:tt) => {
#[allow(unused_macros)]
macro_rules! $name {
($d val:expr) => {{
$crate::num::$name::new($d val).unwrap()
}};
}
};
}
macro_rules! new_unsigned_int_macros {
( $( $name:ident ),+) => {
$(
uint_generate_inner!($name, $);
)+
}
}
macro_rules! new_unsigned_int {
( $( $name:ident, $base:ty, $bit_depth: literal );+) => {
$(
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct $name($base);
impl $name {
pub const ZERO: Self = Self(0);
pub const BITS: u32 = $bit_depth;
#[doc = concat!("The minimum value that may be contained within a [`", stringify!($name), "`]")]
pub const MIN: Self = Self(0);
#[doc = concat!("The maximum value that may be contained within a [`", stringify!($name), "`]")]
pub const MAX: Self = Self(((2 as $base).pow($bit_depth)) - (1 as $base));
#[doc = concat!("The maximum value that may be contained within a [`", stringify!($name), "`]")]
pub const MAX2: $base = Self::MAX.inner();
#[doc = concat!("Get the inner [`", stringify!($base), "`].")]
#[inline]
pub const fn inner(self) -> $base {
self.0
}
#[doc = concat!("Create a new [`", stringify!($name), "`]. If `x` is larger than [`", stringify!($name), "::MAX`], then [`None`] is returned.")]
#[inline]
pub const fn new(x: $base) -> Option<Self> {
if x <= Self::MAX.0 {
Some(Self(x))
} else {
None
}
}
#[doc = concat!("Create a new [`", stringify!($name), "`], clamping `x` to [`", stringify!($name), "::MAX`].")]
#[inline]
pub const fn new_clamp(x: $base) -> Self {
Self(if x > Self::MAX.0 { Self::MAX.0 } else { x })
}
#[doc = concat!("Create a new [`", stringify!($name), "`] without checking for valididty.")]
#[inline]
pub const fn new_unchecked(x: $base) -> Self {
Self(x)
}
#[inline]
pub const fn wrapping_add_base(self, rhs: $base) -> Self {
let mask: $base = (1 << Self::BITS) - 1;
Self(self.inner().wrapping_add(rhs) & mask)
}
#[inline]
pub const fn wrapping_add(self, rhs: Self) -> Self {
Self(self.wrapping_add_base(rhs.inner()).inner())
}
#[inline]
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let sum = self.wrapping_add(rhs);
if sum.inner() < self.inner() {
None
} else {
Some(sum)
}
}
#[inline]
pub const fn wrapping_sub_base(self, rhs: $base) -> Self {
let mask: $base = (1 << Self::BITS) - 1;
Self(self.inner().wrapping_sub(rhs) & mask)
}
#[inline]
pub const fn wrapping_sub(self, rhs: Self) -> Self {
Self(self.wrapping_sub_base(rhs.inner()).inner())
}
#[inline]
pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
if self.inner() > rhs.inner() {
None
} else {
Some(self.wrapping_sub(rhs))
}
}
}
impl PartialEq<$base> for $name {
#[inline]
fn eq(&self, other: &$base) -> bool {
self.0.eq(other)
}
}
impl PartialOrd<$base> for $name {
#[inline]
fn partial_cmp(&self, other: &$base) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(other)
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
write!(f, "{}", self.0)
}
}
impl ::std::ops::Add for $name {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
match self.checked_add(rhs) {
Some(sum) => sum,
None => panic!("Attemped to add with overflow"),
}
}
}
impl ::std::ops::AddAssign for $name {
fn add_assign(&mut self, rhs: Self) {
match self.checked_add(rhs) {
Some(sum) => *self = sum,
None => panic!("Attemped to add with overflow"),
}
}
}
impl ::std::ops::Add<$base> for $name {
type Output = Self;
fn add(self, rhs: $base) -> Self::Output {
let rhs = Self::new(rhs).expect(concat!("`rhs` should be <= `", stringify!($name::MAX), "`"));
self + rhs
}
}
impl ::std::ops::AddAssign<$base> for $name {
fn add_assign(&mut self, rhs: $base) {
let rhs = Self::new(rhs).expect(concat!("`rhs` should be <= `", stringify!($name::MAX), "`"));
*self += rhs
}
}
impl ::std::ops::Sub for $name {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
match self.checked_sub(rhs) {
Some(sum) => sum,
None => panic!("Attemped to subtract with overflow"),
}
}
}
impl ::std::ops::SubAssign for $name {
fn sub_assign(&mut self, rhs: Self) {
match self.checked_sub(rhs) {
Some(sum) => *self = sum,
None => panic!("Attemped to subtract with overflow"),
}
}
}
::concat_idents::concat_idents!(struct_name = NonZero, $name {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct struct_name($name);
impl struct_name {
#[inline]
pub const fn new(num: $name) -> Option<Self> {
if matches!(num, <$name>::ZERO) {
None
} else {
Some(Self(num))
}
}
#[inline]
pub const fn get(self) -> $name {
self.0
}
}
});
)+
};
}
new_unsigned_int!(
U3, u8, 3
; U4, u8, 4
; U5, u8, 5
; U6, u8, 6
; U15, u16, 15
; U20, u32, 20
; U24, u32, 24
; U31, u32, 31
; U36, u64, 36
);
#[macro_use]
pub mod macros {
new_unsigned_int_macros!(U3, U5, U15, U20, U24, U31, U36);
}