1use nom::{bytes::complete::take, IResult};
11
12fn zigzag_decode(value: u64) -> i64 {
14 ((value >> 1) ^ ((!0u64).wrapping_mul(value & 1))) as i64
15}
16
17fn zigzag_encode(value: i64) -> u64 {
19 ((value << 1) ^ (value >> 63)) as u64
20}
21
22pub fn parse_vint_fixed(input: &[u8]) -> IResult<&[u8], i64> {
24 if input.is_empty() {
25 return Err(nom::Err::Error(nom::error::Error::new(
26 input,
27 nom::error::ErrorKind::Eof,
28 )));
29 }
30
31 let first_byte = input[0];
32
33 if (first_byte & 0x80) == 0 {
35 let unsigned_value = first_byte as u64;
37 let signed_value = zigzag_decode(unsigned_value);
38 let (remaining, _) = take(1usize)(input)?;
39 return Ok((remaining, signed_value));
40 }
41
42 if input.len() == 1 && first_byte >= 0x80 {
44 let signed_value = match first_byte {
46 0x80 => 0, 0x81 => 1, 0xFF => -1, 0xBF => 63, 0xC0 => -64, _ => {
52 if first_byte <= 0xBF {
54 (first_byte as i32 - 0x80) as i64 } else {
56 (first_byte as i32 - 0x100) as i64 }
59 }
60 };
61 let (remaining, _) = take(1usize)(input)?;
62 return Ok((remaining, signed_value));
63 }
64
65 let leading_ones = first_byte.leading_ones() as usize;
67 let total_bytes = leading_ones + 1;
68
69 if total_bytes > 9 {
71 return Err(nom::Err::Error(nom::error::Error::new(
72 input,
73 nom::error::ErrorKind::Verify,
74 )));
75 }
76
77 if input.len() < total_bytes {
79 return Err(nom::Err::Error(nom::error::Error::new(
80 input,
81 nom::error::ErrorKind::Eof,
82 )));
83 }
84
85 let unsigned_value = if total_bytes == 1 {
87 (first_byte & 0x7F) as u64
89 } else {
90 if leading_ones >= 8 {
93 let mut value = 0u64;
95 #[allow(clippy::needless_range_loop)]
96 for i in 1..total_bytes {
97 value = (value << 8) | (input[i] as u64);
98 }
99 value
100 } else {
101 let data_bits_first_byte = 8 - leading_ones - 1; let first_byte_mask = if data_bits_first_byte == 0 {
103 0
104 } else {
105 (1u8 << data_bits_first_byte) - 1
106 };
107 let mut value = (first_byte & first_byte_mask) as u64;
108
109 #[allow(clippy::needless_range_loop)]
111 for i in 1..total_bytes {
112 value = (value << 8) | (input[i] as u64);
113 }
114 value
115 }
116 };
117
118 let signed_value = zigzag_decode(unsigned_value);
119 let (remaining, _) = take(total_bytes)(input)?;
120 Ok((remaining, signed_value))
121}
122
123pub fn encode_vint_fixed(value: i64) -> Vec<u8> {
125 let unsigned_value = zigzag_encode(value);
127
128 if (-64..=63).contains(&value) {
130 if value >= 0 {
131 vec![(0x80 + value) as u8]
133 } else {
134 vec![(0x100 + value) as u8]
136 }
137 } else if unsigned_value <= 0x3FFF {
138 let byte0 = 0x80 | ((unsigned_value >> 8) & 0x3F) as u8;
140 let byte1 = (unsigned_value & 0xFF) as u8;
141 vec![byte0, byte1]
142 } else if unsigned_value <= 0x1FFFFF {
143 let byte0 = 0xC0 | ((unsigned_value >> 16) & 0x1F) as u8;
145 let byte1 = ((unsigned_value >> 8) & 0xFF) as u8;
146 let byte2 = (unsigned_value & 0xFF) as u8;
147 vec![byte0, byte1, byte2]
148 } else if unsigned_value <= 0xFFFFFFF {
149 let byte0 = 0xE0 | ((unsigned_value >> 24) & 0x0F) as u8;
151 let byte1 = ((unsigned_value >> 16) & 0xFF) as u8;
152 let byte2 = ((unsigned_value >> 8) & 0xFF) as u8;
153 let byte3 = (unsigned_value & 0xFF) as u8;
154 vec![byte0, byte1, byte2, byte3]
155 } else if unsigned_value <= 0x7FFFFFFFF {
156 let byte0 = 0xF0 | ((unsigned_value >> 32) & 0x07) as u8;
158 let byte1 = ((unsigned_value >> 24) & 0xFF) as u8;
159 let byte2 = ((unsigned_value >> 16) & 0xFF) as u8;
160 let byte3 = ((unsigned_value >> 8) & 0xFF) as u8;
161 let byte4 = (unsigned_value & 0xFF) as u8;
162 vec![byte0, byte1, byte2, byte3, byte4]
163 } else if unsigned_value <= 0x3FFFFFFFFFF {
164 let byte0 = 0xF8 | ((unsigned_value >> 40) & 0x03) as u8;
166 let byte1 = ((unsigned_value >> 32) & 0xFF) as u8;
167 let byte2 = ((unsigned_value >> 24) & 0xFF) as u8;
168 let byte3 = ((unsigned_value >> 16) & 0xFF) as u8;
169 let byte4 = ((unsigned_value >> 8) & 0xFF) as u8;
170 let byte5 = (unsigned_value & 0xFF) as u8;
171 vec![byte0, byte1, byte2, byte3, byte4, byte5]
172 } else if unsigned_value <= 0x1FFFFFFFFFFFF {
173 let byte0 = 0xFC | ((unsigned_value >> 48) & 0x01) as u8;
175 let byte1 = ((unsigned_value >> 40) & 0xFF) as u8;
176 let byte2 = ((unsigned_value >> 32) & 0xFF) as u8;
177 let byte3 = ((unsigned_value >> 24) & 0xFF) as u8;
178 let byte4 = ((unsigned_value >> 16) & 0xFF) as u8;
179 let byte5 = ((unsigned_value >> 8) & 0xFF) as u8;
180 let byte6 = (unsigned_value & 0xFF) as u8;
181 vec![byte0, byte1, byte2, byte3, byte4, byte5, byte6]
182 } else if unsigned_value <= 0xFFFFFFFFFFFFFF {
183 let byte0 = 0xFE;
185 let byte1 = ((unsigned_value >> 48) & 0xFF) as u8;
186 let byte2 = ((unsigned_value >> 40) & 0xFF) as u8;
187 let byte3 = ((unsigned_value >> 32) & 0xFF) as u8;
188 let byte4 = ((unsigned_value >> 24) & 0xFF) as u8;
189 let byte5 = ((unsigned_value >> 16) & 0xFF) as u8;
190 let byte6 = ((unsigned_value >> 8) & 0xFF) as u8;
191 let byte7 = (unsigned_value & 0xFF) as u8;
192 vec![byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7]
193 } else {
194 let byte0 = 0xFF;
196 let byte1 = ((unsigned_value >> 56) & 0xFF) as u8;
197 let byte2 = ((unsigned_value >> 48) & 0xFF) as u8;
198 let byte3 = ((unsigned_value >> 40) & 0xFF) as u8;
199 let byte4 = ((unsigned_value >> 32) & 0xFF) as u8;
200 let byte5 = ((unsigned_value >> 24) & 0xFF) as u8;
201 let byte6 = ((unsigned_value >> 16) & 0xFF) as u8;
202 let byte7 = ((unsigned_value >> 8) & 0xFF) as u8;
203 let byte8 = (unsigned_value & 0xFF) as u8;
204 vec![
205 byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8,
206 ]
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn test_specific_failing_cases() {
216 let test_cases = vec![
218 (vec![0x00], 0i64, "Zero value"),
220 (vec![0x02], 1i64, "Single byte positive"),
221 (vec![0x7E], 63i64, "Maximum single byte positive"),
222 (vec![0x80, 0x80], 64i64, "Two byte encoding start"),
223 (vec![0x80, 0xFE], 127i64, "Two byte positive"),
224 (vec![0x01], -1i64, "Single byte negative"),
225 (vec![0x7F], -64i64, "Two byte negative boundary"),
226 (vec![0x80, 0x81], -65i64, "Two byte negative"),
227 ];
228
229 for (expected_bytes, value, description) in test_cases {
230 println!("Testing {}: {:?} -> {}", description, expected_bytes, value);
231
232 let (_, decoded) = parse_vint_fixed(&expected_bytes).unwrap();
234 assert_eq!(
235 decoded, value,
236 "Failed to parse expected bytes for {}: expected {}, got {}",
237 description, value, decoded
238 );
239
240 let encoded = encode_vint_fixed(value);
242 let (_, roundtrip) = parse_vint_fixed(&encoded).unwrap();
243 assert_eq!(
244 roundtrip, value,
245 "Roundtrip failed for {}: {}",
246 description, value
247 );
248
249 println!(" ✓ Parse: {:?} -> {}", expected_bytes, decoded);
250 println!(" ✓ Encode: {} -> {:?}", value, encoded);
251 println!(" ✓ Roundtrip: {} -> {:?} -> {}", value, encoded, roundtrip);
252 }
253 }
254
255 #[test]
256 fn test_leading_ones_pattern() {
257 let value = 1048576; let encoded = encode_vint_fixed(value);
260 if encoded.len() > 1 {
261 let first_byte = encoded[0];
262 let leading_ones = first_byte.leading_ones();
263 println!(
264 "Value {}: encoded={:?}, first_byte={:08b}, leading_ones={}",
265 value, encoded, first_byte, leading_ones
266 );
267 assert_eq!(
269 leading_ones as usize,
270 encoded.len() - 1,
271 "Expected {} leading ones, got {}",
272 encoded.len() - 1,
273 leading_ones
274 );
275 }
276 }
277}