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