use bytes::BufMut;
use std::io::{self, Read, Write};
#[allow(dead_code)]
pub fn write_unsigned_varint<W: Write>(value: u32, writer: &mut W) -> io::Result<usize> {
let mut v = value;
let mut bytes_written = 0;
while (v & !0x7F) != 0 {
writer.write_all(&[((v as u8) & 0x7F) | 0x80])?;
bytes_written += 1;
v >>= 7;
}
writer.write_all(&[v as u8])?;
bytes_written += 1;
Ok(bytes_written)
}
pub fn write_unsigned_varint_buf(value: u32, buf: &mut impl BufMut) {
let mut v = value;
while (v & !0x7F) != 0 {
buf.put_u8(((v as u8) & 0x7F) | 0x80);
v >>= 7;
}
buf.put_u8(v as u8);
}
#[allow(dead_code)]
pub fn read_unsigned_varint<R: Read>(reader: &mut R) -> io::Result<u32> {
let mut tmp = [0u8; 1];
reader.read_exact(&mut tmp)?;
let mut byte = tmp[0] as i8;
if byte >= 0 {
return Ok(byte as u32);
}
let mut result = (byte & 127) as u32;
reader.read_exact(&mut tmp)?;
byte = tmp[0] as i8;
if byte >= 0 {
result |= (byte as u32) << 7;
} else {
result |= ((byte & 127) as u32) << 7;
reader.read_exact(&mut tmp)?;
byte = tmp[0] as i8;
if byte >= 0 {
result |= (byte as u32) << 14;
} else {
result |= ((byte & 127) as u32) << 14;
reader.read_exact(&mut tmp)?;
byte = tmp[0] as i8;
if byte >= 0 {
result |= (byte as u32) << 21;
} else {
result |= ((byte & 127) as u32) << 21;
reader.read_exact(&mut tmp)?;
byte = tmp[0] as i8;
result |= (byte as u32) << 28;
if byte < 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid u32 varint encoding: too many bytes (most significant bit in the 5th byte is set)",
));
}
}
}
}
Ok(result)
}
pub fn read_unsigned_varint_bytes(bytes: &[u8]) -> io::Result<(u32, usize)> {
if bytes.is_empty() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Cannot read varint from empty buffer",
));
}
let mut byte = bytes[0] as i8;
let mut index = 1;
if byte >= 0 {
return Ok((byte as u32, index));
}
let mut result = (byte & 127) as u32;
if index >= bytes.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Incomplete varint",
));
}
byte = bytes[index] as i8;
index += 1;
if byte >= 0 {
result |= (byte as u32) << 7;
} else {
result |= ((byte & 127) as u32) << 7;
if index >= bytes.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Incomplete varint",
));
}
byte = bytes[index] as i8;
index += 1;
if byte >= 0 {
result |= (byte as u32) << 14;
} else {
result |= ((byte & 127) as u32) << 14;
if index >= bytes.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Incomplete varint",
));
}
byte = bytes[index] as i8;
index += 1;
if byte >= 0 {
result |= (byte as u32) << 21;
} else {
result |= ((byte & 127) as u32) << 21;
if index >= bytes.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Incomplete varint",
));
}
byte = bytes[index] as i8;
index += 1;
result |= (byte as u32) << 28;
if byte < 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid u32 varint encoding: too many bytes (most significant bit in the 5th byte is set)",
));
}
}
}
}
Ok((result, index))
}
pub fn size_of_unsigned_varint(value: u32) -> usize {
let leading_zeros = value.leading_zeros();
let leading_zeros_below_38_divided_by_7 = ((38 - leading_zeros) * 0b10010010010010011) >> 19;
(leading_zeros_below_38_divided_by_7 + (leading_zeros >> 5)) as usize
}
#[allow(dead_code)]
pub fn size_of_unsigned_varint_u64(value: u64) -> usize {
let leading_zeros = value.leading_zeros();
let leading_zeros_below_70_divided_by_7 = ((70 - leading_zeros) * 0b10010010010010011) >> 19;
(leading_zeros_below_70_divided_by_7 + (leading_zeros >> 6)) as usize
}
#[allow(dead_code)]
pub fn write_unsigned_varint_u64_buf(value: u64, buf: &mut impl BufMut) {
let mut v = value;
while (v & !0x7F) != 0 {
buf.put_u8(((v as u8) & 0x7F) | 0x80);
v >>= 7;
}
buf.put_u8(v as u8);
}
pub fn write_unsigned_varint_to_slice(value: u32, slice: &mut [u8]) -> usize {
let mut v = value;
let mut written = 0;
while (v & !0x7F) != 0 {
slice[written] = ((v as u8) & 0x7F) | 0x80;
written += 1;
v >>= 7;
}
slice[written] = v as u8;
written + 1
}
pub fn write_unsigned_varint_u64_to_slice(value: u64, slice: &mut [u8]) -> usize {
let mut v = value;
let mut written = 0;
while (v & !0x7F) != 0 {
slice[written] = ((v as u8) & 0x7F) | 0x80;
written += 1;
v >>= 7;
}
slice[written] = v as u8;
written + 1
}
pub fn read_unsigned_varint_at(
slice: &[u8],
mut pos: usize,
max_bytes: usize,
) -> io::Result<(u32, usize)> {
let mut result: u32 = 0;
let mut shift = 0;
for _ in 0..max_bytes {
if pos >= slice.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Unexpected end of varint",
));
}
let b = slice[pos];
pos += 1;
result |= ((b & 0x7F) as u32) << shift;
if (b & 0x80) == 0 {
return Ok((result, pos));
}
shift += 7;
}
Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid VarInt32 input stream",
))
}
pub fn read_unsigned_varint_u64_at(
slice: &[u8],
mut pos: usize,
max_bytes: usize,
) -> io::Result<(u64, usize)> {
let mut result: u64 = 0;
let mut shift = 0;
for _ in 0..max_bytes {
if pos >= slice.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Unexpected end of varint",
));
}
let b = slice[pos];
pos += 1;
result |= ((b & 0x7F) as u64) << shift;
if (b & 0x80) == 0 {
return Ok((result, pos));
}
shift += 7;
}
Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid VarInt64 input stream",
))
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_unsigned_varint_round_trip() {
let test_values = vec![
0u32,
1,
127,
128,
255,
256,
16383,
16384,
2097151,
2097152,
268435455,
268435456,
u32::MAX,
];
for value in test_values {
let mut buffer = Vec::new();
let written = write_unsigned_varint(value, &mut buffer).unwrap();
let mut reader = Cursor::new(&buffer);
let read_value = read_unsigned_varint(&mut reader).unwrap();
assert_eq!(value, read_value, "Round trip failed for value {value}");
assert_eq!(
written,
buffer.len(),
"Bytes written mismatch for value {value}"
);
let mut buf = bytes::BytesMut::new();
write_unsigned_varint_buf(value, &mut buf);
assert_eq!(buf.len(), written, "BufMut write length mismatch");
let calculated_size = size_of_unsigned_varint(value);
assert_eq!(
calculated_size,
buffer.len(),
"Size calculation failed for value {value}"
);
let (read_value_bytes, bytes_read) = read_unsigned_varint_bytes(&buffer).unwrap();
assert_eq!(
value, read_value_bytes,
"Bytes read failed for value {value}"
);
assert_eq!(
bytes_read,
buffer.len(),
"Bytes read count mismatch for value {value}"
);
}
}
#[test]
fn test_size_of_unsigned_varint() {
assert_eq!(size_of_unsigned_varint(0), 1);
assert_eq!(size_of_unsigned_varint(127), 1);
assert_eq!(size_of_unsigned_varint(128), 2);
assert_eq!(size_of_unsigned_varint(16383), 2);
assert_eq!(size_of_unsigned_varint(16384), 3);
assert_eq!(size_of_unsigned_varint(2097151), 3);
assert_eq!(size_of_unsigned_varint(2097152), 4);
assert_eq!(size_of_unsigned_varint(268435455), 4);
assert_eq!(size_of_unsigned_varint(268435456), 5);
assert_eq!(size_of_unsigned_varint(u32::MAX), 5);
}
#[test]
fn test_size_of_unsigned_varint_u64() {
assert_eq!(size_of_unsigned_varint_u64(0), 1);
assert_eq!(size_of_unsigned_varint_u64(127), 1);
assert_eq!(size_of_unsigned_varint_u64(128), 2);
assert_eq!(size_of_unsigned_varint_u64(16383), 2);
assert_eq!(size_of_unsigned_varint_u64(16384), 3);
assert_eq!(size_of_unsigned_varint_u64(2097151), 3);
assert_eq!(size_of_unsigned_varint_u64(2097152), 4);
assert_eq!(size_of_unsigned_varint_u64(268435455), 4);
assert_eq!(size_of_unsigned_varint_u64(268435456), 5);
assert_eq!(size_of_unsigned_varint_u64(u32::MAX as u64), 5);
assert_eq!(size_of_unsigned_varint_u64(34359738367), 5);
assert_eq!(size_of_unsigned_varint_u64(34359738368), 6);
assert_eq!(size_of_unsigned_varint_u64(4398046511103), 6);
assert_eq!(size_of_unsigned_varint_u64(4398046511104), 7);
assert_eq!(size_of_unsigned_varint_u64(562949953421311), 7);
assert_eq!(size_of_unsigned_varint_u64(562949953421312), 8);
assert_eq!(size_of_unsigned_varint_u64(72057594037927935), 8);
assert_eq!(size_of_unsigned_varint_u64(72057594037927936), 9);
assert_eq!(size_of_unsigned_varint_u64(9223372036854775807), 9);
assert_eq!(size_of_unsigned_varint_u64(9223372036854775808), 10);
assert_eq!(size_of_unsigned_varint_u64(u64::MAX), 10);
}
#[test]
fn test_read_unsigned_varint_bytes_error_handling() {
assert!(read_unsigned_varint_bytes(&[]).is_err());
assert!(read_unsigned_varint_bytes(&[0x80]).is_err());
assert!(read_unsigned_varint_bytes(&[0xFF, 0x80]).is_err());
}
#[test]
fn test_write_read_to_slice() {
let test_values_u32 = vec![0u32, 127, 128, 16384, u32::MAX];
for value in test_values_u32 {
let mut buffer = vec![0u8; 10];
let written = write_unsigned_varint_to_slice(value, &mut buffer);
let (read_value, next_pos) = read_unsigned_varint_at(&buffer, 0, 5).unwrap();
assert_eq!(value, read_value);
assert_eq!(written, next_pos);
}
let test_values_u64 = vec![0u64, 127, 128, 16384, u32::MAX as u64, u64::MAX];
for value in test_values_u64 {
let mut buffer = vec![0u8; 10];
let written = write_unsigned_varint_u64_to_slice(value, &mut buffer);
let (read_value, next_pos) = read_unsigned_varint_u64_at(&buffer, 0, 10).unwrap();
assert_eq!(value, read_value);
assert_eq!(written, next_pos);
}
}
#[test]
fn test_read_at_with_offset() {
let mut buffer = vec![0u8; 20];
let mut pos = 0;
pos += write_unsigned_varint_to_slice(127, &mut buffer[pos..]);
pos += write_unsigned_varint_to_slice(16384, &mut buffer[pos..]);
let end_pos = pos + write_unsigned_varint_to_slice(u32::MAX, &mut buffer[pos..]);
let (val1, pos1) = read_unsigned_varint_at(&buffer, 0, 5).unwrap();
assert_eq!(val1, 127);
let (val2, pos2) = read_unsigned_varint_at(&buffer, pos1, 5).unwrap();
assert_eq!(val2, 16384);
let (val3, pos3) = read_unsigned_varint_at(&buffer, pos2, 5).unwrap();
assert_eq!(val3, u32::MAX);
assert_eq!(pos3, end_pos);
}
}