use crate::traits::*;
#[must_use]
#[inline(always)]
pub const fn byte_len_vbyte(mut n: u64) -> usize {
let mut len = 1;
loop {
n >>= 7;
if n == 0 {
return len;
}
n -= 1;
len += 1;
}
}
#[must_use]
#[inline(always)]
pub const fn bit_len_vbyte(n: u64) -> usize {
8 * byte_len_vbyte(n)
}
pub trait VByteBeRead<E: Endianness>: BitRead<E> {
fn read_vbyte_be(&mut self) -> Result<u64, Self::Error>;
}
pub trait VByteLeRead<E: Endianness>: BitRead<E> {
fn read_vbyte_le(&mut self) -> Result<u64, Self::Error>;
}
impl<E: Endianness, B: BitRead<E>> VByteBeRead<E> for B {
#[inline(always)]
fn read_vbyte_be(&mut self) -> Result<u64, Self::Error> {
let mut byte = self.read_bits(8)?;
let mut value = byte & 0x7F;
while (byte >> 7) != 0 {
value += 1;
byte = self.read_bits(8)?;
value = (value << 7) | (byte & 0x7F);
}
Ok(value)
}
}
impl<E: Endianness, B: BitRead<E>> VByteLeRead<E> for B {
#[inline(always)]
fn read_vbyte_le(&mut self) -> Result<u64, Self::Error> {
let mut result = 0;
let mut shift = 0;
loop {
let byte = self.read_bits(8)?;
result += (byte & 0x7F) << shift;
if (byte >> 7) == 0 {
break;
}
shift += 7;
result += 1 << shift;
}
Ok(result)
}
}
pub trait VByteBeWrite<E: Endianness>: BitWrite<E> {
fn write_vbyte_be(&mut self, n: u64) -> Result<usize, Self::Error>;
}
pub trait VByteLeWrite<E: Endianness>: BitWrite<E> {
fn write_vbyte_le(&mut self, n: u64) -> Result<usize, Self::Error>;
}
impl<E: Endianness, B: BitWrite<E>> VByteBeWrite<E> for B {
#[inline(always)]
fn write_vbyte_be(&mut self, mut n: u64) -> Result<usize, Self::Error> {
let mut buf = [0u8; 10];
let mut pos = buf.len() - 1;
buf[pos] = (n & 0x7F) as u8;
n >>= 7;
while n != 0 {
n -= 1;
pos -= 1;
buf[pos] = 0x80 | (n & 0x7F) as u8;
n >>= 7;
}
let bytes_to_write = buf.len() - pos;
for &byte in &buf[pos..] {
self.write_bits(byte as u64, 8)?;
}
Ok(bytes_to_write * 8)
}
}
impl<E: Endianness, B: BitWrite<E>> VByteLeWrite<E> for B {
#[inline(always)]
fn write_vbyte_le(&mut self, mut n: u64) -> Result<usize, Self::Error> {
let mut len = 1;
loop {
let byte = (n & 0x7F) as u8;
n >>= 7;
if n != 0 {
self.write_bits((byte | 0x80) as u64, 8)?;
} else {
self.write_bits(byte as u64, 8)?;
break;
}
n -= 1;
len += 1;
}
Ok(len * 8)
}
}
#[inline(always)]
#[cfg(feature = "std")]
pub fn vbyte_write<E: Endianness, W: std::io::Write>(
n: u64,
writer: &mut W,
) -> std::io::Result<usize> {
if core::any::TypeId::of::<E>() == core::any::TypeId::of::<BigEndian>() {
vbyte_write_be(n, writer)
} else {
vbyte_write_le(n, writer)
}
}
#[inline(always)]
#[cfg(feature = "std")]
pub fn vbyte_write_be<W: std::io::Write>(mut n: u64, w: &mut W) -> std::io::Result<usize> {
let mut buf = [0u8; 10];
let mut pos = buf.len() - 1;
buf[pos] = (n & 0x7F) as u8;
n >>= 7;
while n != 0 {
n -= 1;
pos -= 1;
buf[pos] = 0x80 | (n & 0x7F) as u8;
n >>= 7;
}
let bytes_to_write = buf.len() - pos;
w.write_all(&buf[pos..])?;
Ok(bytes_to_write)
}
#[inline(always)]
#[cfg(feature = "std")]
pub fn vbyte_write_le<W: std::io::Write>(mut n: u64, writer: &mut W) -> std::io::Result<usize> {
let mut len = 1;
loop {
let byte = (n & 0x7F) as u8;
n >>= 7;
if n != 0 {
writer.write_all(&[byte | 0x80])?;
} else {
writer.write_all(&[byte])?;
break;
}
n -= 1;
len += 1;
}
Ok(len)
}
#[inline(always)]
#[cfg(feature = "std")]
pub fn vbyte_read<E: Endianness, R: std::io::Read>(reader: &mut R) -> std::io::Result<u64> {
if core::any::TypeId::of::<E>() == core::any::TypeId::of::<BigEndian>() {
vbyte_read_be(reader)
} else {
vbyte_read_le(reader)
}
}
#[inline(always)]
#[cfg(feature = "std")]
pub fn vbyte_read_be<R: std::io::Read>(reader: &mut R) -> std::io::Result<u64> {
let mut buf = [0u8; 1];
let mut value: u64;
reader.read_exact(&mut buf)?;
value = (buf[0] & 0x7F) as u64;
while (buf[0] >> 7) != 0 {
value += 1;
reader.read_exact(&mut buf)?;
value = (value << 7) | ((buf[0] & 0x7F) as u64);
}
Ok(value)
}
#[inline(always)]
#[cfg(feature = "std")]
pub fn vbyte_read_le<R: std::io::Read>(reader: &mut R) -> std::io::Result<u64> {
let mut result = 0;
let mut shift = 0;
let mut buffer = [0; 1];
loop {
reader.read_exact(&mut buffer)?;
let byte = buffer[0];
result += ((byte & 0x7F) as u64) << shift;
if (byte >> 7) == 0 {
break;
}
shift += 7;
result += 1 << shift;
}
Ok(result)
}
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
#[allow(unused_imports)]
use super::*;
const UPPER_BOUND_1: u64 = 128;
const UPPER_BOUND_2: u64 = 128_u64.pow(2) + UPPER_BOUND_1;
const UPPER_BOUND_3: u64 = 128_u64.pow(3) + UPPER_BOUND_2;
const UPPER_BOUND_4: u64 = 128_u64.pow(4) + UPPER_BOUND_3;
const UPPER_BOUND_5: u64 = 128_u64.pow(5) + UPPER_BOUND_4;
const UPPER_BOUND_6: u64 = 128_u64.pow(6) + UPPER_BOUND_5;
const UPPER_BOUND_7: u64 = 128_u64.pow(7) + UPPER_BOUND_6;
const UPPER_BOUND_8: u64 = 128_u64.pow(8) + UPPER_BOUND_7;
macro_rules! impl_tests {
($test_name:ident, $E:ty) => {
#[test]
fn $test_name() -> std::io::Result<()> {
const MAX: usize = 1 << 20;
const MIN: usize = 0;
let mut buffer = std::io::Cursor::new(Vec::with_capacity(128));
let mut lens = Vec::new();
for i in MIN..MAX {
lens.push(vbyte_write::<$E, _>(i as _, &mut buffer)?);
}
buffer.set_position(0);
for (i, l) in (MIN..MAX).zip(lens.iter()) {
let j = vbyte_read::<$E, _>(&mut buffer)?;
assert_eq!(byte_len_vbyte(i as _), *l);
assert_eq!(j, i as u64);
}
let values = [
0,
UPPER_BOUND_1 - 1,
UPPER_BOUND_1 + 1,
UPPER_BOUND_2 - 1,
UPPER_BOUND_2 + 1,
UPPER_BOUND_3 - 1,
UPPER_BOUND_3 + 1,
UPPER_BOUND_4 - 1,
UPPER_BOUND_4 + 1,
UPPER_BOUND_5 - 1,
UPPER_BOUND_5 + 1,
UPPER_BOUND_6 - 1,
UPPER_BOUND_6 + 1,
UPPER_BOUND_7 - 1,
UPPER_BOUND_7 + 1,
UPPER_BOUND_8 - 1,
UPPER_BOUND_8 + 1,
u64::MAX,
];
let tell: u64 = buffer.position();
for &i in values.iter() {
vbyte_write::<$E, _>(i, &mut buffer)?;
}
buffer.set_position(tell);
for &i in values.iter() {
assert_eq!(i, vbyte_read::<$E, _>(&mut buffer)?);
}
Ok(())
}
};
}
impl_tests!(test_vbytes_be, BE);
impl_tests!(test_vbytes_le, LE);
}