sdmmc_core/
range.rs

1use crate::result::{Error, Result};
2
3macro_rules! range {
4    ($range:ident, $range_ty:ident) => {
5        ::paste::paste! {
6            #[doc = "Represents ranged type over a bounded range of values."]
7            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
8            pub struct $range<const MIN: $range_ty, const MAX: $range_ty>($range_ty);
9
10            impl<const MIN: $range_ty, const MAX: $range_ty> $range<MIN, MAX> {
11                #[doc = "Creates a new [" $range "]."]
12                pub const fn new() -> Self {
13                    Self(MIN)
14                }
15
16                /// Gets the minimum range value.
17                pub const fn min() -> $range_ty {
18                    MIN
19                }
20
21                /// Gets the maximum range value.
22                pub const fn max() -> $range_ty {
23                    MAX
24                }
25
26                #[doc = "Attempts to convert a raw index value into a [" $range "]."]
27                pub const fn try_from_inner(val: $range_ty) -> Result<Self> {
28                    if val >= MIN && val <= MAX {
29                        Ok(Self(val))
30                    } else {
31                        Err(Error::invalid_field_value("range", val as usize, MIN as usize, MAX as usize))
32                    }
33                }
34
35                #[doc = "Converts a raw index value into a [" $range "] with no bounds check."]
36                #[doc = ""]
37                #[doc = "# Panics"]
38                #[doc = ""]
39                #[doc = "Panics if the provided index is out-of-bounds."]
40                #[doc = ""]
41                #[doc = "Caller must ensure that the index is in the valid range."]
42                pub const fn try_from_unchecked(val: $range_ty) -> Self {
43                    match Self::try_from_inner(val) {
44                        Ok(i) => i,
45                        Err(_) => panic!("ranged value out-of-bounds"),
46                    }
47                }
48
49                #[doc = "Converts a [" $range "] into a raw index value."]
50                pub const fn into_inner(self) -> $range_ty {
51                    self.0
52                }
53            }
54
55            impl<const MIN: $range_ty, const MAX: $range_ty> Default for $range<MIN, MAX> {
56                fn default() -> Self {
57                    Self::new()
58                }
59            }
60
61            impl<const MIN: $range_ty, const MAX: $range_ty> TryFrom<$range_ty> for $range<MIN, MAX> {
62                type Error = Error;
63
64                fn try_from(val: $range_ty) -> Result<Self> {
65                    Self::try_from_inner(val)
66                }
67            }
68
69            impl<const MIN: $range_ty, const MAX: $range_ty> From<$range<MIN, MAX>> for $range_ty {
70                fn from(val: $range<MIN, MAX>) -> Self {
71                    val.into_inner()
72                }
73            }
74
75            #[cfg(test)]
76            mod [<range_ $range_ty _tests>] {
77                use super::*;
78
79                #[test]
80                fn test_range() {
81                    const MIN: $range_ty = 1;
82                    const MAX: $range_ty = $range_ty::MAX - 1;
83
84                    type TestRange = $range<MIN, MAX>;
85
86                    assert_eq!(TestRange::new().into_inner(), MIN);
87                    assert_eq!(TestRange::default().into_inner(), MIN);
88
89                    [MIN, MIN + 1, MAX - 1, MAX].into_iter().for_each(|index| {
90                        let exp_index = TestRange::try_from(index).unwrap();
91
92                        assert_eq!(TestRange::try_from_inner(index), Ok(exp_index));
93                        assert_eq!(TestRange::try_from(index), Ok(exp_index));
94
95                        assert_eq!(exp_index.into_inner(), index);
96                        assert_eq!($range_ty::from(exp_index), index);
97                    });
98
99                    assert!(TestRange::try_from_inner(MIN - 1).is_err());
100                    assert!(TestRange::try_from_inner(MAX + 1).is_err());
101                }
102            }
103        }
104    };
105}
106
107range!(RangeU8, u8);
108range!(RangeU16, u16);
109range!(RangeU32, u32);
110range!(RangeU64, u64);
111range!(RangeUsize, usize);
112
113/// Convenience alias for a ranged index type.
114pub type RangedIndex<const MIN: usize, const MAX: usize> = RangeUsize<MIN, MAX>;
115
116range!(RangeI8, i8);
117range!(RangeI16, i16);
118range!(RangeI32, i32);
119range!(RangeI64, i64);
120range!(RangeIsize, isize);