Skip to main content

dial9_trace_format/
leb128.rs

1// LEB128 encoding/decoding
2
3use 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
19/// Returns (value, bytes_consumed).
20pub 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        } // u64 LEB128 is at most 10 bytes
35    }
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        // worker_id = 3 should be 1 byte
53        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        // 127 fits in 1 byte
59        buf.clear();
60        encode_unsigned(127, &mut buf).unwrap();
61        assert_eq!(buf.len(), 1);
62
63        // 128 needs 2 bytes
64        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        // 50,000 ns (typical poll duration) should be 3 bytes
73        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}