const SINGLE_BYTE_MAX: u32 = 0x7F;
const TWO_BYTE_MAX: u32 = 0x3FFF;
const TWO_BYTE_MARKER: u8 = 0x80;
const FOUR_BYTE_MARKER: u8 = 0xC0;
#[allow(clippy::cast_possible_truncation)]
pub fn write_compressed_uint(value: u32, buffer: &mut Vec<u8>) {
if value <= SINGLE_BYTE_MAX {
buffer.push(value as u8);
} else if value <= TWO_BYTE_MAX {
buffer.push(TWO_BYTE_MARKER | ((value >> 8) as u8));
buffer.push(value as u8);
} else {
buffer.push(FOUR_BYTE_MARKER | ((value >> 24) as u8));
buffer.push((value >> 16) as u8);
buffer.push((value >> 8) as u8);
buffer.push(value as u8);
}
}
pub fn compressed_uint_size(value: usize) -> u64 {
if value <= SINGLE_BYTE_MAX as usize {
1
} else if value <= TWO_BYTE_MAX as usize {
2
} else {
4
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compressed_uint_single_byte() {
let mut buffer = Vec::new();
write_compressed_uint(0, &mut buffer);
assert_eq!(buffer, vec![0x00]);
buffer.clear();
write_compressed_uint(127, &mut buffer);
assert_eq!(buffer, vec![0x7F]);
}
#[test]
fn test_compressed_uint_two_bytes() {
let mut buffer = Vec::new();
write_compressed_uint(128, &mut buffer);
assert_eq!(buffer, vec![0x80, 0x80]);
buffer.clear();
write_compressed_uint(0x3FFF, &mut buffer);
assert_eq!(buffer, vec![0xBF, 0xFF]);
}
#[test]
fn test_compressed_uint_four_bytes() {
let mut buffer = Vec::new();
write_compressed_uint(0x4000, &mut buffer);
assert_eq!(buffer, vec![0xC0, 0x00, 0x40, 0x00]);
buffer.clear();
write_compressed_uint(0x12345678, &mut buffer);
assert_eq!(buffer, vec![0xD2, 0x34, 0x56, 0x78]);
}
#[test]
fn test_compressed_uint_size() {
assert_eq!(compressed_uint_size(0), 1);
assert_eq!(compressed_uint_size(127), 1);
assert_eq!(compressed_uint_size(128), 2);
assert_eq!(compressed_uint_size(0x3FFF), 2);
assert_eq!(compressed_uint_size(0x4000), 4);
assert_eq!(compressed_uint_size(0xFFFFFFFF), 4);
}
#[test]
fn test_size_consistency() {
let test_values = [0, 1, 127, 128, 300, 0x3FFF, 0x4000, 70000, 0x12345678];
for value in test_values {
let predicted_size = compressed_uint_size(value as usize);
let mut buffer = Vec::new();
write_compressed_uint(value, &mut buffer);
let actual_size = buffer.len() as u64;
assert_eq!(
predicted_size, actual_size,
"Size mismatch for value {value}: predicted {predicted_size}, actual {actual_size}"
);
}
}
}