mycelium_bitfield/pack.rs
1//! Packing spec types.
2//!
3//! This module provides a set of types to make packing bit ranges easier. These
4//! utilities can be used in `const fn`.
5//!
6//! The bit packing utilities consist of a type that defines a specification for
7//! a bit range to pack into, and a wrapper type for an unsigned integer
8//! defining methods to pack bit ranges into it. Packing specs are defined for
9//! [`usize`], [`u128`], [`u64`], [`u32`], [`u16`], and [`u8`], as
10//! [`PackUsize`], [`Pack128`], [`Pack64`], [`Pack32`], [`Pack16`], and
11//! [`Pack8`], respectively.
12//!
13//! Note that the bit packing utilities are generic using macros, rather than
14//! using generics and traits, because they are intended to be usable in
15//! const-eval, and trait methods cannot be `const fn`.
16//!
17//! # Examples
18//!
19//! Sorry there are no examples on the individual types, I didn't want to figure
20//! out how to write doctests inside the macro :)
21//!
22//! Packing into the least-significant _n_ bits:
23//! ```
24//! use mycelium_bitfield::Pack32;
25//!
26//! const LEAST_SIGNIFICANT_8: Pack32 = Pack32::least_significant(8);
27//!
28//! // the number we're going to pack bits into.
29//! let base = 0xface_0000;
30//!
31//! // pack 0xed into the least significant 8 bits
32//! let val = LEAST_SIGNIFICANT_8.pack(0xed, base);
33//!
34//! assert_eq!(val, 0xface_00ed);
35//! ```
36//!
37//! Packing specs can be defined in relation to each other.
38//!
39//! ```
40//! use mycelium_bitfield::Pack64;
41//!
42//! const LOW: Pack64 = Pack64::least_significant(12);
43//! const MID: Pack64 = LOW.next(8);
44//! const HIGH: Pack64 = MID.next(4);
45//!
46//! let base = 0xfeed000000;
47//!
48//! // note that we don't need to pack the values in order.
49//! let val = HIGH.pack(0xC, base);
50//! let val = LOW.pack(0xfee, val);
51//! let val = MID.pack(0x0f, val);
52//!
53//! assert_eq!(val, 0xfeedc0ffee); // i want c0ffee
54//! ```
55//!
56//! The same example can be written a little bit more neatly using methods:
57//!
58//! ```
59//! # use mycelium_bitfield::Pack64;
60//! const LOW: Pack64 = Pack64::least_significant(12);
61//! const MID: Pack64 = LOW.next(8);
62//! const HIGH: Pack64 = MID.next(4);
63//!
64//! // Wrap a value to pack it using method calls.
65//! let coffee = Pack64::pack_in(0)
66//! .pack(0xfee, &LOW)
67//! .pack(0xC, &HIGH)
68//! .pack(0x0f, &MID)
69//! .bits();
70//!
71//! assert_eq!(coffee, 0xc0ffee); // i still want c0ffee
72//! ```
73//!
74//! Packing specs can be used to extract values from their packed
75//! representation:
76//!
77//! ```
78//! # use mycelium_bitfield::Pack64;
79//! # const LOW: Pack64 = Pack64::least_significant(12);
80//! # const MID: Pack64 = LOW.next(8);
81//! # const HIGH: Pack64 = MID.next(4);
82//! # let coffee = Pack64::pack_in(0)
83//! # .pack(0xfee, &LOW)
84//! # .pack(0xC, &HIGH)
85//! # .pack(0x0f, &MID)
86//! # .bits();
87//! #
88//! assert_eq!(LOW.unpack_bits(coffee), 0xfee);
89//! assert_eq!(MID.unpack_bits(coffee), 0x0f);
90//! assert_eq!(HIGH.unpack_bits(coffee), 0xc);
91//! ```
92//!
93//! Any previously set bit patterns in the packed range will be overwritten, but
94//! existing values outside of a packing spec's range are preserved:
95//!
96//! ```
97//! # use mycelium_bitfield::Pack64;
98//! # const LOW: Pack64 = Pack64::least_significant(12);
99//! # const MID: Pack64 = LOW.next(8);
100//! # const HIGH: Pack64 = MID.next(4);
101//! // this is not coffee
102//! let not_coffee = 0xc0ff0f;
103//!
104//! let coffee = LOW.pack(0xfee, not_coffee);
105//!
106//! // now it's coffee
107//! assert_eq!(coffee, 0xc0ffee);
108//! ```
109//!
110//! We can also define packing specs for arbitrary bit ranges, in addition to
111//! defining them in relation to each other.
112//!
113//! ```
114//! use mycelium_bitfield::Pack64;
115//!
116//! // pack a 12-bit value starting at the ninth bit
117//! let low = Pack64::from_range(9..=21);
118//!
119//! // pack another value into the next 12 bits following `LOW`.
120//! let mid = low.next(12);
121//!
122//! // pack a third value starting at bit 33 to the end of the `u64`.
123//! let high = Pack64::from_range(33..);
124//!
125//! let val = Pack64::pack_in(0)
126//! .pack(0xc0f, &mid)
127//! .pack(0xfee, &low)
128//! .pack(0xfeed, &high)
129//! .bits();
130//!
131//! assert_eq!(val, 0xfeedc0ffee00); // starting to detect a bit of a theme here...
132//! ```
133//!
134use super::FromBits;
135use core::{
136 any::type_name,
137 fmt,
138 marker::PhantomData,
139 ops::{Bound, Range, RangeBounds},
140};
141
142macro_rules! make_packers {
143 ($(pub struct $Pack:ident { bits: $Bits:ty, packing: $Packing:ident, pair: $Pair:ident $(,)? })+) => {
144 $(
145
146 #[doc = concat!(
147 "A spec for packing values into selected bit ranges of [`",
148 stringify!($Bits),
149 "`] values."
150 )]
151 #[doc = ""]
152 #[doc = "See the [module-level documentation](crate::pack) for details on using packing specs."]
153 pub struct $Pack<T = $Bits, F = ()> {
154 mask: $Bits,
155 shift: u32,
156 _dst_ty: PhantomData<fn(&T, &F)>,
157 }
158
159 #[doc = concat!(
160 "Wraps a [`",
161 stringify!($Bits),
162 "`] to add methods for packing bit ranges specified by [`",
163 stringify!($Pack),
164 "`]."
165 )]
166 #[doc = ""]
167 #[doc = "See the [module-level documentation](crate::pack) for details on using packing specs."]
168 #[derive(Copy, Clone, PartialEq, Eq)]
169 pub struct $Packing($Bits);
170
171 #[doc = concat!(
172 "A pair of [",
173 stringify!($Pack),
174 "]s, allowing a bit range to be unpacked from one offset in a [",
175 stringify!($Bits),
176 "] value, and packed into a different offset in a different value."
177 )]
178 #[doc = ""]
179 #[doc = "See the [module-level documentation](crate::pack) for details on using packing specs."]
180 pub struct $Pair<T = $Bits> {
181 src: $Pack<T>,
182 dst: $Pack<T>,
183 dst_shl: $Bits,
184 dst_shr: $Bits,
185 }
186
187 impl $Pack<$Bits> {
188 #[doc = concat!(
189 "Wrap a [`",
190 stringify!($Bits),
191 "`] to add methods for packing bit ranges using [`",
192 stringify!($Pack),
193 "`]."
194 )]
195 #[doc = ""]
196 #[doc = concat!(
197 "This is equivalent to calling [`",
198 stringify!($Packing),
199 "::new`], but only requires importing the packer type."
200 )]
201 pub const fn pack_in(value: $Bits) -> $Packing {
202 $Packing::new(value)
203 }
204
205
206 /// Returns a packer for packing a value into the first `bits` bits.
207 pub const fn least_significant(n: u32) -> Self {
208 Self {
209 mask: Self::mk_mask(n),
210 shift: 0,
211 _dst_ty: core::marker::PhantomData,
212 }
213 }
214
215
216 /// Returns a packer that will pack a value into the provided mask.
217 pub const fn from_mask(mask: $Bits) -> Self {
218 let shift = mask.leading_zeros();
219 let mask = mask >> shift;
220 Self { mask, shift, _dst_ty: core::marker::PhantomData, }
221 }
222
223 /// This is a `const fn`-compatible equivalent of
224 /// [`Self::from_range`]. Note that it can only be used with
225 /// [`core::ops::Range`]s, and not with
226 /// [`core::ops::RangeInclusive`], [`core::ops::RangeTo`],
227 /// [`core::ops::RangeFrom`], [`core::ops::RangeToInclusive`]. :(
228 pub const fn from_const_range(range: Range<u32>) -> Self {
229 Self::starting_at(range.start, range.end.saturating_sub(range.start))
230 }
231
232 /// Construct a bit packing spec from a range of bits.
233 ///
234 /// # Panics
235 ///
236 /// - If the range does not fit within the integer type packed
237 /// by this packing spec.
238 /// - If the range's start > the range's end (although most
239 /// range types should prevent this).
240 pub fn from_range(range: impl RangeBounds<u32>) -> Self {
241 use Bound::*;
242 let start = match range.start_bound() {
243 Included(&bit) => bit,
244 Excluded(&bit) => bit + 1,
245 Unbounded => 0,
246 };
247 assert!(
248 start < Self::SIZE_BITS,
249 "range start value ({}) must be less than the maximum number of bits in a `u{}`",
250 start,
251 Self::SIZE_BITS,
252 );
253 let end = match range.end_bound() {
254 Included(&bit) => bit,
255 Excluded(&bit) => bit - 1,
256 Unbounded => Self::SIZE_BITS,
257 };
258 assert!(
259 end <= Self::SIZE_BITS,
260 "range end value ({}) must be less than or equal to the maximum number of bits in a `u{}`",
261 end,
262 Self::SIZE_BITS,
263 );
264 debug_assert!(
265 start <= end,
266 "range end value ({}) may not be greater than range start value ({})",
267 start,
268 end,
269 );
270 Self::starting_at(start, end.saturating_sub(start))
271 }
272 }
273
274 impl<T, F> $Pack<T, F> {
275 // XXX(eliza): why is this always `u32`? ask the stdlib i guess...
276 const SIZE_BITS: u32 = <$Bits>::MAX.leading_ones();
277
278 /// Returns a value with the first `n` bits set.
279 const fn mk_mask(n: u32) -> $Bits {
280 if n == 0 {
281 return 0
282 }
283 let one: $Bits = 1; // lolmacros
284 let shift = one.wrapping_shl(n - 1);
285 shift | (shift.saturating_sub(1))
286 }
287
288 const fn shift_next(&self) -> u32 {
289 Self::SIZE_BITS - self.mask.leading_zeros()
290 }
291
292 #[doc(hidden)]
293 pub const fn typed<T2, F2>(self) -> $Pack<T2, F2>
294 where
295 T2: FromBits<$Bits>
296 {
297 assert!(T2::BITS >= self.bits());
298 $Pack {
299 shift: self.shift,
300 mask: self.mask,
301 _dst_ty: PhantomData,
302 }
303 }
304
305
306 /// Returns the number of bits needed to pack this value.
307 pub const fn bits(&self) -> u32 {
308 Self::SIZE_BITS - (self.mask >> self.shift).leading_zeros()
309 }
310
311 /// Returns the maximum value of this packing spec (i.e. a value
312 /// with all the bits set)
313 pub const fn max_value(&self) -> $Bits {
314 (1 << self.bits()) - 1
315 }
316
317 /// Returns a value with the first bit in this packing spec set.
318 #[inline]
319 pub const fn first_bit(&self) -> $Bits {
320 1 << self.shift
321 }
322
323 /// Returns a raw, shifted mask for unpacking this packing spec.
324 #[inline]
325 pub const fn raw_mask(&self) -> $Bits {
326 self.mask
327 }
328
329 /// Pack the [`self.bits()`] least-significant bits from `value` into `base`.
330 ///
331 /// Any bits more significant than the [`self.bits()`]-th bit are ignored.
332 ///
333 /// [`self.bits()`]: Self::bits
334 #[inline]
335 pub const fn pack_truncating(&self, value: $Bits, base: $Bits) -> $Bits {
336 let value = value & self.max_value();
337 // other bits from `base` we don't want to touch
338 let rest = base & !self.mask;
339 rest | (value << self.shift)
340 }
341
342 /// Pack the [`self.bits()`] least-significant bits from `value`
343 /// into `base`, mutating `base`.
344 ///
345 /// Any bits more significant than the [`self.bits()`]-th bit are ignored.
346 ///
347 /// [`self.bits()`]: Self::bits
348 #[inline]
349 pub fn pack_into_truncating<'base>(&self, value: $Bits, base: &'base mut $Bits) -> &'base mut $Bits {
350 let value = value & self.max_value();
351 *base &= !self.mask;
352 *base |= (value << self.shift);
353 base
354 }
355
356 /// Returns a new packer for packing a `T2`-typed value in the
357 /// next [`T2::BITS`](crate::FromBits::BITS) bits after `self`.
358 pub const fn then<T2>(&self) -> $Pack<T2, F>
359 where
360 T2: FromBits<$Bits>
361 {
362 self.next(T2::BITS).typed()
363 }
364
365 /// Returns a packer for packing a value into the next more-significant
366 /// `n` from `self`.
367 pub const fn next(&self, n: u32) -> $Pack<$Bits, F> {
368 let shift = self.shift_next();
369 let mask = Self::mk_mask(n) << shift;
370 $Pack { mask, shift, _dst_ty: core::marker::PhantomData, }
371 }
372
373 /// Returns a packer for packing a value into all the remaining
374 /// more-significant bits after `self`.
375 pub const fn remaining(&self) -> $Pack<$Bits, F> {
376 let shift = self.shift_next();
377 let n = Self::SIZE_BITS - shift;
378 let mask = Self::mk_mask(n) << shift;
379 $Pack { mask, shift, _dst_ty: core::marker::PhantomData, }
380 }
381
382
383 /// Set _all_ bits packed by this packer to 1.
384 ///
385 /// This is a convenience function for
386 /// ```rust,ignore
387 /// self.pack(self.max_value(), base)
388 /// ```
389 #[inline]
390 pub const fn set_all(&self, base: $Bits) -> $Bits {
391 // Note: this will never truncate (the reason why is left
392 // as an exercise to the reader).
393 self.pack_truncating(self.max_value(), base)
394 }
395
396 /// Set _all_ bits packed by this packer to 0.
397 ///
398 /// This is a convenience function for
399 /// ```rust,ignore
400 /// self.pack(0, base)
401 /// ```
402 #[inline]
403 pub const fn unset_all(&self, base: $Bits) -> $Bits {
404 // may be slightly faster than actually calling
405 // `self.pack(0, base)` when not const-evaling
406 base & !self.mask
407 }
408
409 /// Set _all_ bits packed by this packer to 1 in `base`.
410 ///
411 /// This is a convenience function for
412 /// ```rust,ignore
413 /// self.pack_into(self.max_value(), base)
414 /// ```
415 #[inline]
416 pub fn set_all_in<'base>(&self, base: &'base mut $Bits) -> &'base mut $Bits {
417 // Note: this will never truncate (the reason why is left
418 // as an exercise to the reader).
419 self.pack_into_truncating(self.max_value(), base)
420 }
421
422 /// Set _all_ bits packed by this packer to 0.
423 ///
424 /// This is a convenience function for
425 /// ```rust,ignore
426 /// self.pack_into(0, base)
427 /// ```
428 #[inline]
429 pub fn unset_all_in<'base>(&self, base: &'base mut $Bits) -> &'base mut $Bits {
430 // may be slightly faster than actually calling
431 // `self.pack(0, base)` when not const-evaling
432 *base &= !self.mask;
433 base
434 }
435
436
437 /// Unpack this packer's bits from `source`.
438 #[inline]
439 pub const fn unpack_bits(&self, src: $Bits) -> $Bits {
440 (src & self.mask) >> self.shift
441 }
442
443
444 /// Returns `true` if **any** bits specified by this packing spec
445 /// are set in `src`.
446 #[inline]
447 pub const fn contained_in_any(&self, bits: $Bits) -> bool {
448 bits & self.mask != 0
449 }
450
451
452 /// Returns `true` if **all** bits specified by this packing spec
453 /// are set in `src`.
454 #[inline]
455 pub const fn contained_in_all(&self, bits: $Bits) -> bool {
456 bits & self.mask == self.mask
457 }
458
459 /// Asserts that this packing spec is valid.
460 ///
461 /// Because assertions cannot be made in `const fn`, this
462 /// performs validating assertions that would ideally be made
463 /// when constructing a new instance of this type. When packing
464 /// specs are declared as `const`s, this method can be called in
465 /// a unit test to ensure that the spec is valid.
466 #[track_caller]
467 pub fn assert_valid(&self) {
468 self.assert_valid_inner(&"")
469 }
470
471
472 /// Assert all of a set of packing specs are valid for packing
473 /// and unpacking values into the same bitfield.
474 ///
475 /// This asserts that each individual packing spec is valid (by
476 /// calling [`assert_valid`](Self::assert_valid) on that spec),
477 /// and asserts that no two packing specs in `specs` overlap
478 /// (indicating that they can safely represent a single
479 /// bitfield's subranges).
480 ///
481 /// This function takes a slice of `(&str, Self)` tuples, with
482 /// the `&str`s providing a name for each packing spec. This name
483 /// is used to refer to that packing spec in panic messages.
484 #[track_caller]
485 pub fn assert_all_valid(specs: &[(&str, Self)]) {
486 for (name, spec) in specs {
487 spec.assert_valid_inner(&format_args!(" ({name})"));
488 for (other_name, other_spec) in specs {
489 // Don't test if this spec overlaps with itself ---
490 // they obviously overlap.
491 if name == other_name {
492 continue;
493 }
494 if spec.raw_mask() & other_spec.raw_mask() > 0 {
495 let maxlen = core::cmp::max(name.len(), other_name.len());
496 panic!(
497 "mask for {name} overlaps with {other_name}\n\
498 {name:>width$} = {this_mask:#b}\n\
499 {other_name:>width$} = {that_mask:#b}",
500 name = name,
501 other_name = other_name,
502 this_mask = spec.raw_mask(),
503 that_mask = other_spec.raw_mask(),
504 width = maxlen + 2,
505 );
506 }
507 }
508 }
509 }
510
511 /// Returns the index of the least-significant bit of this
512 /// packing spec (i.e. the bit position of the start of the
513 /// packed range).
514 pub const fn least_significant_index(&self) -> u32 {
515 self.shift
516 }
517
518 /// Returns the index of the most-significant bit of this
519 /// packing spec (i.e. the bit position of the end of the
520 /// packed range).
521 ///
522 /// This will always be greater than the value returned by
523 /// [`least_significant_index`](Self::least_significant_index).
524 pub const fn most_significant_index(&self) -> u32 {
525 Self::SIZE_BITS - self.mask.leading_zeros()
526 }
527
528 #[track_caller]
529 fn assert_valid_inner(&self, cx: &impl fmt::Display) {
530 assert!(
531 self.shift < Self::SIZE_BITS,
532 "shift may not exceed maximum bits for {} (would wrap)\n\
533 -> while checking validity of {:?}{}",
534 stringify!($Bits),
535 self,
536 cx,
537 );
538 assert!(
539 self.bits() <= Self::SIZE_BITS,
540 "number of bits ({}) may not exceed maximum bits for {} (would wrap)\n\
541 -> while checking validity of {:?}{}",
542 self.bits(),
543 stringify!($Bits),
544 self,
545 cx,
546 );
547 assert!(
548 self.bits() + self.shift <= Self::SIZE_BITS,
549 "shift + number of bits ({} + {} = {}) may not exceed maximum bits for {} (would wrap)\n\
550 -> while checking validity of {:?}{}",
551 self.shift,
552 self.bits(),
553 self.bits() + self.shift,
554 stringify!($Bits),
555 self,
556 cx,
557 );
558 assert_eq!(self.most_significant_index() - self.least_significant_index(), self.bits(),
559 "most_significant_index - least_significant_index ({} + {} = {}) must equal total number of bits ({})\n\
560 -> while checking validity of {:?}{}",
561 self.most_significant_index(),
562 self.least_significant_index(),
563 self.most_significant_index() - self.least_significant_index(), self.bits(),
564 self, cx
565 )
566 }
567 }
568
569 impl<T, F> $Pack<T, F>
570 where
571 T: FromBits<$Bits>,
572 {
573 /// Returns a packing spec for packing a `T`-typed value in the
574 /// first [`T::BITS`](FromBits::BITS) least-significant bits.
575 pub const fn first() -> Self {
576 $Pack::<$Bits, ()>::least_significant(T::BITS).typed()
577 }
578
579 /// Returns a packer for packing a value into the next `n` more-significant
580 /// after the `bit`th bit.
581 pub const fn starting_at(bit: u32, n: u32) -> Self {
582 let shift = bit.saturating_sub(1);
583 let mask = Self::mk_mask(n) << shift;
584 Self { mask, shift, _dst_ty: PhantomData, }
585 }
586
587 /// Returns a pair type for packing bits from the range
588 /// specified by `self` at the specified offset `at`, which may
589 /// differ from `self`'s offset.
590 ///
591 /// The packing pair can be used to pack bits from one location
592 /// into another location, and vice versa.
593 pub const fn pair_at(&self, at: u32) -> $Pair<T> {
594 let dst = Self::starting_at(at, self.bits());
595 self.pair_with(dst)
596 }
597
598 /// Returns a pair type for packing bits from the range
599 /// specified by `self` after the specified packing spec.
600 pub const fn pair_after(&self, after: Self) -> $Pair<T> {
601 self.pair_at(after.shift_next())
602 }
603
604 /// Returns a pair type for packing bits from the range
605 /// specified by `self` into the range specified by `with`.
606 ///
607 /// # Note
608 ///
609 /// The two ranges must be the same size. This can be asserted
610 /// by the `assert_valid` method on the returned pair type.
611 pub const fn pair_with<F2>(&self, dst: $Pack<T, F2>) -> $Pair<T> {
612 // TODO(eliza): validate that `dst.shift + self.bits() < N_BITS` in
613 // const fn somehow lol
614 let (dst_shl, dst_shr) = if dst.shift > self.shift {
615 // If the destination is greater than `self`, we need to
616 // shift left.
617 ((dst.shift - self.shift) as $Bits, 0)
618 } else {
619 // Otherwise, shift down.
620 (0, (self.shift - dst.shift) as $Bits)
621 };
622
623 $Pair {
624 src: self.typed(),
625 dst: dst.typed(),
626 dst_shl,
627 dst_shr,
628 }
629 }
630
631 /// Pack the [`self.bits()`] least-significant bits from `value` into `base`.
632 ///
633 /// # Panics
634 ///
635 /// Panics if any other bits outside of [`self.bits()`] are set
636 /// in `value`.
637 ///
638 /// [`self.bits()`]: Self::bits
639 pub fn pack(&self, value: T, base: $Bits) -> $Bits {
640 let value = value.into_bits();
641 assert!(
642 value <= self.max_value(),
643 "bits outside of packed range are set!\n value: {:#b},\n max_value: {:#b}",
644 value,
645 self.max_value(),
646 );
647 self.pack_truncating(value, base)
648 }
649
650 /// Pack the [`self.bits()`] least-significant bits from `value`
651 /// into `base`, mutating `base`.
652 ///
653 /// # Panics
654 ///
655 /// Panics if any other bits outside of [`self.bits()`] are set
656 /// in `value`.
657 ///
658 /// [`self.bits()`]: Self::bits
659 pub fn pack_into<'base>(&self, value: T, base: &'base mut $Bits) -> &'base mut $Bits {
660 let value = value.into_bits();
661 assert!(
662 value <= self.max_value(),
663 "bits outside of packed range are set!\n value: {:#b},\n max_value: {:#b}",
664 value,
665 self.max_value(),
666 );
667 *base &= !self.mask;
668 *base |= (value << self.shift);
669 base
670 }
671
672 /// Attempts to unpack a `T`-typed value from `src`.
673 ///
674 /// # Returns
675 ///
676 /// - `Ok(T)` if a `T`-typed value could be constructed from the
677 /// bits in `src`
678 /// - `Err(T::Error)` if `src` does not contain a valid bit
679 /// pattern for a `T`-typed value, as determined by `T`'s
680 /// [`FromBits::try_from_bits`] implementation.
681 pub fn try_unpack(&self, src: $Bits) -> Result<T, T::Error> {
682 T::try_from_bits(self.unpack_bits(src))
683 }
684
685 /// Unpacks a `T`-typed value from `src`.
686 ///
687 /// # Panics
688 ///
689 /// This method panics if `src` does not contain a valid bit
690 /// pattern for a `T`-typed value, as determined by `T`'s
691 /// [`FromBits::try_from_bits`] implementation.
692 pub fn unpack(&self, src: $Bits) -> T
693 where
694 T: FromBits<$Bits>,
695 {
696 let bits = self.unpack_bits(src);
697 match T::try_from_bits(bits) {
698 Ok(value) => value,
699 Err(e) => panic!("failed to construct {} from bits {:#b} ({}): {}", type_name::<T>(), bits, bits, e),
700 }
701 }
702 }
703
704 impl<T, F> Clone for $Pack<T, F> {
705 fn clone(&self) -> Self {
706 *self
707 }
708 }
709
710 impl<T, F> Copy for $Pack<T, F> {}
711
712 impl<T, F> fmt::Debug for $Pack<T, F> {
713 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
714 let Self { mask, shift, _dst_ty } = self;
715 f.debug_struct(stringify!($Pack))
716 .field("mask", &format_args!("{:#b}", mask))
717 .field("shift", shift)
718 .field("dst_type", &format_args!("{}", type_name::<T>()))
719 .finish()
720 }
721 }
722
723 impl<T, F> fmt::UpperHex for $Pack<T, F> {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725 let Self { mask, shift, _dst_ty } = self;
726 f.debug_struct(stringify!($Pack))
727 .field("mask", &format_args!("{:#X}", mask))
728 .field("shift", shift)
729 .field("dst_type", &format_args!("{}", type_name::<T>()))
730 .finish()
731 }
732 }
733
734 impl<T, F> fmt::LowerHex for $Pack<T, F> {
735 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
736 let Self { mask, shift, _dst_ty } = self;
737 f.debug_struct(stringify!($Pack))
738 .field("mask", &format_args!("{:#x}", mask))
739 .field("shift", shift)
740 .field("dst_type", &format_args!("{}", type_name::<T>()))
741 .finish()
742 }
743 }
744
745 impl<T, F> fmt::Binary for $Pack<T, F> {
746 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
747 let Self { mask, shift, _dst_ty } = self;
748 f.debug_struct(stringify!($Pack))
749 .field("mask", &format_args!("{:#b}", mask))
750 .field("shift", shift)
751 .field("dst_type", &format_args!("{}", type_name::<T>()))
752 .finish()
753 }
754 }
755
756 impl<R: RangeBounds<u32>> From<R> for $Pack {
757 fn from(range: R) -> Self {
758 Self::from_range(range)
759 }
760 }
761
762 impl<A, B, F> PartialEq<$Pack<B, F>> for $Pack<A, F> {
763 #[inline]
764 fn eq(&self, other: &$Pack<B, F>) -> bool {
765 self.mask == other.mask && self.shift == other.shift
766 }
767 }
768
769 impl<A, B, F> PartialEq<&'_ $Pack<B, F>> for $Pack<A, F> {
770 #[inline]
771 fn eq(&self, other: &&'_ $Pack<B, F>) -> bool {
772 <Self as PartialEq<$Pack<B, F>>>::eq(self, *other)
773 }
774 }
775
776 impl<A, B, F> PartialEq<$Pack<B, F>> for &'_ $Pack<A, F> {
777 #[inline]
778 fn eq(&self, other: &$Pack<B, F>) -> bool {
779 <$Pack<A, F> as PartialEq<$Pack<B, F>>>::eq(*self, other)
780 }
781 }
782
783 impl<T, F> Eq for $Pack<T, F> {}
784
785 // === packing type ===
786
787 impl $Packing {
788 #[doc = concat!(
789 "Wrap a [`",
790 stringify!($Bits),
791 "`] to add methods for packing bit ranges using [`",
792 stringify!($Pack),
793 "`]."
794 )]
795 pub const fn new(bits: $Bits) -> Self {
796 Self(bits)
797 }
798
799 /// Pack bits from `value` into `self`, using the range
800 /// specified by `packer`.
801 ///
802 /// Any bits in `value` outside the range specified by `packer`
803 /// are ignored.
804 #[inline]
805 pub const fn pack_truncating(self, value: $Bits, packer: &$Pack) -> Self {
806 Self(packer.pack_truncating(value, self.0))
807 }
808
809 /// Pack bits from `src` into `self`, using the packing pair
810 /// specified by `pair`, with `self` serving as the "destination" member
811 /// of the pair, and `src` serving as the "source" member of the
812 /// pair.
813 #[inline]
814 pub const fn pack_from_src(self, value: $Bits, pair: &$Pair) -> Self {
815 Self(pair.pack_from_src(self.0, value))
816 }
817
818 /// Pack bits from `dst` into `self`, using the packing pair
819 /// specified by `pair`, with `self` serving as the "siyrce" member
820 /// of the pair, and `dst` serving as the "destination" member of the
821 /// pair.
822 #[inline]
823 pub const fn pack_from_dst(self, value: $Bits, pair: &$Pair) -> Self {
824 Self(pair.pack_from_dst(value, self.0))
825 }
826
827
828 /// Pack bits from `value` into `self`, using the range
829 /// specified by `packer`.
830 ///
831 /// # Panics
832 ///
833 /// If `value` contains bits outside the range specified by `packer`.
834 pub fn pack<T: FromBits<$Bits>, F>(self, value: T, packer: &$Pack<T, F>) -> Self {
835 Self(packer.pack(value, self.0))
836 }
837
838 /// Set _all_ bits in the range specified by `packer` to 1 in `self`.
839 #[inline]
840 pub const fn set_all<T, F>(self, packer: &$Pack<T, F>) -> Self {
841 Self(packer.set_all(self.0))
842 }
843
844 /// Set _all_ bits in the range specified by `packer` to 0 in
845 /// `self`.
846 #[inline]
847 pub const fn unset_all<T, F>(self, packer: &$Pack<T, F>) -> Self {
848 Self(packer.unset_all(self.0))
849 }
850
851
852 /// Returns `true` if **any** bits specified by `packer` are set
853 /// in `self`.
854 #[inline]
855 pub const fn contains_any<T, F>(self, packer: &$Pack<T, F>) -> bool {
856 packer.contained_in_any(self.0)
857 }
858
859
860 /// Returns `true` if **any** bits specified by `packer` are set
861 /// in `self`.
862 #[inline]
863 pub const fn contains_all<T, F>(self, packer: &$Pack<T, F>) -> bool {
864 packer.contained_in_all(self.0)
865 }
866
867 /// Finish packing bits into `self`, returning the wrapped
868 /// value.
869 #[inline]
870 pub const fn bits(self) -> $Bits {
871 self.0
872 }
873 }
874
875 impl fmt::Debug for $Packing {
876 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877 f.debug_tuple(stringify!($Packing))
878 .field(&format_args!("{:#b}", self.0))
879 .finish()
880 }
881 }
882
883 impl fmt::UpperHex for $Packing {
884 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
885 f.debug_tuple(stringify!($Packing))
886 .field(&format_args!("{:X}", self.0))
887 .finish()
888 }
889 }
890
891 impl fmt::LowerHex for $Packing {
892 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
893 f.debug_tuple(stringify!($Packing))
894 .field(&format_args!("{:#x}", self.0))
895 .finish()
896 }
897 }
898
899 impl fmt::Binary for $Packing {
900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901 f.debug_tuple(stringify!($Packing))
902 .field(&format_args!("{:#b}", self.0))
903 .finish()
904 }
905 }
906
907 impl From<$Bits> for $Packing {
908 fn from(bits: $Bits) -> Self {
909 Self(bits)
910 }
911 }
912
913 impl From<$Packing> for $Bits {
914 fn from(packing: $Packing) -> Self {
915 packing.0
916 }
917 }
918
919 // ==== impl Pair ===
920 impl $Pair {
921 const fn shift_dst(&self, val: $Bits) -> $Bits {
922 (val << self.dst_shl) >> self.dst_shr
923 }
924
925 const fn shift_src(&self, val: $Bits) -> $Bits {
926 (val >> self.dst_shl) << self.dst_shr
927 }
928
929
930 /// Returns the "source" member of the packing pair.
931 pub const fn src(&self) -> &$Pack {
932 &self.src
933 }
934
935
936 /// Returns the "destination" member of the packing pair.
937 pub const fn dst(&self) -> &$Pack {
938 &self.dst
939 }
940
941 /// Pack bits from the source location in `src` into the
942 /// destination location in `dst`.
943 pub const fn pack_from_src(&self, src: $Bits, dst: $Bits) -> $Bits {
944 // extract the bit range from `dst` and shift it over to the
945 // target range in `src`.
946 let bits = self.shift_src(dst & self.dst.mask);
947 // zero packed range in `src`.
948 let src = src & !self.src.mask;
949 src | bits
950 }
951
952 /// Pack bits from the destination location in `dst` into the
953 /// source location in `src`.
954 pub const fn pack_from_dst(&self, src: $Bits, dst: $Bits) -> $Bits {
955 // extract the bit range from `src` and shift it over to
956 // the target range in `dst`.
957 let bits = self.shift_dst(src & self.src.mask);
958 // zero the target range in `dst`.
959 let dst = dst & !self.dst.mask;
960 dst | bits
961 }
962
963 /// Asserts that this packing pair is valid.
964 ///
965 /// Because assertions cannot be made in `const fn`, this
966 /// performs validating assertions that would ideally be made
967 /// when constructing a new instance of this type. When packing
968 /// specs are declared as `const`s, this method can be called in
969 /// a unit test to ensure that the spec is valid.
970 #[track_caller]
971 pub fn assert_valid(&self) {
972 assert_eq!(
973 self.src.bits(), self.dst.bits(),
974 "source and destination packing specs must be the same number of bits wide\n\
975 -> while checking validity of {:?}",
976 self
977 );
978 assert!(
979 self.dst_shl == 0 || self.dst_shr == 0,
980 "destination bits must not be shifted both left and right\n\
981 -> while checking validity of {:?}",
982 self
983 );
984 self.dst.assert_valid_inner(&format_args!("\n-> while checking validity of {:?}", self));
985 self.src.assert_valid_inner(&format_args!("\n-> while checking validity of {:?}", self));
986 }
987 }
988
989 impl<T> Clone for $Pair<T> {
990 fn clone(&self) -> Self {
991 *self
992 }
993 }
994
995 impl<T> Copy for $Pair<T> {}
996
997 impl<T> fmt::Debug for $Pair<T> {
998 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
999 let Self { src, dst, dst_shl, dst_shr } = self;
1000 f.debug_struct(stringify!($Pair))
1001 .field("src", src)
1002 .field("dst", dst)
1003 .field("dst_shl", dst_shl)
1004 .field("dst_shr", dst_shr)
1005 .finish()
1006 }
1007 }
1008
1009 impl<T> fmt::UpperHex for $Pair<T> {
1010 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1011 let Self { src, dst, dst_shl, dst_shr } = self;
1012 f.debug_struct(stringify!($Pair))
1013 .field("src", src)
1014 .field("dst", dst)
1015 .field("dst_shl", dst_shl)
1016 .field("dst_shr", dst_shr)
1017 .finish()
1018 }
1019 }
1020
1021 impl<T> fmt::LowerHex for $Pair<T> {
1022 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1023 let Self { src, dst, dst_shl, dst_shr } = self;
1024 f.debug_struct(stringify!($Pair))
1025 .field("src", src)
1026 .field("dst", dst)
1027 .field("dst_shl", dst_shl)
1028 .field("dst_shr", dst_shr)
1029 .finish()
1030 }
1031 }
1032
1033 impl<T> fmt::Binary for $Pair<T> {
1034 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1035 let Self { src, dst, dst_shl, dst_shr } = self;
1036 f.debug_struct(stringify!($Pair))
1037 .field("src", src)
1038 .field("dst", dst)
1039 .field("dst_shl", dst_shl)
1040 .field("dst_shr", dst_shr)
1041 .finish()
1042 }
1043 }
1044
1045 impl<A, B> PartialEq<$Pair<B>> for $Pair<A> {
1046 #[inline]
1047 fn eq(&self, other: &$Pair<B>) -> bool {
1048 self.src == other.src && self.dst == other.dst
1049 }
1050 }
1051
1052 impl<A, B> PartialEq<&'_ $Pair<B>> for $Pair<A> {
1053 #[inline]
1054 fn eq(&self, other: &&'_ $Pair<B>) -> bool {
1055 <Self as PartialEq<$Pair<B>>>::eq(self, *other)
1056 }
1057 }
1058
1059 impl<A, B> PartialEq<$Pair<B>> for &'_ $Pair<A> {
1060 #[inline]
1061 fn eq(&self, other: &$Pair<B>) -> bool {
1062 <$Pair<A> as PartialEq<$Pair<B>>>::eq(*self, other)
1063 }
1064 }
1065
1066
1067 impl<T> Eq for $Pair<T> {}
1068 )+
1069 }
1070}
1071
1072make_packers! {
1073 pub struct PackUsize { bits: usize, packing: PackingUsize, pair: PairUsize }
1074 pub struct Pack128 { bits: u128, packing: Packing128, pair: Pair128 }
1075 pub struct Pack64 { bits: u64, packing: Packing64, pair: Pair64, }
1076 pub struct Pack32 { bits: u32, packing: Packing32, pair: Pair32, }
1077 pub struct Pack16 { bits: u16, packing: Packing16, pair: Pair16, }
1078 pub struct Pack8 { bits: u8, packing: Packing8, pair: Pair8, }
1079}
1080
1081#[cfg(all(test, not(loom)))]
1082mod tests {
1083 use super::*;
1084 use proptest::prelude::*;
1085 macro_rules! prop_assert_bits_eq {
1086 ($left:expr, $right:expr, $state:expr) => {
1087 let left = $left;
1088 let right = $right;
1089 let lstr = stringify!($left);
1090 let rstr = stringify!($right);
1091 let expr_len = std::cmp::max(lstr.len(), rstr.len()) + 2;
1092 let val_len = 80 - (expr_len + 4);
1093 proptest::prop_assert_eq!(
1094 left,
1095 right,
1096 "\n{:>expr_len$} = {:#0val_len$b}\n{:>expr_len$} = {:#0val_len$b}\n{state}",
1097 lstr,
1098 left,
1099 rstr,
1100 right,
1101 expr_len = expr_len,
1102 val_len = val_len,
1103 state = $state
1104 );
1105 };
1106 ($left:expr, $right:expr) => {
1107 prop_assert_bits_eq!($left, $right, "")
1108 };
1109 }
1110
1111 macro_rules! test_pack_unpack {
1112 ($(fn $fn:ident<$Pack:ident, $Bits:ty>($max:expr);)+) => {
1113 proptest! {
1114 $(
1115 #[test]
1116 fn $fn(
1117 (nbits, val1, val2, base) in (1u32..($max/2)).prop_flat_map(|nbits| (
1118 Just(nbits),
1119 proptest::bits::u64::between(0, nbits as usize - 1),
1120 proptest::bits::u64::between(0, nbits as usize - 1),
1121 any::<$Bits>(),
1122 )),
1123 ) {
1124 let val1 = val1 as $Bits;
1125 let val2 = val2 as $Bits;
1126 let pack1 = $Pack::least_significant(nbits);
1127 let pack2 = pack1.next(nbits);
1128
1129 let packed1 = pack1.pack(val1, base);
1130 prop_assert_bits_eq!(pack1.unpack_bits(packed1), val1);
1131
1132 let packed2 = pack2.pack(val1, base);
1133 prop_assert_bits_eq!(pack2.unpack_bits(packed2), val1);
1134
1135 let packed3 = pack1.pack(val1, pack2.pack(val2, base));
1136 prop_assert_bits_eq!(pack1.unpack_bits(packed3), val1);
1137 prop_assert_bits_eq!(pack2.unpack_bits(packed3), val2);
1138 }
1139 )+
1140 }
1141 };
1142 }
1143
1144 macro_rules! test_pack_methods {
1145 ($(fn $fn:ident<$Pack:ident, $Bits:ty>($max:expr);)+) => {
1146 proptest! {
1147 $(
1148 #[test]
1149 fn $fn(
1150 (nbits, val1, val2, base) in (1u32..($max/2)).prop_flat_map(|nbits| (
1151 Just(nbits),
1152 proptest::bits::u64::between(0, nbits as usize - 1),
1153 proptest::bits::u64::between(0, nbits as usize - 1),
1154 any::<$Bits>(),
1155 )),
1156 ) {
1157 let val1 = val1 as $Bits;
1158 let val2 = val2 as $Bits;
1159 let pack1 = $Pack::least_significant(nbits);
1160 let pack2 = pack1.next(nbits);
1161
1162
1163 let packed_methods = $Pack::pack_in(base)
1164 .pack(val1, &pack1)
1165 .pack(val2, &pack2)
1166 .bits();
1167 let packed_calls = pack1.pack(val1, pack2.pack(val2, base));
1168 prop_assert_bits_eq!(packed_methods, packed_calls);
1169 }
1170 )+
1171 }
1172 };
1173 }
1174
1175 macro_rules! test_from_range {
1176 ($(fn $fn:ident<$Pack:ident, $Bits:ty>($max:expr);)+) => {
1177 proptest! {
1178 $(
1179 #[test]
1180 fn $fn(
1181 (start, len) in (1u32..($max-1)).prop_flat_map(|start| (
1182 Just(start),
1183 (1..($max - start)),
1184 )),
1185 ) {
1186 let range_inclusive = start..=(start + len);
1187 let range_exclusive = start..(start + len + 1);
1188 let state = format!(
1189 "start={}; len={}; range_inclusive={:?}, range_exclusive={:?}",
1190 start, len, range_inclusive, range_exclusive,
1191 );
1192 let least_sig = $Pack::least_significant(start - 1);
1193 let pack_next = least_sig.next(len);
1194 let pack_range_inclusive = $Pack::from_range(range_inclusive);
1195 let pack_range_exclusive = $Pack::from_range(range_exclusive);
1196
1197 prop_assert_bits_eq!(pack_next, pack_range_inclusive, &state);
1198 prop_assert_bits_eq!(pack_next, pack_range_exclusive, &state);
1199 }
1200 )+
1201 }
1202 };
1203 }
1204
1205 // Test packing and unpacking through a pair with other bits zeroed.
1206 // This just tests that the shift calculations are reasonable.
1207 macro_rules! test_pair_least_sig_zeroed {
1208 ($(fn $fn:ident<$Pack:ident, $Bits:ty>($max:expr);)+) => {
1209 proptest! {
1210 $(
1211 #[test]
1212 fn $fn(
1213 (src_len, dst_at) in (1u32..($max/2)).prop_flat_map(|nbits| (
1214 Just(nbits),
1215 (0..$max-nbits),
1216 )),
1217 ) {
1218 let pack_from_src = $Pack::least_significant(src_len);
1219 let src = 0;
1220 let pack_from_dst = $Pack::<$Bits>::starting_at(dst_at, src_len);
1221 let dst = pack_from_dst.set_all(0);
1222 let pair = pack_from_src.pair_at(dst_at);
1223 let state = format!(
1224 "src_len={}; dst_at={}; src={:#x}; dst={:#x};\npack_from_dst={:#?}\npair={:#?}",
1225 src_len, dst_at, src, dst, pack_from_dst, pair,
1226 );
1227
1228 let packed = pair.pack_from_src(src, dst);
1229 prop_assert_bits_eq!(packed, pack_from_src.set_all(0), state);
1230 prop_assert_bits_eq!(pack_from_src.unpack_bits(packed), pack_from_dst.unpack_bits(dst), &state);
1231
1232 let dst = <$Bits>::MAX;
1233 let packed = pair.pack_from_src(src, dst);
1234 prop_assert_bits_eq!(packed, pack_from_src.set_all(0), state);
1235 prop_assert_bits_eq!(pack_from_src.unpack_bits(packed), pack_from_dst.unpack_bits(dst), &state);
1236 }
1237 )+
1238 }
1239 };
1240 }
1241
1242 // Test packing and unpacking through a pair with arbitrary src/dst values.
1243 // This tests that we don't leave behind unwanted bits, etc.
1244 macro_rules! test_pair_least_sig_arbitrary {
1245 ($(fn $fn:ident<$Pack:ident, $Bits:ty>($max:expr);)+) => {
1246 proptest! {
1247 $(
1248 #[test]
1249 fn $fn(
1250 (src_len, dst_at, src, dst) in (1u32..($max/2)).prop_flat_map(|nbits| (
1251 Just(nbits),
1252 (0..$max-nbits),
1253 any::<$Bits>(),
1254 any::<$Bits>(),
1255 )),
1256 ) {
1257 let pack_from_src = $Pack::least_significant(src_len);
1258 let pack_from_dst = $Pack::<$Bits>::starting_at(dst_at, src_len);
1259 let pair = pack_from_src.pair_at(dst_at);
1260 let state = format!(
1261 "src_len={}; dst_at={}; src={:#x}; dst={:#x};\npack_from_dst={:#?}\npair={:#?}",
1262 src_len, dst_at, src, dst, pack_from_dst, pair,
1263 );
1264
1265 let packed = pair.pack_from_src(src, dst);
1266 prop_assert_bits_eq!(pack_from_src.unpack_bits(packed), pack_from_dst.unpack_bits(dst), &state);
1267
1268 let dst_unset = pack_from_dst.unset_all(dst);
1269 prop_assert_bits_eq!(pair.pack_from_dst(packed, dst_unset), dst, &state);
1270 }
1271 )+
1272 }
1273 };
1274 }
1275
1276 test_pack_unpack! {
1277 fn pack_unpack_128<Pack128, u128>(128);
1278 fn pack_unpack_64<Pack64, u64>(64);
1279 fn pack_unpack_32<Pack32, u32>(32);
1280 fn pack_unpack_16<Pack16, u16>(16);
1281 fn pack_unpack_8<Pack8, u8>(8);
1282 }
1283
1284 test_pack_methods! {
1285
1286 fn pack_methods_128<Pack128, u128>(128);
1287 fn pack_methods_64<Pack64, u64>(64);
1288 fn pack_methods_32<Pack32, u32>(32);
1289 fn pack_methods_16<Pack16, u16>(16);
1290 fn pack_methods_8<Pack8, u8>(8);
1291 }
1292
1293 test_from_range! {
1294 fn pack_from_src_range_128<Pack128, u128>(128);
1295 fn pack_from_src_range_64<Pack64, u64>(64);
1296 fn pack_from_src_range_32<Pack32, u32>(32);
1297 fn pack_from_src_range_16<Pack16, u16>(16);
1298 fn pack_from_src_range_8<Pack8, u8>(8);
1299 }
1300
1301 test_pair_least_sig_zeroed! {
1302
1303 fn pair_least_sig_zeroed_128<Pack128, u128>(128);
1304 fn pair_least_sig_zeroed_64<Pack64, u64>(64);
1305 fn pair_least_sig_zeroed_32<Pack32, u32>(32);
1306 fn pair_least_sig_zeroed_16<Pack16, u16>(16);
1307 fn pair_least_sig_zeroed_8<Pack8, u8>(8);
1308 }
1309
1310 test_pair_least_sig_arbitrary! {
1311 fn pair_least_sig_arbitrary_128<Pack128, u128>(128);
1312 fn pair_least_sig_arbitrary_64<Pack64, u64>(64);
1313 fn pair_least_sig_arbitrary_32<Pack32, u32>(32);
1314 fn pair_least_sig_arbitrary_16<Pack16, u16>(16);
1315 fn pair_least_sig_arbitrary_8<Pack8, u8>(8);
1316 }
1317}