use crate::courierust_error::{Error, Result};
use alloc::vec::Vec;
pub const MAX: u64 = (1 << 62) - 1;
pub fn encode(value: u64) -> Vec<u8> {
assert!(value <= MAX, "varint value {value} exceeds 2^62-1");
if value < (1 << 6) {
vec![value as u8]
} else if value < (1 << 14) {
vec![0x40 | ((value >> 8) as u8), (value & 0xff) as u8]
} else if value < (1 << 30) {
vec![
0x80 | ((value >> 24) as u8),
((value >> 16) & 0xff) as u8,
((value >> 8) & 0xff) as u8,
(value & 0xff) as u8,
]
} else {
let mut out = Vec::with_capacity(8);
out.push(0xc0 | ((value >> 56) as u8));
for shift in (0..56).step_by(8).rev() {
out.push(((value >> shift) & 0xff) as u8);
}
out
}
}
pub fn decode(buf: &[u8]) -> Result<(u64, usize)> {
let first = *buf.first().ok_or_else(Error::eof)?;
let len = match first >> 6 {
0 => 1,
1 => 2,
2 => 4,
_ => 8,
};
if buf.len() < len {
return Err(Error::eof());
}
let mut value: u64 = (first & 0x3f) as u64;
for &byte in &buf[1..len] {
value = (value << 8) | byte as u64;
}
Ok((value, len))
}
pub fn read(buf: &[u8]) -> Result<u64> {
decode(buf).map(|(v, _)| v)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rfc_9000_section_16_examples() {
assert_eq!(decode(&[0x00]).unwrap(), (0, 1));
assert_eq!(decode(&[0x3f]).unwrap(), (63, 1));
assert_eq!(decode(&[0x40, 0x25]).unwrap(), (37, 2));
assert_eq!(decode(&[0x7f, 0xff]).unwrap(), (16383, 2));
assert_eq!(decode(&[0x80, 0x00, 0x25, 0x00]).unwrap(), (9472, 4));
assert_eq!(
decode(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]).unwrap(),
(4611686018427387903, 8)
);
}
#[test]
fn round_trip_all_widths() {
for value in [
0u64,
1,
62,
63,
64,
16383,
16384,
(1 << 30) - 1,
1 << 30,
MAX,
] {
let wire = encode(value);
let (decoded, used) = decode(&wire).unwrap();
assert_eq!(decoded, value, "value {value}");
assert_eq!(used, wire.len(), "length for {value}");
}
}
#[test]
fn truncated_errors() {
assert!(decode(&[]).is_err());
assert!(decode(&[0x40]).is_err());
assert!(decode(&[0x80, 0x00]).is_err());
assert!(decode(&[0xc0, 0, 0, 0]).is_err());
}
}