1use derive_more::{Display, Error};
2
3use super::sequential::Sequential;
4
5macro_rules! impl_bounded_uint_types {
6 ($int_type:ty, $at_least:ident, $at_most:ident, $between:ident) => {
7 #[repr(transparent)]
8 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9 pub struct $between<const MIN: $int_type, const MAX: $int_type>($int_type);
10
11 pub type $at_least<const MIN: $int_type> = $between<MIN, { <$int_type>::MAX }>;
12 pub type $at_most<const MAX: $int_type> = $between<{ <$int_type>::MIN }, MAX>;
13
14 impl<const MIN: $int_type, const MAX: $int_type> $between<MIN, MAX> {
15 const MIN_INDEX: usize = MIN as _;
16
17 pub const fn new(value: $int_type) -> Option<Self> {
18 if MIN <= value && value <= MAX {
19 Some(Self(value))
20 } else {
21 None
22 }
23 }
24
25 pub const unsafe fn new_unchecked(value: $int_type) -> Self {
26 Self(value)
27 }
28
29 pub const fn get(&self) -> $int_type {
30 self.0
31 }
32 }
33
34 unsafe impl<const MIN: $int_type, const MAX: $int_type> Sequential for $between<MIN, MAX>
35 where
36 $int_type: Sequential,
37 {
38 const CARDINALITY: usize = (MAX.saturating_sub(MIN) as usize) + 1;
39
40 fn to_index(&self) -> usize {
41 let full_index = self.0.to_index();
42 full_index - Self::MIN_INDEX
43 }
44
45 unsafe fn from_index_unchecked(index: usize) -> Self {
46 let full_index = index + Self::MIN_INDEX;
47 let value = unsafe { <$int_type as Sequential>::from_index_unchecked(full_index) };
48 unsafe { Self::new_unchecked(value) }
49 }
50 }
51
52 impl<const MIN: $int_type, const MAX: $int_type> From<$between<MIN, MAX>> for $int_type {
53 fn from(value: $between<MIN, MAX>) -> Self {
54 value.get()
55 }
56 }
57
58 impl<const MIN: $int_type, const MAX: $int_type> TryFrom<$int_type> for $between<MIN, MAX> {
59 type Error = TryFromUnboundedError;
60
61 fn try_from(value: $int_type) -> Result<Self, Self::Error> {
62 Self::new(value).ok_or(TryFromUnboundedError(()))
63 }
64 }
65 };
66}
67
68impl_bounded_uint_types!(u8, AtLeastU8, AtMostU8, BetweenU8);
69impl_bounded_uint_types!(u16, AtLeastU16, AtMostU16, BetweenU16);
70impl_bounded_uint_types!(u32, AtLeastU32, AtMostU32, BetweenU32);
71
72#[derive(Debug, Clone, Copy, Display, Error)]
73#[display("TODO")]
74pub struct TryFromUnboundedError(#[error(not(source))] ());