beetle_nonzero/
lib.rs

1//! Combines the Rust standard library's `NonZero` types into a single struct
2
3use num_traits::Zero;
4use std::{
5    fmt::Display,
6    num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize},
7    ops::Not,
8};
9
10/// An integer that is known to not equal zero.
11#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
12pub struct NonZero<T> {
13    value: T,
14}
15
16impl<T> Display for NonZero<T>
17where
18    T: Display,
19{
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        write!(f, "{}", self.value)
22    }
23}
24
25impl<T> NonZero<T>
26where
27    T: Zero,
28{
29    /// Returns a new `NonZero<T>` if `value` is nonzero
30    pub fn new(value: T) -> Option<Self> {
31        value.is_zero().not().then_some(Self { value })
32    }
33
34    /// Returns a new `NonZero` without checking that the provided value is nonzero.
35    /// # Safety
36    /// `value` must be known to be nonzero
37    pub const unsafe fn new_unchecked(value: T) -> Self {
38        Self { value }
39    }
40
41    /// Tries replacing the nonzero value with a new one.
42    /// If the new value is nonzero this returns the old value,
43    /// otherwise this returns None.
44    pub fn replace(&mut self, new_value: T) -> Option<T> {
45        let mut other = Self::new(new_value)?;
46        self.swap(&mut other);
47        Some(other.value)
48    }
49
50    /// Sets `self.value` using the provided value.
51    /// Only succeeds if the value provided was nonzero.
52    /// Returns whether the operation succeeded.
53    pub fn set(&mut self, value: T) -> bool {
54        let nonzero = value.is_zero().not();
55        if nonzero {
56            unsafe { self.set_unchecked(value) }
57        }
58        nonzero
59    }
60
61    /// Sets the internal value of the nonzero integer.
62    /// If the value equals zero, this panics.
63    /// # Safety
64    /// `value` must be known to be nonzero
65    pub unsafe fn set_unchecked(&mut self, value: T) {
66        self.value = value;
67    }
68
69    /// Applies a function to the inner value and returns a `NonZero` if the result was nonzero.
70    pub fn map(self, f: impl Fn(T) -> T) -> Option<Self> {
71        Self::new(f(self.value))
72    }
73
74    /// Applies a function to the inner value and returns a `NonZero` if the result was nonzero.
75    /// # Safety
76    /// `f` must return a nonzero integer
77    #[must_use]
78    pub unsafe fn map_unchecked(self, f: impl Fn(T) -> T) -> Self {
79        Self::new_unchecked(f(self.value))
80    }
81
82    /// A reference to the nonzero value
83    pub const fn get(&self) -> &T {
84        &self.value
85    }
86
87    /// A mutable reference to the nonzero value
88    /// # Safety
89    /// The caller must guarantee that the value is nonzero when the mutable reference is dropped
90    #[deprecated(since = "0.3.14", note = "use `swap` instead")]
91    pub const unsafe fn get_mut(&mut self) -> &mut T {
92        &mut self.value
93    }
94
95    /// Swap the nonzero value of two `NonZero`s
96    pub fn swap(&mut self, other: &mut Self) {
97        std::mem::swap(self, other);
98    }
99
100    /// Destructures the `NonZero`, returning the contained value.
101    /// You should probably use [`get`] unless you are trying to avoid cloning.
102    ///
103    /// [`get`]: `NonZero::get`
104    pub fn into_inner(self) -> T {
105        self.value
106    }
107}
108
109macro_rules! impl_from_primitive {
110    ($new_name: ty, $primitive: ty) => {
111        impl From<$primitive> for $new_name {
112            fn from(value: $primitive) -> Self {
113                Self { value: value.get() }
114            }
115        }
116    };
117}
118
119impl_from_primitive!(NonZero<u8>, NonZeroU8);
120impl_from_primitive!(NonZero<u16>, NonZeroU16);
121impl_from_primitive!(NonZero<u32>, NonZeroU32);
122impl_from_primitive!(NonZero<u64>, NonZeroU64);
123impl_from_primitive!(NonZero<u128>, NonZeroU128);
124impl_from_primitive!(NonZero<usize>, NonZeroUsize);