1use crate::data::string_pair::StringPair;
2
3use crate::codec::{
4 mqtt_reader::{self, MqttReader},
5 mqtt_writer::{self, MqttWriter},
6 read::Read,
7 write::Write,
8};
9
10use core::marker::PhantomData;
11pub trait Property<'a, T> {
12 const IDENTIFIER: u32;
13 fn value(&self) -> T;
14}
15
16#[macro_export]
17macro_rules! property_owned {
18 ( $n:ident, $t:ty, $c:literal ) => {
19 #[derive(Debug, PartialEq)]
20 pub struct $n<'a> {
21 value: $t,
22 phantom: PhantomData<&'a $t>,
23 }
24
25 impl<'a> $n<'a> {
26 pub fn new(value: $t) -> Self {
27 Self {
28 value,
29 phantom: PhantomData,
30 }
31 }
32 }
33
34 impl Write for $n<'_> {
35 fn write<'a, W: MqttWriter<'a> + ?Sized>(
36 &self,
37 writer: &mut W,
38 ) -> mqtt_writer::Result<()> {
39 self.value.write(writer)
40 }
41 }
42
43 impl<'a> Read<'a> for $n<'_> {
44 fn read<R: MqttReader<'a>>(reader: &mut R) -> mqtt_reader::Result<Self>
45 where
46 Self: Sized,
47 {
48 let value = <$t as Read>::read(reader)?;
49 Ok(Self::new(value))
50 }
51 }
52
53 impl<'a> Property<'a, $t> for $n<'a> {
54 const IDENTIFIER: u32 = $c;
55 fn value(&self) -> $t {
56 self.value
57 }
58 }
59
60 impl From<$t> for $n<'_> {
61 fn from(value: $t) -> Self {
62 Self::new(value)
63 }
64 }
65 };
66}
67
68#[macro_export]
69macro_rules! property_variable_u32 {
70 ( $n:ident, $c:literal ) => {
71 #[derive(Debug, PartialEq)]
72 pub struct $n<'a> {
73 value: u32,
74 phantom: PhantomData<&'a u32>,
75 }
76
77 impl<'a> $n<'a> {
78 pub fn new(value: u32) -> Self {
79 Self {
80 value,
81 phantom: PhantomData,
82 }
83 }
84 }
85
86 impl Write for $n<'_> {
87 fn write<'a, W: MqttWriter<'a> + ?Sized>(
88 &self,
89 writer: &mut W,
90 ) -> mqtt_writer::Result<()> {
91 writer.put_variable_u32(self.value)
92 }
93 }
94
95 impl<'a> Read<'a> for $n<'_> {
96 fn read<R: MqttReader<'a>>(reader: &mut R) -> mqtt_reader::Result<Self>
97 where
98 Self: Sized,
99 {
100 let value = reader.get_variable_u32()?;
101 Ok(Self::new(value))
102 }
103 }
104
105 impl<'a> Property<'a, u32> for $n<'a> {
106 const IDENTIFIER: u32 = $c;
107 fn value(&self) -> u32 {
108 self.value
109 }
110 }
111
112 impl From<u32> for $n<'_> {
113 fn from(value: u32) -> Self {
114 Self::new(value)
115 }
116 }
117 };
118}
119
120#[macro_export]
121macro_rules! property_str {
122 ( $n:ident, $c:literal ) => {
123 #[derive(Debug, PartialEq)]
124 pub struct $n<'a> {
125 value: &'a str,
126 }
127
128 impl<'a> $n<'a> {
129 pub fn new(value: &'a str) -> Self {
130 Self { value }
131 }
132 }
133
134 impl Write for $n<'_> {
135 fn write<'a, W: MqttWriter<'a>>(&self, writer: &mut W) -> mqtt_writer::Result<()> {
136 writer.put_str(self.value)
137 }
138 }
139
140 impl<'a> Read<'a> for $n<'a> {
141 fn read<R: MqttReader<'a>>(reader: &mut R) -> mqtt_reader::Result<Self>
142 where
143 Self: Sized,
144 {
145 let value = reader.get_str()?;
146 Ok(Self::new(value))
147 }
148 }
149
150 impl<'a> Property<'a, &'a str> for $n<'a> {
151 const IDENTIFIER: u32 = $c;
152 fn value(&self) -> &'a str {
153 self.value
154 }
155 }
156
157 impl<'a> From<&'a str> for $n<'a> {
158 fn from(value: &'a str) -> Self {
159 Self::new(value)
160 }
161 }
162 };
163}
164
165#[macro_export]
166macro_rules! property_string_pair {
167 ( $n:ident, $c:literal ) => {
168 #[derive(Debug, PartialEq)]
169 pub struct $n<'a> {
170 value: StringPair<'a>,
171 }
172
173 impl<'a> $n<'a> {
174 pub fn new(value: StringPair<'a>) -> Self {
175 Self { value }
176 }
177 }
178
179 impl Write for $n<'_> {
180 fn write<'a, W: MqttWriter<'a>>(&self, writer: &mut W) -> mqtt_writer::Result<()> {
181 writer.put_string_pair(&self.value)
182 }
183 }
184
185 impl<'a> Read<'a> for $n<'a> {
186 fn read<R: MqttReader<'a>>(reader: &mut R) -> mqtt_reader::Result<Self>
187 where
188 Self: Sized,
189 {
190 let value = reader.get_string_pair()?;
191 Ok(Self::new(value))
192 }
193 }
194
195 impl<'a> Property<'a, StringPair<'a>> for $n<'a> {
196 const IDENTIFIER: u32 = $c;
197 fn value(&self) -> StringPair<'a> {
198 self.value
199 }
200 }
201
202 impl<'a> From<StringPair<'a>> for $n<'a> {
203 fn from(value: StringPair<'a>) -> Self {
204 Self::new(value)
205 }
206 }
207 };
208}
209
210#[macro_export]
211macro_rules! property_binary_data {
212 ( $n:ident, $c:literal ) => {
213 #[derive(Debug, PartialEq)]
214 pub struct $n<'a> {
215 value: &'a [u8],
216 }
217
218 impl<'a> $n<'a> {
219 pub fn new(value: &'a [u8]) -> Self {
220 Self { value }
221 }
222 }
223
224 impl Write for $n<'_> {
225 fn write<'a, W: MqttWriter<'a>>(&self, writer: &mut W) -> mqtt_writer::Result<()> {
226 writer.put_binary_data(self.value)
227 }
228 }
229
230 impl<'a> Read<'a> for $n<'a> {
231 fn read<R: MqttReader<'a>>(reader: &mut R) -> mqtt_reader::Result<Self>
232 where
233 Self: Sized,
234 {
235 let value = reader.get_binary_data()?;
236 Ok(Self::new(value))
237 }
238 }
239
240 impl<'a> Property<'a, &'a [u8]> for $n<'a> {
241 const IDENTIFIER: u32 = $c;
242 fn value(&self) -> &'a [u8] {
243 self.value
244 }
245 }
246
247 impl<'a> From<&'a [u8]> for $n<'a> {
248 fn from(value: &'a [u8]) -> Self {
249 Self::new(value)
250 }
251 }
252 };
253}
254
255#[macro_export]
256macro_rules! packet_properties {
257 ( $n:ident, [ $( $p:ident ),+ ] ) => {
258
259 #[derive(Debug, PartialEq)]
260 pub enum $n<'a>{
261 $(
262 $p($p<'a>),
263 )*
264 }
265
266 impl Write for $n<'_> {
267 fn write<'a, W: MqttWriter<'a>>(&self, writer: &mut W) -> mqtt_writer::Result<()> {
268 match self {
269 $(
270 Self::$p(v) => {
271 writer.put_variable_u32($p::IDENTIFIER)?;
272 v.write(writer)?;
273 Ok(())
274 }
275 )*
276 }
277 }
278 }
279
280 impl<'a> Read<'a> for $n<'a> {
281 fn read<R: MqttReader<'a>>(reader: &mut R) -> mqtt_reader::Result<Self>
282 where
283 Self: Sized,
284 {
285 let id = reader.get_variable_u32()?;
286 match id {
287 $(
288 $p::IDENTIFIER => {
289 let v = $p::read(reader)?;
290 Ok(Self::$p(v))
291 }
292 )*
293 _ => Err($crate::error::PacketReadError::UnexpectedPropertyIdentifier),
294 }
295 }
296 }
297 };
298}
299
300property_owned!(PayloadFormatIndicator, u8, 0x01);
302property_owned!(MessageExpiryInterval, u32, 0x02);
303property_str!(ContentType, 0x03);
304property_str!(ResponseTopic, 0x08);
305property_binary_data!(CorrelationData, 0x09);
306property_variable_u32!(SubscriptionIdentifier, 0x0B);
307property_owned!(SessionExpiryInterval, u32, 0x11);
308property_str!(AssignedClientIdentifier, 0x12);
309property_owned!(ServerKeepAlive, u16, 0x13);
310property_str!(AuthenticationMethod, 0x15);
311property_binary_data!(AuthenticationData, 0x16);
312property_owned!(RequestProblemInformation, u8, 0x17);
313property_owned!(WillDelayInterval, u32, 0x18);
314property_owned!(RequestResponseInformation, u8, 0x19);
315property_str!(ResponseInformation, 0x1A);
316property_str!(ServerReference, 0x1C);
317property_str!(ReasonString, 0x1F);
318property_owned!(ReceiveMaximum, u16, 0x21);
319property_owned!(TopicAliasMaximum, u16, 0x22);
320property_owned!(TopicAlias, u16, 0x23);
321property_owned!(MaximumQos, u8, 0x24);
322property_owned!(RetainAvailable, u8, 0x25);
323property_string_pair!(UserProperty, 0x26);
324property_owned!(MaximumPacketSize, u32, 0x27);
325property_owned!(WildcardSubscriptionAvailable, u8, 0x28);
326property_owned!(SubscriptionIdentifierAvailable, u8, 0x29);
327property_owned!(SharedSubscriptionAvailable, u8, 0x2A);
328
329packet_properties!(
330 ConnectProperty,
331 [
332 SessionExpiryInterval,
333 AuthenticationMethod,
334 AuthenticationData,
335 RequestProblemInformation,
336 RequestResponseInformation,
337 ReceiveMaximum,
338 TopicAliasMaximum,
339 UserProperty,
340 MaximumPacketSize
341 ]
342);
343packet_properties!(
344 ConnackProperty,
345 [
346 SessionExpiryInterval,
347 AssignedClientIdentifier,
348 ServerKeepAlive,
349 AuthenticationMethod,
350 AuthenticationData,
351 ResponseInformation,
352 ServerReference,
353 ReasonString,
354 ReceiveMaximum,
355 TopicAliasMaximum,
356 MaximumQos,
357 RetainAvailable,
358 UserProperty,
359 MaximumPacketSize,
360 WildcardSubscriptionAvailable,
361 SubscriptionIdentifierAvailable,
362 SharedSubscriptionAvailable
363 ]
364);
365
366packet_properties!(
367 PublishProperty,
368 [
369 PayloadFormatIndicator,
370 MessageExpiryInterval,
371 ContentType,
372 ResponseTopic,
373 CorrelationData,
374 SubscriptionIdentifier,
375 TopicAlias,
376 UserProperty
377 ]
378);
379packet_properties!(PubackProperty, [ReasonString, UserProperty]);
380packet_properties!(PubrecProperty, [ReasonString, UserProperty]);
381packet_properties!(PubrelProperty, [ReasonString, UserProperty]);
382packet_properties!(PubcompProperty, [ReasonString, UserProperty]);
383
384packet_properties!(SubscribeProperty, [SubscriptionIdentifier, UserProperty]);
385packet_properties!(SubackProperty, [ReasonString, UserProperty]);
386
387packet_properties!(UnsubscribeProperty, [UserProperty]);
388packet_properties!(UnsubackProperty, [ReasonString, UserProperty]);
389
390packet_properties!(
391 DisconnectProperty,
392 [
393 SessionExpiryInterval,
394 ServerReference,
395 ReasonString,
396 UserProperty
397 ]
398);
399
400packet_properties!(
401 AuthProperty,
402 [
403 AuthenticationMethod,
404 AuthenticationData,
405 ReasonString,
406 UserProperty
407 ]
408);
409
410packet_properties!(
411 WillProperty,
412 [
413 PayloadFormatIndicator,
414 MessageExpiryInterval,
415 ContentType,
416 ResponseTopic,
417 CorrelationData,
418 WillDelayInterval,
419 UserProperty
420 ]
421);
422
423#[cfg(test)]
424mod tests {
425 use heapless::Vec;
426
427 use crate::{
428 codec::{mqtt_reader::MqttBufReader, mqtt_writer::MqttBufWriter},
429 error::PacketReadError,
430 };
431
432 use super::*;
433
434 property_owned!(PropertyU8, u8, 0x01);
435 property_owned!(PropertyU16, u16, 0x02);
436 property_owned!(PropertyU32, u32, 0x03);
437 property_variable_u32!(PropertyVariableU32, 0x04);
438 property_str!(PropertyString, 0x05);
439 property_string_pair!(PropertyStringPair, 0x06);
440 property_binary_data!(PropertyBinaryData, 0x07);
441
442 packet_properties!(
443 PacketAnyProperty,
444 [
445 PropertyU8,
446 PropertyU16,
447 PropertyU32,
448 PropertyVariableU32,
449 PropertyString,
450 PropertyStringPair,
451 PropertyBinaryData
452 ]
453 );
454
455 packet_properties!(
456 PacketFirstThreeProperty,
457 [PropertyU8, PropertyU16, PropertyU32]
458 );
459
460 #[test]
461 fn write_and_read_a_property_u8() {
462 let mut buf = [0xFFu8; 4];
463 let p = PropertyU8::new(42);
464 let position = {
465 let mut r = MqttBufWriter::new(&mut buf);
466
467 p.write(&mut r).unwrap();
468 r.position()
469 };
470 assert_eq!(buf[0..position], [42u8]);
471
472 let mut r = MqttBufReader::new(&buf);
473 let read_p = PropertyU8::read(&mut r).unwrap();
474 assert_eq!(read_p, p);
475 }
476
477 #[test]
478 fn write_and_read_a_packet_property_u8() {
479 let mut buf = [0xFFu8; 4];
480
481 let p = PacketAnyProperty::PropertyU8(PropertyU8::new(42));
482
483 let position = {
484 let mut r = MqttBufWriter::new(&mut buf);
485
486 p.write(&mut r).unwrap();
487 r.position()
488 };
489 assert_eq!(
490 buf[0..position],
491 [PropertyU8::IDENTIFIER as u8, 42u8]
493 );
494
495 let mut r = MqttBufReader::new(&buf);
496 let read_p = PacketAnyProperty::read(&mut r).unwrap();
497 assert_eq!(read_p, p);
498 }
499
500 #[test]
501 fn write_and_read_a_full_set_of_properties() {
502 let mut buf = [0xFFu8; 1024];
503 let data: &[u8] = &[1u8, 2, 3, 4, 5, 6];
504
505 let properties = [
506 PacketAnyProperty::PropertyU8(1.into()),
507 PacketAnyProperty::PropertyU16(2.into()),
508 PacketAnyProperty::PropertyU32(3.into()),
509 PacketAnyProperty::PropertyVariableU32(4.into()),
510 PacketAnyProperty::PropertyString("hello world".into()),
511 PacketAnyProperty::PropertyStringPair(StringPair::new("name", "value").into()),
512 PacketAnyProperty::PropertyBinaryData(data.into()),
513 ];
514
515 let position = {
516 let mut r = MqttBufWriter::new(&mut buf);
517
518 for p in properties.iter() {
519 p.write(&mut r).unwrap();
520 }
521 r.position()
522 };
523
524 let mut r = MqttBufReader::new(&buf[0..position]);
525 for p in properties.iter() {
526 let p_read = PacketAnyProperty::read(&mut r).unwrap();
527 assert_eq!(&p_read, p);
528 }
529 }
530
531 #[test]
532 fn write_and_read_a_variable_u32_delimited_vec_of_properties() {
533 let data: &[u8] = &[1u8, 2, 3, 4, 5, 6];
534
535 let mut vec: Vec<PacketAnyProperty<'_>, 16> = Vec::new();
536 vec.extend([
537 PacketAnyProperty::PropertyU8(1.into()),
538 PacketAnyProperty::PropertyU16(2.into()),
539 PacketAnyProperty::PropertyU32(3.into()),
540 PacketAnyProperty::PropertyVariableU32(4.into()),
541 PacketAnyProperty::PropertyString("hello world".into()),
542 PacketAnyProperty::PropertyStringPair(StringPair::new("name", "value").into()),
543 PacketAnyProperty::PropertyBinaryData(data.into()),
544 ]);
545
546 let mut buf = [0xFFu8; 1024];
547 let encoded_length = {
548 let mut r = MqttBufWriter::new(&mut buf);
549 r.put_variable_u32_delimited_vec(&vec).unwrap();
550 r.position()
551 };
552
553 assert_eq!(encoded_length, 50);
563
564 let mut r = MqttBufReader::new(&buf[0..encoded_length]);
567 let mut read_vec: Vec<PacketAnyProperty<'_>, 16> = Vec::new();
568 r.get_property_list(&mut read_vec).unwrap();
569
570 assert_eq!(0, r.remaining());
571 assert_eq!(read_vec, vec);
572
573 let mut r = MqttBufReader::new(&buf[0..encoded_length]);
575 let mut read_vec: Vec<PacketAnyProperty<'_>, 3> = Vec::new();
576 assert_eq!(
577 r.get_property_list(&mut read_vec),
578 Err(PacketReadError::TooManyProperties)
579 );
580 }
581
582 #[test]
583 fn write_and_read_expected_subset_of_properties_for_packet() {
584 let mut buf = [0xFFu8; 1024];
585
586 let properties = [
589 PacketAnyProperty::PropertyU8(1.into()),
590 PacketAnyProperty::PropertyU16(2.into()),
591 PacketAnyProperty::PropertyU32(3.into()),
592 ];
593
594 let expected_properties = [
595 PacketFirstThreeProperty::PropertyU8(1.into()),
596 PacketFirstThreeProperty::PropertyU16(2.into()),
597 PacketFirstThreeProperty::PropertyU32(3.into()),
598 ];
599
600 let position = {
602 let mut r = MqttBufWriter::new(&mut buf);
603
604 for p in properties.iter() {
605 p.write(&mut r).unwrap();
606 }
607 r.position()
608 };
609
610 let mut r = MqttBufReader::new(&buf[0..position]);
612 for p in expected_properties.iter() {
613 let p_read = PacketFirstThreeProperty::read(&mut r).unwrap();
614 assert_eq!(&p_read, p);
615 }
616 }
617
618 #[test]
619 fn fail_with_unexpected_property_identifier_on_reading_property_outside_subset_for_packet() {
620 let data: &[u8] = &[1u8, 2, 3, 4, 5, 6];
623 let unexpected_properties = [
624 PacketAnyProperty::PropertyVariableU32(4.into()),
625 PacketAnyProperty::PropertyString("hello world".into()),
626 PacketAnyProperty::PropertyStringPair(StringPair::new("name", "value").into()),
627 PacketAnyProperty::PropertyBinaryData(data.into()),
628 ];
629
630 let mut buf = [0xFFu8; 1024];
631 for p in unexpected_properties.iter() {
632 buf.fill(0xFFu8);
633 let position = {
634 let mut r = MqttBufWriter::new(&mut buf);
635 p.write(&mut r).unwrap();
636 r.position()
637 };
638
639 let mut r = MqttBufReader::new(&buf[0..position]);
640 assert_eq!(
641 PacketFirstThreeProperty::read(&mut r),
642 Err(PacketReadError::UnexpectedPropertyIdentifier)
643 );
644 }
645 }
646}