Skip to main content

vunsigned_varint/
decode.rs

1use num_traits::{CheckedShl, FromPrimitive, PrimInt, Unsigned};
2use thiserror::Error;
3
4/// Decodes an unsigned integer from a given buffer, returning the integer and the amount of bytes read.
5///
6/// Note that this implementation protects against memory attacks by limiting the number of
7/// processed bytes to the number of bytes needed to represent the max value of `N`.
8/// If you want to be more strict, please limit the buffer length.
9/// The unsigned-varint spec recommends a limit of 9 Bytes.
10///
11/// # Example
12///
13/// ```
14/// # use vunsigned_varint::decode;
15/// let (num, read) = decode::<u16>(&[0x80, 0x80, 0x01, 0xFF]).unwrap();
16/// assert_eq!(num, 0x4000);
17/// assert_eq!(read, 3);
18/// ```
19pub fn decode<N>(buffer: &[u8]) -> Result<(N, usize), Error>
20where
21    N: PrimInt + Unsigned + FromPrimitive + CheckedShl,
22{
23    let mut num = N::zero();
24    if buffer.is_empty() {
25        return Err(Error::EmptyBuffer);
26    }
27    let byte_num = (core::mem::size_of::<N>() * 8).div_ceil(7);
28    for (i, byte) in buffer.iter().take(byte_num).copied().enumerate() {
29        num = num
30            | N::from_u8(byte & 0x7F)
31                .expect("Anything should be able to represent a byte")
32                .checked_shl(7 * i as u32)
33                .ok_or(Error::Overflow)?;
34        if byte & 0x80 == 0 {
35            return Ok((num, i + 1));
36        }
37    }
38    Err(Error::UnexpectedEof)
39}
40
41/// Errors that can occur decoding an unsigned varint.
42#[derive(Debug, Error, PartialEq, Eq, Hash, Clone, Copy)]
43pub enum Error {
44    /// buffer is empty
45    #[error("buffer is empty")]
46    EmptyBuffer,
47    /// unexpected end of buffer before end of varint
48    #[error("unexpected end of buffer before end of varint")]
49    UnexpectedEof,
50    /// decoded value does not fit into the target integer type
51    #[error("decoded value does not fit into the target integer type")]
52    Overflow,
53}
54
55impl Error {
56    /// Convenience Wrapper around `Error::into`.
57    #[cfg(feature = "std")]
58    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
59    #[must_use]
60    pub fn into_io_error(self) -> std::io::Error {
61        self.into()
62    }
63}
64
65#[cfg(feature = "std")]
66#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
67impl From<Error> for std::io::Error {
68    fn from(error: Error) -> Self {
69        let kind = match error {
70            Error::EmptyBuffer | Error::UnexpectedEof => std::io::ErrorKind::UnexpectedEof,
71            Error::Overflow => std::io::ErrorKind::InvalidData,
72        };
73        Self::new(kind, error)
74    }
75}
76
77#[cfg(test)]
78mod test {
79    use crate::decode;
80
81    #[test]
82    fn d1() {
83        let num: u8 = decode(&[0x01]).unwrap().0;
84        assert_eq!(num, 0x01_u8);
85    }
86
87    #[test]
88    fn d7f() {
89        let num: u8 = decode(&[0x7f]).unwrap().0;
90        assert_eq!(num, 0x7f_u8);
91    }
92
93    #[test]
94    fn d80() {
95        let num: u8 = decode(&[0x80, 0x01]).unwrap().0;
96        assert_eq!(num, 0x80_u8);
97    }
98
99    #[test]
100    fn dff() {
101        let num: u8 = decode(&[0xff, 0x01]).unwrap().0;
102        assert_eq!(num, 0xff_u8);
103    }
104
105    #[test]
106    fn d12c() {
107        let num: u16 = decode(&[0xac, 0x02]).unwrap().0;
108        assert_eq!(num, 0x12c_u16);
109    }
110
111    #[test]
112    fn d4000() {
113        let num: u16 = decode(&[0x80, 0x80, 0x01]).unwrap().0;
114        assert_eq!(num, 0x4000_u16);
115    }
116}