Skip to main content

nonany/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3
4/// An error type used to differentiate between overflow and niche errors.
5#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
6pub enum CheckedError {
7    Overflow,
8    Niche,
9}
10
11macro_rules! nonany {
12    ($name:ident, $nonzero:ident, $int:ty, $signed:ident) => {
13        /// An integer that is known not to equal `NICHE`.
14        /// 
15        /// This enables some memory layout optimization.
16        #[doc = concat!("For example, `Option<", stringify!($name), "<0>>` is the same size as `", stringify!($int), "`:")]
17        ///
18        /// ```rust
19        #[doc = concat!("assert_eq!(core::mem::size_of::<Option<nonany::", stringify!($name), "<0>>>(), core::mem::size_of::<", stringify!($int), ">());")]
20        /// ```
21        #[derive(Clone, Copy, Eq, Hash, PartialEq)]
22        pub struct $name<const NICHE: $int>(core::num::$nonzero);
23
24        impl<const NICHE: $int> $name<NICHE> {
25            /// The niche value of this integer type.
26            pub const NICHE: $int = NICHE;
27
28            /// The size of this integer type in bits.
29            pub const BITS: u32 = <$int>::BITS;
30
31            /// Creates a non-any if the given value is not `NICHE`.
32            pub const fn new(value: $int) -> Option<Self> {
33                match core::num::$nonzero::new(value ^ NICHE) {
34                    Some(value) => Some(Self(value)),
35                    None => None
36                }
37            }
38
39            /// Creates a non-any without checking whether the value is `NICHE`.
40            /// This results in undefined behaviour if the value is `NICHE`.
41            ///
42            /// # Safety
43            ///
44            /// The value must not be `NICHE`.
45            pub const unsafe fn new_unchecked(value: $int) -> Self {
46                Self(core::num::$nonzero::new_unchecked(value ^ NICHE))
47            }
48    
49            /// Returns the contained value as a primitive type.
50            pub const fn get(self) -> $int {
51                self.0.get() ^ NICHE
52            }
53
54            nonany!(@$signed, $name, $nonzero, $int);
55        }
56
57        impl<const NICHE: $int> core::cmp::PartialOrd for $name<NICHE> {
58            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
59                Some(self.cmp(other))
60            }
61        }
62
63        impl<const NICHE: $int> core::cmp::Ord for $name<NICHE> {
64            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
65                self.get().cmp(&other.get())
66            }
67        }
68
69        impl<const NICHE: $int> core::fmt::Debug for $name<NICHE> {
70            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71                core::fmt::Debug::fmt(&self.get(), f)
72            }
73        }
74
75        impl<const NICHE: $int> core::fmt::Display for $name<NICHE> {
76            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77                core::fmt::Display::fmt(&self.get(), f)
78            }
79        }
80
81        impl<const NICHE: $int> core::fmt::UpperHex for $name<NICHE> {
82            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83                core::fmt::UpperHex::fmt(&self.get(), f)
84            }
85        }
86
87        impl<const NICHE: $int> core::fmt::LowerHex for $name<NICHE> {
88            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89                core::fmt::LowerHex::fmt(&self.get(), f)
90            }
91        }
92
93        impl<const NICHE: $int> core::fmt::Octal for $name<NICHE> {
94            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95                core::fmt::Octal::fmt(&self.get(), f)
96            }
97        }
98
99        impl<const NICHE: $int> core::fmt::Binary for $name<NICHE> {
100            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101                core::fmt::Binary::fmt(&self.get(), f)
102            }
103        }
104
105        impl<const NICHE: $int> core::fmt::LowerExp for $name<NICHE> {
106            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107                core::fmt::LowerExp::fmt(&self.get(), f)
108            }
109        }
110
111        impl<const NICHE: $int> core::fmt::UpperExp for $name<NICHE> {
112            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113                core::fmt::UpperExp::fmt(&self.get(), f)
114            }
115        }
116    };
117
118    (@signed, $name:ident, $nonzero:ident, $int:ty) => {
119        pub const fn abs(self) -> Option<Self> {
120            let value = self.get().abs();
121            Self::new(value)
122        }
123
124        pub const fn checked_abs(self) -> Result<Self, CheckedError> {
125            match self.get().checked_abs() {
126                Some(value) => match Self::new(value) {
127                    Some(value) => Ok(value),
128                    None => Err(CheckedError::Niche)
129                },
130                None => Err(CheckedError::Overflow)
131            }
132        }
133
134        pub const fn is_positive(self) -> bool {
135            self.get().is_positive()
136        }
137
138        pub const fn is_negative(self) -> bool {
139            self.get().is_negative()
140        }
141    };
142    
143
144    (@unsigned, $name:ident, $nonzero:ident, $int:ty) => {
145        
146    };
147}
148
149nonany!(NonAnyI8, NonZeroI8, i8, signed);
150nonany!(NonAnyI16, NonZeroI16, i16, signed);
151nonany!(NonAnyI32, NonZeroI32, i32, signed);
152nonany!(NonAnyI64, NonZeroI64, i64, signed);
153nonany!(NonAnyI128, NonZeroI128, i128, signed);
154nonany!(NonAnyIsize, NonZeroIsize, isize, signed);
155
156nonany!(NonAnyU8, NonZeroU8, u8, unsigned);
157nonany!(NonAnyU16, NonZeroU16, u16, unsigned);
158nonany!(NonAnyU32, NonZeroU32, u32, unsigned);
159nonany!(NonAnyU64, NonZeroU64, u64, unsigned);
160nonany!(NonAnyU128, NonZeroU128, u128, unsigned);
161nonany!(NonAnyUsize, NonZeroUsize, usize, unsigned);
162
163macro_rules! nonany_tryfrom_int {
164    ($nonany:ident, $to_int:ty) => {
165        nonany_tryfrom_int!($nonany, $to_int, i8);
166        nonany_tryfrom_int!($nonany, $to_int, i16);
167        nonany_tryfrom_int!($nonany, $to_int, i32);
168        nonany_tryfrom_int!($nonany, $to_int, i64);
169        nonany_tryfrom_int!($nonany, $to_int, i128);
170        nonany_tryfrom_int!($nonany, $to_int, isize);
171        nonany_tryfrom_int!($nonany, $to_int, u8);
172        nonany_tryfrom_int!($nonany, $to_int, u16);
173        nonany_tryfrom_int!($nonany, $to_int, u32);
174        nonany_tryfrom_int!($nonany, $to_int, u64);
175        nonany_tryfrom_int!($nonany, $to_int, u128);
176        nonany_tryfrom_int!($nonany, $to_int, usize);
177    };
178
179    ($nonany:ident, $to_int:ty, $from_int:ty) => {
180        impl<const NICHE: $to_int> core::convert::TryFrom<$from_int> for $crate::$nonany<NICHE> {
181            type Error = $crate::CheckedError;    
182            fn try_from(value: $from_int) -> Result<Self, Self::Error> {
183                match core::convert::TryInto::<$to_int>::try_into(value) {
184                    Ok(value) => match Self::new(value) {
185                        Some(value) => Ok(value),
186                        None => Err(CheckedError::Niche)
187                    },
188                    Err(_) => Err(CheckedError::Overflow)
189                }
190            }
191        }
192    };
193}
194
195nonany_tryfrom_int!(NonAnyI8, i8);
196nonany_tryfrom_int!(NonAnyI16, i16);
197nonany_tryfrom_int!(NonAnyI32, i32);
198nonany_tryfrom_int!(NonAnyI64, i64);
199nonany_tryfrom_int!(NonAnyI128, i128);
200nonany_tryfrom_int!(NonAnyIsize, isize);
201
202nonany_tryfrom_int!(NonAnyU8, u8);
203nonany_tryfrom_int!(NonAnyU16, u16);
204nonany_tryfrom_int!(NonAnyU32, u32);
205nonany_tryfrom_int!(NonAnyU64, u64);
206nonany_tryfrom_int!(NonAnyU128, u128);
207nonany_tryfrom_int!(NonAnyUsize, usize);
208
209macro_rules! nonany_tryfrom_nonany {
210    ($to_nonany:tt, $to_int:tt) => {
211        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyI8, i8);
212        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyI16, i16);
213        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyI32, i32);
214        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyI64, i64);
215        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyI128, i128);
216        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyIsize, isize);
217        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyU8, u8);
218        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyU16, u16);
219        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyU32, u32);
220        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyU64, u64);
221        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyU128, u128);
222        nonany_tryfrom_nonany!($to_nonany, $to_int, NonAnyUsize, usize);
223    };
224
225    (NonAnyI8, i8, NonAnyI8, i8) => { };
226    (NonAnyI16, i16, NonAnyI16, i16) => { };
227    (NonAnyI32, i32, NonAnyI32, i32) => { };
228    (NonAnyI64, i64, NonAnyI64, i64) => { };
229    (NonAnyI128, i128, NonAnyI128, i128) => { };
230    (NonAnyIsize, isize, NonAnyIsize, isize) => { };
231    (NonAnyU8, u8, NonAnyU8, u8) => { };
232    (NonAnyU16, u16, NonAnyU16, u16) => { };
233    (NonAnyU32, u32, NonAnyU32, u32) => { };
234    (NonAnyU64, u64, NonAnyU64, u64) => { };
235    (NonAnyU128, u128, NonAnyU128, u128) => { };
236    (NonAnyUsize, usize, NonAnyUsize, usize) => { };
237
238    ($to_nonany:ident, $to_int:ty, $from_nonany:ident, $from_int:ty) => {
239        impl<const TO_NICHE: $to_int, const FROM_NICHE: $from_int> core::convert::TryFrom<$crate::$from_nonany<FROM_NICHE>> for $crate::$to_nonany<TO_NICHE> {
240            type Error = $crate::CheckedError;    
241            fn try_from(value: $crate::$from_nonany<FROM_NICHE>) -> Result<Self, Self::Error> {
242                match core::convert::TryInto::<$to_int>::try_into(value.get()) {
243                    Ok(value) => match Self::new(value) {
244                        Some(value) => Ok(value),
245                        None => Err(CheckedError::Niche)
246                    },
247                    Err(_) => Err(CheckedError::Overflow)
248                }
249            }
250        }
251    };
252}
253
254nonany_tryfrom_nonany!(NonAnyI8, i8);
255nonany_tryfrom_nonany!(NonAnyI16, i16);
256nonany_tryfrom_nonany!(NonAnyI32, i32);
257nonany_tryfrom_nonany!(NonAnyI64, i64);
258nonany_tryfrom_nonany!(NonAnyI128, i128);
259nonany_tryfrom_nonany!(NonAnyIsize, isize);
260
261nonany_tryfrom_nonany!(NonAnyU8, u8);
262nonany_tryfrom_nonany!(NonAnyU16, u16);
263nonany_tryfrom_nonany!(NonAnyU32, u32);
264nonany_tryfrom_nonany!(NonAnyU64, u64);
265nonany_tryfrom_nonany!(NonAnyU128, u128);
266nonany_tryfrom_nonany!(NonAnyUsize, usize);
267
268macro_rules! nonany_tryfrom_nonzero {
269    ($to_nonany:tt, $to_int:tt) => {
270        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroI8, i8);
271        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroI16, i16);
272        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroI32, i32);
273        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroI64, i64);
274        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroI128, i128);
275        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroIsize, isize);
276        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroU8, u8);
277        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroU16, u16);
278        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroU32, u32);
279        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroU64, u64);
280        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroU128, u128);
281        nonany_tryfrom_nonzero!($to_nonany, $to_int, NonZeroUsize, usize);
282    };
283
284    ($to_nonany:ident, $to_int:ty, $from_nonzero:ident, $from_int:ty) => {
285        impl<const NICHE: $to_int> core::convert::TryFrom<core::num::$from_nonzero> for $crate::$to_nonany<NICHE> {
286            type Error = $crate::CheckedError;    
287            fn try_from(value: core::num::$from_nonzero) -> Result<Self, Self::Error> {
288                match core::convert::TryInto::<$to_int>::try_into(value.get()) {
289                    Ok(value) => match Self::new(value) {
290                        Some(value) => Ok(value),
291                        None => Err(CheckedError::Niche)
292                    },
293                    Err(_) => Err(CheckedError::Overflow)
294                }
295            }
296        }
297    };
298}
299
300nonany_tryfrom_nonzero!(NonAnyI8, i8);
301nonany_tryfrom_nonzero!(NonAnyI16, i16);
302nonany_tryfrom_nonzero!(NonAnyI32, i32);
303nonany_tryfrom_nonzero!(NonAnyI64, i64);
304nonany_tryfrom_nonzero!(NonAnyI128, i128);
305nonany_tryfrom_nonzero!(NonAnyIsize, isize);
306
307nonany_tryfrom_nonzero!(NonAnyU8, u8);
308nonany_tryfrom_nonzero!(NonAnyU16, u16);
309nonany_tryfrom_nonzero!(NonAnyU32, u32);
310nonany_tryfrom_nonzero!(NonAnyU64, u64);
311nonany_tryfrom_nonzero!(NonAnyU128, u128);
312nonany_tryfrom_nonzero!(NonAnyUsize, usize);
313
314macro_rules! nonany_typedef {
315    ($nonzero:ident, $nonmin:ident, $nonmax:ident, $nonany:ident, $int:ident) => {
316        /// An integer that is known not to equal zero.
317        pub type $nonzero = $nonany<0>;
318
319        #[doc = concat!("An integer that is known not to equal `", stringify!($int), "::MIN`.")]
320        pub type $nonmin = $nonany<{ $int::MIN }>;
321
322        #[doc = concat!("An integer that is known not to equal `", stringify!($int), "::MAX`.")]
323        pub type $nonmax = $nonany<{ $int::MAX }>;
324    }
325}
326
327nonany_typedef!(NonZeroI8, NonMinI8, NonMaxI8, NonAnyI8, i8);
328nonany_typedef!(NonZeroI16, NonMinI16, NonMaxI16, NonAnyI16, i16);
329nonany_typedef!(NonZeroI32, NonMinI32, NonMaxI32, NonAnyI32, i32);
330nonany_typedef!(NonZeroI64, NonMinI64, NonMaxI64, NonAnyI64, i64);
331nonany_typedef!(NonZeroI128, NonMinI128, NonMaxI128, NonAnyI128, i128);
332nonany_typedef!(NonZeroIsize, NonMinIsize, NonMaxIsize, NonAnyIsize, isize);
333
334nonany_typedef!(NonZeroU8, NonMinU8, NonMaxU8, NonAnyU8, u8);
335nonany_typedef!(NonZeroU16, NonMinU16, NonMaxU16, NonAnyU16, u16);
336nonany_typedef!(NonZeroU32, NonMinU32, NonMaxU32, NonAnyU32, u32);
337nonany_typedef!(NonZeroU64, NonMinU64, NonMaxU64, NonAnyU64, u64);
338nonany_typedef!(NonZeroU128, NonMinU128, NonMaxU128, NonAnyU128, u128);
339nonany_typedef!(NonZeroUsize, NonMinUsize, NonMaxUsize, NonAnyUsize, usize);
340
341#[cfg(test)]
342mod tests;