Skip to main content

sark_core/http/
varint.rs

1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum Error {
3    TooLarge,
4    Underflow,
5}
6
7pub struct VarInt;
8
9impl VarInt {
10    pub const MAX: u64 = (1u64 << 62) - 1;
11
12    pub fn size_for(value: u64) -> Result<usize, Error> {
13        match value {
14            0..=63 => Ok(1),
15            64..=16_383 => Ok(2),
16            16_384..=1_073_741_823 => Ok(4),
17            v if v <= Self::MAX => Ok(8),
18            _ => Err(Error::TooLarge),
19        }
20    }
21
22    pub fn encode(value: u64, out: &mut Vec<u8>) -> Result<(), Error> {
23        match value {
24            0..=63 => out.push(value as u8),
25            64..=16_383 => {
26                let v = (value as u16) | 0x4000;
27                out.extend_from_slice(&v.to_be_bytes());
28            }
29            16_384..=1_073_741_823 => {
30                let v = (value as u32) | 0x8000_0000;
31                out.extend_from_slice(&v.to_be_bytes());
32            }
33            v if v <= Self::MAX => {
34                let w = v | 0xC000_0000_0000_0000;
35                out.extend_from_slice(&w.to_be_bytes());
36            }
37            _ => return Err(Error::TooLarge),
38        }
39        Ok(())
40    }
41
42    pub fn decode(input: &[u8]) -> Result<(u64, usize), Error> {
43        let first = *input.first().ok_or(Error::Underflow)?;
44        let len = 1usize << (first >> 6);
45        if input.len() < len {
46            return Err(Error::Underflow);
47        }
48        let mut buf = [0u8; 8];
49        buf[8 - len..].copy_from_slice(&input[..len]);
50        let mut value = u64::from_be_bytes(buf);
51        value &= (1u64 << (len * 8 - 2)) - 1;
52        Ok((value, len))
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn round_trips_boundaries() {
62        for value in [0, 63, 64, 16_383, 16_384, 1_073_741_823, VarInt::MAX] {
63            let mut out = Vec::new();
64            VarInt::encode(value, &mut out).unwrap();
65            assert_eq!(VarInt::decode(&out), Ok((value, out.len())));
66        }
67    }
68}