1use std::fmt;
2
3#[derive(Clone, Copy, PartialEq)]
4pub(crate) struct Pack {
5 mask: usize,
6 shift: u32,
7}
8
9impl Pack {
10 /// Value is packed in the `width` least-significant bits.
11 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.
18 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.
26 pub(crate) const fn width(&self) -> u32 {
27 pointer_width() - (self.mask >> self.shift).leading_zeros()
28 }
29
30 /// Max representable value.
31 pub(crate) const fn max_value(&self) -> usize {
32 (1 << self.width()) - 1
33 }
34
35 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 pub(crate) fn unpack(&self, src: usize) -> usize {
41 unpack(src, self.mask, self.shift)
42 }
43}
44
45impl fmt::Debug for Pack {
46 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 the width of a pointer in bits.
56pub(crate) const fn pointer_width() -> u32 {
57 std::mem::size_of::<usize>() as u32 * 8
58}
59
60/// Returns a `usize` with the right-most `n` bits set.
61pub(crate) const fn mask_for(n: u32) -> usize {
62 let shift = 1usize.wrapping_shl(n - 1);
63 shift | (shift - 1)
64}
65
66/// Unpacks a value using a mask & shift.
67pub(crate) const fn unpack(src: usize, mask: usize, shift: u32) -> usize {
68 (src & mask) >> shift
69}
70