use num_traits::Zero;
use std::{
fmt::Display,
num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize},
ops::Not,
};
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct NonZero<T> {
value: T,
}
impl<T> Display for NonZero<T>
where
T: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)
}
}
impl<T> NonZero<T>
where
T: Zero,
{
pub fn new(value: T) -> Option<Self> {
value.is_zero().not().then_some(Self { value })
}
pub const unsafe fn new_unchecked(value: T) -> Self {
Self { value }
}
pub fn replace(&mut self, new_value: T) -> Option<T> {
let mut other = Self::new(new_value)?;
self.swap(&mut other);
Some(other.value)
}
pub fn set(&mut self, value: T) -> bool {
let nonzero = value.is_zero().not();
if nonzero {
unsafe { self.set_unchecked(value) }
}
nonzero
}
pub unsafe fn set_unchecked(&mut self, value: T) {
self.value = value;
}
pub fn map(self, f: impl Fn(T) -> T) -> Option<Self> {
Self::new(f(self.value))
}
#[must_use]
pub unsafe fn map_unchecked(self, f: impl Fn(T) -> T) -> Self {
Self::new_unchecked(f(self.value))
}
pub const fn get(&self) -> &T {
&self.value
}
#[deprecated(since = "0.3.14", note = "use `swap` instead")]
pub const unsafe fn get_mut(&mut self) -> &mut T {
&mut self.value
}
pub fn swap(&mut self, other: &mut Self) {
std::mem::swap(self, other);
}
pub fn into_inner(self) -> T {
self.value
}
}
macro_rules! impl_from_primitive {
($new_name: ty, $primitive: ty) => {
impl From<$primitive> for $new_name {
fn from(value: $primitive) -> Self {
Self { value: value.get() }
}
}
};
}
impl_from_primitive!(NonZero<u8>, NonZeroU8);
impl_from_primitive!(NonZero<u16>, NonZeroU16);
impl_from_primitive!(NonZero<u32>, NonZeroU32);
impl_from_primitive!(NonZero<u64>, NonZeroU64);
impl_from_primitive!(NonZero<u128>, NonZeroU128);
impl_from_primitive!(NonZero<usize>, NonZeroUsize);