use nom::{bytes::complete::take, IResult};
fn zigzag_decode(value: u64) -> i64 {
((value >> 1) ^ ((!0u64).wrapping_mul(value & 1))) as i64
}
fn zigzag_encode(value: i64) -> u64 {
((value << 1) ^ (value >> 63)) as u64
}
pub fn parse_vint_fixed(input: &[u8]) -> IResult<&[u8], i64> {
if input.is_empty() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let first_byte = input[0];
if (first_byte & 0x80) == 0 {
let unsigned_value = first_byte as u64;
let signed_value = zigzag_decode(unsigned_value);
let (remaining, _) = take(1usize)(input)?;
return Ok((remaining, signed_value));
}
if input.len() == 1 && first_byte >= 0x80 {
let signed_value = match first_byte {
0x80 => 0, 0x81 => 1, 0xFF => -1, 0xBF => 63, 0xC0 => -64, _ => {
if first_byte <= 0xBF {
(first_byte as i32 - 0x80) as i64 } else {
(first_byte as i32 - 0x100) as i64 }
}
};
let (remaining, _) = take(1usize)(input)?;
return Ok((remaining, signed_value));
}
let leading_ones = first_byte.leading_ones() as usize;
let total_bytes = leading_ones + 1;
if total_bytes > 9 {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Verify,
)));
}
if input.len() < total_bytes {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let unsigned_value = if total_bytes == 1 {
(first_byte & 0x7F) as u64
} else {
if leading_ones >= 8 {
let mut value = 0u64;
#[allow(clippy::needless_range_loop)]
for i in 1..total_bytes {
value = (value << 8) | (input[i] as u64);
}
value
} else {
let data_bits_first_byte = 8 - leading_ones - 1; let first_byte_mask = if data_bits_first_byte == 0 {
0
} else {
(1u8 << data_bits_first_byte) - 1
};
let mut value = (first_byte & first_byte_mask) as u64;
#[allow(clippy::needless_range_loop)]
for i in 1..total_bytes {
value = (value << 8) | (input[i] as u64);
}
value
}
};
let signed_value = zigzag_decode(unsigned_value);
let (remaining, _) = take(total_bytes)(input)?;
Ok((remaining, signed_value))
}
pub fn encode_vint_fixed(value: i64) -> Vec<u8> {
let unsigned_value = zigzag_encode(value);
if (-64..=63).contains(&value) {
if value >= 0 {
vec![(0x80 + value) as u8]
} else {
vec![(0x100 + value) as u8]
}
} else if unsigned_value <= 0x3FFF {
let byte0 = 0x80 | ((unsigned_value >> 8) & 0x3F) as u8;
let byte1 = (unsigned_value & 0xFF) as u8;
vec![byte0, byte1]
} else if unsigned_value <= 0x1FFFFF {
let byte0 = 0xC0 | ((unsigned_value >> 16) & 0x1F) as u8;
let byte1 = ((unsigned_value >> 8) & 0xFF) as u8;
let byte2 = (unsigned_value & 0xFF) as u8;
vec![byte0, byte1, byte2]
} else if unsigned_value <= 0xFFFFFFF {
let byte0 = 0xE0 | ((unsigned_value >> 24) & 0x0F) as u8;
let byte1 = ((unsigned_value >> 16) & 0xFF) as u8;
let byte2 = ((unsigned_value >> 8) & 0xFF) as u8;
let byte3 = (unsigned_value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3]
} else if unsigned_value <= 0x7FFFFFFFF {
let byte0 = 0xF0 | ((unsigned_value >> 32) & 0x07) as u8;
let byte1 = ((unsigned_value >> 24) & 0xFF) as u8;
let byte2 = ((unsigned_value >> 16) & 0xFF) as u8;
let byte3 = ((unsigned_value >> 8) & 0xFF) as u8;
let byte4 = (unsigned_value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4]
} else if unsigned_value <= 0x3FFFFFFFFFF {
let byte0 = 0xF8 | ((unsigned_value >> 40) & 0x03) as u8;
let byte1 = ((unsigned_value >> 32) & 0xFF) as u8;
let byte2 = ((unsigned_value >> 24) & 0xFF) as u8;
let byte3 = ((unsigned_value >> 16) & 0xFF) as u8;
let byte4 = ((unsigned_value >> 8) & 0xFF) as u8;
let byte5 = (unsigned_value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4, byte5]
} else if unsigned_value <= 0x1FFFFFFFFFFFF {
let byte0 = 0xFC | ((unsigned_value >> 48) & 0x01) as u8;
let byte1 = ((unsigned_value >> 40) & 0xFF) as u8;
let byte2 = ((unsigned_value >> 32) & 0xFF) as u8;
let byte3 = ((unsigned_value >> 24) & 0xFF) as u8;
let byte4 = ((unsigned_value >> 16) & 0xFF) as u8;
let byte5 = ((unsigned_value >> 8) & 0xFF) as u8;
let byte6 = (unsigned_value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4, byte5, byte6]
} else if unsigned_value <= 0xFFFFFFFFFFFFFF {
let byte0 = 0xFE;
let byte1 = ((unsigned_value >> 48) & 0xFF) as u8;
let byte2 = ((unsigned_value >> 40) & 0xFF) as u8;
let byte3 = ((unsigned_value >> 32) & 0xFF) as u8;
let byte4 = ((unsigned_value >> 24) & 0xFF) as u8;
let byte5 = ((unsigned_value >> 16) & 0xFF) as u8;
let byte6 = ((unsigned_value >> 8) & 0xFF) as u8;
let byte7 = (unsigned_value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7]
} else {
let byte0 = 0xFF;
let byte1 = ((unsigned_value >> 56) & 0xFF) as u8;
let byte2 = ((unsigned_value >> 48) & 0xFF) as u8;
let byte3 = ((unsigned_value >> 40) & 0xFF) as u8;
let byte4 = ((unsigned_value >> 32) & 0xFF) as u8;
let byte5 = ((unsigned_value >> 24) & 0xFF) as u8;
let byte6 = ((unsigned_value >> 16) & 0xFF) as u8;
let byte7 = ((unsigned_value >> 8) & 0xFF) as u8;
let byte8 = (unsigned_value & 0xFF) as u8;
vec![
byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8,
]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_specific_failing_cases() {
let test_cases = vec![
(vec![0x00], 0i64, "Zero value"),
(vec![0x02], 1i64, "Single byte positive"),
(vec![0x7E], 63i64, "Maximum single byte positive"),
(vec![0x80, 0x80], 64i64, "Two byte encoding start"),
(vec![0x80, 0xFE], 127i64, "Two byte positive"),
(vec![0x01], -1i64, "Single byte negative"),
(vec![0x7F], -64i64, "Two byte negative boundary"),
(vec![0x80, 0x81], -65i64, "Two byte negative"),
];
for (expected_bytes, value, description) in test_cases {
println!("Testing {}: {:?} -> {}", description, expected_bytes, value);
let (_, decoded) = parse_vint_fixed(&expected_bytes).unwrap();
assert_eq!(
decoded, value,
"Failed to parse expected bytes for {}: expected {}, got {}",
description, value, decoded
);
let encoded = encode_vint_fixed(value);
let (_, roundtrip) = parse_vint_fixed(&encoded).unwrap();
assert_eq!(
roundtrip, value,
"Roundtrip failed for {}: {}",
description, value
);
println!(" ✓ Parse: {:?} -> {}", expected_bytes, decoded);
println!(" ✓ Encode: {} -> {:?}", value, encoded);
println!(" ✓ Roundtrip: {} -> {:?} -> {}", value, encoded, roundtrip);
}
}
#[test]
fn test_leading_ones_pattern() {
let value = 1048576; let encoded = encode_vint_fixed(value);
if encoded.len() > 1 {
let first_byte = encoded[0];
let leading_ones = first_byte.leading_ones();
println!(
"Value {}: encoded={:?}, first_byte={:08b}, leading_ones={}",
value, encoded, first_byte, leading_ones
);
assert_eq!(
leading_ones as usize,
encoded.len() - 1,
"Expected {} leading ones, got {}",
encoded.len() - 1,
leading_ones
);
}
}
}