1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct PackedInt {
    inner: u16,
}

macro_rules! impl_from_type {
    ($type:ty, $name:ident) => {
        pub fn $name(mut value: $type) -> Self {
            let mut prefix = 0u16;

            while value > 0x1ff {
                prefix += 1;
                value += 1;
                value >>= 1;
            }

            return Self {
                inner: (prefix << 8) + (value as u16),
            };
        }
    };
}

macro_rules! impl_into_type {
    ($type:ty, $name:ident) => {
        pub fn $name(&self) -> $type {
            let prefix = (self.inner >> 8) as $type;
            let suffix = (self.inner & 0xff) as $type;

            if prefix == 0 {
                suffix
            } else {
                (1 << (7 + prefix)) | (suffix << (prefix - 1))
            }
        }
    };
}

macro_rules! impl_traits {
    ($type:ty, $from:ident, $into:ident) => {
        impl From<$type> for PackedInt {
            fn from(value: $type) -> Self {
                Self::$from(value)
            }
        }

        impl Into<$type> for PackedInt {
            fn into(self) -> $type {
                self.$into()
            }
        }
    };
}

impl PackedInt {
    pub fn from_12_bits(bits: &[u8; 2]) -> Self {
        Self {
            inner: ((bits[1] as u16) << 4) | (bits[0] as u16),
        }
    }

    pub fn to_12_bits(&self) -> [u8; 2] {
        [self.inner as u8, 0xF0 & (self.inner >> 4) as u8]
    }

    pub fn from_16_bits(bits: &[u8; 2]) -> Self {
        Self {
            inner: u16::from_le_bytes(*bits),
        }
    }

    pub fn to_16_bits(&self) -> [u8; 2] {
        self.inner.to_le_bytes()
    }

    pub fn from_inner_u16(inner: u16) -> Self {
        Self { inner }
    }

    pub fn to_inner_u16(&self) -> u16 {
        self.inner
    }

    impl_from_type!(usize, from_usize);
    impl_from_type!(u128, from_u128);
    impl_from_type!(u64, from_u64);
    impl_from_type!(u32, from_u32);
    impl_from_type!(u16, from_u16);

    impl_into_type!(usize, to_usize);
    impl_into_type!(u128, to_u128);
    impl_into_type!(u64, to_u64);
    impl_into_type!(u32, to_u32);
    impl_into_type!(u16, to_u16);
}

impl_traits!(usize, from_usize, to_usize);
impl_traits!(u128, from_u128, to_u128);
impl_traits!(u64, from_u64, to_u64);
impl_traits!(u32, from_u32, to_u32);

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    pub fn test_int_packing() {
        let check = |value| {
            let packed = PackedInt::from_u64(value);
            let unpacked = packed.to_u64();
            assert_eq!(value, unpacked);
        };

        for value in 0..512 {
            for shift in 0..64 {
                check(value << shift)
            }
        }

        for inner in 0..0x3900 {
            check((PackedInt { inner }).to_u64())
        }
    }
}