pub struct VarInt;
impl VarInt {
pub const fn write(mut value: u64) -> (usize, [u8; 10]) {
let mut buf = [0u8; 10];
let mut i = 0;
loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
buf[i] = byte;
i += 1;
if value == 0 {
break;
}
}
(i, buf)
}
#[allow(unsafe_op_in_unsafe_fn)]
pub unsafe fn read(ptr: *const u8) -> (usize, usize) {
let mut result = 0usize;
let mut shift = 0;
let mut i = 0;
loop {
let byte = *ptr.add(i);
result |= ((byte & 0x7F) as usize) << shift;
shift += 7;
i += 1;
if byte & 0x80 == 0 {
break;
}
}
(result, i)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_correct(x: u64) {
let (wrote, b) = VarInt::write(x);
assert!((1..=10).contains(&wrote));
let ptr = b.as_ptr();
let (y, read) = unsafe { VarInt::read(ptr) };
assert_eq!(wrote, read);
assert_eq!(x, y as u64);
}
#[test]
fn vint_round_trip() {
for x in 0..=1024 {
assert_correct(x);
}
let mut shift = 7;
while shift < usize::BITS {
let boundary = 1usize << shift;
for x in boundary - 1..=boundary + 1 {
assert_correct(x as u64);
}
shift += 7;
}
for x in 0..=100 {
assert_correct(usize::MAX as u64 - x);
}
}
}