mqtt5_protocol/encoding/
binary.rs

1use crate::error::{MqttError, Result};
2use bytes::{Buf, BufMut, Bytes};
3
4/// Encodes binary data with a 2-byte length prefix
5///
6/// # MQTT Binary Format:
7/// - 2 bytes: data length (big-endian)
8/// - N bytes: binary data
9///
10/// # Errors
11///
12/// Returns an error if the data length exceeds maximum string length
13pub fn encode_binary<B: BufMut>(buf: &mut B, data: &[u8]) -> Result<()> {
14    if data.len() > crate::constants::limits::MAX_STRING_LENGTH as usize {
15        return Err(MqttError::MalformedPacket(format!(
16            "Binary data length {} exceeds maximum {}",
17            data.len(),
18            crate::constants::limits::MAX_STRING_LENGTH
19        )));
20    }
21
22    // Write length as 2-byte big-endian
23    // Safe cast: length was already validated to be <= u16::MAX
24    #[allow(clippy::cast_possible_truncation)]
25    buf.put_u16(data.len() as u16);
26    // Write binary data
27    buf.put_slice(data);
28
29    Ok(())
30}
31
32/// Decodes binary data with a 2-byte length prefix
33///
34/// # Errors
35///
36/// Returns an error if there are insufficient bytes in the buffer
37pub fn decode_binary<B: Buf>(buf: &mut B) -> Result<Bytes> {
38    if buf.remaining() < 2 {
39        return Err(MqttError::MalformedPacket(
40            "Insufficient bytes for binary data length".to_string(),
41        ));
42    }
43
44    let len = buf.get_u16() as usize;
45
46    if buf.remaining() < len {
47        return Err(MqttError::MalformedPacket(format!(
48            "Insufficient bytes for binary data: expected {}, got {}",
49            len,
50            buf.remaining()
51        )));
52    }
53
54    Ok(buf.copy_to_bytes(len))
55}
56
57/// Encodes optional binary data
58///
59/// If data is None, nothing is written to the buffer
60///
61/// # Errors
62///
63/// Returns an error if the data length exceeds maximum string length
64pub fn encode_optional_binary<B: BufMut>(buf: &mut B, data: Option<&[u8]>) -> Result<()> {
65    if let Some(data) = data {
66        encode_binary(buf, data)?;
67    }
68    Ok(())
69}
70
71/// Calculates the encoded length of binary data (2 bytes for length + data bytes)
72#[must_use]
73pub fn binary_len(data: &[u8]) -> usize {
74    2 + data.len()
75}
76
77/// Calculates the encoded length of optional binary data
78#[must_use]
79pub fn optional_binary_len(data: Option<&[u8]>) -> usize {
80    data.map_or(0, binary_len)
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use bytes::BytesMut;
87
88    #[test]
89    fn test_encode_decode_binary() {
90        let mut buf = BytesMut::new();
91
92        // Test various binary data
93        let test_data = [
94            vec![],
95            vec![0x00],
96            vec![0x01, 0x02, 0x03],
97            vec![0xFF; 100],
98            (0..=255).collect::<Vec<u8>>(),
99        ];
100
101        for data in &test_data {
102            buf.clear();
103            encode_binary(&mut buf, data).unwrap();
104
105            let decoded = decode_binary(&mut buf).unwrap();
106            assert_eq!(&decoded[..], data.as_slice());
107        }
108    }
109
110    #[test]
111    fn test_encode_binary_too_long() {
112        let mut buf = BytesMut::new();
113        let data = vec![0u8; crate::constants::limits::MAX_BINARY_LENGTH as usize];
114        let result = encode_binary(&mut buf, &data);
115        assert!(result.is_err());
116    }
117
118    #[test]
119    fn test_decode_insufficient_length_bytes() {
120        let mut buf = BytesMut::new();
121        buf.put_u8(0); // Only 1 byte instead of 2
122
123        let result = decode_binary(&mut buf);
124        assert!(result.is_err());
125    }
126
127    #[test]
128    fn test_decode_insufficient_data_bytes() {
129        let mut buf = BytesMut::new();
130        buf.put_u16(10); // Claims 10 bytes
131        buf.put_slice(&[1, 2, 3, 4, 5]); // Only 5 bytes
132
133        let result = decode_binary(&mut buf);
134        assert!(result.is_err());
135    }
136
137    #[test]
138    fn test_encode_optional_binary() {
139        let mut buf = BytesMut::new();
140
141        // Test None - nothing should be written
142        encode_optional_binary(&mut buf, None).unwrap();
143        assert_eq!(buf.len(), 0);
144
145        // Test Some
146        buf.clear();
147        encode_optional_binary(&mut buf, Some(&[1, 2, 3])).unwrap();
148        assert_eq!(buf.len(), 5); // 2 bytes length + 3 bytes data
149    }
150
151    #[test]
152    fn test_binary_len() {
153        assert_eq!(binary_len(&[]), 2);
154        assert_eq!(binary_len(&[1, 2, 3]), 5);
155        assert_eq!(binary_len(&[0u8; 100]), 102);
156    }
157
158    #[test]
159    fn test_optional_binary_len() {
160        assert_eq!(optional_binary_len(None), 0);
161        assert_eq!(optional_binary_len(Some(&[])), 2);
162        assert_eq!(optional_binary_len(Some(&[1, 2, 3])), 5);
163    }
164
165    #[test]
166    fn test_empty_binary() {
167        let mut buf = BytesMut::new();
168        encode_binary(&mut buf, &[]).unwrap();
169
170        assert_eq!(buf.len(), 2);
171        assert_eq!(buf[0], 0);
172        assert_eq!(buf[1], 0);
173
174        let decoded = decode_binary(&mut buf).unwrap();
175        assert_eq!(decoded.len(), 0);
176    }
177}