feophantlib/engine/io/
utility.rs1use bytes::{Buf, BufMut};
3use thiserror::Error;
4
5pub fn expected_encoded_size(size: usize) -> usize {
7 (size + 127 - 1) / 127
9}
10
11pub 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}