Skip to main content

ix/
varint.rs

1//! Protobuf-style varint encoding/decoding.
2//!
3//! value < 128:     1 byte  [0xxxxxxx]
4//! value < 16384:   2 bytes [1xxxxxxx 0xxxxxxx]
5//! ... up to 10 bytes for u64
6
7use crate::error::{Error, Result};
8
9/// Encode a u64 as a varint, appending bytes to `buf`.
10#[inline]
11pub fn encode(mut value: u64, buf: &mut Vec<u8>) {
12    while value >= 0x80 {
13        buf.push((value as u8) | 0x80);
14        value >>= 7;
15    }
16    buf.push(value as u8);
17}
18
19/// Decode a varint from `data` starting at `pos`. Advances `pos` past the varint.
20#[inline]
21pub fn decode(data: &[u8], pos: &mut usize) -> Result<u64> {
22    let mut result: u64 = 0;
23    let mut shift: u32 = 0;
24    loop {
25        if *pos >= data.len() {
26            return Err(Error::TruncatedVarint(*pos));
27        }
28        if shift >= 70 {
29            return Err(Error::OverflowVarint);
30        }
31        let byte = data[*pos];
32        *pos += 1;
33        result |= ((byte & 0x7F) as u64) << shift;
34        if byte & 0x80 == 0 {
35            return Ok(result);
36        }
37        shift += 7;
38    }
39}
40
41/// Return the encoded byte length of a varint without allocating.
42#[inline]
43pub fn encoded_len(value: u64) -> usize {
44    if value == 0 {
45        return 1;
46    }
47    let bits = 64 - value.leading_zeros() as usize;
48    bits.div_ceil(7)
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn roundtrip_small() {
57        for v in 0..300u64 {
58            let mut buf = Vec::new();
59            encode(v, &mut buf);
60            let mut pos = 0;
61            assert_eq!(decode(&buf, &mut pos).unwrap(), v);
62            assert_eq!(pos, buf.len());
63        }
64    }
65
66    #[test]
67    fn roundtrip_large() {
68        let values = [0, 1, 127, 128, 16383, 16384, u32::MAX as u64, u64::MAX];
69        for &v in &values {
70            let mut buf = Vec::new();
71            encode(v, &mut buf);
72            let mut pos = 0;
73            assert_eq!(decode(&buf, &mut pos).unwrap(), v);
74        }
75    }
76
77    #[test]
78    fn encoded_lengths() {
79        assert_eq!(encoded_len(0), 1);
80        assert_eq!(encoded_len(127), 1);
81        assert_eq!(encoded_len(128), 2);
82        assert_eq!(encoded_len(16383), 2);
83        assert_eq!(encoded_len(16384), 3);
84    }
85
86    #[test]
87    fn truncated_error() {
88        let mut pos = 0;
89        assert!(decode(&[0x80], &mut pos).is_err()); // continuation bit set but no next byte
90    }
91
92    #[test]
93    fn multiple_sequential() {
94        let mut buf = Vec::new();
95        encode(42, &mut buf);
96        encode(1000, &mut buf);
97        encode(0, &mut buf);
98
99        let mut pos = 0;
100        assert_eq!(decode(&buf, &mut pos).unwrap(), 42);
101        assert_eq!(decode(&buf, &mut pos).unwrap(), 1000);
102        assert_eq!(decode(&buf, &mut pos).unwrap(), 0);
103        assert_eq!(pos, buf.len());
104    }
105}