sdmmc_core/macros/
enums.rs1#[macro_export]
3macro_rules! lib_enum {
4 (
5 $(#[$enum_meta:meta])+
6 $enum_ty:ident: $base_ty:ident {
7 default: $default_variant:ident,
8 error: $err_ty:ident,
9 $(
10 $(#[$var_doc:meta])*
11 $variant:ident = $value:literal$(,)?
12 )+
13 }
14 ) => {
15 paste::paste! {
16 $(#[$enum_meta])+
17 #[repr($base_ty)]
18 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
19 pub enum $enum_ty {
20 $(
21 $(#[$var_doc])*
22 $variant = $value,
23 )+
24 }
25
26 impl $enum_ty {
27 #[doc = "Creates a new [" $enum_ty "]."]
28 pub const fn new() -> Self {
29 Self::$default_variant
30 }
31
32 #[doc = "Converts a [`" $base_ty "`] into a [" $enum_ty "]."]
33 #[doc = ""]
34 #[doc = "# Panics"]
35 #[doc = ""]
36 #[doc = "Panics if the passed value is an invalid variant"]
37 pub const fn from_raw_unchecked(val: $base_ty) -> Self {
38 match Self::from_raw(val) {
39 Ok(v) => v,
40 Err(err) => panic!("invalid variant"),
41 }
42 }
43
44 #[doc = "Attempts to convert a [`" $base_ty "`] into a [" $enum_ty "]."]
45 pub const fn from_raw(val: $base_ty) -> ::core::result::Result<Self, $err_ty> {
46 match val {
47 $(
48 $value => Ok(Self::$variant),
49 )+
50 _ => Err($err_ty::InvalidVariant(val as usize)),
51 }
52 }
53
54 #[doc = "Converts a [" $enum_ty "] into a [`" $base_ty "`]."]
55 pub const fn into_raw(self) -> $base_ty {
56 self as $base_ty
57 }
58 }
59
60 impl Default for $enum_ty {
61 fn default() -> Self {
62 Self::new()
63 }
64 }
65
66 impl TryFrom<$base_ty> for $enum_ty {
67 type Error = $err_ty;
68
69 fn try_from(val: $base_ty) -> ::core::result::Result<Self, Self::Error> {
70 Self::from_raw(val)
71 }
72 }
73
74 impl From<$enum_ty> for $base_ty {
75 fn from(val: $enum_ty) -> Self {
76 val.into_raw()
77 }
78 }
79
80 #[cfg(test)]
81 mod tests {
82 use super::*;
83
84 #[test]
85 fn test_variants() {
86 let raw = [
87 $($value,)+
88 ];
89
90 let exp = [
91 $($enum_ty::$variant,)+
92 ];
93
94 raw.into_iter().zip(exp).for_each(|(r, e)| {
95 assert_eq!($enum_ty::from_raw(r), Ok(e));
96 assert_eq!($enum_ty::try_from(r), Ok(e));
97
98 assert_eq!(e.into_raw(), r);
99 assert_eq!($base_ty::from(e), r);
100 });
101 }
102
103 #[test]
104 fn test_invalid_variants() {
105 let raw = [
106 $($value,)+
107 ];
108
109 let upper = match $base_ty::BITS {
111 128 | 64 | 32 | 16 => $base_ty::MAX >> ($base_ty::BITS - 10),
112 _ => $base_ty::MAX,
113 };
114
115 (0..=upper).chain([$base_ty::MAX]).filter(|r| !raw.iter().any(|v| v == r)).for_each(|r| {
116 assert_eq!($enum_ty::from_raw(r), Err($err_ty::InvalidVariant(r as usize)));
117 assert_eq!($enum_ty::try_from(r), Err($err_ty::InvalidVariant(r as usize)));
118 });
119 }
120 }
121 }
122 };
123}
124
125#[macro_export]
127macro_rules! lib_bool_enum {
128 (
129 $(#[$enum_meta:meta])+
130 $enum_ty:ident {
131 $(#[$false_var_doc:meta])*
132 $false_variant:ident = false,
133 $(#[$true_var_doc:meta])*
134 $true_variant:ident = true,
135 }
136 ) => {
137 paste::paste! {
138 $(#[$enum_meta])+
139 #[repr(u8)]
140 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
141 pub enum $enum_ty {
142 $(#[$false_var_doc])+
143 $false_variant = 0,
144 $(#[$true_var_doc])+
145 $true_variant = 1,
146 }
147
148 impl $enum_ty {
149 #[doc = "Creates a new [" $enum_ty "]."]
150 pub const fn new() -> Self {
151 Self::$false_variant
152 }
153
154 #[doc = "Attempts to convert a [`bool`] into a [" $enum_ty "]."]
155 pub const fn from_bool(val: bool) -> Self {
156 match val {
157 false => Self::$false_variant,
158 true => Self::$true_variant,
159 }
160 }
161
162 #[doc = "Converts a [" $enum_ty "] into a [`bool`]."]
163 pub const fn into_bool(self) -> bool {
164 match self {
165 Self::$false_variant => false,
166 Self::$true_variant => true,
167 }
168 }
169
170 #[doc = " Attempts to convert a [`u8`] into a [" $enum_ty "]."]
171 pub const fn try_from_u8(val: u8) -> $crate::result::Result<Self> {
172 match val {
173 0 => Ok(Self::$false_variant),
174 1 => Ok(Self::$true_variant),
175 _ => Err($crate::result::Error::invalid_field_variant(stringify!($enum_ty), val as usize)),
176 }
177 }
178
179 #[doc = "Converts a [" $enum_ty "] into a [`u8`]."]
180 pub const fn into_u8(self) -> u8 {
181 self as u8
182 }
183 }
184
185 impl Default for $enum_ty {
186 fn default() -> Self {
187 Self::new()
188 }
189 }
190
191 impl From<bool> for $enum_ty {
192 fn from(val: bool) -> Self {
193 Self::from_bool(val)
194 }
195 }
196
197 impl From<$enum_ty> for bool {
198 fn from(val: $enum_ty) -> Self {
199 val.into_bool()
200 }
201 }
202
203 impl TryFrom<u8> for $enum_ty {
204 type Error = $crate::result::Error;
205
206 fn try_from(val: u8) -> ::core::result::Result<Self, Self::Error> {
207 Self::try_from_u8(val)
208 }
209 }
210
211 impl From<$enum_ty> for u8 {
212 fn from(val: $enum_ty) -> Self {
213 val.into_u8()
214 }
215 }
216
217 #[cfg(test)]
218 mod tests {
219 use super::*;
220
221 #[test]
222 fn test_variants() {
223 let raw = [0, 1];
224
225 let exp = [$enum_ty::$false_variant, $enum_ty::$true_variant];
226
227 raw.into_iter().zip(exp).for_each(|(r, e)| {
228 let raw_bool = r != 0;
229
230 assert_eq!($enum_ty::from_bool(raw_bool), e);
231 assert_eq!($enum_ty::from(raw_bool), e);
232
233 assert_eq!($enum_ty::try_from_u8(r), Ok(e));
234 assert_eq!($enum_ty::try_from(r), Ok(e));
235
236 assert_eq!(e.into_bool(), raw_bool);
237 assert_eq!(bool::from(e), raw_bool);
238
239 assert_eq!(e.into_u8(), r);
240 assert_eq!(u8::from(e), r);
241 });
242 }
243
244 #[test]
245 fn test_invalid_variants() {
246 (2..=u8::MAX).for_each(|r| {
247 let exp_err = $crate::result::Error::invalid_field_variant(stringify!($enum_ty), r as usize);
248 assert_eq!($enum_ty::try_from_u8(r), Err(exp_err));
249 assert_eq!($enum_ty::try_from(r), Err(exp_err));
250 });
251 }
252 }
253 }
254 };
255}