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