mqtt_tiny/packets/
_ack.rs

1/// Defines an ACK-like packet (i.e. a response packet with a single 16bit packet-ID field)
2#[rustfmt::skip]
3macro_rules! acklike {
4    ($docstr:expr, $type:ident => $typeconst:expr) => {
5        #[doc = $docstr]
6        #[derive(Debug, Clone, PartialEq, Eq)]
7        pub struct $type {
8            /// The packet identifier
9            packet_id: u16,
10        }
11        impl $type {
12            /// The packet type constant
13            pub const TYPE: u8 = $typeconst;
14
15            /// For this packet, the body length is fixed
16            const BODY_LEN: usize = 2;
17
18            /// Creates a new packet
19            pub const fn new(packet_id: u16) -> Self {
20                Self { packet_id }
21            }
22            
23            /// The packet ID
24            pub const fn packet_id(&self) -> u16 {
25                self.packet_id
26            }
27        }
28        impl $crate::packets::TryFromIterator for $type {
29            fn try_from_iter<T>(iter: T) -> Result<Self, crate::error::DecoderError>
30            where
31                T: IntoIterator<Item = u8>,
32            {
33                use crate::err;
34                use crate::coding::Decoder;
35                use crate::error::Data;
36
37                // Read packet:
38                //  - header type and `0` flags
39                //  - packet len
40                //  - packet ID
41                let mut decoder = Decoder::new(iter);
42                let (Self::TYPE, _flags) = decoder.header()? else {
43                    return Err(err!(Data::SpecViolation, "invalid packet type"))?;
44                };
45                let Self::BODY_LEN = decoder.packetlen()? else {
46                    return Err(err!(Data::SpecViolation, "invalid packet length"))?;
47                };
48                // Read fields
49                let packet_id = decoder.u16()?;
50        
51                // Init self
52                Ok(Self { packet_id })
53            }
54        }
55        impl IntoIterator for $type {
56            type Item = u8;
57            #[rustfmt::skip]
58            type IntoIter = 
59                // Complex iterator built out of the individual message fields
60                core::iter::Chain<core::iter::Chain<core::iter::Chain<
61                    // - header type and `0` flags
62                    $crate::coding::encoder::Unit, $crate::coding::encoder::U8Iter>, 
63                    // - packet len
64                    $crate::coding::encoder::PacketLenIter>,
65                    // - packet ID
66                    $crate::coding::encoder::U16Iter>;
67        
68            fn into_iter(self) -> Self::IntoIter {
69                use crate::coding::Encoder;
70
71                // Write packet:
72                //  - header type and `0` flags
73                //  - packet len
74                //  - packet ID
75                Encoder::default()
76                    .header(Self::TYPE, [false, false, false, false])
77                    .packetlen(Self::BODY_LEN)
78                    .u16(self.packet_id)
79                    .into_iter()
80            }
81        }
82    };
83}
84
85pub mod puback {
86    //! MQTT [`PUBACK`](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043)
87    acklike! {
88        "An MQTT [`PUBACK` packet](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043)",
89        Puback => 4
90    }
91}
92
93pub mod pubcomp {
94    //! MQTT [`PUBCOMP`](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718058)
95    acklike! {
96        "An MQTT [`PUBCOMP` packet](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718058)",
97        Pubcomp => 7
98    }
99}
100
101pub mod pubrec {
102    //! MQTT [`PUBREC`](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718048)
103    acklike! {
104        "An MQTT [`PUBREC` packet](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718048)",
105        Pubrec => 5
106    }
107}
108
109pub mod pubrel {
110    //! MQTT [`PUBREL`](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053)
111    acklike! {
112        "An MQTT [`PUBREL` packet](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053)",
113        Pubrel => 6
114    }
115}
116
117pub mod suback {
118    //! MQTT [`SUBACK`](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718068)
119    acklike! {
120        "An MQTT [`SUBACK` packet](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718068)",
121        Suback => 9
122    }
123}
124
125pub mod unsuback {
126    //! MQTT [`UNSUBACK`](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718077)
127    acklike! {
128        "An MQTT [`UNSUBACK` packet](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718077)",
129        Unsuback => 11
130    }
131}