Skip to main content

intid_core/
impls.rs

1//! Implementations of [`IntegerId`](crate::IntegerId) for foreign types.
2
3macro_rules! impl_primint {
4    ($($target:ident),*) => {$(
5        impl crate::IntegerId for $target {
6            type Int = $target;
7            const MIN_ID: Option<Self> = Some(0);
8            const MAX_ID: Option<Self> = Some($target::MAX);
9            const MIN_ID_INT: Option<Self::Int> = Some(0);
10            const MAX_ID_INT: Option<Self::Int> = Some($target::MAX);
11            // SAFETY: Range is correct
12            const TRUSTED_RANGE: Option<crate::trusted::TrustedRangeToken<Self>> = unsafe { Some(crate::trusted::TrustedRangeToken::assume_valid()) };
13            #[inline]
14            fn from_int_checked(id: Self::Int) -> Option<Self> {
15                Some(id)
16            }
17            #[inline]
18            fn to_int(self) -> Self::Int {
19                self
20            }
21        }
22        impl crate::IntegerIdContiguous for $target {}
23        impl crate::IntegerIdCounter for $target {
24            const START: Self = 0;
25            const START_INT: Self = 0;
26        }
27    )*};
28}
29impl_primint!(u8, u16, u32, u64, u128, usize);
30// Can't use generic NonZero, because that requires Rust 1.79
31macro_rules! impl_nonzero_int {
32    (@main_body $target:path, $int:ident, one => $one:expr, max => $max:expr) => {
33        type Int = $int;
34        const MIN_ID: Option<Self> = {
35            // while using NonZero::MIN might be nice, that requires rust 1.70
36            // SAFETY: One is not zero
37            unsafe {
38                Some(<$target>::new_unchecked($one))
39            }
40        };
41        const MAX_ID: Option<Self> = {
42            // SAFETY: Maximum is not zero
43            unsafe {
44                Some(<$target>::new_unchecked($max))
45            }
46        };
47        const MIN_ID_INT: Option<Self::Int> = Some($one);
48        const MAX_ID_INT: Option<Self::Int> = Some($max);
49        // SAFETY: Range is correct
50        const TRUSTED_RANGE: Option<crate::trusted::TrustedRangeToken<Self>> = unsafe { Some(crate::trusted::TrustedRangeToken::assume_valid()) };
51
52        #[inline]
53        fn from_int_checked(id: Self::Int) -> Option<Self> {
54            <$target>::new(id)
55        }
56
57        #[inline]
58        unsafe fn from_int_unchecked(id: Self::Int) -> Self {
59            // SAFETY: Guaranteed by caller
60            unsafe {
61                <$target>::new_unchecked(id)
62            }
63        }
64
65        #[inline]
66        fn to_int(self) -> Self::Int {
67            self.get()
68        }
69    };
70    (@counter_body $target:path, $int:ident) => {
71        const START: Self = match <Self as crate::IntegerId>::MIN_ID {
72            Some(valid) => valid,
73            None => panic!("type should be inhabited")
74        };
75        const START_INT: $int = Self::START.get();
76    };
77    (@stdlib $($target:ident => $int:ident),*) => {$(
78        impl crate::IntegerId for core::num::$target {
79            impl_nonzero_int!(@main_body core::num::$target, $int, one => 1, max => $int::MAX);
80        }
81        impl crate::IntegerIdContiguous for core::num::$target {}
82        impl crate::IntegerIdCounter for core::num::$target {
83            impl_nonzero_int!(@counter_body core::num::$target, $int);
84        }
85    )*}
86}
87impl_nonzero_int!(
88    @stdlib
89    NonZeroU8 => u8,
90    NonZeroU16 => u16,
91    NonZeroU32 => u32,
92    NonZeroU64 => u64,
93    NonZeroU128 => u128,
94    NonZeroUsize => usize
95);
96#[cfg(feature = "primint-nonzero")]
97mod primint_nonzero {
98    use primint::UnsignedPrimInt;
99
100    impl<T: UnsignedPrimInt> crate::IntegerId for primint::num::NonZero<T> {
101        impl_nonzero_int!(@main_body primint::num::NonZero<T>, T, one => primint::one(), max => primint::max_value());
102    }
103    impl<T: UnsignedPrimInt> crate::IntegerIdContiguous for primint::num::NonZero<T> {}
104    impl<T: UnsignedPrimInt> crate::IntegerIdCounter for primint::num::NonZero<T> {
105        impl_nonzero_int!(@counter_body primint::num::NonZero<T>, T);
106    }
107}
108
109#[cfg(any(feature = "nonmax", feature = "primint-nonmax"))]
110macro_rules! do_nonmax_impl {
111    (@main_body $target:path, $int:ident) => {
112        type Int = $int;
113        const MIN_ID: Option<Self> = Some({
114            assert!(primint::is_signed::<$int>());
115            // SAFETY: Zero is never the maximum value
116            unsafe { <$target>::new_unchecked(primint::zero()) }
117        });
118        const MAX_ID: Option<Self> = Some(<$target>::MAX);
119        const MIN_ID_INT: Option<Self::Int> = Some(primint::zero());
120        const MAX_ID_INT: Option<Self::Int> = Some(<$target>::MAX.get());
121        // SAFETY: Range is correct
122        const TRUSTED_RANGE: Option<crate::trusted::TrustedRangeToken<Self>> = unsafe { Some(crate::trusted::TrustedRangeToken::assume_valid()) };
123
124        #[inline]
125        fn from_int_checked(id: Self::Int) -> Option<Self> {
126            <$target>::new(id)
127        }
128        #[inline]
129        unsafe fn from_int_unchecked(id: Self::Int) -> Self {
130            // SAFETY: Guaranteed by caller
131            unsafe { <$target>::new_unchecked(id) }
132        }
133        #[inline]
134        fn to_int(self) -> Self::Int {
135            self.get()
136        }
137    };
138    (@nonmax_crate $($target:ident => $int:ident),*) => {$(
139        impl crate::IntegerId for nonmax::$target {
140            do_nonmax_impl!(@main_body nonmax::$target, $int);
141        }
142        impl crate::IntegerIdContiguous for nonmax::$target {}
143        impl crate::IntegerIdCounter for nonmax::$target {
144            const START: Self = nonmax::$target::ZERO;
145            const START_INT: Self::Int = 0;
146        }
147    )*};
148}
149#[cfg(feature = "nonmax")]
150do_nonmax_impl!(
151    @nonmax_crate
152    NonMaxU8 => u8,
153    NonMaxU16 => u16,
154    NonMaxU32 => u32,
155    NonMaxU64 => u64,
156    NonMaxU128 => u128,
157    NonMaxUsize => usize
158);
159
160#[cfg(feature = "primint-nonmax")]
161mod primint_nonmax {
162    use primint::UnsignedPrimInt;
163
164    impl<T: UnsignedPrimInt> crate::IntegerId for primint::num::NonMax<T> {
165        do_nonmax_impl!(@main_body primint::num::NonMax<T>, T);
166    }
167    impl<T: UnsignedPrimInt> crate::IntegerIdContiguous for primint::num::NonMax<T> {}
168    impl<T: UnsignedPrimInt> crate::IntegerIdCounter for primint::num::NonMax<T> {
169        const START: Self = primint::num::NonMax::<T>::MIN;
170        const START_INT: T = primint::zero();
171    }
172}
173
174macro_rules! impl_uninhabited {
175    ($target:ty) => {
176        impl crate::IntegerId for $target {
177            type Int = u8;
178            const MIN_ID: Option<Self> = None;
179            const MAX_ID: Option<Self> = None;
180            const MIN_ID_INT: Option<Self::Int> = None;
181            const MAX_ID_INT: Option<Self::Int> = None;
182            const TRUSTED_RANGE: Option<crate::trusted::TrustedRangeToken<Self>> = {
183                // SAFETY: Range is correct (vacuously)
184                unsafe { Some(crate::trusted::TrustedRangeToken::assume_valid()) }
185            };
186
187            #[track_caller]
188            #[inline]
189            fn from_int(id: Self::Int) -> Self {
190                panic!(
191                    "Cannot initialize uninhabited type {this} with {id}",
192                    this = stringify!($target),
193                )
194            }
195
196            #[inline]
197            fn from_int_checked(_id: Self::Int) -> Option<Self> {
198                None
199            }
200
201            #[inline]
202            unsafe fn from_int_unchecked(_id: Self::Int) -> Self {
203                // SAFETY: Caller guarantees this is called only if `id` is a valid index,
204                // and there are no valid indices
205                unsafe {
206                    core::hint::unreachable_unchecked();
207                }
208            }
209
210            #[inline]
211            fn to_int(self) -> Self::Int {
212                match self {}
213            }
214        }
215        impl crate::IntegerIdContiguous for $target {}
216    };
217}
218impl_uninhabited!(core::convert::Infallible);