sdmmc_core/
macros.rs

1//! Macros for reducing boilerplate, and increasing consistency in the library.
2
3mod bitfield;
4mod command;
5mod enums;
6mod response;
7
8/// Implements a function to determine if a `bitflag` has a set flag.
9#[macro_export]
10macro_rules! bitflag_is_set {
11    ($ty:ident) => {
12        impl $ty {
13            /// Determines whether `oth` flag is set.
14            pub fn is_set(self, oth: Self) -> bool {
15                self & oth != Self::NONE
16            }
17        }
18    };
19}
20
21#[macro_export]
22macro_rules! data_block {
23    (
24        $(#[$block_doc:meta])+
25        $block:ident: $block_len:expr,
26        $(#[$wide_block_doc:meta])+
27        $wide_block:ident: $wide_block_len:expr$(,)?
28    ) => {
29        paste::paste! {
30            $(#[$block_doc])+
31            #[repr(C)]
32            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
33            pub struct $block {
34                data: [u8; $block_len],
35            }
36
37            impl $block {
38                #[doc = "Creates a new [" $block "]."]
39                pub const fn new() -> Self {
40                    Self {
41                        data: [0u8; $block_len],
42                    }
43                }
44
45                #[doc = "Creates a new [" $block "] from line data."]
46                pub const fn from_bytes(data: [u8; $block_len]) -> Self {
47                    Self { data }
48                }
49
50                /// Gets a reference to the inner data bytes.
51                pub const fn data(&self) -> &[u8] {
52                    &self.data
53                }
54
55                #[doc = "Converts the [" $block "] into a [" $wide_block "]."]
56                #[doc = ""]
57                #[doc = "This is for using all four `DAT` lines on a SD bus."]
58                pub const fn wide_data(&self) -> $wide_block {
59                    use $crate::data::{wide_bus_encode, DataLine};
60
61                    let mut wide = $wide_block::new();
62
63                    let mut i = 0;
64                    let len = self.data.len();
65
66                    while i < len {
67                        let b = self.data[i];
68                        let dat_idx = i.saturating_div(WIDE_BUS_WIDTH);
69
70                        wide.dat0[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat0);
71                        wide.dat1[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat1);
72                        wide.dat2[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat2);
73                        wide.dat3[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat3);
74
75                        i += 1;
76                    }
77
78                    wide
79                }
80            }
81
82            impl Default for $block {
83                fn default() -> Self {
84                    Self::new()
85                }
86            }
87
88            $(#[$wide_block_doc])+
89            #[repr(C)]
90            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
91            pub struct $wide_block {
92                dat0: [u8; $wide_block_len],
93                dat1: [u8; $wide_block_len],
94                dat2: [u8; $wide_block_len],
95                dat3: [u8; $wide_block_len],
96            }
97
98            impl $wide_block {
99                #[doc = "Creates a new [" $wide_block "]."]
100                pub const fn new() -> Self {
101                    Self {
102                        dat0: [0u8; $wide_block_len],
103                        dat1: [0u8; $wide_block_len],
104                        dat2: [0u8; $wide_block_len],
105                        dat3: [0u8; $wide_block_len],
106                    }
107                }
108
109                #[doc = "Creates a new [" $wide_block "] from `DAT` line data."]
110                pub const fn from_data_lines(
111                    dat0: [u8; $wide_block_len],
112                    dat1: [u8; $wide_block_len],
113                    dat2: [u8; $wide_block_len],
114                    dat3: [u8; $wide_block_len],
115                ) -> Self {
116                    Self {
117                        dat0,
118                        dat1,
119                        dat2,
120                        dat3,
121                    }
122                }
123
124                #[doc = "Converts the [" $wide_block "] into a [" $block "]."]
125                #[doc = ""]
126                #[doc = "This is for using all four `DAT` lines on a SD bus."]
127                pub const fn decode(&self) -> $block {
128                    use $crate::data::{wide_bus_decode, DataLine, WIDE_BUS_WIDTH};
129
130                    let mut block = $block::new();
131
132                    let mut i = 0;
133                    let len = block.data.len();
134
135                    while i < len {
136                        let j = i.saturating_div(WIDE_BUS_WIDTH);
137
138                        block.data[i] |= wide_bus_decode(self.dat0[j], i, DataLine::Dat0);
139                        block.data[i] |= wide_bus_decode(self.dat1[j], i, DataLine::Dat1);
140                        block.data[i] |= wide_bus_decode(self.dat2[j], i, DataLine::Dat2);
141                        block.data[i] |= wide_bus_decode(self.dat3[j], i, DataLine::Dat3);
142
143                        i += 1;
144                    }
145
146                    block
147                }
148            }
149
150            impl Default for $wide_block {
151                fn default() -> Self {
152                    Self::new()
153                }
154            }
155
156            impl From<$block> for $wide_block {
157                fn from(val: $block) -> Self {
158                    val.wide_data()
159                }
160            }
161        }
162    };
163}
164
165/// Convenience macro to define a library struct.
166///
167/// Useful for reducing boilerplate, and increasing consistency.
168#[macro_export]
169macro_rules! lib_struct {
170    (
171        $(#[$doc:meta])+
172        $ty:ident {
173            $($field:ident: $field_ty:ident$(,)?)+
174        }
175    ) => {
176        paste::paste! {
177            $(#[$doc])+
178            #[repr(C)]
179            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
180            pub struct $ty {
181                $($field: $field_ty,)+
182            }
183
184            impl $ty {
185                $(
186                #[doc = "Gets the [" $field_ty "] for the [" $ty "]."]
187                pub const fn $field(&self) -> $field_ty {
188                    self.$field
189                }
190
191                #[doc = "Sets the [" $field_ty "] for the [" $ty "]."]
192                pub fn [<set_ $field>](&mut self, $field: $field_ty) {
193                    self.$field = $field;
194                }
195
196                #[doc = "Builder function that sets the [" $field_ty "] for the [" $ty "]."]
197                pub const fn [<with_ $field>](self, $field: $field_ty) -> Self {
198                    Self {
199                        $field: $field,
200                        ..self
201                    }
202                }
203                )+
204            }
205        }
206    }
207}
208
209/// Convenience macro for testing bitfields.
210#[macro_export]
211macro_rules! test_field {
212    ($t:ident, $field:ident) => {
213        paste::paste! {
214            $t.[<set_ $field>](true);
215            assert!($t.$field());
216
217            $t.[<set_ $field>](false);
218            assert!(!$t.$field());
219        }
220    };
221
222    ($t:ident, $field:ident: $bit:expr) => {
223        paste::paste! {
224            $t.[<set_ $field>](true);
225            assert!($t.$field());
226            assert_eq!($t.bits() & (1 << $bit), 1 << $bit);
227
228            $t.[<set_ $field>](false);
229            assert!(!$t.$field());
230            assert_eq!($t.bits() & (1 << $bit), 0);
231        }
232    };
233
234    ($t:ident, $field:ident { bit: $bit:expr, [$base:ty; $N:expr] }) => {
235        paste::paste! {
236            let idx = ($N - (($bit / $base::BITS) as usize) - 1);
237            let bit = $bit % $base::BITS;
238
239            $t.[<set_ $field>](true);
240            assert!($t.$field());
241
242            assert_eq!($t.bytes()[idx] & (1 << bit), 1 << bit);
243
244            $t.[<set_ $field>](false);
245            assert!(!$t.$field());
246            assert_eq!($t.bytes()[idx] & (1 << bit), 0);
247        }
248    };
249}
250
251/// Helper macro for a `const` version of the `?` operator.
252#[macro_export]
253macro_rules! const_try {
254    ($e:expr) => {
255        match $e {
256            Ok(v) => v,
257            Err(err) => return Err(err),
258        }
259    };
260}