dial9_trace_format/
leb128.rs1use std::io::{self, Write};
4
5#[inline]
6pub fn encode_unsigned(mut value: u64, w: &mut impl Write) -> io::Result<()> {
7 let mut buf = [0u8; 10];
8 let mut i = 0;
9 while value >= 0x80 {
10 buf[i] = (value as u8) | 0x80;
11 value >>= 7;
12 i += 1;
13 }
14 buf[i] = value as u8;
15 i += 1;
16 w.write_all(&buf[..i])
17}
18
19pub fn decode_unsigned(data: &[u8]) -> Option<(u64, usize)> {
21 let mut result: u64 = 0;
22 let mut shift = 0u32;
23 let mut pos = 0;
24 loop {
25 let byte = *data.get(pos)?;
26 pos += 1;
27 result |= ((byte & 0x7f) as u64) << shift;
28 shift += 7;
29 if byte & 0x80 == 0 {
30 return Some((result, pos));
31 }
32 if pos >= 10 {
33 return None;
34 } }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn unsigned_zero() {
44 let mut buf = Vec::new();
45 encode_unsigned(0, &mut buf).unwrap();
46 assert_eq!(buf, [0x00]);
47 assert_eq!(decode_unsigned(&buf), Some((0, 1)));
48 }
49
50 #[test]
51 fn unsigned_small_values_compact() {
52 let mut buf = Vec::new();
54 encode_unsigned(3, &mut buf).unwrap();
55 assert_eq!(buf.len(), 1);
56 assert_eq!(decode_unsigned(&buf).unwrap().0, 3);
57
58 buf.clear();
60 encode_unsigned(127, &mut buf).unwrap();
61 assert_eq!(buf.len(), 1);
62
63 buf.clear();
65 encode_unsigned(128, &mut buf).unwrap();
66 assert_eq!(buf.len(), 2);
67 assert_eq!(decode_unsigned(&buf).unwrap().0, 128);
68 }
69
70 #[test]
71 fn unsigned_timestamp_compact() {
72 let mut buf = Vec::new();
74 encode_unsigned(50_000, &mut buf).unwrap();
75 assert!(
76 buf.len() <= 3,
77 "50k should fit in 3 bytes, got {}",
78 buf.len()
79 );
80 assert_eq!(decode_unsigned(&buf).unwrap().0, 50_000);
81 }
82
83 #[test]
84 fn unsigned_round_trip_extremes() {
85 for val in [0u64, 1, 127, 128, 16383, 16384, u32::MAX as u64, u64::MAX] {
86 let mut buf = Vec::new();
87 encode_unsigned(val, &mut buf).unwrap();
88 let (decoded, consumed) = decode_unsigned(&buf).unwrap();
89 assert_eq!(decoded, val, "failed for {val}");
90 assert_eq!(consumed, buf.len());
91 }
92 }
93}