use std::{
fmt::Display,
num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize},
};
use num::{Integer, PrimInt};
use parity_map::{Parity, ParityMap};
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct NonZero<T: PrimInt + Integer> {
value: T,
}
impl<T> Display for NonZero<T>
where
T: PrimInt + Integer + Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get())
}
}
impl<T> ParityMap for NonZero<T>
where
T: PrimInt + Integer,
{
fn parity(&self) -> Parity {
if self.is_even() {
Parity::Even
} else {
Parity::Odd
}
}
}
impl<T: PrimInt + Integer> NonZero<T> {
pub fn new(value: T) -> Option<Self> {
(!value.is_zero()).then(|| unsafe { Self::new_unchecked(value) })
}
pub const unsafe fn new_unchecked(value: T) -> Self {
Self { value }
}
pub const fn get_ref(&self) -> &T {
&self.value
}
pub fn is_even(&self) -> bool {
self.get_ref().is_even()
}
pub fn is_odd(&self) -> bool {
self.get_ref().is_odd()
}
pub fn set_value(&mut self, value: T) {
assert!(!value.is_zero(), "Cannot set a NonZero's value to zero");
unsafe { self.set_value_unchecked(value) }
}
pub unsafe fn set_value_unchecked(&mut self, value: T) {
self.value = value;
}
pub const fn get(&self) -> T {
self.value
}
pub fn map(&self, f: fn(T) -> T) -> Option<Self> {
Self::new(f(self.get()))
}
#[must_use]
pub unsafe fn map_unchecked(&self, f: fn(T) -> T) -> Self {
Self::new_unchecked(f(self.get()))
}
}
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);
#[allow(unused_imports, clippy::unwrap_used)]
mod tests {
use std::ops::Range;
use num::{BigInt, FromPrimitive, One};
use crate::NonZero;
#[test]
fn new_works() {
assert!(NonZero::new(1u8).is_some());
assert!(NonZero::new(1u16).is_some());
assert!(NonZero::new(1u32).is_some());
assert!(NonZero::new(1u64).is_some());
assert!(NonZero::new(1u128).is_some());
assert!(NonZero::new(1usize).is_some());
}
}