Skip to main content

proto_packet/io/wire/
decode.rs

1use crate::io::{DecodingError, WireType};
2use enc::DecodeFromReadPrefix;
3use enc::var_int::VarIntSize;
4use std::io::{Error, Read};
5
6macro_rules! decode_fixed {
7    ($name:ident, $size:expr, $wire:literal) => {
8        #[doc = concat!("Decodes a `", $wire, "` value from the `Read` prefix given the `first` byte.")]
9        pub fn $name<R>(r: &mut R, first: u8) -> Result<[u8; $size], Error>
10        where
11            R: Read,
12        {
13            let mut buffer: [u8; $size] = [0u8; $size];
14            buffer[0] = first;
15            r.read_exact(&mut buffer[1..])?;
16            Ok(buffer)
17        }
18    };
19}
20
21impl WireType {
22    //! Decode
23
24    decode_fixed!(decode_fixed_2_byte, 2, "Fixed2Byte");
25    decode_fixed!(decode_fixed_4_byte, 4, "Fixed4Byte");
26    decode_fixed!(decode_fixed_8_byte, 8, "Fixed8Byte");
27    decode_fixed!(decode_fixed_16_byte, 16, "Fixed16Byte");
28
29    /// Decodes a `LengthPrefixed` `[]u8` value from the `Read` prefix given the `first` byte.
30    pub fn decode_length_prefixed_bytes<R>(r: &mut R, first: u8) -> Result<Vec<u8>, DecodingError>
31    where
32        R: Read,
33    {
34        let prefix: usize = VarIntSize::decode_from_read_prefix_with_first_byte(r, first)
35            .map_err(DecodingError::from_length_prefix_error)?
36            .value();
37        let mut result: Vec<u8> = Vec::with_capacity(prefix);
38        let read: usize = r.take(prefix as u64).read_to_end(&mut result)?;
39        if read != prefix {
40            return Err(std::io::Error::new(
41                std::io::ErrorKind::UnexpectedEof,
42                "short read for length-prefixed bytes",
43            )
44            .into());
45        }
46        Ok(result)
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use crate::io::WireType;
53    use std::io::{Cursor, Error};
54
55    #[test]
56    fn decode_fixed_2_byte() -> Result<(), Error> {
57        let mut source: Cursor<Vec<u8>> = Cursor::new(vec![1, 2]);
58
59        let result: [u8; 2] = WireType::decode_fixed_2_byte(&mut source, 0)?;
60        assert_eq!(result, [0, 1]);
61
62        Ok(())
63    }
64
65    #[test]
66    fn decode_fixed_4_byte() -> Result<(), Error> {
67        let mut source: Cursor<Vec<u8>> = Cursor::new(vec![1, 2, 3, 4]);
68
69        let result: [u8; 4] = WireType::decode_fixed_4_byte(&mut source, 0)?;
70        assert_eq!(result, [0, 1, 2, 3]);
71
72        Ok(())
73    }
74
75    #[test]
76    fn decode_fixed_8_byte() -> Result<(), Error> {
77        let mut source: Cursor<Vec<u8>> = Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8]);
78
79        let result: [u8; 8] = WireType::decode_fixed_8_byte(&mut source, 0)?;
80        assert_eq!(result, [0, 1, 2, 3, 4, 5, 6, 7]);
81
82        Ok(())
83    }
84
85    #[test]
86    fn decode_fixed_16_byte() -> Result<(), Error> {
87        let mut source: Cursor<Vec<u8>> =
88            Cursor::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
89
90        let result: [u8; 16] = WireType::decode_fixed_16_byte(&mut source, 0)?;
91        assert_eq!(
92            result,
93            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
94        );
95
96        Ok(())
97    }
98
99    #[test]
100    #[allow(clippy::type_complexity)]
101    fn decode_length_prefixed_bytes() {
102        // 200-byte body with multi-byte varint prefix. After consuming first=0xC8, the
103        // continuation byte 0x01 still in `rest` completes the varint to 200, then 200 body bytes.
104        let mut large_rest: Vec<u8> = vec![0x01];
105        large_rest.extend(std::iter::repeat_n(0xAB, 200));
106        let large_expected: Vec<u8> = vec![0xAB; 200];
107
108        // Each case: (first_byte, rest_bytes, Some(expected) for Ok, None for Err).
109        let cases: &[(u8, &[u8], Option<&[u8]>)] = &[
110            // Empty body: first=0 = varint(0), no body bytes.
111            (0, &[], Some(&[])),
112            // Small body: first=3 = varint(3), then 3 body bytes.
113            (3, &[1, 2, 3], Some(&[1, 2, 3])),
114            // Body with extra bytes — only consumes the declared 3.
115            (3, &[1, 2, 3, 99], Some(&[1, 2, 3])),
116            // Multi-byte varint prefix: first=0xC8 (continuation), rest starts with 0x01 to
117            // complete varint(200), then 200 body bytes.
118            (0xC8, large_rest.as_slice(), Some(large_expected.as_slice())),
119            // Body shorter than declared length — should error with EOF.
120            (5, &[1, 2, 3], None),
121        ];
122
123        for (first, rest, expected) in cases {
124            let mut source: Cursor<&[u8]> = Cursor::new(*rest);
125            let result = WireType::decode_length_prefixed_bytes(&mut source, *first);
126            match (result, expected) {
127                (Ok(bytes), Some(exp)) => {
128                    assert_eq!(
129                        bytes.as_slice(),
130                        *exp,
131                        "first={first:#x} rest_len={}",
132                        rest.len()
133                    );
134                }
135                (Err(_), None) => {}
136                (Ok(bytes), None) => panic!(
137                    "first={first:#x} rest_len={}: expected error, got Ok({} bytes)",
138                    rest.len(),
139                    bytes.len()
140                ),
141                (Err(e), Some(_)) => panic!(
142                    "first={first:#x} rest_len={}: expected Ok, got error: {e:?}",
143                    rest.len()
144                ),
145            }
146        }
147    }
148}