1use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
26use crate::utils::buffer_reader::BuffReader;
27use crate::utils::buffer_writer::BuffWriter;
28use crate::utils::types::{BinaryData, BufferError, EncodedString, StringPair};
29
30#[derive(Debug, Clone)]
31pub enum Property<'a> {
32 PayloadFormat(u8),
33 MessageExpiryInterval(u32),
34 ContentType(EncodedString<'a>),
35 ResponseTopic(EncodedString<'a>),
36 CorrelationData(BinaryData<'a>),
37 SubscriptionIdentifier(u32),
38 SessionExpiryInterval(u32),
39 AssignedClientIdentifier(EncodedString<'a>),
40 ServerKeepAlive(u16),
41 AuthenticationMethod(EncodedString<'a>),
42 AuthenticationData(BinaryData<'a>),
43 RequestProblemInformation(u8),
44 WillDelayInterval(u32),
45 RequestResponseInformation(u8),
46 ResponseInformation(EncodedString<'a>),
47 ServerReference(EncodedString<'a>),
48 ReasonString(EncodedString<'a>),
49 ReceiveMaximum(u16),
50 TopicAliasMaximum(u16),
51 TopicAlias(u16),
52 MaximumQoS(u8),
53 RetainAvailable(u8),
54 UserProperty(StringPair<'a>),
55 MaximumPacketSize(u32),
56 WildcardSubscriptionAvailable(u8),
57 SubscriptionIdentifierAvailable(u8),
58 SharedSubscriptionAvailable(u8),
59 Reserved(),
60}
61
62impl<'a> Property<'a> {
63 pub fn connect_property(&self) -> bool {
64 #[allow(clippy::match_like_matches_macro)]
66 match self {
67 Property::SessionExpiryInterval(_u) => true,
68 Property::ReceiveMaximum(_u) => true,
69 Property::MaximumPacketSize(_u) => true,
70 Property::TopicAliasMaximum(_u) => true,
71 Property::RequestResponseInformation(_u) => true,
72 Property::RequestProblemInformation(_u) => true,
73 Property::UserProperty(_u) => true,
74 Property::AuthenticationMethod(_u) => true,
75 Property::AuthenticationData(_u) => true,
76 _ => false,
77 }
78 }
79
80 pub fn connack_property(&self) -> bool {
81 #[allow(clippy::match_like_matches_macro)]
83 match self {
84 Property::SessionExpiryInterval(_u) => true,
85 Property::ReceiveMaximum(_u) => true,
86 Property::MaximumQoS(_u) => true,
87 Property::MaximumPacketSize(_u) => true,
88 Property::AssignedClientIdentifier(_u) => true,
89 Property::TopicAliasMaximum(_u) => true,
90 Property::ReasonString(_u) => true,
91 Property::UserProperty(_u) => true,
92 Property::WildcardSubscriptionAvailable(_u) => true,
93 Property::SubscriptionIdentifierAvailable(_u) => true,
94 Property::SharedSubscriptionAvailable(_u) => true,
95 Property::ServerKeepAlive(_u) => true,
96 Property::ResponseInformation(_u) => true,
97 Property::ServerReference(_u) => true,
98 Property::AuthenticationMethod(_u) => true,
99 Property::AuthenticationData(_u) => true,
100 _ => false,
101 }
102 }
103
104 pub fn publish_property(&self) -> bool {
105 #[allow(clippy::match_like_matches_macro)]
107 match self {
108 Property::PayloadFormat(_u) => true,
109 Property::MessageExpiryInterval(_u) => true,
110 Property::TopicAlias(_u) => true,
111 Property::ResponseTopic(_u) => true,
112 Property::CorrelationData(_u) => true,
113 Property::UserProperty(_u) => true,
114 Property::SubscriptionIdentifier(_u) => true,
115 Property::ContentType(_u) => true,
116 _ => false,
117 }
118 }
119
120 pub fn puback_property(&self) -> bool {
121 #[allow(clippy::match_like_matches_macro)]
123 match self {
124 Property::ReasonString(_u) => true,
125 Property::UserProperty(_u) => true,
126 _ => false,
127 }
128 }
129
130 pub fn pubrec_property(&self) -> bool {
131 #[allow(clippy::match_like_matches_macro)]
133 match self {
134 Property::ReasonString(_u) => true,
135 Property::UserProperty(_u) => true,
136 _ => false,
137 }
138 }
139
140 pub fn pubrel_property(&self) -> bool {
141 #[allow(clippy::match_like_matches_macro)]
143 match self {
144 Property::ReasonString(_u) => true,
145 Property::UserProperty(_u) => true,
146 _ => false,
147 }
148 }
149
150 pub fn pubcomp_property(&self) -> bool {
151 #[allow(clippy::match_like_matches_macro)]
153 match self {
154 Property::ReasonString(_u) => true,
155 Property::UserProperty(_u) => true,
156 _ => false,
157 }
158 }
159
160 pub fn subscribe_property(&self) -> bool {
161 #[allow(clippy::match_like_matches_macro)]
163 match self {
164 Property::SubscriptionIdentifier(_u) => true,
165 Property::UserProperty(_u) => true,
166 _ => false,
167 }
168 }
169
170 pub fn suback_property(&self) -> bool {
171 #[allow(clippy::match_like_matches_macro)]
173 match self {
174 Property::ReasonString(_u) => true,
175 Property::UserProperty(_u) => true,
176 _ => false,
177 }
178 }
179
180 pub fn unsubscribe_property(&self) -> bool {
181 matches!(self, Property::UserProperty(_u))
182 }
183
184 pub fn unsuback_property(&self) -> bool {
185 #[allow(clippy::match_like_matches_macro)]
187 match self {
188 Property::ReasonString(_u) => true,
189 Property::UserProperty(_u) => true,
190 _ => false,
191 }
192 }
193
194 pub fn pingreq_property(&self) -> bool {
195 warn!("pingreq property list is incomplete");
196 false
197 }
198
199 pub fn pingresp_property(&self) -> bool {
200 warn!("pingresp property list is incomplete");
201 false
202 }
203
204 pub fn disconnect_property(&self) -> bool {
205 #[allow(clippy::match_like_matches_macro)]
207 match self {
208 Property::SessionExpiryInterval(_u) => true,
209 Property::ReasonString(_u) => true,
210 Property::UserProperty(_u) => true,
211 Property::ServerReference(_u) => true,
212 _ => false,
213 }
214 }
215
216 pub fn auth_property(&self) -> bool {
217 #[allow(clippy::match_like_matches_macro)]
219 match self {
220 Property::AuthenticationMethod(_u) => true,
221 Property::AuthenticationData(_u) => true,
222 Property::ReasonString(_u) => true,
223 Property::UserProperty(_u) => true,
224 _ => false,
225 }
226 }
227
228 pub fn encoded_len(&self) -> u16 {
229 match self {
230 Property::PayloadFormat(_u) => 1,
231 Property::MessageExpiryInterval(_u) => 4,
232 Property::ContentType(u) => u.encoded_len(),
233 Property::ResponseTopic(u) => u.encoded_len(),
234 Property::CorrelationData(u) => u.encoded_len(),
235 Property::SubscriptionIdentifier(u) => {
236 VariableByteIntegerEncoder::len(VariableByteIntegerEncoder::encode(*u).unwrap())
237 as u16
238 }
239 Property::SessionExpiryInterval(_u) => 4,
240 Property::AssignedClientIdentifier(u) => u.encoded_len(),
241 Property::ServerKeepAlive(_u) => 2,
242 Property::AuthenticationMethod(u) => u.encoded_len(),
243 Property::AuthenticationData(u) => u.encoded_len(),
244 Property::RequestProblemInformation(_u) => 1,
245 Property::WillDelayInterval(_u) => 4,
246 Property::RequestResponseInformation(_u) => 1,
247 Property::ResponseInformation(u) => u.encoded_len(),
248 Property::ServerReference(u) => u.encoded_len(),
249 Property::ReasonString(u) => u.encoded_len(),
250 Property::ReceiveMaximum(_u) => 2,
251 Property::TopicAliasMaximum(_u) => 2,
252 Property::TopicAlias(_u) => 2,
253 Property::MaximumQoS(_u) => 1,
254 Property::RetainAvailable(_u) => 1,
255 Property::UserProperty(u) => u.encoded_len(),
256 Property::MaximumPacketSize(_u) => 4,
257 Property::WildcardSubscriptionAvailable(_u) => 1,
258 Property::SubscriptionIdentifierAvailable(_u) => 1,
259 Property::SharedSubscriptionAvailable(_u) => 1,
260 _ => 0,
261 }
262 }
263
264 pub fn encode(&self, buff_writer: &mut BuffWriter<'a>) -> Result<(), BufferError> {
265 match self {
266 Property::PayloadFormat(u) => buff_writer.write_u8(*u),
267 Property::MessageExpiryInterval(u) => buff_writer.write_u32(*u),
268 Property::ContentType(u) => buff_writer.write_string_ref(u),
269 Property::ResponseTopic(u) => buff_writer.write_string_ref(u),
270 Property::CorrelationData(u) => buff_writer.write_binary_ref(u),
271 Property::SubscriptionIdentifier(u) => buff_writer.write_variable_byte_int(*u),
272 Property::SessionExpiryInterval(u) => buff_writer.write_u32(*u),
273 Property::AssignedClientIdentifier(u) => buff_writer.write_string_ref(u),
274 Property::ServerKeepAlive(u) => buff_writer.write_u16(*u),
275 Property::AuthenticationMethod(u) => buff_writer.write_string_ref(u),
276 Property::AuthenticationData(u) => buff_writer.write_binary_ref(u),
277 Property::RequestProblemInformation(u) => buff_writer.write_u8(*u),
278 Property::WillDelayInterval(u) => buff_writer.write_u32(*u),
279 Property::RequestResponseInformation(u) => buff_writer.write_u8(*u),
280 Property::ResponseInformation(u) => buff_writer.write_string_ref(u),
281 Property::ServerReference(u) => buff_writer.write_string_ref(u),
282 Property::ReasonString(u) => buff_writer.write_string_ref(u),
283 Property::ReceiveMaximum(u) => buff_writer.write_u16(*u),
284 Property::TopicAliasMaximum(u) => buff_writer.write_u16(*u),
285 Property::TopicAlias(u) => buff_writer.write_u16(*u),
286 Property::MaximumQoS(u) => buff_writer.write_u8(*u),
287 Property::RetainAvailable(u) => buff_writer.write_u8(*u),
288 Property::UserProperty(u) => buff_writer.write_string_pair_ref(u),
289 Property::MaximumPacketSize(u) => buff_writer.write_u32(*u),
290 Property::WildcardSubscriptionAvailable(u) => buff_writer.write_u8(*u),
291 Property::SubscriptionIdentifierAvailable(u) => buff_writer.write_u8(*u),
292 Property::SharedSubscriptionAvailable(u) => buff_writer.write_u8(*u),
293 _ => Err(BufferError::PropertyNotFound),
294 }
295 }
296
297 pub fn decode(buff_reader: &mut BuffReader<'a>) -> Result<Property<'a>, BufferError> {
298 let property_identifier = buff_reader.read_u8();
299 return match property_identifier {
300 Ok(0x01) => Ok(Property::PayloadFormat(buff_reader.read_u8()?)),
301 Ok(0x02) => Ok(Property::MessageExpiryInterval(buff_reader.read_u32()?)),
302 Ok(0x03) => Ok(Property::ContentType(buff_reader.read_string()?)),
303 Ok(0x08) => Ok(Property::ResponseTopic(buff_reader.read_string()?)),
304 Ok(0x09) => Ok(Property::CorrelationData(buff_reader.read_binary()?)),
305 Ok(0x0B) => Ok(Property::SubscriptionIdentifier(
306 buff_reader.read_variable_byte_int()?,
307 )),
308 Ok(0x11) => Ok(Property::SessionExpiryInterval(buff_reader.read_u32()?)),
309 Ok(0x12) => Ok(Property::AssignedClientIdentifier(
310 buff_reader.read_string()?,
311 )),
312 Ok(0x13) => Ok(Property::ServerKeepAlive(buff_reader.read_u16()?)),
313 Ok(0x15) => Ok(Property::AuthenticationMethod(buff_reader.read_string()?)),
314 Ok(0x16) => Ok(Property::AuthenticationData(buff_reader.read_binary()?)),
315 Ok(0x17) => Ok(Property::RequestProblemInformation(buff_reader.read_u8()?)),
316 Ok(0x18) => Ok(Property::WillDelayInterval(buff_reader.read_u32()?)),
317 Ok(0x19) => Ok(Property::RequestResponseInformation(buff_reader.read_u8()?)),
318 Ok(0x1A) => Ok(Property::ResponseInformation(buff_reader.read_string()?)),
319 Ok(0x1C) => Ok(Property::ServerReference(buff_reader.read_string()?)),
320 Ok(0x1F) => Ok(Property::ReasonString(buff_reader.read_string()?)),
321 Ok(0x21) => Ok(Property::ReceiveMaximum(buff_reader.read_u16()?)),
322 Ok(0x22) => Ok(Property::TopicAliasMaximum(buff_reader.read_u16()?)),
323 Ok(0x23) => Ok(Property::TopicAlias(buff_reader.read_u16()?)),
324 Ok(0x24) => Ok(Property::MaximumQoS(buff_reader.read_u8()?)),
325 Ok(0x25) => Ok(Property::RetainAvailable(buff_reader.read_u8()?)),
326 Ok(0x26) => Ok(Property::UserProperty(buff_reader.read_string_pair()?)),
327 Ok(0x27) => Ok(Property::MaximumPacketSize(buff_reader.read_u32()?)),
328 Ok(0x28) => Ok(Property::WildcardSubscriptionAvailable(
329 buff_reader.read_u8()?,
330 )),
331 Ok(0x29) => Ok(Property::SubscriptionIdentifierAvailable(
332 buff_reader.read_u8()?,
333 )),
334 Ok(0x2A) => Ok(Property::SharedSubscriptionAvailable(
335 buff_reader.read_u8()?,
336 )),
337 Err(err) => Err(err),
338 _ => Err(BufferError::IdNotFound),
339 };
340 }
341}
342
343impl<'a> From<&Property<'a>> for u8 {
344 fn from(value: &Property<'a>) -> Self {
345 match value {
346 Property::PayloadFormat(_u) => 0x01,
347 Property::MessageExpiryInterval(_u) => 0x02,
348 Property::ContentType(_u) => 0x03,
349 Property::ResponseTopic(_u) => 0x08,
350 Property::CorrelationData(_u) => 0x09,
351 Property::SubscriptionIdentifier(_u) => 0x0B,
352 Property::SessionExpiryInterval(_u) => 0x11,
353 Property::AssignedClientIdentifier(_u) => 0x12,
354 Property::ServerKeepAlive(_u) => 0x13,
355 Property::AuthenticationMethod(_u) => 0x15,
356 Property::AuthenticationData(_u) => 0x16,
357 Property::RequestProblemInformation(_u) => 0x17,
358 Property::WillDelayInterval(_u) => 0x18,
359 Property::RequestResponseInformation(_u) => 0x19,
360 Property::ResponseInformation(_u) => 0x1A,
361 Property::ServerReference(_u) => 0x1C,
362 Property::ReasonString(_u) => 0x1F,
363 Property::ReceiveMaximum(_u) => 0x21,
364 Property::TopicAliasMaximum(_u) => 0x22,
365 Property::TopicAlias(_u) => 0x23,
366 Property::MaximumQoS(_u) => 0x24,
367 Property::RetainAvailable(_u) => 0x25,
368 Property::UserProperty(_u) => 0x26,
369 Property::MaximumPacketSize(_u) => 0x27,
370 Property::WildcardSubscriptionAvailable(_u) => 0x28,
371 Property::SubscriptionIdentifierAvailable(_u) => 0x29,
372 Property::SharedSubscriptionAvailable(_u) => 0x2A,
373 _ => 0x00,
374 }
375 }
376}
377
378impl<'a> From<u8> for Property<'a> {
379 fn from(_orig: u8) -> Self {
380 warn!("Deserialization of Properties from u8 is not implemented");
381 Property::Reserved()
382 }
383}