1 /*! Internal implementation macros for the public exports.
2
3 The macros in this module are required to be exported from the crate, as the
4 public macros will call them from client contexts (`macro_rules!` expansion
5 bodies are not in source crate scope, as they are token expansion rather than
6 symbolic calls). However, they are not part of the public *API* of the crate,
7 and are not intended for use anywhere but in the expansion bodies of the
8 public-API constructor macros.
9 !*/
10
11 #![doc(hidden)]
12
13 /** Accumulates a stream of bit expressions into a compacted array of elements.
14
15 This macro constructs a well-ordered `[T; N]` array expression usable in `const`
16 contexts. Callers may then use that expression as the source slice over which to
17 construct `bitvec` types.
18 **/
19 #[doc(hidden)]
20 #[macro_export]
21 macro_rules! __bits_store_array {
22 // Reroute `usize` to the correct concrete type, and mark the alias.
23 // The `@ usz` causes `as usize` to be appended to exprs as needed.
24 ($order:tt, usize; $($val:expr),*) => {{
25 const LEN: usize = $crate::__count_elts!(usize; $($val),*);
26
27 // Attributes are not currently allowed on expressions, only items and
28 // statements, so the routing here must bind to a name.
29 #[cfg(target_pointer_width = "32")]
30 const OUT: [usize; LEN] = $crate::__bits_store_array!(
31 $order, u32 @ usz; $($val),*
32 );
33
34 #[cfg(target_pointer_width = "64")]
35 const OUT: [usize; LEN] = $crate::__bits_store_array!(
36 $order, u64 @ usz; $($val),*
37 );
38
39 OUT
40 }};
41 // Entry point.
42 ($order:tt, $store:ident $(@ $usz:ident )?; $($val:expr),*) => {
43 $crate::__bits_store_array!(
44 $order, $store $(@ $usz)?, []; $($val,)*
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 48
48 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 64
49 );
50 };
51
52 /* NOTE: These have to be first. They (ab)use a quirk of `macro_rules!`
53 where `:expr` captures are considered a single `:tt` after being matched.
54 Even if the `:expr` matcher was a literal `0`, after being wrapped by the
55 `:expr` fragment, it is no longer considered to match a literal `0`, so
56 these patterns will only match the extra padding `0`s added at the end.
57
58 Once the user-provided `$val` expressions are all consumed, the remaining
59 `0` tokens inserted by the arm above are all removed, ensuring that the
60 produced array has no wasted elements.
61 */
62 ($order:tt, $store:ident @ usz, [$( ($($elt:tt),*) )*]; $(0),*) => {
63 [$(
64 $crate::__elt_from_bits!($order, $store; $($elt),*) as usize
65 ),*]
66 };
67 ($order:tt, $store:ident, [$( ($($elt:tt),*) )*]; $(0),*) => {
68 [$(
69 $crate::__elt_from_bits!($order, $store; $($elt),*)
70 ),*]
71 };
72
73 // Matchers for each size of word. The end of the word may be padded out
74 // with `0`s.
75 (
76 $order:tt, u8 $(@ $usz:ident)?, [$($w:tt)*];
77 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt
78 $(, $($t:tt)*)?
79 ) => {
80 $crate::__bits_store_array!(
81 $order, u8 $(@ $usz)?, [$($w)* (
82 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0
83 )];
84 $($($t)*)?
85 )
86 };
87 (
88 $order:tt, u16 $(@ $usz:ident)?, [$($w:tt)*];
89 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt,
90 $a1:tt, $b1:tt, $c1:tt, $d1:tt, $e1:tt, $f1:tt, $g1:tt, $h1:tt
91 $(, $($t:tt)*)?
92 ) => {
93 $crate::__bits_store_array!(
94 $order, u16 $(@ $usz)?, [$($w)* (
95 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0,
96 $a1, $b1, $c1, $d1, $e1, $f1, $g1, $h1
97 )];
98 $($($t)*)?
99 )
100 };
101 (
102 $order:tt, u32 $(@ $usz:ident)?, [$($w:tt)*];
103 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt,
104 $a1:tt, $b1:tt, $c1:tt, $d1:tt, $e1:tt, $f1:tt, $g1:tt, $h1:tt,
105 $a2:tt, $b2:tt, $c2:tt, $d2:tt, $e2:tt, $f2:tt, $g2:tt, $h2:tt,
106 $a3:tt, $b3:tt, $c3:tt, $d3:tt, $e3:tt, $f3:tt, $g3:tt, $h3:tt
107 $(, $($t:tt)*)?
108 ) => {
109 $crate::__bits_store_array!(
110 $order, u32 $(@ $usz)?, [$($w)* (
111 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0,
112 $a1, $b1, $c1, $d1, $e1, $f1, $g1, $h1,
113 $a2, $b2, $c2, $d2, $e2, $f2, $g2, $h2,
114 $a3, $b3, $c3, $d3, $e3, $f3, $g3, $h3
115 )];
116 $($($t)*)?
117 )
118 };
119 (
120 $order:tt, u64 $(@ $usz:ident)?, [$($w:tt)*];
121 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt,
122 $a1:tt, $b1:tt, $c1:tt, $d1:tt, $e1:tt, $f1:tt, $g1:tt, $h1:tt,
123 $a2:tt, $b2:tt, $c2:tt, $d2:tt, $e2:tt, $f2:tt, $g2:tt, $h2:tt,
124 $a3:tt, $b3:tt, $c3:tt, $d3:tt, $e3:tt, $f3:tt, $g3:tt, $h3:tt,
125 $a4:tt, $b4:tt, $c4:tt, $d4:tt, $e4:tt, $f4:tt, $g4:tt, $h4:tt,
126 $a5:tt, $b5:tt, $c5:tt, $d5:tt, $e5:tt, $f5:tt, $g5:tt, $h5:tt,
127 $a6:tt, $b6:tt, $c6:tt, $d6:tt, $e6:tt, $f6:tt, $g6:tt, $h6:tt,
128 $a7:tt, $b7:tt, $c7:tt, $d7:tt, $e7:tt, $f7:tt, $g7:tt, $h7:tt
129 $(, $($t:tt)*)?
130 ) => {
131 $crate::__bits_store_array!(
132 $order, u64 $(@ $usz)?, [$($w)* (
133 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0,
134 $a1, $b1, $c1, $d1, $e1, $f1, $g1, $h1,
135 $a2, $b2, $c2, $d2, $e2, $f2, $g2, $h2,
136 $a3, $b3, $c3, $d3, $e3, $f3, $g3, $h3,
137 $a4, $b4, $c4, $d4, $e4, $f4, $g4, $h4,
138 $a5, $b5, $c5, $d5, $e5, $f5, $g5, $h5,
139 $a6, $b6, $c6, $d6, $e6, $f6, $g6, $h6,
140 $a7, $b7, $c7, $d7, $e7, $f7, $g7, $h7
141 )];
142 $($($t)*)?
143 )
144 };
145 }
146
147 /// Counts the number of repetitions inside a `$()*` sequence.
148 #[doc(hidden)]
149 #[macro_export]
150 macro_rules! __count {
151 (@ $val:expr) => { 1 };
152 ($($val:expr),*) => {{
153 /* Clippy warns that `.. EXPR + 1`, for any value of `EXPR`, should be
154 replaced with `..= EXPR`. This means that `.. $crate::__count!` raises
155 the lint, causing `bits![(val,)…]` to have an unfixable lint warning.
156 By binding to a `const`, then returning the `const`, this syntax
157 construction is avoided as macros only expand to
158 `.. { const LEN = …; LEN }` rather than `.. 0 (+ 1)…`.
159 */
160 const LEN: usize = 0usize $(+ $crate::__count!(@ $val))*;
161 LEN
162 }};
163 }
164
165 /// Counts the number of elements needed to store a number of bits.
166 #[doc(hidden)]
167 #[macro_export]
168 macro_rules! __count_elts {
169 ($t:ident; $($val:expr),*) => {{
170 $crate::mem::elts::<$t>($crate::__count!($($val),*))
171 }};
172 }
173
174 /// Construct a `T` element from an array of `u8`.
175 #[doc(hidden)]
176 #[macro_export]
177 macro_rules! __elt_from_bits {
178 // Known orderings can be performed immediately.
179 (
180 Lsb0, $store:ident;
181 $(
182 $a:expr, $b:expr, $c:expr, $d:expr,
183 $e:expr, $f:expr, $g:expr, $h:expr
184 ),*
185 ) => {
186 $crate::__ty_from_bytes!(
187 Lsb0, $store, [$($crate::macros::internal::u8_from_le_bits(
188 $a != 0, $b != 0, $c != 0, $d != 0,
189 $e != 0, $f != 0, $g != 0, $h != 0,
190 )),*]
191 )
192 };
193 (
194 Msb0, $store:ident;
195 $(
196 $a:expr, $b:expr, $c:expr, $d:expr,
197 $e:expr, $f:expr, $g:expr, $h:expr
198 ),*
199 ) => {
200 $crate::__ty_from_bytes!(
201 Msb0, $store, [$($crate::macros::internal::u8_from_be_bits(
202 $a != 0, $b != 0, $c != 0, $d != 0,
203 $e != 0, $f != 0, $g != 0, $h != 0,
204 )),*]
205 )
206 };
207 (
208 LocalBits, $store:ident;
209 $(
210 $a:expr, $b:expr, $c:expr, $d:expr,
211 $e:expr, $f:expr, $g:expr, $h:expr
212 ),*
213 ) => {
214 $crate::__ty_from_bytes!(
215 LocalBits, $store, [$($crate::macros::internal::u8_from_ne_bits(
216 $a != 0, $b != 0, $c != 0, $d != 0,
217 $e != 0, $f != 0, $g != 0, $h != 0,
218 )),*]
219 )
220 };
221
222 (
223 $order:tt, $store:ident;
224 $(
225 $a:expr, $b:expr, $c:expr, $d:expr,
226 $e:expr, $f:expr, $g:expr, $h:expr
227 ),*
228 ) => {{
229 let mut tmp: $store = 0;
230 let _tmp_bits = BitSlice::<$order, $store>::from_element_mut(&mut tmp);
231 let mut _idx = 0;
232 $(
233 _tmp_bits.set(_idx, $a != 0); _idx += 1;
234 _tmp_bits.set(_idx, $b != 0); _idx += 1;
235 _tmp_bits.set(_idx, $c != 0); _idx += 1;
236 _tmp_bits.set(_idx, $d != 0); _idx += 1;
237 _tmp_bits.set(_idx, $e != 0); _idx += 1;
238 _tmp_bits.set(_idx, $f != 0); _idx += 1;
239 _tmp_bits.set(_idx, $g != 0); _idx += 1;
240 _tmp_bits.set(_idx, $h != 0); _idx += 1;
241 )*
242 tmp
243 }};
244 }
245
246 /// Extend a single bit to fill an element.
247 #[doc(hidden)]
248 #[macro_export]
249 macro_rules! __extend_bool {
250 ($val:expr, $typ:ident) => {
251 (0 as $typ).wrapping_sub(($val != 0) as $typ)
252 };
253 }
254
255 /// Constructs a fundamental integer from a list of bytes.
256 #[doc(hidden)]
257 #[macro_export]
258 macro_rules! __ty_from_bytes {
259 (Msb0, u8, [$($byte:expr),*]) => {
260 u8::from_be_bytes([$($byte),*])
261 };
262 (Lsb0, u8, [$($byte:expr),*]) => {
263 u8::from_le_bytes([$($byte),*])
264 };
265 (LocalBits, u8, [$($byte:expr),*]) => {
266 u8::from_ne_bytes([$($byte),*])
267 };
268 (Msb0, u16, [$($byte:expr),*]) => {
269 u16::from_be_bytes([$($byte),*])
270 };
271 (Lsb0, u16, [$($byte:expr),*]) => {
272 u16::from_le_bytes([$($byte),*])
273 };
274 (LocalBits, u16, [$($byte:expr),*]) => {
275 u16::from_ne_bytes([$($byte),*])
276 };
277 (Msb0, u32, [$($byte:expr),*]) => {
278 u32::from_be_bytes([$($byte),*])
279 };
280 (Lsb0, u32, [$($byte:expr),*]) => {
281 u32::from_le_bytes([$($byte),*])
282 };
283 (LocalBits, u32, [$($byte:expr),*]) => {
284 u32::from_ne_bytes([$($byte),*])
285 };
286 (Msb0, u64, [$($byte:expr),*]) => {
287 u64::from_be_bytes([$($byte),*])
288 };
289 (Lsb0, u64, [$($byte:expr),*]) => {
290 u64::from_le_bytes([$($byte),*])
291 };
292 (LocalBits, u64, [$($byte:expr),*]) => {
293 u64::from_ne_bytes([$($byte),*])
294 };
295 (Msb0, usize, [$($byte:expr),*]) => {
296 usize::from_be_bytes([$($byte),*])
297 };
298 (Lsb0, usize, [$($byte:expr),*]) => {
299 usize::from_le_bytes([$($byte),*])
300 };
301 (LocalBits, usize, [$($byte:expr),*]) => {
302 usize::from_ne_bytes([$($byte),*])
303 };
304 }
305
306 /// Construct a `u8` from bits applied in Lsb0-order.
307 #[allow(clippy::many_single_char_names)]
308 #[allow(clippy::too_many_arguments)]
u8_from_le_bits( a: bool, b: bool, c: bool, d: bool, e: bool, f: bool, g: bool, h: bool, ) -> u8309 pub const fn u8_from_le_bits(
310 a: bool,
311 b: bool,
312 c: bool,
313 d: bool,
314 e: bool,
315 f: bool,
316 g: bool,
317 h: bool,
318 ) -> u8
319 {
320 (a as u8)
321 | ((b as u8) << 1)
322 | ((c as u8) << 2)
323 | ((d as u8) << 3)
324 | ((e as u8) << 4)
325 | ((f as u8) << 5)
326 | ((g as u8) << 6)
327 | ((h as u8) << 7)
328 }
329
330 /// Construct a `u8` from bits applied in Msb0-order.
331 #[allow(clippy::many_single_char_names)]
332 #[allow(clippy::too_many_arguments)]
u8_from_be_bits( a: bool, b: bool, c: bool, d: bool, e: bool, f: bool, g: bool, h: bool, ) -> u8333 pub const fn u8_from_be_bits(
334 a: bool,
335 b: bool,
336 c: bool,
337 d: bool,
338 e: bool,
339 f: bool,
340 g: bool,
341 h: bool,
342 ) -> u8
343 {
344 (h as u8)
345 | ((g as u8) << 1)
346 | ((f as u8) << 2)
347 | ((e as u8) << 3)
348 | ((d as u8) << 4)
349 | ((c as u8) << 5)
350 | ((b as u8) << 6)
351 | ((a as u8) << 7)
352 }
353
354 #[doc(hidden)]
355 #[cfg(target_endian = "little")]
356 pub use self::u8_from_le_bits as u8_from_ne_bits;
357
358 #[doc(hidden)]
359 #[cfg(target_endian = "big")]
360 pub use self::u8_from_be_bits as u8_from_ne_bits;
361
362 #[cfg(test)]
363 mod tests {
364 use super::*;
365
366 #[test]
byte_assembly()367 fn byte_assembly() {
368 assert_eq!(
369 u8_from_le_bits(false, false, true, true, false, true, false, true),
370 0b1010_1100
371 );
372
373 assert_eq!(
374 u8_from_be_bits(false, false, true, true, false, true, false, true),
375 0b0011_0101
376 );
377 }
378 }
379