use nom::{bytes::complete::take, IResult};
type VintParseResult<'a> = Result<Option<(usize, i64)>, nom::Err<nom::error::Error<&'a [u8]>>>;
#[allow(dead_code)]
fn detect_ascii_corruption(input: &[u8]) -> bool {
if input.len() < 4 {
return false;
}
let bytes = &input[0..4];
let corrupted_patterns: &[&[u8]] = &[
b"data", b"bin", b"node", b"base", b"temp", b"logs", b"meta", b"main", b"root", b"home",
];
for pattern in corrupted_patterns {
if bytes.starts_with(pattern) {
return true;
}
}
let ascii_count = bytes
.iter()
.filter(|&&b| (0x20..=0x7E).contains(&b))
.count();
if ascii_count >= 3 {
return true;
}
let value = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
match value {
2959239534 | 1684108385 => true, _ => false,
}
}
pub const MAX_VINT_SIZE: usize = 9;
pub const MAX_VINT_LENGTH: i64 = 1024 * 1024 * 1024;
pub fn parse_vint(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];
match crate::parser::vint_fixed::parse_vint_fixed(input) {
Ok(result) => Ok(result),
Err(_) => {
parse_zigzag_vint(input)
}
}
}
fn parse_zigzag_vint(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];
let (bytes_used, unsigned_value) = if first_byte < 0x80 {
(1, first_byte as u64)
} else if first_byte < 0xC0 {
if input.len() < 2 {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let value = ((first_byte & 0x3F) as u64) << 8 | input[1] as u64;
(2, value)
} else if first_byte < 0xE0 {
if input.len() < 3 {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let value = ((first_byte & 0x1F) as u64) << 16 | (input[1] as u64) << 8 | input[2] as u64;
(3, value)
} else if first_byte == 0xF0 {
if input.len() < 2 {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let mut value = 0u64;
let bytes_to_read = input.len() - 1; #[allow(clippy::needless_range_loop)]
for i in 1..=bytes_to_read.min(8) {
value = (value << 8) | (input[i] as u64);
}
(bytes_to_read + 1, value)
} else if first_byte == 0xFF {
if input.len() < 2 {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let mut value = 0u64;
let bytes_to_read = input.len() - 1; #[allow(clippy::needless_range_loop)]
for i in 1..=bytes_to_read.min(8) {
value = (value << 8) | (input[i] as u64);
}
(bytes_to_read + 1, value)
} else {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Verify,
)));
};
let signed_value = zigzag_decode(unsigned_value);
let (remaining_input, _) = take(bytes_used)(input)?;
Ok((remaining_input, signed_value))
}
#[allow(dead_code)]
fn parse_cassandra_vint_format(input: &[u8]) -> VintParseResult<'_> {
if input.is_empty() {
return Ok(None);
}
let first_byte = input[0];
let leading_ones = first_byte.leading_ones() as usize;
let total_length = leading_ones + 1;
if total_length > 9 || input.len() < total_length {
return Ok(None); }
let value = if total_length == 1 {
if first_byte & 0x80 == 0x80 {
(first_byte & 0x7F) as i64
} else if first_byte == 0xFF {
-1
} else if first_byte & 0xC0 == 0xC0 {
-((first_byte & 0x3F) as i64)
} else {
return Ok(None);
}
} else {
let data_bits = (total_length * 8) - leading_ones - 1;
let first_data_bits = 8 - leading_ones - 1;
let first_data_mask = (1u8 << first_data_bits) - 1;
let mut value = (first_byte & first_data_mask) as i64;
#[allow(clippy::needless_range_loop)]
for i in 1..total_length {
value = (value << 8) | (input[i] as i64);
}
let max_positive = (1i64 << (data_bits - 1)) - 1;
if value > max_positive {
value -= 1i64 << data_bits;
}
value
};
Ok(Some((total_length, value)))
}
#[allow(dead_code)]
fn parse_custom_vint_format(input: &[u8]) -> VintParseResult<'_> {
if input.is_empty() {
return Ok(None);
}
let first_byte = input[0];
let (total_length, value) = if first_byte < 0x80 {
let unsigned_value = first_byte & 0x7F;
let value = if unsigned_value < 64 {
unsigned_value as i64
} else {
(unsigned_value as i64) - 128
};
(1, value)
} else if first_byte < 0xC0 {
let value = (first_byte & 0x3F) as i64;
(1, value)
} else if first_byte == 0xFF {
(1, -1)
} else if first_byte >= 0xC0 {
if input.len() == 1 {
let value = -64 + (first_byte - 0xC0) as i64;
(1, value)
} else if first_byte == 0xC0 && input.len() >= 2 {
let second_byte = input[1];
let value = if second_byte <= 0x7F {
second_byte as i64
} else if second_byte == 0x80 {
-128
} else {
second_byte as i64
};
(2, value)
} else {
return Ok(None); }
} else {
return Ok(None);
};
if input.len() < total_length {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
Ok(Some((total_length, value)))
}
#[allow(dead_code)]
fn encode_cassandra_vint(value: i64) -> Vec<u8> {
let _unsigned_value = if value >= 0 {
value as u64
} else {
value as u64 };
let bytes_needed = if value == 0 {
1
} else if (-63..=63).contains(&value) {
1 } else if (-8192..=8191).contains(&value) {
2 } else if (-1048576..=1048575).contains(&value) {
3 } else if (-134217728..=134217727).contains(&value) {
4 } else {
let abs_value = value.unsigned_abs();
if abs_value <= 0xFF {
2
} else if abs_value <= 0xFFFF {
3
} else if abs_value <= 0xFFFFFF {
4
} else if abs_value <= 0xFFFFFFFF {
5
} else {
8 }
};
match bytes_needed {
1 => {
if (0..=63).contains(&value) {
vec![0x80 | (value as u8)]
} else if value == -1 {
vec![0xFF]
} else if (-63..0).contains(&value) {
vec![0xC0 | ((-value) as u8)]
} else {
encode_cassandra_vint_multi_byte(value, 2)
}
}
2 => encode_cassandra_vint_multi_byte(value, 2),
3 => encode_cassandra_vint_multi_byte(value, 3),
4 => encode_cassandra_vint_multi_byte(value, 4),
_ => encode_cassandra_vint_multi_byte(value, bytes_needed),
}
}
#[allow(dead_code)]
fn encode_cassandra_vint_multi_byte(value: i64, num_bytes: usize) -> Vec<u8> {
let mut result = vec![0u8; num_bytes];
let leading_ones = num_bytes - 1;
let first_byte_mask = (0xFF << (8 - leading_ones)) & 0xFF;
let value_bytes = if value >= 0 {
value.to_be_bytes()
} else {
(value as u64).to_be_bytes() };
let data_bits = (num_bytes * 8) - leading_ones - 1; let data_bytes = data_bits.div_ceil(8);
let start_idx = 8 - data_bytes;
for (i, &byte) in value_bytes[start_idx..].iter().enumerate() {
if i == 0 {
let data_mask = (1u8 << (8 - leading_ones - 1)) - 1;
result[0] = first_byte_mask as u8 | (byte & data_mask);
} else {
result[i] = byte;
}
}
result
}
#[allow(dead_code)]
fn encode_zigzag_vint(value: i64) -> Vec<u8> {
let unsigned_value = zigzag_encode(value);
if unsigned_value <= 0x7F {
vec![unsigned_value as u8]
} else if unsigned_value <= 0x3FFF {
let high = ((unsigned_value >> 8) & 0x3F) | 0x80;
let low = unsigned_value & 0xFF;
vec![high as u8, low as u8]
} else if unsigned_value <= 0x1FFFFF {
let high = ((unsigned_value >> 16) & 0x1F) | 0xC0;
let mid = (unsigned_value >> 8) & 0xFF;
let low = unsigned_value & 0xFF;
vec![high as u8, mid as u8, low as u8]
} else {
let bytes = unsigned_value.to_be_bytes();
let mut result = vec![0xF0];
let start = bytes.iter().position(|&b| b != 0).unwrap_or(7);
result.extend_from_slice(&bytes[start..]);
result
}
}
#[allow(dead_code)]
pub fn zigzag_encode(value: i64) -> u64 {
((value << 1) ^ (value >> 63)) as u64
}
#[allow(dead_code)]
pub fn zigzag_decode(value: u64) -> i64 {
((value >> 1) ^ ((!0u64).wrapping_mul(value & 1))) as i64
}
#[allow(dead_code)]
fn vint_size(value: u64) -> usize {
if value == 0 {
return 1;
}
if value <= 127 {
1
} else if value <= 16383 {
2
} else if value <= 2097151 {
3
} else if value <= 268435455 {
4
} else if value <= 34359738367 {
5
} else if value <= 4398046511103 {
6
} else if value <= 562949953421311 {
7
} else if value <= 72057594037927935 {
8
} else {
9 }
}
pub fn encode_vint(value: i64) -> Vec<u8> {
encode_vint_zigzag(value)
}
pub fn encode_vint_zigzag(value: i64) -> Vec<u8> {
let unsigned_value = zigzag_encode(value);
if unsigned_value <= 0x7F {
vec![unsigned_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,
]
}
}
pub fn encode_vint_cassandra(value: i64) -> Vec<u8> {
crate::parser::vint_fixed::encode_vint_fixed(value)
}
pub fn parse_vint_cassandra(input: &[u8]) -> IResult<&[u8], i64> {
crate::parser::vint_fixed::parse_vint_fixed(input)
}
pub fn parse_unsigned_vint32(input: &[u8]) -> IResult<&[u8], u32> {
if input.is_empty() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let first_byte = input[0];
let num_extra_bytes = first_byte.leading_ones() as usize;
if num_extra_bytes > 4 || num_extra_bytes + 1 > input.len() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let value = if num_extra_bytes == 0 {
(first_byte & 0x7F) as u32
} else {
let data_bits_first = 8 - num_extra_bytes - 1;
let mask = (1u8 << data_bits_first) - 1;
let mut value = (first_byte & mask) as u32;
for &byte in input.iter().skip(1).take(num_extra_bytes) {
value = (value << 8) | (byte as u32);
}
value
};
let bytes_consumed = num_extra_bytes + 1;
let (remaining, _) = take(bytes_consumed)(input)?;
Ok((remaining, value))
}
pub fn parse_vuint(input: &[u8]) -> IResult<&[u8], u64> {
if input.is_empty() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let first_byte = input[0];
let num_extra_bytes = first_byte.leading_ones() as usize;
if num_extra_bytes > 8 || num_extra_bytes + 1 > input.len() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
let value = if num_extra_bytes == 0 {
(first_byte & 0x7F) as u64
} else if num_extra_bytes == 8 {
let mut value = 0u64;
for &byte in input.iter().skip(1).take(num_extra_bytes) {
value = (value << 8) | (byte as u64);
}
value
} else {
let data_bits_first = 8 - num_extra_bytes - 1;
let mask = (1u8 << data_bits_first) - 1;
let mut value = (first_byte & mask) as u64;
for &byte in input.iter().skip(1).take(num_extra_bytes) {
value = (value << 8) | (byte as u64);
}
value
};
let bytes_consumed = num_extra_bytes + 1;
let (remaining, _) = take(bytes_consumed)(input)?;
Ok((remaining, value))
}
pub fn encode_vuint(value: u64) -> Vec<u8> {
if value <= 0x7F {
vec![value as u8]
} else if value <= 0x3FFF {
let byte0 = 0x80 | ((value >> 8) & 0x3F) as u8;
let byte1 = (value & 0xFF) as u8;
vec![byte0, byte1]
} else if value <= 0x1FFFFF {
let byte0 = 0xC0 | ((value >> 16) & 0x1F) as u8;
let byte1 = ((value >> 8) & 0xFF) as u8;
let byte2 = (value & 0xFF) as u8;
vec![byte0, byte1, byte2]
} else if value <= 0xFFFFFFF {
let byte0 = 0xE0 | ((value >> 24) & 0x0F) as u8;
let byte1 = ((value >> 16) & 0xFF) as u8;
let byte2 = ((value >> 8) & 0xFF) as u8;
let byte3 = (value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3]
} else if value <= 0x7FFFFFFFF {
let byte0 = 0xF0 | ((value >> 32) & 0x07) as u8;
let byte1 = ((value >> 24) & 0xFF) as u8;
let byte2 = ((value >> 16) & 0xFF) as u8;
let byte3 = ((value >> 8) & 0xFF) as u8;
let byte4 = (value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4]
} else if value <= 0x3FFFFFFFFFF {
let byte0 = 0xF8 | ((value >> 40) & 0x03) as u8;
let byte1 = ((value >> 32) & 0xFF) as u8;
let byte2 = ((value >> 24) & 0xFF) as u8;
let byte3 = ((value >> 16) & 0xFF) as u8;
let byte4 = ((value >> 8) & 0xFF) as u8;
let byte5 = (value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4, byte5]
} else if value <= 0x1FFFFFFFFFFFF {
let byte0 = 0xFC | ((value >> 48) & 0x01) as u8;
let byte1 = ((value >> 40) & 0xFF) as u8;
let byte2 = ((value >> 32) & 0xFF) as u8;
let byte3 = ((value >> 24) & 0xFF) as u8;
let byte4 = ((value >> 16) & 0xFF) as u8;
let byte5 = ((value >> 8) & 0xFF) as u8;
let byte6 = (value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4, byte5, byte6]
} else if value <= 0xFFFFFFFFFFFFFF {
let byte0 = 0xFE;
let byte1 = ((value >> 48) & 0xFF) as u8;
let byte2 = ((value >> 40) & 0xFF) as u8;
let byte3 = ((value >> 32) & 0xFF) as u8;
let byte4 = ((value >> 24) & 0xFF) as u8;
let byte5 = ((value >> 16) & 0xFF) as u8;
let byte6 = ((value >> 8) & 0xFF) as u8;
let byte7 = (value & 0xFF) as u8;
vec![byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7]
} else {
let byte0 = 0xFF;
let byte1 = ((value >> 56) & 0xFF) as u8;
let byte2 = ((value >> 48) & 0xFF) as u8;
let byte3 = ((value >> 40) & 0xFF) as u8;
let byte4 = ((value >> 32) & 0xFF) as u8;
let byte5 = ((value >> 24) & 0xFF) as u8;
let byte6 = ((value >> 16) & 0xFF) as u8;
let byte7 = ((value >> 8) & 0xFF) as u8;
let byte8 = (value & 0xFF) as u8;
vec![
byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8,
]
}
}
pub fn parse_vint_length(input: &[u8]) -> IResult<&[u8], usize> {
let (remaining, value) = parse_vint(input)?;
if value < 0 {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Verify,
)));
}
if value > MAX_VINT_LENGTH {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::TooLarge,
)));
}
Ok((remaining, value as usize))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zigzag_encoding() {
assert_eq!(zigzag_encode(0), 0);
assert_eq!(zigzag_encode(-1), 1);
assert_eq!(zigzag_encode(1), 2);
assert_eq!(zigzag_encode(-2), 3);
assert_eq!(zigzag_encode(2), 4);
assert_eq!(zigzag_encode(-3), 5);
assert_eq!(zigzag_encode(i64::MAX), u64::MAX - 1);
assert_eq!(zigzag_encode(i64::MIN), u64::MAX);
}
#[test]
fn test_zigzag_roundtrip() {
let test_values = vec![0, 1, -1, 127, -128, 32767, -32768, i64::MAX, i64::MIN];
for value in test_values {
let encoded = zigzag_encode(value);
let decoded = zigzag_decode(encoded);
assert_eq!(decoded, value, "ZigZag roundtrip failed for {}", value);
}
}
#[test]
fn test_vint_size_calculation() {
assert_eq!(vint_size(0), 1);
assert_eq!(vint_size(0x7F), 1); assert_eq!(vint_size(0x80), 2); assert_eq!(vint_size(0x3FFF), 2); assert_eq!(vint_size(0x4000), 3); }
#[test]
fn test_vint_single_byte_encoding() {
for i in 0..=63 {
let encoded = encode_vint(i);
assert_eq!(encoded.len(), 1, "Value {} should encode to 1 byte", i);
assert_eq!(encoded[0] & 0x80, 0, "Single byte should have leading 0");
let (_, decoded) = parse_vint(&encoded).unwrap();
assert_eq!(decoded, i, "Roundtrip failed for {}", i);
}
for i in -63..=0 {
let encoded = encode_vint(i);
assert_eq!(encoded.len(), 1, "Value {} should encode to 1 byte", i);
let (_, decoded) = parse_vint(&encoded).unwrap();
assert_eq!(decoded, i, "Roundtrip failed for {}", i);
}
}
#[test]
fn test_vint_multi_byte_encoding() {
let value = 128;
let encoded = encode_vint(value);
assert_eq!(encoded.len(), 2, "Value {} should encode to 2 bytes", value);
assert_eq!(
encoded[0] & 0x80,
0x80,
"Two-byte encoding should start with 10"
);
assert_eq!(
encoded[0] & 0x40,
0,
"Two-byte encoding should start with 10"
);
let (_, decoded) = parse_vint(&encoded).unwrap();
assert_eq!(decoded, value);
let value = 16384; let encoded = encode_vint(value);
assert_eq!(encoded.len(), 3, "Value {} should encode to 3 bytes", value);
assert_eq!(
encoded[0] & 0xE0,
0xC0,
"Three-byte encoding should start with 110"
);
let (_, decoded) = parse_vint(&encoded).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn test_vint_comprehensive_roundtrip() {
let test_values = vec![
0,
1,
-1,
63,
-63,
64,
-64,
127,
-127,
128,
-128,
255,
-255,
256,
-256,
1023,
-1023,
1024,
-1024,
2047,
-2047,
2048,
-2048,
32767,
-32768,
65535,
-65535,
1000000,
-1000000,
i32::MAX as i64,
i32::MIN as i64,
i64::MAX / 2,
i64::MIN / 2,
];
for value in test_values {
let encoded = encode_vint(value);
assert!(
encoded.len() <= MAX_VINT_SIZE,
"Encoded length {} exceeds maximum {} for value {}",
encoded.len(),
MAX_VINT_SIZE,
value
);
let (remaining, decoded) = parse_vint(&encoded).unwrap();
assert!(remaining.is_empty(), "Parsing should consume all bytes");
assert_eq!(decoded, value, "Roundtrip failed for value {}", value);
}
}
#[test]
fn test_vint_format_compliance() {
let encoded = encode_vint(0);
assert_eq!(encoded, vec![0x00]);
let encoded = encode_vint(1);
assert_eq!(encoded, vec![0x02]);
let encoded = encode_vint(-1);
assert_eq!(encoded, vec![0x01]);
let encoded = encode_vint(64);
assert_eq!(encoded.len(), 2);
assert_eq!(encoded[0] & 0xC0, 0x80);
let (_, decoded) = parse_vint(&encoded).unwrap();
assert_eq!(decoded, 64);
}
#[test]
fn test_vuint_positive() {
let value = 1000u64;
let encoded = encode_vuint(value);
let (_, decoded) = parse_vuint(&encoded).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn test_vint_length() {
let bytes = encode_vint(42);
let (_, length) = parse_vint_length(&bytes).unwrap();
assert_eq!(length, 42);
}
#[test]
fn test_collection_vint_debug() {
let encoded_4 = encode_vint(4);
println!("encode_vint(4) = {:?}", encoded_4);
let (_, decoded_4) = parse_vint(&encoded_4).unwrap();
println!("parse_vint({:?}) = {}", encoded_4, decoded_4);
let test_10 = [10u8];
let (_, decoded_10) = parse_vint(&test_10).unwrap();
println!("parse_vint([10]) = {}", decoded_10);
for i in 0..20 {
let encoded = encode_vint(i);
if encoded == vec![10] {
println!("Value {} encodes to [10]", i);
}
}
assert_eq!(decoded_4, 4, "Roundtrip test for 4");
let long_string = "this is a longer string";
let encoded_23 = encode_vint(long_string.len() as i64);
println!("encode_vint(23) = {:?}", encoded_23);
println!(
"String length: {}, bytes: {:?}",
long_string.len(),
long_string.as_bytes()
);
match parse_vint(&encoded_23) {
Ok((_, decoded)) => println!("parse_vint({:?}) = {}", encoded_23, decoded),
Err(e) => println!("parse_vint({:?}) failed: {:?}", encoded_23, e),
}
println!("\n🔍 Debug failing VInt cases:");
let failing_values = vec![256, 1048576, 64];
for value in failing_values {
let encoded = encode_vint(value);
println!(
"Value {}: encoded={:?}, hex={:02X?}, len={}",
value,
encoded,
encoded,
encoded.len()
);
if !encoded.is_empty() {
let first_byte = encoded[0];
println!(
" First byte: 0x{:02X} ({:08b}), leading_ones: {}",
first_byte,
first_byte,
first_byte.leading_ones()
);
if encoded.len() > 1 {
println!(
" Expected leading ones: {}, got: {}",
encoded.len() - 1,
first_byte.leading_ones()
);
}
}
}
println!("\n🔍 Testing Cassandra format:");
let cassandra_bytes = vec![0xE0, 0x01, 0x00]; match parse_vint(&cassandra_bytes) {
Ok((_, decoded)) => println!("Cassandra bytes {:?} -> {}", cassandra_bytes, decoded),
Err(e) => println!(
"Failed to parse Cassandra bytes {:?}: {:?}",
cassandra_bytes, e
),
}
}
#[test]
fn test_vint_errors() {
assert!(parse_vint(&[]).is_err());
let negative_bytes = encode_vint(-10);
assert!(parse_vint_length(&negative_bytes).is_err());
assert!(parse_vint(&[0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]).is_ok());
assert!(parse_vint(&[0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]).is_ok()); assert!(parse_vint(&[0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]).is_ok());
assert!(parse_vint(&[0x80, 0x00]).is_ok()); assert!(parse_vint(&[0xC0, 0x00, 0x00]).is_ok());
let _corrupted_data = b"data"; }
#[test]
fn test_vint_edge_case_patterns() {
let max_single = 63;
let encoded = encode_vint(max_single);
assert_eq!(encoded.len(), 1);
assert_eq!(encoded[0] & 0x80, 0);
let min_double = 64;
let encoded = encode_vint(min_double);
assert_eq!(encoded.len(), 2);
assert_eq!(encoded[0] & 0xC0, 0x80); }
#[test]
fn test_detect_ascii_corruption_patterns() {
assert!(detect_ascii_corruption(b"data_payload"));
assert!(detect_ascii_corruption(b"node_meta"));
assert!(!detect_ascii_corruption(&[0x00, 0x80, 0xFF, 0x10]));
}
#[test]
fn test_parse_vint_extended_formats() {
let bytes = [0xF0, 0x00, 0x00, 0x00, 0x10];
let _ = parse_vint(&bytes).expect("extended format parses");
let bytes = [0xFF, 0x00, 0x00, 0x00, 0x05];
let _ = parse_vint(&bytes).expect("fallback parse");
}
#[test]
fn test_vint_overflow_protection() {
let large_value = encode_vint(2_000_000_000i64); let result = parse_vint_length(&large_value);
assert!(
result.is_err(),
"Should reject values > 1GB for length fields"
);
let safe_value = encode_vint(MAX_VINT_LENGTH - 1);
let result = parse_vint_length(&safe_value);
assert!(result.is_ok(), "Should accept values < 1GB");
let (_, length) = result.unwrap();
assert_eq!(length, (MAX_VINT_LENGTH - 1) as usize);
let limit_value = encode_vint(MAX_VINT_LENGTH + 1);
let result = parse_vint_length(&limit_value);
assert!(result.is_err(), "Should reject values > MAX_VINT_LENGTH");
let negative_value = encode_vint(-1i64);
let result = parse_vint_length(&negative_value);
assert!(result.is_err(), "Should reject negative values");
let zero_value = encode_vint(0i64);
let result = parse_vint_length(&zero_value);
assert!(result.is_ok(), "Should accept zero");
let (_, length) = result.unwrap();
assert_eq!(length, 0);
let sixteen_mb = encode_vint(16 * 1024 * 1024i64);
let result = parse_vint_length(&sixteen_mb);
assert!(result.is_ok(), "Should accept 16MB (common limit)");
}
}