mqtt5_protocol/encoding/
binary.rs

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