• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = pointer_width() - 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         pointer_width() - (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 
40     /// Packs the value with `base`, losing any bits of `value` that fit.
41     ///
42     /// If `value` is larger than the max value that can be represented by the
43     /// allotted width, the most significant bits are truncated.
pack_lossy(&self, value: usize, base: usize) -> usize44     pub(crate) fn pack_lossy(&self, value: usize, base: usize) -> usize {
45         self.pack(value & self.max_value(), base)
46     }
47 
unpack(&self, src: usize) -> usize48     pub(crate) fn unpack(&self, src: usize) -> usize {
49         unpack(src, self.mask, self.shift)
50     }
51 }
52 
53 impl fmt::Debug for Pack {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result54     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
55         write!(
56             fmt,
57             "Pack {{ mask: {:b}, shift: {} }}",
58             self.mask, self.shift
59         )
60     }
61 }
62 
63 /// Returns the width of a pointer in bits.
pointer_width() -> u3264 pub(crate) const fn pointer_width() -> u32 {
65     std::mem::size_of::<usize>() as u32 * 8
66 }
67 
68 /// Returns a `usize` with the right-most `n` bits set.
mask_for(n: u32) -> usize69 pub(crate) const fn mask_for(n: u32) -> usize {
70     let shift = 1usize.wrapping_shl(n - 1);
71     shift | (shift - 1)
72 }
73 
74 /// Unpacks a value using a mask & shift.
unpack(src: usize, mask: usize, shift: u32) -> usize75 pub(crate) const fn unpack(src: usize, mask: usize, shift: u32) -> usize {
76     (src & mask) >> shift
77 }
78