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 let zeroes = self.0.leading_zeros();
27 let num_bytes = 8u8.saturating_sub((zeroes / 8) as u8);
28
29 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 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 let mut bytes = [0u8; 8];
48 reader.read_exact(&mut bytes[..num_bytes[0] as usize])?;
49
50 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}