1#![no_std]
2#![doc = include_str!("../README.md")]
3
4#[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 #[doc = concat!("For example, `Option<", stringify!($name), "<0>>` is the same size as `", stringify!($int), "`:")]
17 #[doc = concat!("assert_eq!(core::mem::size_of::<Option<nonany::", stringify!($name), "<0>>>(), core::mem::size_of::<", stringify!($int), ">());")]
20 #[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 pub const NICHE: $int = NICHE;
27
28 pub const BITS: u32 = <$int>::BITS;
30
31 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 pub const unsafe fn new_unchecked(value: $int) -> Self {
46 Self(core::num::$nonzero::new_unchecked(value ^ NICHE))
47 }
48
49 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 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;