Skip to main content

ordinal_map/ordinal/impls/
non_zero.rs

1use std::num::NonZeroI16;
2use std::num::NonZeroI32;
3use std::num::NonZeroI64;
4use std::num::NonZeroI8;
5use std::num::NonZeroIsize;
6use std::num::NonZeroU16;
7use std::num::NonZeroU32;
8use std::num::NonZeroU64;
9use std::num::NonZeroU8;
10use std::num::NonZeroUsize;
11
12use crate::Ordinal;
13
14impl Ordinal for NonZeroU8 {
15    const ORDINAL_SIZE: usize = u8::MAX as usize;
16
17    #[inline]
18    fn ordinal(&self) -> usize {
19        self.get() as usize - 1
20    }
21
22    #[inline]
23    fn from_ordinal(ordinal: usize) -> Option<Self> {
24        NonZeroU8::try_from(u8::try_from(ordinal.checked_add(1)?).ok()?).ok()
25    }
26}
27
28impl Ordinal for NonZeroI8 {
29    const ORDINAL_SIZE: usize = NonZeroU8::ORDINAL_SIZE;
30
31    #[inline]
32    fn ordinal(&self) -> usize {
33        if self.get() > 0 {
34            127 + self.get() as usize
35        } else {
36            self.get().abs_diff(i8::MIN) as usize
37        }
38    }
39
40    #[inline]
41    fn from_ordinal(ordinal: usize) -> Option<Self> {
42        match ordinal.checked_sub(i8::MAX as usize + 1) {
43            None => NonZeroI8::new(
44                i8::MIN
45                    .checked_add_unsigned(u8::try_from(ordinal).unwrap())
46                    .unwrap(),
47            ),
48            Some(rem) => NonZeroI8::new(i8::try_from(rem + 1).ok()?),
49        }
50    }
51}
52
53impl Ordinal for NonZeroU16 {
54    const ORDINAL_SIZE: usize = u16::MAX as usize;
55
56    #[inline]
57    fn ordinal(&self) -> usize {
58        self.get() as usize - 1
59    }
60
61    #[inline]
62    fn from_ordinal(ordinal: usize) -> Option<Self> {
63        NonZeroU16::try_from(u16::try_from(ordinal.checked_add(1)?).ok()?).ok()
64    }
65}
66
67impl Ordinal for NonZeroI16 {
68    const ORDINAL_SIZE: usize = NonZeroU16::ORDINAL_SIZE;
69
70    #[inline]
71    fn ordinal(&self) -> usize {
72        if self.get() > 0 {
73            32767 + self.get() as usize
74        } else {
75            self.get().abs_diff(i16::MIN) as usize
76        }
77    }
78
79    #[inline]
80    fn from_ordinal(ordinal: usize) -> Option<Self> {
81        match ordinal.checked_sub(i16::MAX as usize + 1) {
82            None => NonZeroI16::new(
83                i16::MIN
84                    .checked_add_unsigned(u16::try_from(ordinal).unwrap())
85                    .unwrap(),
86            ),
87            Some(rem) => NonZeroI16::new(i16::try_from(rem + 1).ok()?),
88        }
89    }
90}
91
92impl Ordinal for NonZeroU32 {
93    const ORDINAL_SIZE: usize = u32::MAX as usize;
94
95    #[inline]
96    fn ordinal(&self) -> usize {
97        self.get() as usize - 1
98    }
99
100    #[inline]
101    fn from_ordinal(ordinal: usize) -> Option<Self> {
102        NonZeroU32::try_from(u32::try_from(ordinal.checked_add(1)?).ok()?).ok()
103    }
104}
105
106impl Ordinal for NonZeroI32 {
107    const ORDINAL_SIZE: usize = NonZeroU32::ORDINAL_SIZE;
108
109    #[inline]
110    fn ordinal(&self) -> usize {
111        if self.get() > 0 {
112            2147483647 + self.get() as usize
113        } else {
114            self.get().abs_diff(i32::MIN) as usize
115        }
116    }
117
118    #[inline]
119    fn from_ordinal(ordinal: usize) -> Option<Self> {
120        match ordinal.checked_sub(i32::MAX as usize + 1) {
121            None => NonZeroI32::new(
122                i32::MIN
123                    .checked_add_unsigned(u32::try_from(ordinal).unwrap())
124                    .unwrap(),
125            ),
126            Some(rem) => NonZeroI32::new(i32::try_from(rem + 1).ok()?),
127        }
128    }
129}
130
131impl Ordinal for NonZeroUsize {
132    const ORDINAL_SIZE: usize = usize::MAX;
133
134    #[inline]
135    fn ordinal(&self) -> usize {
136        self.get() - 1
137    }
138
139    #[inline]
140    fn from_ordinal(ordinal: usize) -> Option<Self> {
141        NonZeroUsize::new(ordinal.checked_add(1)?)
142    }
143}
144
145impl Ordinal for NonZeroIsize {
146    const ORDINAL_SIZE: usize = NonZeroUsize::ORDINAL_SIZE;
147
148    #[inline]
149    fn ordinal(&self) -> usize {
150        if self.get() > 0 {
151            usize::MAX / 2 + self.get() as usize
152        } else {
153            self.get().abs_diff(isize::MIN)
154        }
155    }
156
157    #[inline]
158    fn from_ordinal(ordinal: usize) -> Option<Self> {
159        match ordinal.checked_sub(isize::MAX as usize + 1) {
160            None => NonZeroIsize::new(isize::MIN.checked_add_unsigned(ordinal).unwrap()),
161            Some(rem) => NonZeroIsize::new(isize::try_from(rem + 1).ok()?),
162        }
163    }
164}
165
166/// It is compile-time error to use this impl on 32-bit platforms.
167impl Ordinal for NonZeroU64 {
168    const ORDINAL_SIZE: usize = if u64::MAX == usize::MAX as u64 {
169        usize::MAX
170    } else {
171        panic!("NonZeroU64::ORDINAL_SIZE is too large for 32-bit platforms")
172    };
173
174    fn ordinal(&self) -> usize {
175        const { Self::ORDINAL_SIZE };
176        NonZeroUsize::new(self.get() as usize).unwrap().ordinal()
177    }
178
179    fn from_ordinal(ordinal: usize) -> Option<Self> {
180        const { Self::ORDINAL_SIZE };
181        Some(NonZeroU64::new(NonZeroUsize::from_ordinal(ordinal)?.get() as u64).unwrap())
182    }
183}
184
185impl Ordinal for NonZeroI64 {
186    const ORDINAL_SIZE: usize = NonZeroU64::ORDINAL_SIZE;
187
188    fn ordinal(&self) -> usize {
189        const { Self::ORDINAL_SIZE };
190        NonZeroIsize::new(self.get() as isize).unwrap().ordinal()
191    }
192
193    fn from_ordinal(ordinal: usize) -> Option<Self> {
194        const { Self::ORDINAL_SIZE };
195        Some(NonZeroI64::new(NonZeroIsize::from_ordinal(ordinal)?.get() as i64).unwrap())
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use std::num::NonZeroI16;
202    use std::num::NonZeroI32;
203    use std::num::NonZeroI64;
204    use std::num::NonZeroI8;
205    use std::num::NonZeroIsize;
206    use std::num::NonZeroU16;
207    use std::num::NonZeroU64;
208    use std::num::NonZeroU8;
209    use std::num::NonZeroUsize;
210
211    use crate::tests::util::test_ordinal;
212    use crate::tests::util::test_ordinal_some;
213    use crate::tests::util::test_ordinal_value;
214
215    #[test]
216    fn test_non_zero_u8() {
217        test_ordinal((1..=u8::MAX).map(|i| NonZeroU8::new(i).unwrap()));
218    }
219
220    #[test]
221    fn test_non_zero_i8() {
222        test_ordinal((i8::MIN..=i8::MAX).filter_map(NonZeroI8::new));
223    }
224
225    #[test]
226    fn test_non_zero_u16() {
227        test_ordinal((1..=u16::MAX).map(|i| NonZeroU16::new(i).unwrap()));
228    }
229
230    #[test]
231    fn test_non_zero_i16() {
232        test_ordinal((i16::MIN..=i16::MAX).filter_map(NonZeroI16::new));
233    }
234
235    #[test]
236    fn test_non_zero_u32() {
237        test_ordinal_some::<u32>();
238    }
239
240    #[test]
241    fn test_non_zero_i32() {
242        test_ordinal_some::<i32>();
243        test_ordinal_value(NonZeroI32::new(-1));
244        test_ordinal_value(NonZeroI32::new(1));
245    }
246
247    #[test]
248    fn test_non_zero_u64() {
249        if cfg!(target_pointer_width = "64") {
250            test_ordinal_some::<NonZeroU64>();
251        }
252    }
253
254    #[test]
255    fn test_non_zero_i64() {
256        if cfg!(target_pointer_width = "64") {
257            test_ordinal_some::<NonZeroI64>();
258            test_ordinal_value(NonZeroI64::new(-1));
259            test_ordinal_value(NonZeroI64::new(1));
260        }
261    }
262
263    #[test]
264    fn test_non_zero_usize() {
265        test_ordinal_some::<NonZeroUsize>();
266    }
267
268    #[test]
269    fn test_non_zero_isize() {
270        test_ordinal_some::<NonZeroIsize>();
271        test_ordinal_value(NonZeroIsize::new(-1));
272        test_ordinal_value(NonZeroIsize::new(1));
273    }
274}