delimited_protobuf/
lib.rs

1use protobuf::Message;
2use simple_error::SimpleError;
3
4/// Read one length-delimited message from the given stream.
5pub fn read<MSG: Message>(reader: &mut dyn std::io::Read) -> Result<MSG, SimpleError> {
6    let size = read_u32(reader).map_err(SimpleError::from)?;
7    if size == 0_u32 {
8        return Err(SimpleError::new("empty message"));
9    }
10    let mut buf = vec![0_u8; size as usize];
11    reader.read_exact(&mut buf).unwrap();
12
13    MSG::parse_from_bytes(&buf).map_err(SimpleError::from)
14}
15
16/// Write one length-delimited message to the given stream.
17pub fn write<MSG: Message>(msg: &MSG, writer: &mut dyn std::io::Write) -> protobuf::Result<()> {
18    msg.write_length_delimited_to_writer(writer)
19}
20
21// forked from https://github.com/amandasaurus/vartyint/blob/main/src/lib.rs#L94
22fn read_u32(reader: &mut dyn std::io::Read) -> Result<u32, SimpleError> {
23    let mut buf = [0_u8; 1];
24    let mut num_bits_read = 0;
25    let mut val: u32 = 0;
26    let mut is_last: bool;
27    let mut byte: u32;
28
29    loop {
30        reader.read_exact(&mut buf).map_err(SimpleError::from)?;
31        byte = buf[0] as u32;
32
33        is_last = byte >> 7 == 0;
34        byte &= 0b0111_1111;
35
36        byte = match byte.checked_shl(num_bits_read) {
37            None => {
38                return Err(SimpleError::new("too many bytes for u32"));
39            }
40            Some(v) => v,
41        };
42        val |= byte;
43        num_bits_read += 7;
44        if is_last {
45            // last byte
46            break;
47        }
48    }
49
50    Ok(val)
51}