1use crate::error::{Error, Result};
8
9#[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#[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#[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()); }
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}