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}