use crate::error::{CrousError, Result};
#[inline]
pub fn zigzag_encode(n: i64) -> u64 {
((n << 1) ^ (n >> 63)) as u64
}
#[inline]
pub fn zigzag_decode(n: u64) -> i64 {
((n >> 1) as i64) ^ (-((n & 1) as i64))
}
#[inline]
pub fn encode_varint(mut value: u64, buf: &mut [u8; 10]) -> usize {
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
}
#[inline]
pub fn encode_varint_vec(value: u64, out: &mut Vec<u8>) {
let mut buf = [0u8; 10];
let n = encode_varint(value, &mut buf);
out.extend_from_slice(&buf[..n]);
}
#[inline]
pub fn decode_varint(data: &[u8], offset: usize) -> Result<(u64, usize)> {
let mut result: u64 = 0;
let mut shift: u32 = 0;
let mut i = 0usize;
loop {
if offset + i >= data.len() {
return Err(CrousError::UnexpectedEof(offset + i));
}
let byte = data[offset + i];
i += 1;
if i > 10 {
return Err(CrousError::VarintOverflow);
}
if i == 10 && byte > 0x01 {
return Err(CrousError::VarintOverflow);
}
result |= ((byte & 0x7F) as u64) << shift;
if byte & 0x80 == 0 {
return Ok((result, i));
}
shift += 7;
}
}
#[inline]
pub fn encode_signed_varint_vec(value: i64, out: &mut Vec<u8>) {
encode_varint_vec(zigzag_encode(value), out);
}
#[inline]
pub fn decode_signed_varint(data: &[u8], offset: usize) -> Result<(i64, usize)> {
let (raw, len) = decode_varint(data, offset)?;
Ok((zigzag_decode(raw), len))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zigzag_roundtrip() {
for &v in &[0i64, 1, -1, 2, -2, 127, -128, i64::MAX, i64::MIN] {
assert_eq!(
zigzag_decode(zigzag_encode(v)),
v,
"ZigZag roundtrip failed for {v}"
);
}
}
#[test]
fn varint_single_byte() {
let mut buf = [0u8; 10];
for v in 0..=127u64 {
let n = encode_varint(v, &mut buf);
assert_eq!(
n, 1,
"values 0–127 should encode in 1 byte, got {n} for {v}"
);
assert_eq!(buf[0], v as u8);
let (decoded, consumed) = decode_varint(&buf[..n], 0).unwrap();
assert_eq!(decoded, v);
assert_eq!(consumed, 1);
}
}
#[test]
fn varint_multi_byte() {
let test_cases: &[(u64, &[u8])] = &[
(128, &[0x80, 0x01]),
(300, &[0xac, 0x02]),
(16384, &[0x80, 0x80, 0x01]),
(
u64::MAX,
&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01],
),
];
for &(value, expected) in test_cases {
let mut buf = [0u8; 10];
let n = encode_varint(value, &mut buf);
assert_eq!(&buf[..n], expected, "encoding mismatch for {value}");
let (decoded, consumed) = decode_varint(expected, 0).unwrap();
assert_eq!(decoded, value, "decode mismatch for {value}");
assert_eq!(consumed, expected.len());
}
}
#[test]
fn varint_overflow_detection() {
let bad = [0x80u8; 11];
assert!(decode_varint(&bad, 0).is_err());
}
#[test]
fn varint_unexpected_eof() {
let truncated = [0x80u8];
assert!(decode_varint(&truncated, 0).is_err());
}
#[test]
fn signed_varint_roundtrip() {
for &v in &[0i64, 1, -1, 42, -42, 1000, -1000, i64::MAX, i64::MIN] {
let mut buf = Vec::new();
encode_signed_varint_vec(v, &mut buf);
let (decoded, _) = decode_signed_varint(&buf, 0).unwrap();
assert_eq!(decoded, v, "signed varint roundtrip failed for {v}");
}
}
}