snops_common/format/
packed_int.rs

1use std::io::{Read, Write};
2
3use super::{DataFormat, DataReadError, DataWriteError};
4
5pub struct PackedUint(pub u64);
6
7impl From<PackedUint> for usize {
8    fn from(value: PackedUint) -> Self {
9        value.0 as usize
10    }
11}
12
13impl From<usize> for PackedUint {
14    fn from(value: usize) -> Self {
15        PackedUint(value as u64)
16    }
17}
18
19impl DataFormat for PackedUint {
20    type Header = ();
21    const LATEST_HEADER: Self::Header = ();
22
23    fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
24        // count number of leading zeroes and calculate the number of bytes needed
25        // to store the non-zero bits
26        let zeroes = self.0.leading_zeros();
27        let num_bytes = 8u8.saturating_sub((zeroes / 8) as u8);
28
29        // write the number of bytes and the bytes themselves
30        let bytes = &self.0.to_le_bytes()[..num_bytes as usize];
31        Ok(writer.write(&[num_bytes])? + writer.write(bytes)?)
32    }
33
34    fn read_data<R: Read>(reader: &mut R, _header: &Self::Header) -> Result<Self, DataReadError> {
35        // read the number of bytes to read
36        let mut num_bytes = [0u8; 1];
37        reader.read_exact(&mut num_bytes)?;
38
39        if num_bytes[0] > 8 {
40            return Err(DataReadError::Custom(format!(
41                "PackedUint received `{}` length, which is greater than 8",
42                num_bytes[0]
43            )));
44        }
45
46        // read that many bytes
47        let mut bytes = [0u8; 8];
48        reader.read_exact(&mut bytes[..num_bytes[0] as usize])?;
49
50        // convert the LE bytes to a u64
51        Ok(PackedUint(u64::from_le_bytes(bytes)))
52    }
53}
54
55#[cfg(test)]
56#[rustfmt::skip]
57#[allow(clippy::unusual_byte_groupings)]
58mod test {
59    use super::*;
60
61    macro_rules! case {
62        ($a:expr, $b:expr) => {
63            paste::paste! {
64                #[test]
65                fn [<test_ $a>]() {
66                    let mut data = Vec::new();
67                    let value = PackedUint($a);
68                    value.write_data(&mut data).unwrap();
69                    assert_eq!(data, &$b);
70
71                    let mut reader = &data[..];
72                    let read_value = PackedUint::read_data(&mut reader, &()).unwrap();
73                    assert_eq!(read_value.0, value.0);
74                }
75
76            }
77        };
78    }
79    case!(0x12345678, [4, 0x78, 0x56, 0x34, 0x12]);
80
81    case!(0, [0]);
82    case!(0xff, [1, 0xff]);
83    case!(0xffff, [2, 0xff, 0xff]);
84    case!(0xffff_ff, [3, 0xff, 0xff, 0xff]);
85    case!(0xffff_ffff, [4, 0xff, 0xff, 0xff, 0xff]);
86    case!(0xffff_ffff_ff, [5, 0xff, 0xff, 0xff, 0xff, 0xff]);
87    case!(0xffff_ffff_ffff, [6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
88    case!(0xffff_ffff_ffff_ff, [7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
89    case!(0xffff_ffff_ffff_ffff, [8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
90
91    case!(0x1, [1, 0x1]);
92    case!(0x10, [1, 0x10]);
93    case!(0x100, [2, 0, 0x1]);
94    case!(0x1000, [2, 0, 0x10]);
95    case!(0x10000, [3, 0, 0, 0x1]);
96    case!(0x100000, [3, 0, 0, 0x10]);
97    case!(0x1000000, [4, 0, 0, 0, 0x1]);
98    case!(0x10000000, [4, 0, 0, 0, 0x10]);
99    case!(0x100000000, [5, 0, 0, 0, 0, 0x1]);
100    case!(0x1000000000, [5, 0, 0, 0, 0, 0x10]);
101    case!(0x10000000000, [6, 0, 0, 0, 0, 0, 0x1]);
102    case!(0x100000000000, [6, 0, 0, 0, 0, 0, 0x10]);
103    case!(0x1000000000000, [7, 0, 0, 0, 0, 0, 0, 0x1]);
104    case!(0x10000000000000, [7, 0, 0, 0, 0, 0, 0, 0x10]);
105    case!(0x100000000000000, [8, 0, 0, 0, 0, 0, 0, 0, 0x1]);
106    case!(0x1000000000000000, [8, 0, 0, 0, 0, 0, 0, 0, 0x10]);
107
108
109    case!(0x11, [1, 0x11]);
110    case!(0x101, [2, 1, 0x1]);
111    case!(0x1001, [2, 1, 0x10]);
112    case!(0x10001, [3, 1, 0, 0x1]);
113    case!(0x100001, [3, 1, 0, 0x10]);
114    case!(0x1000001, [4, 1, 0, 0, 0x1]);
115    case!(0x10000001, [4, 1, 0, 0, 0x10]);
116    case!(0x100000001, [5, 1, 0, 0, 0, 0x1]);
117    case!(0x1000000001, [5, 1, 0, 0, 0, 0x10]);
118    case!(0x10000000001, [6, 1, 0, 0, 0, 0, 0x1]);
119    case!(0x100000000001, [6, 1, 0, 0, 0, 0, 0x10]);
120    case!(0x1000000000001, [7, 1, 0, 0, 0, 0, 0, 0x1]);
121    case!(0x10000000000001, [7, 1, 0, 0, 0, 0, 0, 0x10]);
122    case!(0x100000000000001, [8, 1, 0, 0, 0, 0, 0, 0, 0x1]);
123    case!(0x1000000000000001, [8, 1, 0, 0, 0, 0, 0, 0, 0x10]);
124}