oxihuman_core/
protobuf_varint.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, PartialEq)]
9pub enum VarintError {
10 BufferTooShort,
11 Overflow,
12 TrailingBytes,
13}
14
15impl std::fmt::Display for VarintError {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 match self {
18 Self::BufferTooShort => write!(f, "buffer too short for varint"),
19 Self::Overflow => write!(f, "varint overflows u64"),
20 Self::TrailingBytes => write!(f, "unexpected trailing bytes"),
21 }
22 }
23}
24
25pub fn encode_varint(mut value: u64, buf: &mut Vec<u8>) {
27 loop {
28 let mut byte = (value & 0x7F) as u8;
29 value >>= 7;
30 if value != 0 {
31 byte |= 0x80;
32 }
33 buf.push(byte);
34 if value == 0 {
35 break;
36 }
37 }
38}
39
40pub fn decode_varint(buf: &[u8]) -> Result<(u64, usize), VarintError> {
43 let mut result: u64 = 0;
44 let mut shift = 0u32;
45 for (i, &byte) in buf.iter().enumerate() {
46 if shift >= 64 {
47 return Err(VarintError::Overflow);
48 }
49 result |= ((byte & 0x7F) as u64) << shift;
50 if byte & 0x80 == 0 {
51 return Ok((result, i + 1));
52 }
53 shift += 7;
54 }
55 Err(VarintError::BufferTooShort)
56}
57
58pub fn encode_zigzag(value: i64, buf: &mut Vec<u8>) {
60 let zz = ((value << 1) ^ (value >> 63)) as u64;
61 encode_varint(zz, buf);
62}
63
64pub fn decode_zigzag(buf: &[u8]) -> Result<(i64, usize), VarintError> {
66 let (zz, n) = decode_varint(buf)?;
67 let value = ((zz >> 1) as i64) ^ (-((zz & 1) as i64));
68 Ok((value, n))
69}
70
71pub fn varint_size(mut value: u64) -> usize {
73 let mut n = 1;
74 loop {
75 value >>= 7;
76 if value == 0 {
77 break;
78 }
79 n += 1;
80 }
81 n
82}
83
84pub fn varint_roundtrip_ok(value: u64) -> bool {
86 let mut buf = vec![];
87 encode_varint(value, &mut buf);
88 decode_varint(&buf)
89 .map(|(v, _)| v == value)
90 .unwrap_or(false)
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_encode_zero() {
99 let mut buf = vec![];
101 encode_varint(0, &mut buf);
102 assert_eq!(buf, &[0x00]);
103 }
104
105 #[test]
106 fn test_encode_one() {
107 let mut buf = vec![];
109 encode_varint(1, &mut buf);
110 assert_eq!(buf, &[0x01]);
111 }
112
113 #[test]
114 fn test_decode_single_byte() {
115 let (v, n) = decode_varint(&[0x05]).expect("should succeed");
117 assert_eq!(v, 5);
118 assert_eq!(n, 1);
119 }
120
121 #[test]
122 fn test_roundtrip_small() {
123 assert!(varint_roundtrip_ok(42));
125 }
126
127 #[test]
128 fn test_roundtrip_large() {
129 assert!(varint_roundtrip_ok(u64::MAX));
131 }
132
133 #[test]
134 fn test_varint_size_one_byte() {
135 assert_eq!(varint_size(127), 1);
137 }
138
139 #[test]
140 fn test_varint_size_two_bytes() {
141 assert_eq!(varint_size(128), 2);
143 }
144
145 #[test]
146 fn test_zigzag_positive() {
147 let mut buf = vec![];
149 encode_zigzag(100, &mut buf);
150 let (v, _) = decode_zigzag(&buf).expect("should succeed");
151 assert_eq!(v, 100);
152 }
153
154 #[test]
155 fn test_zigzag_negative() {
156 let mut buf = vec![];
158 encode_zigzag(-50, &mut buf);
159 let (v, _) = decode_zigzag(&buf).expect("should succeed");
160 assert_eq!(v, -50);
161 }
162
163 #[test]
164 fn test_buffer_too_short() {
165 assert_eq!(
167 decode_varint(&[0x80]).unwrap_err(),
168 VarintError::BufferTooShort
169 );
170 }
171}