use crate::items;
impl_non_value![U 8, u8];
impl_non_value![U 16, u16];
impl_non_value![U 32, u32];
impl_non_value![U 64, u64];
impl_non_value![U 128, u128];
impl_non_value![I 8, i8];
impl_non_value![I 16, i16];
impl_non_value![I 32, i32];
impl_non_value![I 64, i64];
impl_non_value![I 128, i128];
#[cfg(target_pointer_width = "8")]
items! { impl_non_value![U 8, usize]; impl_non_value![I 8, isize]; }
#[cfg(target_pointer_width = "16")]
items! { impl_non_value![U 16, usize]; impl_non_value![I 16, isize]; }
#[cfg(target_pointer_width = "32")]
items! { impl_non_value![U 32, usize]; impl_non_value![I 32, isize]; }
#[cfg(target_pointer_width = "64")]
items! { impl_non_value![U 64, usize]; impl_non_value![I 64, isize]; }
#[cfg(target_pointer_width = "128")]
items! { impl_non_value![U 128, usize]; impl_non_value![I 128, isize]; }
#[doc = crate::_doc_location!("num/grain/niche")]
macro_rules! impl_non_value {
(I $bits:literal, $IP:ty) => { impl_non_value![@MIN, "A signed", i, $bits, $IP]; };
(U $bits:literal, $IP:ty) => { impl_non_value![@MAX, "An unsigned", u, $bits, $IP]; };
(@$XTR:ident, $doc:literal, $s:ident, $b:literal, $IP:ty) => {
$crate::paste!{
impl_non_value![@
[<NonValue $IP:camel>], [<NonZero $IP:camel>], [<NonExtreme $IP:camel>], $XTR,
$doc,
$IP,
$s,
$b
];
}
};
(
// $name: the full name of the new type. E.g. NonValueI8.
// $n0: the full name of the inner NonZero. E.g. NonZeroI8.
// $ne: the full name of the new type. E.g. NonExtremeI8.
//
// $XTR: the *extreme* value constant for this type. (MIN | MAX).
@$name:ident, $n0:ident, $ne:ident, $XTR:ident, $doc:literal, $IP:ty, $s:ident, $b:literal)
=> { $crate::paste! {
pub use [<__impls_ $name >]::*;
#[allow(non_snake_case)]
mod [<__impls_ $name >] {
#[doc = crate::_tags!(num niche)]
#[doc = $doc " integer that is known not to equal some specific value." ]
#[doc = crate::_doc_location!("num/grain/niche")]
#[doc = "It has the same memory layout optimization as [`NonZero<" $IP
">`][crate::NonZero], so that `Option<" $name ">` is the same size as `" $name "`."]
#[doc = "See also [`" $ne "`]."]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $name <const V: $IP>(pub(in crate::num::grain::niche::mem) $crate::$n0);
#[doc = crate::_tags!(num niche)]
#[doc = $doc " integer that is known not to equal its most extreme value ([`"
$XTR "`][" $IP "::" $XTR "])."]
#[doc = crate::_doc_location!("num/grain/niche")]
#[doc = crate::_DOCLINK_CONST_INIT!()]
pub type $ne = $crate::$name <{$IP::$XTR}>;
impl Default for $ne {
fn default() -> Self {
#[cfg(any(feature = "safe_num", not(feature = "unsafe_niche")))]
return $ne::new($IP::default()).unwrap();
#[cfg(all(not(feature = "safe_num"), feature = "unsafe_niche"))]
unsafe { return $ne::new_unchecked($IP::default()); }
}
}
impl<const V: $IP> crate::ConstInit for $name<V> {
const INIT: Self = if V == 0 { Self::MIN } else {
$crate::unwrap![some_guaranteed_or_ub Self::new(0)] };
}
impl<const V: $IP> $name<V> {
pub const MAX: Self = {
if $IP::MAX > V {
$crate::unwrap![some Self::new($IP::MAX)]
} else {
$crate::unwrap![some Self::new($IP::MAX - 1)]
}
};
pub const MIN: Self = {
if $IP::MIN < V {
$crate::unwrap![some Self::new($IP::MIN)]
} else {
$crate::unwrap![some Self::new($IP::MIN + 1)]
}
};
pub const VALID_VALUES: $IP = $IP::MAX;
pub const INVALID_VALUES: $IP = 1;
#[doc = "Returns a `" $name "` with the given `value`,"
" if it is not equal to `V`."]
#[must_use]
pub const fn new(value: $IP) -> Option<Self> {
if $IP::MIN == 0 && V == $IP::MAX { if value == V { return None; }
$crate::is![let Some(nz) = $crate::$n0::new(!value), Some(Self(nz)), None]
} else { $crate::is![let Some(nz) = $crate::$n0::new(value ^ V), Some(Self(nz)), None]
}
}
#[must_use]
pub const fn new_lossy(value: $IP) -> Self {
let transformed = if $IP::MIN == 0 && V == $IP::MAX { let transformed = if value == V { V - 1 } else { value };
!transformed
} else { let transformed =
$crate::is![value == V, $crate::is![V == $IP::MIN, V + 1, V - 1], value];
transformed ^ V
};
#[cfg(any(feature = "safe_num",
not(feature = "unsafe_niche")))]
{ Self($crate::unwrap![some $crate::$n0::new(transformed)]) }
#[cfg(all(not(feature = "safe_num"),
feature = "unsafe_niche"))]
unsafe {
const { if $IP::MIN == 0 && V == $IP::MAX {
assert!(!(V - 1) != 0); } else if V == $IP::MIN {
assert!((V + 1) ^ V != 0); } else {
assert!((V - 1) ^ V != 0); }
}
Self($crate::$n0::new_unchecked(transformed))
}
}
#[doc = "Returns a `" $name "` if the given `value`" " if it is not equal to `V`."]
#[cfg(all(not(feature = "safe_num"), feature = "unsafe_niche"))]
#[cfg_attr(nightly_doc, doc(cfg(feature = "unsafe_niche")))]
pub const unsafe fn new_unchecked(value: $IP) -> Self {
#[cfg(debug_assertions)]
if value == V { panic!("The given value was specifically prohibited.") }
Self(unsafe { $crate::$n0::new_unchecked(value ^ V) })
}
#[must_use]
pub const fn get(&self) -> $IP {
if $IP::MIN == 0 && V == $IP::MAX { !self.0.get()
} else {
self.0.get() ^ V
}
}
#[must_use]
pub const fn is_max(&self) -> bool { self.get() == $IP::MAX }
#[must_use]
pub const fn is_min(&self) -> bool { self.get() == $IP::MIN }
pub const fn checked_add(&self, other: $IP) -> Result<Self, $crate::NicheValueError> {
let res = $crate::unwrap![some_ok_or? self.get().checked_add(other),
$crate::NicheValueError::Overflow(None)];
$crate::unwrap![some_ok_or Self::new(res), $crate::NicheValueError::InvalidValue]
}
pub const fn checked_sub(&self, other: $IP) -> Result<Self, $crate::NicheValueError> {
let res = $crate::unwrap![some_ok_or? self.get().checked_sub(other),
$crate::NicheValueError::Overflow(None)];
$crate::unwrap![some_ok_or Self::new(res), $crate::NicheValueError::InvalidValue]
}
pub const fn strict_add(&self, other: $IP) -> Self {
let res = $crate::unwrap![some self.get().checked_add(other)];
$crate::unwrap![some Self::new(res)]
}
pub const fn strict_sub(&self, other: $IP) -> Self {
let res = $crate::unwrap![some self.get().checked_sub(other)];
$crate::unwrap![some Self::new(res)]
}
pub const fn saturating_add(&self, other: $IP) -> Self {
let res = self.get().saturating_add(other);
$crate::unwrap![some Self::new($crate::is![res == V, res - 1, res])]
}
pub const fn saturating_sub(&self, other: $IP) -> Self {
let res = self.get().saturating_sub(other);
$crate::unwrap![some Self::new($crate::is![res == V, res + 1, res])]
}
pub const fn wrapping_add(&self, other: $IP) -> Self {
let res = self.get().wrapping_add(other);
$crate::unwrap![some Self::new($crate::is![res == V, res + 1, res])]
}
pub const fn wrapping_sub(&self, other: $IP) -> Self {
let res = self.get().wrapping_sub(other);
$crate::unwrap![some Self::new($crate::is![res == V, res - 1, res])]
}
}
$crate::impl_trait! { fmt::Display for $name[const V: $IP][V] |self, f| {
write!(f, "{}", self.get()) } }
$crate::impl_trait! { fmt::Debug for $name[const V: $IP][V] |self, f| {
write!(f, "{}::<{}>({})", stringify!($name), V, self.get()) }}
$crate::impl_trait! { fmt::Binary for $name[const V: $IP][V] |self, f| {
$crate::Binary::fmt(&self.get(), f) }}
$crate::impl_trait! { fmt::Octal for $name[const V: $IP][V] |self, f| {
$crate::Octal::fmt(&self.get(), f) }}
$crate::impl_trait! { fmt::LowerHex for $name[const V: $IP][V] |self, f| {
$crate::LowerHex::fmt(&self.get(), f) }}
$crate::impl_trait! { fmt::UpperHex for $name[const V: $IP][V] |self, f| {
$crate::UpperHex::fmt(&self.get(), f) }}
$crate::impl_trait! { FromStr<$crate::ParseIntError> for $name[const V: $IP][V] |s|
{ Self::new($IP::from_str(s)?) .ok_or_else(|| "".parse::<i32>().unwrap_err()) }}
impl<const V: $IP> From<$name<V>> for $IP {
fn from(value: $name<V>) -> $IP { value.get() }
}
impl<const V: $IP> TryFrom<$IP> for $name<V> {
type Error = $crate::TryFromIntError;
fn try_from(value: $IP) -> Result<Self, Self::Error> {
#[cfg(any(feature = "safe_num",
not(feature = "unsafe_niche")))]
return Self::new(value).ok_or_else(|| i8::try_from(255_u8).unwrap_err());
#[cfg(all(not(feature = "safe_num"),
feature = "unsafe_niche"))]
return Self::new(value)
.ok_or_else(|| unsafe { i8::try_from(255_u8).unwrap_err_unchecked() });
}
}
}
}};
}
use impl_non_value;