treena/
nonmax.rs

1//! `NonMaxUsize` for node ID.
2
3use core::cmp::Ordering;
4use core::fmt;
5
6/// Implements formatting traits under `core::fmt` for a non-max integer type.
7macro_rules! impl_fmt {
8    ($ty:ty, $($trait:ident),*) => {
9        $(
10            impl fmt::$trait for $ty {
11                #[inline]
12                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13                    self.get().fmt(f)
14                }
15            }
16        )*
17    };
18}
19
20/// Defines a non-max type and implements necessary traits.
21macro_rules! define_type {
22    ($ty:ident, $backend:ty, $tyint:ident) => {
23        #[doc = concat!("`", stringify!($tyint), "`")]
24        ///  that is known not to equal
25        #[doc = concat!(" `", stringify!($tyint), "::MAX`")]
26        /// .
27        ///
28        #[doc = concat!("`Option<", stringify!($ty), ">`")]
29        ///  is guaranteed to be the same size as
30        #[doc = concat!("`", stringify!($ty), "`")]
31        ///  itself.
32        #[derive(Clone, Copy, PartialEq, Eq, Hash)]
33        #[repr(transparent)]
34        pub(crate) struct $ty($backend);
35
36        impl $ty {
37            /// Creates a non-max
38            #[doc = concat!("`", stringify!($tyint), "`")]
39            ///  value.
40            #[inline]
41            #[must_use]
42            pub(crate) fn new(n: usize) -> Option<Self> {
43                <$tyint>::try_from(n)
44                    .ok()
45                    .and_then(|n| <$backend>::new(!n))
46                    .map(Self)
47            }
48
49            /// Returns the value as a `usize` type value.
50            #[inline]
51            #[must_use]
52            pub(crate) const fn get(self) -> usize {
53                // The internal value must be representable by `usize`, since the
54                // value should be created from `usize` by `Self::new` method.
55                !self.0.get() as usize
56            }
57        }
58
59        impl Default for $ty {
60            fn default() -> Self {
61                Self::new(0).expect("[validity] 0 is not the max value of the internal integer")
62            }
63        }
64
65        impl Ord for $ty {
66            #[inline]
67            fn cmp(&self, other: &Self) -> Ordering {
68                self.0.cmp(&other.0).reverse()
69            }
70        }
71
72        impl PartialOrd for $ty {
73            #[inline]
74            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
75                Some(self.cmp(other))
76            }
77        }
78
79        impl_fmt!($ty, Debug, Display, Binary, Octal, LowerHex, UpperHex);
80    };
81}
82
83define_type!(NonMaxU8, core::num::NonZeroU8, u8);
84define_type!(NonMaxU16, core::num::NonZeroU16, u16);
85define_type!(NonMaxU32, core::num::NonZeroU32, u32);
86define_type!(NonMaxU64, core::num::NonZeroU64, u64);
87define_type!(NonMaxUsize, core::num::NonZeroUsize, usize);
88
89#[cfg(test)]
90mod tests {
91    use super::NonMaxUsize;
92
93    use core::mem::size_of;
94
95    #[test]
96    fn types_size() {
97        assert_eq!(
98            size_of::<NonMaxUsize>(),
99            size_of::<usize>(),
100            "`NonMaxUsize` should be same size as `usize`"
101        );
102        assert_eq!(
103            size_of::<Option<NonMaxUsize>>(),
104            size_of::<NonMaxUsize>(),
105            "`Option<NonMaxUsize>` should be same size as `NonMaxUsize`"
106        );
107    }
108}