#[inline(always)]
pub(crate) fn len(value: u64) -> usize {
(64 - (value | 1).leading_zeros() as usize).div_ceil(7)
}
#[inline(always)]
pub(crate) fn push(out: &mut Vec<u8>, mut value: u64) {
while value >= 0x80 {
out.push(value as u8 | 0x80);
value >>= 7;
}
out.push(value as u8);
}
#[inline(always)]
pub(crate) fn write(out: &mut [u8], pos: &mut usize, mut value: u64) {
while value >= 0x80 {
out[*pos] = value as u8 | 0x80;
*pos += 1;
value >>= 7;
}
out[*pos] = value as u8;
*pos += 1;
}
#[inline(always)]
pub(crate) fn read(bytes: &[u8], pos: &mut usize) -> u64 {
let first = bytes[*pos];
*pos += 1;
if first < 0x80 {
return u64::from(first);
}
let mut value = u64::from(first & 0x7f);
let mut shift = 7;
loop {
let byte = bytes[*pos];
*pos += 1;
value |= u64::from(byte & 0x7f) << shift;
if byte < 0x80 {
return value;
}
shift += 7;
}
}
#[inline(always)]
pub(crate) fn read_len(bytes: &[u8], pos: &mut usize) -> usize {
let mut value = 0usize;
let mut shift = 0;
loop {
let byte = bytes[*pos];
*pos += 1;
value |= ((byte & 0x7f) as usize) << shift;
if byte < 0x80 {
return value;
}
shift += 7;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn varints_round_trip_through_both_writers() {
for value in [0u64, 1, 127, 128, 16_383, 16_384, u32::MAX as u64, u64::MAX] {
let mut pushed = Vec::new();
push(&mut pushed, value);
assert_eq!(pushed.len(), len(value), "{value}");
let mut written = vec![0; len(value) + 2];
let mut end = 1;
write(&mut written, &mut end, value);
assert_eq!(&written[1..end], &pushed[..]);
let mut pos = 0;
assert_eq!(read(&pushed, &mut pos), value);
assert_eq!(pos, pushed.len());
if let Ok(value) = usize::try_from(value) {
let mut pos = 0;
assert_eq!(read_len(&pushed, &mut pos), value);
assert_eq!(pos, pushed.len());
}
}
}
}