use crate::error::{Error, Result};
pub fn varint_bytes(v: u64) -> Vec<u8> {
let mut out = Vec::with_capacity(varint_packed_size(v));
append_varint(&mut out, v);
out
}
pub fn append_varint(out: &mut Vec<u8>, mut v: u64) {
while v >= 0x80 {
out.push((v as u8 & 0x7f) | 0x80);
v >>= 7;
}
out.push(v as u8);
}
pub fn varint_packed_size(v: u64) -> usize {
let bits = 64 - v.leading_zeros() as usize;
bits.div_ceil(7).max(1)
}
pub fn take_varint(buf: &[u8]) -> Result<(u64, &[u8])> {
let mut v: u64 = 0;
let mut shift = 0u32;
for (i, b) in buf.iter().enumerate() {
v |= ((*b as u64) & 0x7f) << shift;
if b & 0x80 == 0 {
return Ok((v, &buf[i + 1..]));
}
shift += 7;
if shift >= 70 {
return Err(Error::msg("varint is too long"));
}
}
Err(Error::UnexpectedEof)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip() {
for v in [
0u64,
42,
127,
128,
129,
1337,
0x3fff,
0x4000,
0x123456789,
0xabcdef123456789,
u64::MAX,
] {
let buf = varint_bytes(v);
assert_eq!(buf.len(), varint_packed_size(v), "size of {v:#x}");
let (dec, rest) = take_varint(&buf).unwrap();
assert_eq!(dec, v, "decoding {v:#x}");
assert!(rest.is_empty(), "trailing data decoding {v:#x}");
}
}
#[test]
fn one_twenty_eight_is_two_bytes() {
assert_eq!(varint_bytes(128), vec![0x80, 0x01]);
}
#[test]
fn known_encodings() {
assert_eq!(varint_bytes(0), vec![0x00]);
assert_eq!(varint_bytes(127), vec![0x7f]);
assert_eq!(varint_bytes(300), vec![0xac, 0x02]);
}
#[test]
fn truncated_input_errors() {
assert!(take_varint(&[]).is_err());
assert!(take_varint(&[0x80]).is_err());
}
}