feophantlib/engine/io/
utility.rs

1//! Set of utility functions I've written a few times, but not enough (yet) to break into a submodule.
2use bytes::{Buf, BufMut};
3use thiserror::Error;
4
5/// Will provide the length in bytes the supplied usize will encode to without encoding
6pub fn expected_encoded_size(size: usize) -> usize {
7    //Discussion here: https://github.com/rust-lang/rfcs/issues/2844
8    (size + 127 - 1) / 127
9}
10
11/// Writes a length out to a byte stream as a series of 7 bit numbers, with the high
12/// bit used to indicate we have hit the end of the length
13pub fn encode_size(buffer: &mut impl BufMut, mut size: usize) {
14    while size > 0 {
15        let last_count = size as u8;
16        let mut digit: u8 = last_count & 0x7f;
17        size >>= 7;
18        if size > 0 {
19            digit |= 0x80;
20        }
21        buffer.put_u8(digit);
22    }
23}
24
25pub fn parse_size(buffer: &mut impl Buf) -> Result<usize, SizeError> {
26    let mut size: usize = 0;
27    let mut high_bit = 1;
28    let mut loop_count = 0;
29    while high_bit == 1 {
30        if !buffer.has_remaining() {
31            return Err(SizeError::BufferTooShort());
32        }
33
34        let b = buffer.get_u8();
35        high_bit = b >> 7;
36
37        let mut low_bits: usize = (b & 0x7f).into();
38        low_bits <<= 7 * loop_count;
39        loop_count += 1;
40
41        size = size
42            .checked_add(low_bits)
43            .ok_or_else(SizeError::SizeOverflow)?;
44    }
45
46    Ok(size)
47}
48
49#[derive(Debug, Error)]
50pub enum SizeError {
51    #[error("Buffer too short to parse")]
52    BufferTooShort(),
53    #[error("Size Overflow!")]
54    SizeOverflow(),
55}
56
57#[cfg(test)]
58mod tests {
59    use bytes::BytesMut;
60
61    use super::*;
62
63    #[test]
64    fn test_size_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
65        let test = 1;
66
67        let mut buffer = BytesMut::with_capacity(expected_encoded_size(test));
68        encode_size(&mut buffer, test);
69        let mut serialized = buffer.freeze();
70
71        assert_eq!(serialized.len(), expected_encoded_size(test));
72        let parsed = parse_size(&mut serialized)?;
73        assert_eq!(test, parsed);
74
75        let test = 128;
76
77        let mut buffer = BytesMut::with_capacity(expected_encoded_size(test));
78        encode_size(&mut buffer, test);
79        let mut serialized = buffer.freeze();
80
81        assert_eq!(serialized.len(), expected_encoded_size(test));
82        let parsed = parse_size(&mut serialized)?;
83        assert_eq!(test, parsed);
84
85        Ok(())
86    }
87}