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 /** Ensures that the ordering tokens map to a known ordering type path.
14
15 Note: non-`const` constructor expressions cannot be used to initialize `static`
16 bindings. Unfortunately, replacing the `from_slice` calls with literal
17 construction of the pointer representation, and type-casting it into the correct
18 type, is *also* unstable, as it requires dereferencing a raw pointer inside a
19 `static` context.
20 **/
21 #[doc(hidden)]
22 #[macro_export]
23 macro_rules! __bits_from_slice {
24 (mut LocalBits, $len:expr, $slice:ident) => {
25 $crate::slice::BitSlice::<$crate::order::LocalBits, _>::from_slice_mut(
26 &mut $slice,
27 )
28 .expect("slice construction exceeded capacity")
29 .get_unchecked_mut(.. $len)
30 };
31 (mut Lsb0, $len:expr, $slice:ident) => {
32 $crate::slice::BitSlice::<$crate::order::Lsb0, _>::from_slice_mut(
33 &mut $slice,
34 )
35 .expect("slice construction exceeded capacity")
36 .get_unchecked_mut(.. $len)
37 };
38 (mut Msb0, $len:expr, $slice:ident) => {
39 $crate::slice::BitSlice::<$crate::order::Msb0, _>::from_slice_mut(
40 &mut $slice,
41 )
42 .expect("slice construction exceeded capacity")
43 .get_unchecked_mut(.. $len)
44 };
45 (mut $order:tt, $len:expr, $slice:ident) => {
46 $crate::slice::BitSlice::<$order, _>::from_slice_mut(&mut $slice)
47 .expect("slice construction exceeded capacity")
48 .get_unchecked_mut(.. $len)
49 };
50
51 (LocalBits, $len:expr, $slice:ident) => {
52 $crate::slice::BitSlice::<$crate::order::LocalBits, _>::from_slice(
53 &$slice,
54 )
55 .expect("slice construction exceeded capacity")
56 .get_unchecked(.. $len)
57 };
58 (Lsb0, $len:expr, $slice:ident) => {
59 $crate::slice::BitSlice::<$crate::order::Lsb0, _>::from_slice(&$slice)
60 .expect("slice construction exceeded capacity")
61 .get_unchecked(.. $len)
62 };
63 (Msb0, $len:expr, $slice:ident) => {
64 $crate::slice::BitSlice::<$crate::order::Msb0, _>::from_slice(&$slice)
65 .expect("slice construction exceeded capacity")
66 .get_unchecked(.. $len)
67 };
68 ($order:tt, $len:expr, $slice:ident) => {
69 $crate::slice::BitSlice::<$order, _>::from_slice(&$slice)
70 .expect("slice construction exceeded capacity")
71 .get_unchecked(.. $len)
72 };
73 }
74
75 /** Accumulates a stream of bit expressions into a compacted array of elements.
76
77 This macro constructs a well-ordered `[T; N]` array expression usable in `const`
78 contexts. Callers may then use that expression as the source slice over which to
79 construct `bitvec` types.
80 **/
81 #[doc(hidden)]
82 #[macro_export]
83 macro_rules! __bits_store_array {
84 // Reroute `usize` to the correct concrete type, and mark the alias.
85 // The `@ usz` causes `as usize` to be appended to exprs as needed.
86 ($order:tt, usize; $($val:expr),*) => {{
87 const LEN: usize = $crate::__count_elts!(usize; $($val),*);
88
89 // Attributes are not currently allowed on expressions, only items and
90 // statements, so the routing here must bind to a name.
91 #[cfg(target_pointer_width = "32")]
92 const OUT: [usize; LEN] = $crate::__bits_store_array!(
93 $order, u32 @ usz; $($val),*
94 );
95
96 #[cfg(target_pointer_width = "64")]
97 const OUT: [usize; LEN] = $crate::__bits_store_array!(
98 $order, u64 @ usz; $($val),*
99 );
100
101 OUT
102 }};
103 // Entry point.
104 ($order:tt, $store:ident $(@ $usz:ident )?; $($val:expr),*) => {
105 $crate::__bits_store_array!(
106 $order, $store $(@ $usz)?, []; $($val,)*
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 48
110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 64
111 );
112 };
113
114 /* NOTE: These have to be first. They (ab)use a quirk of `macro_rules!`
115 where `:expr` captures are considered a single `:tt` after being matched.
116 Even if the `:expr` matcher was a literal `0`, after being wrapped by the
117 `:expr` fragment, it is no longer considered to match a literal `0`, so
118 these patterns will only match the extra padding `0`s added at the end.
119
120 Once the user-provided `$val` expressions are all consumed, the remaining
121 `0` tokens inserted by the arm above are all removed, ensuring that the
122 produced array has no wasted elements.
123 */
124 ($order:tt, $store:ident @ usz, [$( ($($elt:tt),*) )*]; $(0),*) => {
125 [$(
126 $crate::__elt_from_bits!($order, $store; $($elt),*) as usize
127 ),*]
128 };
129 ($order:tt, $store:ident, [$( ($($elt:tt),*) )*]; $(0),*) => {
130 [$(
131 $crate::__elt_from_bits!($order, $store; $($elt),*)
132 ),*]
133 };
134
135 // Matchers for each size of word. The end of the word may be padded out
136 // with `0`s.
137 (
138 $order:tt, u8 $(@ $usz:ident)?, [$($w:tt)*];
139 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt
140 $(, $($t:tt)*)?
141 ) => {
142 $crate::__bits_store_array!(
143 $order, u8 $(@ $usz)?, [$($w)* (
144 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0
145 )];
146 $($($t)*)?
147 )
148 };
149 (
150 $order:tt, u16 $(@ $usz:ident)?, [$($w:tt)*];
151 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt,
152 $a1:tt, $b1:tt, $c1:tt, $d1:tt, $e1:tt, $f1:tt, $g1:tt, $h1:tt
153 $(, $($t:tt)*)?
154 ) => {
155 $crate::__bits_store_array!(
156 $order, u16 $(@ $usz)?, [$($w)* (
157 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0,
158 $a1, $b1, $c1, $d1, $e1, $f1, $g1, $h1
159 )];
160 $($($t)*)?
161 )
162 };
163 (
164 $order:tt, u32 $(@ $usz:ident)?, [$($w:tt)*];
165 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt,
166 $a1:tt, $b1:tt, $c1:tt, $d1:tt, $e1:tt, $f1:tt, $g1:tt, $h1:tt,
167 $a2:tt, $b2:tt, $c2:tt, $d2:tt, $e2:tt, $f2:tt, $g2:tt, $h2:tt,
168 $a3:tt, $b3:tt, $c3:tt, $d3:tt, $e3:tt, $f3:tt, $g3:tt, $h3:tt
169 $(, $($t:tt)*)?
170 ) => {
171 $crate::__bits_store_array!(
172 $order, u32 $(@ $usz)?, [$($w)* (
173 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0,
174 $a1, $b1, $c1, $d1, $e1, $f1, $g1, $h1,
175 $a2, $b2, $c2, $d2, $e2, $f2, $g2, $h2,
176 $a3, $b3, $c3, $d3, $e3, $f3, $g3, $h3
177 )];
178 $($($t)*)?
179 )
180 };
181 (
182 $order:tt, u64 $(@ $usz:ident)?, [$($w:tt)*];
183 $a0:tt, $b0:tt, $c0:tt, $d0:tt, $e0:tt, $f0:tt, $g0:tt, $h0:tt,
184 $a1:tt, $b1:tt, $c1:tt, $d1:tt, $e1:tt, $f1:tt, $g1:tt, $h1:tt,
185 $a2:tt, $b2:tt, $c2:tt, $d2:tt, $e2:tt, $f2:tt, $g2:tt, $h2:tt,
186 $a3:tt, $b3:tt, $c3:tt, $d3:tt, $e3:tt, $f3:tt, $g3:tt, $h3:tt,
187 $a4:tt, $b4:tt, $c4:tt, $d4:tt, $e4:tt, $f4:tt, $g4:tt, $h4:tt,
188 $a5:tt, $b5:tt, $c5:tt, $d5:tt, $e5:tt, $f5:tt, $g5:tt, $h5:tt,
189 $a6:tt, $b6:tt, $c6:tt, $d6:tt, $e6:tt, $f6:tt, $g6:tt, $h6:tt,
190 $a7:tt, $b7:tt, $c7:tt, $d7:tt, $e7:tt, $f7:tt, $g7:tt, $h7:tt
191 $(, $($t:tt)*)?
192 ) => {
193 $crate::__bits_store_array!(
194 $order, u64 $(@ $usz)?, [$($w)* (
195 $a0, $b0, $c0, $d0, $e0, $f0, $g0, $h0,
196 $a1, $b1, $c1, $d1, $e1, $f1, $g1, $h1,
197 $a2, $b2, $c2, $d2, $e2, $f2, $g2, $h2,
198 $a3, $b3, $c3, $d3, $e3, $f3, $g3, $h3,
199 $a4, $b4, $c4, $d4, $e4, $f4, $g4, $h4,
200 $a5, $b5, $c5, $d5, $e5, $f5, $g5, $h5,
201 $a6, $b6, $c6, $d6, $e6, $f6, $g6, $h6,
202 $a7, $b7, $c7, $d7, $e7, $f7, $g7, $h7
203 )];
204 $($($t)*)?
205 )
206 };
207 }
208
209 /// Counts the number of repetitions inside a `$()*` sequence.
210 #[doc(hidden)]
211 #[macro_export]
212 macro_rules! __count {
213 (@ $val:expr) => { 1 };
214 ($($val:expr),*) => {{
215 /* Clippy warns that `.. EXPR + 1`, for any value of `EXPR`, should be
216 replaced with `..= EXPR`. This means that `.. $crate::__count!` raises
217 the lint, causing `bits![(val,)…]` to have an unfixable lint warning.
218 By binding to a `const`, then returning the `const`, this syntax
219 construction is avoided as macros only expand to
220 `.. { const LEN = …; LEN }` rather than `.. 0 (+ 1)…`.
221 */
222 const LEN: usize = 0usize $(+ $crate::__count!(@ $val))*;
223 LEN
224 }};
225 }
226
227 /// Counts the number of elements needed to store a number of bits.
228 #[doc(hidden)]
229 #[macro_export]
230 macro_rules! __count_elts {
231 ($t:ident; $($val:expr),*) => {{
232 $crate::mem::elts::<$t>($crate::__count!($($val),*))
233 }};
234 }
235
236 /// Construct a `T` element from an array of `u8`.
237 #[doc(hidden)]
238 #[macro_export]
239 macro_rules! __elt_from_bits {
240 // Known orderings can be performed immediately.
241 (
242 Lsb0, $store:ident;
243 $($a:tt, $b:tt, $c:tt, $d:tt, $e:tt, $f:tt, $g:tt, $h:tt),*
244 ) => {
245 $crate::__ty_from_bytes!(
246 Lsb0, $store, [$($crate::macros::internal::u8_from_le_bits(
247 $a != 0, $b != 0, $c != 0, $d != 0,
248 $e != 0, $f != 0, $g != 0, $h != 0,
249 )),*]
250 )
251 };
252 (
253 Msb0, $store:ident;
254 $($a:tt, $b:tt, $c:tt, $d:tt, $e:tt, $f:tt, $g:tt, $h:tt),*
255 ) => {
256 $crate::__ty_from_bytes!(
257 Msb0, $store, [$($crate::macros::internal::u8_from_be_bits(
258 $a != 0, $b != 0, $c != 0, $d != 0,
259 $e != 0, $f != 0, $g != 0, $h != 0,
260 )),*]
261 )
262 };
263 (
264 LocalBits, $store:ident;
265 $($a:tt, $b:tt, $c:tt, $d:tt, $e:tt, $f:tt, $g:tt, $h:tt),*
266 ) => {
267 $crate::__ty_from_bytes!(
268 LocalBits, $store, [$($crate::macros::internal::u8_from_ne_bits(
269 $a != 0, $b != 0, $c != 0, $d != 0,
270 $e != 0, $f != 0, $g != 0, $h != 0,
271 )),*]
272 )
273 };
274
275 // Unknown orders are currently unsupported in `macro_rules!`.
276 ($order:tt, $store:ident; $($a:tt),*) => {{
277 /* Note: they can *become* supported, by adding a `ident <-` argument
278 to `bits!` that allows construction of runtime values into a binding
279 which outlives the returned reference without necessarily being `static`
280 (which requires `const` constructors).
281
282 The call-site syntax
283
284 ```rust
285 let slab;
286 let bits = bits![slab <- args…];
287 ```
288
289 would construct the array literal into `slab` and then produce a
290 `&BitSlice` reference from `&slab`. This works because Rust allows
291 delayed initialization if there is exactly one initialization point in
292 all program branch pathways. The expansion of `bits!` would be something
293 like
294
295 ```rust
296 let slab;
297 let bits = {
298 slab = __bits_store_array!($args…);
299 BitSlice::<$o, $t>::from_slice(&slab).get_unchecked(.. $len);
300 };
301 ```
302
303 The `slab` binding outlives the `bits` reference; construction of the
304 `slab` value occurs at runtime in non-`const` contexts.
305
306 This is a deferred item.
307 */
308 compile_error!("The ordering argument you provided is unrecognized, \
309 and as such cannot be used in const contexts.");
310 let mut tmp: $store = 0;
311 let mut _idx = 0u8;
312 let slice = $crate::slice::BitSlice::<$order, _>::from_element_mut(&mut tmp);
313 $(
314 slice.set(_idx, $a != 0);
315 _idx += 1;
316 )*
317 tmp
318 }};
319 }
320
321 /// Extend a single bit to fill an element.
322 #[doc(hidden)]
323 #[macro_export]
324 macro_rules! __extend_bool {
325 ($val:expr, $typ:ident) => {
326 (0 as $typ).wrapping_sub(($val != 0) as $typ)
327 };
328 }
329
330 /// Constructs a fundamental integer from a list of bytes.
331 #[doc(hidden)]
332 #[macro_export]
333 macro_rules! __ty_from_bytes {
334 (Msb0, u8, [$($byte:expr),*]) => {
335 u8::from_be_bytes([$($byte),*])
336 };
337 (Lsb0, u8, [$($byte:expr),*]) => {
338 u8::from_le_bytes([$($byte),*])
339 };
340 (LocalBits, u8, [$($byte:expr),*]) => {
341 u8::from_ne_bytes([$($byte),*])
342 };
343 (Msb0, u16, [$($byte:expr),*]) => {
344 u16::from_be_bytes([$($byte),*])
345 };
346 (Lsb0, u16, [$($byte:expr),*]) => {
347 u16::from_le_bytes([$($byte),*])
348 };
349 (LocalBits, u16, [$($byte:expr),*]) => {
350 u16::from_ne_bytes([$($byte),*])
351 };
352 (Msb0, u32, [$($byte:expr),*]) => {
353 u32::from_be_bytes([$($byte),*])
354 };
355 (Lsb0, u32, [$($byte:expr),*]) => {
356 u32::from_le_bytes([$($byte),*])
357 };
358 (LocalBits, u32, [$($byte:expr),*]) => {
359 u32::from_ne_bytes([$($byte),*])
360 };
361 (Msb0, u64, [$($byte:expr),*]) => {
362 u64::from_be_bytes([$($byte),*])
363 };
364 (Lsb0, u64, [$($byte:expr),*]) => {
365 u64::from_le_bytes([$($byte),*])
366 };
367 (LocalBits, u64, [$($byte:expr),*]) => {
368 u64::from_ne_bytes([$($byte),*])
369 };
370 (Msb0, usize, [$($byte:expr),*]) => {
371 usize::from_be_bytes([$($byte),*])
372 };
373 (Lsb0, usize, [$($byte:expr),*]) => {
374 usize::from_le_bytes([$($byte),*])
375 };
376 (LocalBits, usize, [$($byte:expr),*]) => {
377 usize::from_ne_bytes([$($byte),*])
378 };
379 }
380
381 /// Construct a `u8` from bits applied in Lsb0-order.
382 #[allow(clippy::many_single_char_names)]
383 #[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, ) -> u8384 pub const fn u8_from_le_bits(
385 a: bool,
386 b: bool,
387 c: bool,
388 d: bool,
389 e: bool,
390 f: bool,
391 g: bool,
392 h: bool,
393 ) -> u8
394 {
395 (a as u8)
396 | ((b as u8) << 1)
397 | ((c as u8) << 2)
398 | ((d as u8) << 3)
399 | ((e as u8) << 4)
400 | ((f as u8) << 5)
401 | ((g as u8) << 6)
402 | ((h as u8) << 7)
403 }
404
405 /// Construct a `u8` from bits applied in Msb0-order.
406 #[allow(clippy::many_single_char_names)]
407 #[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, ) -> u8408 pub const fn u8_from_be_bits(
409 a: bool,
410 b: bool,
411 c: bool,
412 d: bool,
413 e: bool,
414 f: bool,
415 g: bool,
416 h: bool,
417 ) -> u8
418 {
419 (h as u8)
420 | ((g as u8) << 1)
421 | ((f as u8) << 2)
422 | ((e as u8) << 3)
423 | ((d as u8) << 4)
424 | ((c as u8) << 5)
425 | ((b as u8) << 6)
426 | ((a as u8) << 7)
427 }
428
429 #[doc(hidden)]
430 #[cfg(target_endian = "little")]
431 pub use self::u8_from_le_bits as u8_from_ne_bits;
432
433 #[doc(hidden)]
434 #[cfg(target_endian = "big")]
435 pub use self::u8_from_be_bits as u8_from_ne_bits;
436
437 #[cfg(test)]
438 mod tests {
439 use super::*;
440
441 #[test]
byte_assembly()442 fn byte_assembly() {
443 assert_eq!(
444 u8_from_le_bits(false, false, true, true, false, true, false, true),
445 0b1010_1100
446 );
447
448 assert_eq!(
449 u8_from_be_bits(false, false, true, true, false, true, false, true),
450 0b0011_0101
451 );
452 }
453 }
454