1 use std::fmt;
2 
3 #[derive(Clone, Copy, PartialEq)]
4 pub(crate) struct Pack {
5     mask: usize,
6     shift: u32,
7 }
8 
9 impl Pack {
10     /// Value is packed in the `width` least-significant bits.
least_significant(width: u32) -> Pack11     pub(crate) const fn least_significant(width: u32) -> Pack {
12         let mask = mask_for(width);
13 
14         Pack { mask, shift: 0 }
15     }
16 
17     /// Value is packed in the `width` more-significant bits.
then(&self, width: u32) -> Pack18     pub(crate) const fn then(&self, width: u32) -> Pack {
19         let shift = usize::BITS - self.mask.leading_zeros();
20         let mask = mask_for(width) << shift;
21 
22         Pack { mask, shift }
23     }
24 
25     /// Width, in bits, dedicated to storing the value.
width(&self) -> u3226     pub(crate) const fn width(&self) -> u32 {
27         usize::BITS - (self.mask >> self.shift).leading_zeros()
28     }
29 
30     /// Max representable value.
max_value(&self) -> usize31     pub(crate) const fn max_value(&self) -> usize {
32         (1 << self.width()) - 1
33     }
34 
pack(&self, value: usize, base: usize) -> usize35     pub(crate) fn pack(&self, value: usize, base: usize) -> usize {
36         assert!(value <= self.max_value());
37         (base & !self.mask) | (value << self.shift)
38     }
39 
unpack(&self, src: usize) -> usize40     pub(crate) fn unpack(&self, src: usize) -> usize {
41         unpack(src, self.mask, self.shift)
42     }
43 }
44 
45 impl fmt::Debug for Pack {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result46     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
47         write!(
48             fmt,
49             "Pack {{ mask: {:b}, shift: {} }}",
50             self.mask, self.shift
51         )
52     }
53 }
54 
55 /// Returns a `usize` with the right-most `n` bits set.
mask_for(n: u32) -> usize56 pub(crate) const fn mask_for(n: u32) -> usize {
57     let shift = 1usize.wrapping_shl(n - 1);
58     shift | (shift - 1)
59 }
60 
61 /// Unpacks a value using a mask & shift.
unpack(src: usize, mask: usize, shift: u32) -> usize62 pub(crate) const fn unpack(src: usize, mask: usize, shift: u32) -> usize {
63     (src & mask) >> shift
64 }
65