mqtt5_protocol/packet/
ack_common.rs1use crate::types::ReasonCode;
2
3macro_rules! define_ack_packet {
4 (
5 $(#[$meta:meta])*
6 $vis:vis struct $name:ident;
7 packet_type = $packet_type:expr;
8 validator = $validator:path;
9 error_prefix = $error_prefix:literal;
10 ) => {
11 $crate::packet::ack_common::define_ack_packet_inner! {
12 $(#[$meta])*
13 $vis struct $name;
14 packet_type = $packet_type;
15 validator = $validator;
16 error_prefix = $error_prefix;
17 flags = (None);
18 }
19 };
20 (
21 $(#[$meta:meta])*
22 $vis:vis struct $name:ident;
23 packet_type = $packet_type:expr;
24 validator = $validator:path;
25 error_prefix = $error_prefix:literal;
26 flags = $flags:literal;
27 validate_flags = true;
28 ) => {
29 $crate::packet::ack_common::define_ack_packet_inner! {
30 $(#[$meta])*
31 $vis struct $name;
32 packet_type = $packet_type;
33 validator = $validator;
34 error_prefix = $error_prefix;
35 flags = (Some($flags));
36 }
37 };
38}
39
40#[doc(hidden)]
41macro_rules! ack_impl_flags {
42 ((None)) => {};
43 ((Some($val:literal))) => {
44 fn flags(&self) -> u8 {
45 $val
46 }
47 };
48}
49
50#[doc(hidden)]
51macro_rules! ack_validate_flags {
52 ((None), $fh:ident, $prefix:literal) => {
53 let _ = $fh;
54 };
55 ((Some($val:literal)), $fh:ident, $prefix:literal) => {
56 if $fh.flags != $val {
57 return Err($crate::error::MqttError::MalformedPacket(format!(
58 concat!(
59 "Invalid ",
60 $prefix,
61 " flags: expected 0x{:02X}, got 0x{:02X}"
62 ),
63 $val, $fh.flags
64 )));
65 }
66 };
67}
68
69#[doc(hidden)]
70macro_rules! define_ack_packet_inner {
71 (
72 $(#[$meta:meta])*
73 $vis:vis struct $name:ident;
74 packet_type = $packet_type:expr;
75 validator = $validator:path;
76 error_prefix = $error_prefix:literal;
77 flags = $flags:tt;
78 ) => {
79 $(#[$meta])*
80 #[derive(Debug, Clone)]
81 $vis struct $name {
82 pub packet_id: u16,
83 pub reason_code: $crate::types::ReasonCode,
84 pub properties: $crate::protocol::v5::properties::Properties,
85 }
86
87 impl $name {
88 #[must_use]
89 pub fn new(packet_id: u16) -> Self {
90 Self {
91 packet_id,
92 reason_code: $crate::types::ReasonCode::Success,
93 properties: $crate::protocol::v5::properties::Properties::default(),
94 }
95 }
96
97 #[must_use]
98 pub fn new_with_reason(packet_id: u16, reason_code: $crate::types::ReasonCode) -> Self {
99 Self {
100 packet_id,
101 reason_code,
102 properties: $crate::protocol::v5::properties::Properties::default(),
103 }
104 }
105
106 #[must_use]
107 pub fn with_reason_string(mut self, reason: String) -> Self {
108 self.properties.set_reason_string(reason);
109 self
110 }
111
112 #[must_use]
113 pub fn with_user_property(mut self, key: String, value: String) -> Self {
114 self.properties.add_user_property(key, value);
115 self
116 }
117 }
118
119 impl $crate::packet::MqttPacket for $name {
120 fn packet_type(&self) -> $crate::packet::PacketType {
121 $packet_type
122 }
123
124 $crate::packet::ack_common::ack_impl_flags!($flags);
125
126 fn encode_body<B: bytes::BufMut>(&self, buf: &mut B) -> $crate::error::Result<()> {
127 buf.put_u16(self.packet_id);
128 if self.reason_code != $crate::types::ReasonCode::Success || !self.properties.is_empty() {
129 buf.put_u8(u8::from(self.reason_code));
130 self.properties.encode(buf)?;
131 }
132 Ok(())
133 }
134
135 fn decode_body<B: bytes::Buf>(
136 buf: &mut B,
137 fixed_header: &$crate::packet::FixedHeader,
138 ) -> $crate::error::Result<Self> {
139 $crate::packet::ack_common::ack_validate_flags!($flags, fixed_header, $error_prefix);
140
141 if buf.remaining() < 2 {
142 return Err($crate::error::MqttError::MalformedPacket(
143 concat!($error_prefix, " missing packet identifier").to_string(),
144 ));
145 }
146 let packet_id = buf.get_u16();
147
148 let (reason_code, properties) = if buf.has_remaining() {
149 let reason_byte = buf.get_u8();
150 let code = $crate::types::ReasonCode::from_u8(reason_byte).ok_or_else(|| {
151 $crate::error::MqttError::MalformedPacket(format!(
152 concat!("Invalid ", $error_prefix, " reason code: {}"),
153 reason_byte
154 ))
155 })?;
156
157 if !$validator(code) {
158 return Err($crate::error::MqttError::MalformedPacket(format!(
159 concat!("Invalid ", $error_prefix, " reason code: {:?}"),
160 code
161 )));
162 }
163
164 let props = if buf.has_remaining() {
165 $crate::protocol::v5::properties::Properties::decode(buf)?
166 } else {
167 $crate::protocol::v5::properties::Properties::default()
168 };
169
170 (code, props)
171 } else {
172 ($crate::types::ReasonCode::Success, $crate::protocol::v5::properties::Properties::default())
173 };
174
175 Ok(Self {
176 packet_id,
177 reason_code,
178 properties,
179 })
180 }
181 }
182 };
183}
184
185pub(crate) use ack_impl_flags;
186pub(crate) use ack_validate_flags;
187pub(crate) use define_ack_packet;
188pub(crate) use define_ack_packet_inner;
189
190pub fn is_valid_publish_ack_reason_code(code: ReasonCode) -> bool {
191 matches!(
192 code,
193 ReasonCode::Success
194 | ReasonCode::NoMatchingSubscribers
195 | ReasonCode::UnspecifiedError
196 | ReasonCode::ImplementationSpecificError
197 | ReasonCode::NotAuthorized
198 | ReasonCode::TopicNameInvalid
199 | ReasonCode::PacketIdentifierInUse
200 | ReasonCode::QuotaExceeded
201 | ReasonCode::PayloadFormatInvalid
202 )
203}
204
205pub fn is_valid_pubrel_reason_code(code: ReasonCode) -> bool {
206 matches!(
207 code,
208 ReasonCode::Success | ReasonCode::PacketIdentifierNotFound
209 )
210}