linearize/impls/
integers.rs

1#![allow(unexpected_cfgs)]
2
3use {crate::Linearize, cfg_if::cfg_if};
4
5macro_rules! impls {
6    ($unsigned:ty, $signed:ty, $test:ident) => {
7        // SAFETY:
8        // - Storage and CopyStorage have the required type.
9        // - linearize and from_linear_unchecked behave as required.
10        unsafe impl Linearize for $unsigned {
11            type Storage<T> = [T; Self::LENGTH];
12            type CopyStorage<T>
13                = [T; Self::LENGTH]
14            where
15                T: Copy;
16            const LENGTH: usize = <$unsigned>::MAX as usize + 1;
17
18            #[inline]
19            fn linearize(&self) -> usize {
20                *self as usize
21            }
22
23            #[inline]
24            unsafe fn from_linear_unchecked(linear: usize) -> Self
25            where
26                Self: Sized,
27            {
28                linear as $unsigned
29            }
30        }
31
32        // SAFETY:
33        // - Storage and CopyStorage have the required type.
34        // - linearize and from_linear_unchecked behave as required.
35        unsafe impl Linearize for $signed {
36            type Storage<T> = [T; Self::LENGTH];
37            type CopyStorage<T>
38                = [T; Self::LENGTH]
39            where
40                T: Copy;
41            const LENGTH: usize = <$unsigned>::MAX as usize + 1;
42
43            #[inline]
44            fn linearize(&self) -> usize {
45                (*self as $unsigned).wrapping_sub(<$signed>::MIN as $unsigned) as usize
46            }
47
48            #[inline]
49            unsafe fn from_linear_unchecked(linear: usize) -> Self {
50                (linear as $unsigned).wrapping_add(<$signed>::MIN as $unsigned) as $signed
51            }
52        }
53
54        impl_assert!($unsigned);
55        impl_assert!($signed);
56
57        #[cfg(test)]
58        static_assertions::const_assert_eq! {
59            <$unsigned>::LENGTH,
60            <$unsigned>::MAX as usize + 1,
61        }
62
63        #[cfg(test)]
64        static_assertions::const_assert_eq! {
65            <$signed>::LENGTH,
66            <$unsigned>::MAX as usize + 1,
67        }
68
69        #[test]
70        fn $test() {
71            let umin = <$unsigned>::MIN;
72            let umax = <$unsigned>::MAX;
73            let umid = umax / 2;
74            assert_eq!(umin.linearize(), umin as usize);
75            assert_eq!(umax.linearize(), umax as usize);
76            assert_eq!(umid.linearize(), umid as usize);
77            unsafe {
78                assert_eq!(<$unsigned>::from_linear_unchecked(umin.linearize()), umin);
79                assert_eq!(<$unsigned>::from_linear_unchecked(umax.linearize()), umax);
80                assert_eq!(<$unsigned>::from_linear_unchecked(umid.linearize()), umid);
81            }
82            let imin = <$signed>::MIN;
83            let imax = <$signed>::MAX;
84            let imid = 0 as $signed;
85            let imin_lin = imin.linearize();
86            let imax_lin = imax.linearize();
87            let imid_lin = imid.linearize();
88            assert_eq!(imax_lin, umax as usize);
89            assert_eq!(imin_lin, umin as usize);
90            assert_eq!(imid_lin, umid as usize + 1);
91            unsafe {
92                assert_eq!(<$signed>::from_linear_unchecked(imax_lin), imax);
93                assert_eq!(<$signed>::from_linear_unchecked(imin_lin), imin);
94                assert_eq!(<$signed>::from_linear_unchecked(imid_lin), imid);
95            }
96        }
97    };
98}
99
100cfg_if! {
101    if #[cfg(not(target_pointer_width = "8"))] {
102        impls!(u8, i8, test_u8);
103        cfg_if! {
104            if #[cfg(not(target_pointer_width = "16"))] {
105                impls!(u16, i16, test_u16);
106                cfg_if! {
107                    if #[cfg(not(target_pointer_width = "32"))] {
108                        impls!(u32, i32, test_u32);
109                        cfg_if! {
110                            if #[cfg(not(target_pointer_width = "64"))] {
111                                impls!(u64, i64, test_u64);
112                                cfg_if! {
113                                    if #[cfg(not(target_pointer_width = "128"))] {
114                                        impls!(u128, i128, test_u128);
115                                    }
116                                }
117                            }
118                        }
119                    }
120                }
121            }
122        }
123    }
124}