Skip to main content

steel_utils/codec/
var_uint.rs

1use std::io::{Cursor, Error, Write};
2
3use crate::serial::{ReadFrom, WriteTo};
4
5/// A variable-length unsigned integer.
6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct VarUint(pub u32);
8
9impl VarUint {
10    const MAX_SIZE: usize = 5;
11
12    /// Returns the exact number of bytes this `VarUInt` will write when
13    /// [`WriteTo::write`] is called, assuming no error occurs.
14    #[must_use]
15    pub const fn written_size(self) -> usize {
16        (32 - self.0.leading_zeros() as usize).max(1).div_ceil(7)
17    }
18
19    /// Writes a `VarUint` to a writer.
20    ///
21    /// # Errors
22    /// - If the writer fails to write.
23    pub fn write(self, writer: &mut impl Write) -> Result<(), Error> {
24        let mut val = self.0;
25        loop {
26            let mut byte = (val & 0x7F) as u8;
27            val >>= 7;
28            if val != 0 {
29                byte |= 0x80;
30            }
31            byte.write(writer)?;
32            if val == 0 {
33                break;
34            }
35        }
36        Ok(())
37    }
38
39    /// Reads a `VarUint` from a cursor.
40    ///
41    /// # Errors
42    /// - If the `VarUint` is too long.
43    pub fn read(read: &mut Cursor<&[u8]>) -> Result<u32, Error> {
44        let mut val = 0;
45        for i in 0..Self::MAX_SIZE {
46            let byte = u8::read(read)?;
47            val |= (u32::from(byte) & 0x7F) << (i * 7);
48            if byte & 0x80 == 0 {
49                return Ok(val);
50            }
51        }
52        Err(Error::other("Malformed VarUint"))
53    }
54}