mqtt5_protocol/encoding/
mqtt_binary.rs1use crate::error::{MqttError, Result};
6use bebytes::BeBytes;
7use bytes::Bytes;
8
9#[derive(Debug, Clone, PartialEq, Eq, BeBytes)]
11pub struct MqttBinary {
12 length: u16,
14
15 #[bebytes(size = "length")]
17 data: Vec<u8>,
18}
19
20impl MqttBinary {
21 pub fn create(data: &[u8]) -> Result<Self> {
26 let len = data.len();
27 if len > u16::MAX as usize {
28 return Err(MqttError::MalformedPacket(format!(
29 "Binary data length {} exceeds maximum {}",
30 len,
31 u16::MAX
32 )));
33 }
34
35 Ok(Self {
36 #[allow(clippy::cast_possible_truncation)]
37 length: len as u16, data: data.to_vec(),
39 })
40 }
41
42 pub fn from_bytes(bytes: &Bytes) -> Result<Self> {
47 Self::create(bytes)
48 }
49
50 #[must_use]
52 pub fn as_slice(&self) -> &[u8] {
53 &self.data
54 }
55
56 #[must_use]
58 pub fn into_vec(self) -> Vec<u8> {
59 self.data
60 }
61
62 #[must_use]
64 pub fn into_bytes(self) -> Bytes {
65 Bytes::from(self.data)
66 }
67
68 #[must_use]
70 pub fn encoded_size(&self) -> usize {
71 2 + self.data.len()
72 }
73}
74
75impl TryFrom<&[u8]> for MqttBinary {
76 type Error = MqttError;
77
78 fn try_from(data: &[u8]) -> Result<Self> {
79 Self::create(data)
80 }
81}
82
83impl TryFrom<Vec<u8>> for MqttBinary {
84 type Error = MqttError;
85
86 fn try_from(data: Vec<u8>) -> Result<Self> {
87 Self::create(&data)
88 }
89}
90
91impl TryFrom<Bytes> for MqttBinary {
92 type Error = MqttError;
93
94 fn try_from(bytes: Bytes) -> Result<Self> {
95 Self::from_bytes(&bytes)
96 }
97}
98
99pub fn encode_binary<B: bytes::BufMut>(buf: &mut B, data: &[u8]) -> Result<()> {
108 let mqtt_binary = MqttBinary::create(data)?;
109 let encoded = mqtt_binary.to_be_bytes();
110 buf.put_slice(&encoded);
111 Ok(())
112}
113
114pub fn decode_binary<B: bytes::Buf>(buf: &mut B) -> Result<Bytes> {
123 if buf.remaining() < 2 {
124 return Err(MqttError::MalformedPacket(
125 "Insufficient bytes for binary data length".to_string(),
126 ));
127 }
128
129 let len = buf.get_u16() as usize;
130
131 if buf.remaining() < len {
132 return Err(MqttError::MalformedPacket(format!(
133 "Insufficient bytes for binary data: expected {}, got {}",
134 len,
135 buf.remaining()
136 )));
137 }
138
139 Ok(buf.copy_to_bytes(len))
140}
141
142pub fn encode_optional_binary<B: bytes::BufMut>(buf: &mut B, data: Option<&[u8]>) -> Result<()> {
150 if let Some(data) = data {
151 encode_binary(buf, data)?;
152 }
153 Ok(())
154}
155
156#[must_use]
158pub fn binary_len(data: &[u8]) -> usize {
159 2 + data.len()
160}
161
162#[must_use]
164pub fn optional_binary_len(data: Option<&[u8]>) -> usize {
165 data.map_or(0, binary_len)
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use bytes::BytesMut;
172
173 #[test]
174 fn test_mqtt_binary_encoding() {
175 let mqtt_bin = MqttBinary::create(&[0x01, 0x02, 0x03]).unwrap();
176 let bytes = mqtt_bin.to_be_bytes();
177
178 assert_eq!(bytes, vec![0x00, 0x03, 0x01, 0x02, 0x03]);
180 }
181
182 #[test]
183 fn test_mqtt_binary_decoding() {
184 let data = vec![0x00, 0x03, 0x01, 0x02, 0x03];
185 let (mqtt_bin, consumed) = MqttBinary::try_from_be_bytes(&data).unwrap();
186
187 assert_eq!(mqtt_bin.as_slice(), &[0x01, 0x02, 0x03]);
188 assert_eq!(consumed, 5);
189 }
190
191 #[test]
192 fn test_mqtt_binary_round_trip() {
193 let original = MqttBinary::create(&[0xFF, 0x00, 0xAB]).unwrap();
194 let bytes = original.to_be_bytes();
195 let (decoded, _) = MqttBinary::try_from_be_bytes(&bytes).unwrap();
196
197 assert_eq!(original, decoded);
198 }
199
200 #[test]
201 fn test_empty_binary() {
202 let mqtt_bin = MqttBinary::create(&[]).unwrap();
203 let bytes = mqtt_bin.to_be_bytes();
204
205 assert_eq!(bytes, vec![0x00, 0x00]);
206 }
207
208 #[test]
209 fn test_binary_too_long() {
210 let long_data = vec![0u8; 65536];
211 let result = MqttBinary::create(&long_data);
212
213 assert!(result.is_err());
214 }
215
216 #[test]
217 fn test_compatibility_functions() {
218 let mut buf = BytesMut::new();
219 let test_data = vec![0x01, 0x02, 0x03];
220
221 encode_binary(&mut buf, &test_data).unwrap();
223 let decoded = decode_binary(&mut buf).unwrap();
224
225 assert_eq!(&decoded[..], &test_data[..]);
226 }
227}