sdmmc_core/macros/
bitfield.rs

1/// Macro to define a bitfield struct.
2///
3/// For types using a base integer type:
4///
5/// - fields access bits in big-endian bit order (MSB = $base::BITS - 1).
6///
7/// For types using a base byte-array type:
8///
9/// - `MSB0` indicates big-endian byte access (Most-Significant-Byte = 0)
10/// - fields access bits in big-endian bit order (Most-Significant-Bit = $base::BITS - 1)
11#[macro_export]
12macro_rules! lib_bitfield {
13    (
14        $(#[$doc:meta])+
15        $ty_vis:vis $ty:ident ($base:ty): $ret:ty {
16            $(
17                $(#[$field_doc:meta])*
18                $field_vis:vis $field:ident: $msb:expr $(, $lsb:expr)?;
19            )+
20        }
21    ) => {
22        paste::paste! {
23            $(#[$doc])+
24            #[repr(C)]
25            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
26            $ty_vis struct $ty($base);
27
28            impl $ty {
29                #[doc = "Gets the bit value for [" $ty "]."]
30                pub const fn bits(&self) -> $base {
31                    self.0
32                }
33
34                $(
35                    $crate::lib_bitfield_impl! {
36                        $ty ( $base ): $ret,
37                        $(#[$field_doc])*
38                        $field_vis $field: $msb $(, $lsb)?;
39                    }
40                )+
41            }
42        }
43    };
44
45    (
46        $(#[$doc:meta])+
47        $ty_vis:vis $ty:ident (MSB0 [$base:ty; $N:expr]): $ret:ty {
48            $(
49                $(#[$field_doc:meta])*
50                $field_vis:vis $field:ident: $msb:expr $(, $lsb:expr)?;
51            )+
52        }
53    ) => {
54        paste::paste! {
55            $(#[$doc])+
56            #[repr(C)]
57            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
58            $ty_vis struct $ty(pub [$base; $N]);
59
60            impl $ty {
61                #[doc = "Gets the byte value for [" $ty "]."]
62                pub const fn bytes(&self) -> [$base; $N] {
63                    self.0
64                }
65
66                $(
67                    $crate::lib_bitfield_impl! {
68                        $ty (MSB0 [$base; $N]): $ret,
69                        $(#[$field_doc])*
70                        $field_vis $field: $msb $(, $lsb)?;
71                    }
72                )+
73            }
74        }
75    };
76
77    (
78        $(#[$doc:meta])+
79        $bitfield_ty:ident: $base:ty,
80        mask: $mask:expr,
81        default: $default:expr,
82        {
83            $(
84                $(#[$field_doc:meta])*
85                $field:ident: $msb:literal$(, $lsb:literal)?;
86            )+
87        }$(,)?
88    ) => {
89        ::paste::paste! {
90            $crate::lib_bitfield! {
91                $(#[$doc])+
92                pub $bitfield_ty($base): $base {
93                    $(pub $field: $msb $(, $lsb)?;)+
94                }
95            }
96
97            impl $bitfield_ty {
98                #[doc = "Represents the bitmask for the [" $bitfield_ty "]."]
99                pub const MASK: $base = $mask;
100                #[doc = "Represents the default value for the [" $bitfield_ty "]."]
101                pub const DEFAULT: $base = $default;
102
103                #[doc = "Creates a new [" $bitfield_ty "]."]
104                pub const fn new() -> Self {
105                    Self(Self::DEFAULT)
106                }
107
108                #[doc = "Converts an inner representation into a [" $bitfield_ty "]."]
109                pub const fn from_inner(val: $base) -> Self {
110                    Self(val & Self::MASK)
111                }
112
113                #[doc = "Attempts to convert an inner representation into a [" $bitfield_ty "]."]
114                pub const fn try_from_inner(val: $base) -> $crate::result::Result<Self> {
115                    Ok(Self::from_inner(val))
116                }
117
118                #[doc = "Converts a [" $bitfield_ty "] into an inner representation."]
119                pub const fn into_inner(self) -> $base {
120                    self.0
121                }
122            }
123
124            impl Default for $bitfield_ty {
125                fn default() -> Self {
126                    Self::new()
127                }
128            }
129
130            impl From<$base> for $bitfield_ty {
131                fn from(val: $base) -> Self {
132                    Self::from_inner(val)
133                }
134            }
135
136            impl From<$bitfield_ty> for $base {
137                fn from(val: $bitfield_ty) -> Self {
138                    val.into_inner()
139                }
140            }
141        }
142    };
143
144    (
145        $(#[$doc:meta])+
146        $bitfield_ty:ident: $base:ty,
147        mask: $mask:expr,
148        default: $default:expr,
149        {
150            $(
151                $(#[$field_doc:meta])*
152                $field:ident: $field_ty:ident, $msb:expr$(, $lsb:expr)?;
153            )+
154        }$(,)?
155    ) => {
156        ::paste::paste! {
157            $crate::lib_bitfield! {
158                $(#[$doc])+
159                pub $bitfield_ty($base): $base {
160                    $([<raw_ $field>]: $msb $(, $lsb)?;)+
161                }
162            }
163
164            impl $bitfield_ty {
165                #[doc = "Represents the bitmask for the [" $bitfield_ty "]."]
166                pub const MASK: $base = $mask;
167                #[doc = "Represents the default value for the [" $bitfield_ty "]."]
168                pub const DEFAULT: $base = $default;
169
170                #[doc = "Creates a new [" $bitfield_ty "]."]
171                pub const fn new() -> Self {
172                    Self(Self::DEFAULT)
173                }
174
175                $(
176                    #[doc = "Gets the " $field " of the [" $bitfield_ty "]."]
177                    $(
178                        #[doc = ""]
179                        #[$field_doc]
180                    )*
181                    pub const fn $field(&self) -> $crate::result::Result<$field_ty> {
182                        $field_ty::try_from_inner(self.[<raw_ $field>]())
183                    }
184
185                    #[doc = "Sets the " $field " of the [" $bitfield_ty "]."]
186                    $(
187                        #[doc = ""]
188                        #[$field_doc]
189                    )*
190                    pub fn [<set_ $field>](&mut self, val: $field_ty) {
191                        self.[<set_raw_ $field>](val.into_inner())
192                    }
193                )+
194
195                #[doc = "Attempts to convert an inner representation into a [" $bitfield_ty "]."]
196                pub const fn try_from_inner(val: $base) -> $crate::result::Result<Self> {
197                    match Self(val & Self::MASK) {
198                        $(
199                            v if v.$field().is_err() => Err($crate::result::Error::invalid_field_variant(stringify!($bitfield_ty::$field), v.[<raw_ $field>]() as usize)),
200                        )+
201                        v => Ok(v),
202                    }
203                }
204
205                #[doc = "Converts a [" $bitfield_ty "] into an inner representation."]
206                pub const fn into_inner(self) -> $base {
207                    self.0
208                }
209            }
210
211            impl Default for $bitfield_ty {
212                fn default() -> Self {
213                    Self::new()
214                }
215            }
216
217            impl TryFrom<$base> for $bitfield_ty {
218                type Error = $crate::result::Error;
219
220                fn try_from(val: $base) -> $crate::result::Result<Self> {
221                    Self::try_from_inner(val)
222                }
223            }
224
225            impl From<$bitfield_ty> for $base {
226                fn from(val: $bitfield_ty) -> Self {
227                    val.into_inner()
228                }
229            }
230        }
231    };
232}
233
234/// Inner implementation of the bitfield accessor functions.
235#[macro_export]
236macro_rules! lib_bitfield_impl {
237    (
238        $ty:ident ( $base:ty ): $ret:ty,
239        $(#[$field_doc:meta])*
240        $field_vis:vis $field:ident: $msb:expr, $lsb:expr;
241    ) => {
242        paste::paste! {
243            #[doc = "Getter for " $field " field of [" $ty "]."]
244            $(
245                #[doc = ""]
246                #[$field_doc]
247            )*
248            $field_vis const fn $field(&self) -> $ret {
249                $crate::check_bitfield!($msb, $lsb, $base, $ret);
250
251                let mask = ((1u128 << ($msb - $lsb + 1)) - 1) as $base;
252                ((self.0 & (mask << $lsb)) >> $lsb) as $ret
253            }
254
255            #[doc = "Setter for " $field " field of [" $ty "]."]
256            $(
257                #[doc = ""]
258                #[$field_doc]
259            )*
260            $field_vis fn [<set_ $field>](&mut self, val: $base) {
261                $crate::check_bitfield!($msb, $lsb, $base, $ret);
262
263                let mask = ((1u128 << ($msb - $lsb + 1)) - 1) as $base;
264                self.0 = (self.0 & !(mask << $lsb)) | ((val & mask) << $lsb);
265            }
266        }
267    };
268
269    (
270        $ty:ident ( $base:ty ): $ret:ty,
271        $(#[$field_doc:meta])*
272        $field_vis:vis $field:ident: $bit:expr;
273    ) => {
274        paste::paste! {
275            #[doc = "Getter for " $field " field of [" $ty "]."]
276            $(
277                #[doc = ""]
278                #[$field_doc]
279            )*
280            $field_vis const fn $field(&self) -> bool {
281                $crate::check_bitfield!($bit, $base);
282
283                let mask = (1u128 << $bit) as $base;
284                ((self.0 & mask) >> $bit) != 0
285            }
286
287            #[doc = "Setter for " $field " field of [" $ty "]."]
288            $(
289                #[doc = ""]
290                #[$field_doc]
291            )*
292            $field_vis fn [<set_ $field>](&mut self, val: bool) {
293                $crate::check_bitfield!($bit, $base);
294
295                let mask = (1u128 << $bit) as $base;
296                self.0 = (self.0 & !mask) | ((val as $base) << $bit);
297            }
298        }
299    };
300
301    (
302        $ty:ident (MSB0 [$base:ty; $N:expr] ): $ret:ty,
303        $(#[$field_doc:meta])*
304        $field_vis:vis $field:ident: $msb:expr, $lsb:expr;
305    ) => {
306        paste::paste! {
307            #[doc = "Getter for `" $field "` field of [" $ty "]."]
308            $(
309                #[doc = ""]
310                #[$field_doc]
311            )*
312            $field_vis const fn $field(&self) -> $ret {
313                $crate::check_bitfield!($msb, $lsb, $base, $N, $ret);
314
315                let msb_idx = $N - ($msb / _BASE_BITS) - 1;
316                let mut msb_bit = $msb % _BASE_BITS;
317
318                let lsb_idx = $N - ($lsb / _BASE_BITS) - 1;
319
320                let mut idx = msb_idx;
321                let mut bits = ($msb - $lsb + 1) as usize;
322
323                let mut ret = 0;
324
325                while idx <= lsb_idx {
326                    let lsb_bit = if idx == lsb_idx {
327                        $lsb % _BASE_BITS
328                    } else {
329                        0
330                    };
331
332                    let (width, bit) = (msb_bit - lsb_bit + 1, lsb_bit);
333
334                    let mask = ((1u128 << width) - 1) as $base;
335
336                    bits = bits.saturating_sub(width);
337
338                    ret |= (((self.0[idx] & (mask << bit)) as $ret) >> bit) << bits;
339
340                    idx += 1;
341                    msb_bit = _BASE_BITS - 1;
342                }
343
344                ret
345            }
346
347            #[doc = "Setter for `" $field "` field of [" $ty "]."]
348            $(
349                #[doc = ""]
350                #[$field_doc]
351            )*
352            $field_vis fn [<set_ $field>](&mut self, val: $ret) {
353                $crate::check_bitfield!($msb, $lsb, $base, $N, $ret);
354
355                let msb_idx = $N - ($msb / _BASE_BITS) - 1;
356                let mut msb_bit = $msb % _BASE_BITS;
357
358                let lsb_idx = $N - ($lsb / _BASE_BITS) - 1;
359
360                let mut idx = msb_idx;
361                let mut bits = ($msb - $lsb + 1) as usize;
362
363                while idx <= lsb_idx {
364                    let lsb_bit = if idx == lsb_idx {
365                        $lsb % _BASE_BITS
366                    } else {
367                        0
368                    };
369
370                    let (width, bit) = (msb_bit - lsb_bit + 1, lsb_bit);
371
372                    let mask = ((1u128 << width) - 1) as $base;
373
374                    bits = bits.saturating_sub(width);
375
376                    let val_base = ((val >> bits) as $base) << bit;
377                    self.0[idx] = (self.0[idx] & !(mask << bit)) | val_base;
378
379                    idx += 1;
380                    msb_bit = _BASE_BITS - 1;
381                }
382            }
383        }
384    };
385
386    (
387        $ty:ident (MSB0 [$base:ty; $N:expr] ): $ret:ty,
388        $(#[$field_doc:meta])*
389        $field_vis:vis $field:ident: $bit:expr;
390    ) => {
391        paste::paste! {
392            #[doc = "Getter for `" $field "` field of [" $ty "]."]
393            $(
394                #[doc = ""]
395                #[$field_doc]
396            )*
397            $field_vis const fn $field(&self) -> bool {
398                $crate::check_bitfield!($bit, $base, $N);
399
400                let idx = $N - ($bit / _BASE_BITS) - 1;
401                let bit = $bit % _BASE_BITS;
402
403                let mask = (1u128 << bit) as $base;
404
405                (self.0[idx] & mask) != 0
406            }
407
408            #[doc = "Setter for `" $field "` field of [" $ty "]."]
409            $(
410                #[doc = ""]
411                #[$field_doc]
412            )*
413            $field_vis fn [<set_ $field>](&mut self, val: bool) {
414                $crate::check_bitfield!($bit, $base, $N);
415
416                let idx = $N - ($bit / _BASE_BITS) - 1;
417                let bit = $bit % _BASE_BITS;
418
419                let mask = (1u128 << bit) as $base;
420
421                self.0[idx] = (self.0[idx] & !mask) | ((val as $base) << bit);
422            }
423        }
424    };
425}
426
427/// Helper macro to check bitfield invariants at compile-time.
428#[macro_export]
429macro_rules! check_bitfield {
430    (
431        $msb:expr, $lsb:expr, $base:ty, $ret:ty$(,)?
432    ) => {
433        const _BASE_BITS: usize = <$base>::BITS as usize;
434        const _RET_BITS: usize = <$ret>::BITS as usize;
435        const _WIDTH: usize = $msb - $lsb + 1;
436
437        const _: () = assert!($lsb <= $msb);
438        const _: () = assert!(($msb as usize) < _BASE_BITS);
439        const _: () = assert!(($msb - $lsb) < _RET_BITS);
440    };
441
442    (
443        $bit:expr, $base:ty$(,)?
444    ) => {
445        const _BASE_BITS: usize = <$base>::BITS as usize;
446        const _RET_BITS: usize = 1;
447        const _WIDTH: usize = 1;
448
449        const _: () = assert!(($bit as usize) < _BASE_BITS);
450    };
451
452    (
453        $msb:expr, $lsb:expr, $base:ty, $N:expr, $ret:ty$(,)?
454    ) => {
455        const _BASE_BITS: usize = <$base>::BITS as usize;
456        const _TOTAL_BITS: usize = _BASE_BITS * $N;
457        const _RET_BITS: usize = <$ret>::BITS as usize;
458        const _WIDTH: usize = $msb - $lsb + 1;
459
460        const _: () = assert!($lsb <= $msb);
461        const _: () = assert!(($msb as usize) < _TOTAL_BITS);
462        const _: () = assert!(($msb - $lsb) < _RET_BITS);
463    };
464
465    (
466        $bit:expr, $base:ty, $N:expr$(,)?
467    ) => {
468        const _BASE_BITS: usize = <$base>::BITS as usize;
469        const _TOTAL_BITS: usize = _BASE_BITS * $N;
470
471        const _: () = assert!(($bit as usize) < _TOTAL_BITS);
472    };
473}