pub const MAX_VARINT_SIZE: usize = 8;
pub const MAX_VARINT_VALUE: u64 = (1u64 << 62) - 1;
#[inline]
pub fn encode_varint_buf(value: u64, out: &mut [u8]) -> Result<usize, &'static str> {
if out.len() < MAX_VARINT_SIZE {
return Err("buffer too small for varint encoding");
}
if value < 64 {
out[0] = value as u8;
Ok(1)
} else if value < 16384 {
out[0] = 0x40 | ((value >> 8) as u8);
out[1] = (value & 0xFF) as u8;
Ok(2)
} else if value < (1u64 << 30) {
out[0] = 0x80 | ((value >> 24) as u8);
out[1] = ((value >> 16) & 0xFF) as u8;
out[2] = ((value >> 8) & 0xFF) as u8;
out[3] = (value & 0xFF) as u8;
Ok(4)
} else if value <= MAX_VARINT_VALUE {
out[0] = 0xC0 | (((value >> 56) & 0x3F) as u8);
out[1] = ((value >> 48) & 0xFF) as u8;
out[2] = ((value >> 40) & 0xFF) as u8;
out[3] = ((value >> 32) & 0xFF) as u8;
out[4] = ((value >> 24) & 0xFF) as u8;
out[5] = ((value >> 16) & 0xFF) as u8;
out[6] = ((value >> 8) & 0xFF) as u8;
out[7] = (value & 0xFF) as u8;
Ok(8)
} else {
Err("varint value exceeds maximum (2^62 - 1)")
}
}
#[inline]
pub fn encode_varint(value: u64, out: &mut Vec<u8>) -> Result<(), &'static str> {
let mut buf = [0u8; MAX_VARINT_SIZE];
let len = encode_varint_buf(value, &mut buf)?;
out.extend_from_slice(&buf[..len]);
Ok(())
}
#[inline]
pub fn parse_varint(input: &[u8]) -> Option<(u64, usize)> {
if input.is_empty() {
return None;
}
let first = input[0];
let len_tag = first >> 6;
let len = 1usize << len_tag;
if input.len() < len {
return None;
}
let mut v: u64 = (first & 0x3F) as u64;
for &b in input.iter().take(len).skip(1) {
v = (v << 8) | (b as u64);
}
Some((v, len))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rfc9000_appendix_a_known_values() {
let cases: &[(u64, &[u8])] = &[
(37, &[0x25]),
(63, &[0x3f]),
(64, &[0x40, 0x40]),
(83, &[0x40, 0x53]),
(15_293, &[0x7b, 0xbd]),
(16_383, &[0x7f, 0xff]),
(16_384, &[0x80, 0x00, 0x40, 0x00]),
(494_878_333, &[0x9d, 0x7f, 0x3e, 0x7d]),
(1_073_741_823, &[0xbf, 0xff, 0xff, 0xff]),
(1_073_741_824, &[0xc0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]),
(151_288_809_941_952_652, &[0xc2, 0x19, 0x7c, 0x5e, 0xff, 0x14, 0xe8, 0x8c]),
((1u64 << 62) - 1, &[0xff; 8]),
];
for (value, expected) in cases {
let mut buf = [0u8; MAX_VARINT_SIZE];
let n = encode_varint_buf(*value, &mut buf).unwrap();
assert_eq!(&buf[..n], *expected, "encode({value}) mismatch");
let mut v = Vec::new();
encode_varint(*value, &mut v).unwrap();
assert_eq!(v.as_slice(), *expected, "encode_vec({value}) mismatch");
}
}
#[test]
fn test_over_max_rejected() {
let mut buf = [0u8; MAX_VARINT_SIZE];
assert!(encode_varint_buf(1u64 << 62, &mut buf).is_err());
let mut v = Vec::new();
assert!(encode_varint(u64::MAX, &mut v).is_err());
assert!(v.is_empty(), "fail-closed: 拒绝时不得写入任何字节");
}
#[test]
fn test_small_buffer_rejected() {
let mut buf = [0u8; 4];
assert!(encode_varint_buf(37, &mut buf).is_err());
}
}