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