Skip to main content

gamut_bitstream/
leb128.rs

1//! Unsigned LEB128 (little-endian base 128) integers (AV1 ยง4.10.5, Annex B `leb128()`).
2//!
3//! Used to carry `obu_size` in the low-overhead bitstream format. The spec permits up to 8 bytes;
4//! this writer always emits the minimal-length encoding, which every conformant reader accepts.
5
6/// Appends the minimal unsigned LEB128 encoding of `value` to `out`.
7pub fn write_leb128(out: &mut Vec<u8>, mut value: u64) {
8    loop {
9        let mut byte = (value & 0x7f) as u8;
10        value >>= 7;
11        if value != 0 {
12            byte |= 0x80;
13        }
14        out.push(byte);
15        if value == 0 {
16            break;
17        }
18    }
19}
20
21/// Returns the number of bytes the minimal unsigned LEB128 encoding of `value` occupies.
22#[must_use]
23pub fn leb128_len(mut value: u64) -> usize {
24    let mut n = 1;
25    while value >= 0x80 {
26        value >>= 7;
27        n += 1;
28    }
29    n
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    /// Minimal reference LEB128 reader for round-trip assertions.
37    fn read_leb128(bytes: &[u8]) -> (u64, usize) {
38        let mut value = 0u64;
39        let mut i = 0;
40        loop {
41            let byte = bytes[i];
42            value |= u64::from(byte & 0x7f) << (7 * i);
43            i += 1;
44            if byte & 0x80 == 0 {
45                break;
46            }
47        }
48        (value, i)
49    }
50
51    #[test]
52    fn known_encodings() {
53        let mut out = Vec::new();
54        write_leb128(&mut out, 0);
55        assert_eq!(out, &[0x00]);
56
57        out.clear();
58        write_leb128(&mut out, 127);
59        assert_eq!(out, &[0x7f]);
60
61        out.clear();
62        write_leb128(&mut out, 128);
63        assert_eq!(out, &[0x80, 0x01]);
64
65        out.clear();
66        write_leb128(&mut out, 0x3fff);
67        assert_eq!(out, &[0xff, 0x7f]);
68    }
69
70    #[test]
71    fn len_matches_written_and_roundtrips() {
72        for &v in &[0u64, 1, 127, 128, 300, 0xffff, 0x10_0000, u32::MAX as u64] {
73            let mut out = Vec::new();
74            write_leb128(&mut out, v);
75            assert_eq!(out.len(), leb128_len(v), "len mismatch for {v}");
76            let (decoded, used) = read_leb128(&out);
77            assert_eq!(decoded, v);
78            assert_eq!(used, out.len());
79        }
80    }
81}