1use core::fmt::{Display, Formatter};
2
3use crate::codec::{read::Read, write::Write};
4use crate::error::PacketReadError;
5
6#[macro_export]
7macro_rules! packet_reason_codes {
8 ( $n:ident, [ $( $c:ident ),+ ] ) => {
9 #[derive(Debug, PartialEq, Clone, Copy)]
10 #[repr(u8)]
11 pub enum $n{
12 $(
13 $c = ReasonCode::$c as u8,
14 )*
15 }
16
17 impl From<$n> for ReasonCode {
18 fn from(value: $n) -> Self {
19 match value {
20 $(
21 $n::$c => ReasonCode::$c,
22 )*
23 }
24 }
25 }
26
27 impl TryFrom<u8> for $n {
28 type Error = PacketReadError;
29
30 fn try_from(value: u8) -> Result<Self, Self::Error> {
31 $(
32 if value == ReasonCode::$c as u8 {
33 Ok(Self::$c)
34 } else
35 )*
36 {
37 Err(PacketReadError::UnknownReasonCode)
38 }
39 }
40 }
41
42 impl TryFrom<ReasonCode> for $n {
43 type Error = PacketReadError;
44
45 fn try_from(value: ReasonCode) -> Result<Self, Self::Error> {
46 match value {
47 $(
48 ReasonCode::$c => Ok(Self::$c),
49 )*
50
51 _ => Err(PacketReadError::UnknownReasonCode),
52 }
53 }
54 }
55
56 impl $n {
57 pub fn is_error(&self) -> bool {
58 (*self as u8) > 128
59 }
60 }
61
62 impl<'a> Read<'a> for $n {
63 fn read<R: $crate::codec::mqtt_reader::MqttReader<'a>>(
64 reader: &mut R,
65 ) -> $crate::codec::mqtt_reader::Result<Self>
66 where
67 Self: Sized,
68 {
69 let encoded = reader.get_u8()?;
70 encoded.try_into()
71 }
72 }
73
74 impl Write for $n {
75 fn write<'a, W: $crate::codec::mqtt_writer::MqttWriter<'a>>(
76 &self,
77 writer: &mut W,
78 ) -> $crate::codec::mqtt_writer::Result<()> {
79 writer.put_u8(*self as u8)
80 }
81 }
82
83 impl Display for $n {
84 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
85 match self {
86 $(
87 Self::$c => write!(f, "$n($c)"),
88 )*
89 }
90 }
91 }
92
93 #[cfg(feature = "defmt")]
94 impl defmt::Format for $n {
95 fn format(&self, f: defmt::Formatter) {
96 match self {
97 $(
98 Self::$c => defmt::write!(f, "$n($c)"),
99 )*
100 }
101 }
102 }
103
104 };
105}
106
107#[repr(u8)]
111#[derive(Clone, Copy, PartialEq, Debug)]
112pub enum ReasonCode {
113 Success = 0,
114 GrantedQos1 = 1,
115 GrantedQos2 = 2,
116 DisconnectWithWillMessage = 4,
117 NoMatchingSubscribers = 16,
118 NoSubscriptionExisted = 17,
119 ContinueAuthentication = 24,
120 ReAuthenticate = 25,
121 UnspecifiedError = 128,
122 MalformedPacket = 129,
123 ProtocolError = 130,
124 ImplementationSpecificError = 131,
125 UnsupportedProtocolVersion = 132,
126 ClientIdentifierNotValid = 133,
127 BadUserNameOrPassword = 134,
128 NotAuthorized = 135,
129 ServerUnavailable = 136,
130 ServerBusy = 137,
131 Banned = 138,
132 ServerShuttingDown = 139,
133 BadAuthenticationMethod = 140,
134 KeepAliveTimeout = 141,
135 SessionTakenOver = 142,
136 TopicFilterInvalid = 143,
137 TopicNameInvalid = 144,
138 PacketIdentifierInUse = 145,
139 PacketIdentifierNotFound = 146,
140 ReceiveMaximumExceeded = 147,
141 TopicAliasInvalid = 148,
142 PacketTooLarge = 149,
143 MessageRateTooHigh = 150,
144 QuotaExceeded = 151,
145 AdministrativeAction = 152,
146 PayloadFormatInvalid = 153,
147 RetainNotSupported = 154,
148 QosNotSupported = 155,
149 UseAnotherServer = 156,
150 ServerMoved = 157,
151 SharedSubscriptionsNotSupported = 158,
152 ConnectionRateExceeded = 159,
153 MaximumConnectTime = 160,
154 SubscriptionIdentifiersNotSupported = 161,
155 WildcardSubscriptionsNotSupported = 162,
156}
157
158impl ReasonCode {
159 pub fn is_error(&self) -> bool {
160 (*self as u8) > 128
161 }
162}
163
164packet_reason_codes!(
165 ConnectReasonCode,
166 [
167 Success,
168 UnspecifiedError,
169 MalformedPacket,
170 ProtocolError,
171 ImplementationSpecificError,
172 UnsupportedProtocolVersion,
173 ClientIdentifierNotValid,
174 BadUserNameOrPassword,
175 NotAuthorized,
176 ServerUnavailable,
177 ServerBusy,
178 Banned,
179 BadAuthenticationMethod,
180 TopicNameInvalid,
181 PacketTooLarge,
182 QuotaExceeded,
183 PayloadFormatInvalid,
184 RetainNotSupported,
185 QosNotSupported,
186 UseAnotherServer,
187 ServerMoved,
188 ConnectionRateExceeded
189 ]
190);
191
192packet_reason_codes!(
193 DisconnectReasonCode,
194 [
195 Success, DisconnectWithWillMessage,
197 UnspecifiedError,
198 MalformedPacket,
199 ProtocolError,
200 ImplementationSpecificError,
201 NotAuthorized,
202 ServerBusy,
203 ServerShuttingDown,
204 KeepAliveTimeout,
205 SessionTakenOver,
206 TopicFilterInvalid,
207 TopicNameInvalid,
208 ReceiveMaximumExceeded,
209 TopicAliasInvalid,
210 PacketTooLarge,
211 MessageRateTooHigh,
212 QuotaExceeded,
213 AdministrativeAction,
214 PayloadFormatInvalid,
215 RetainNotSupported,
216 QosNotSupported,
217 UseAnotherServer,
218 ServerMoved,
219 SharedSubscriptionsNotSupported,
220 ConnectionRateExceeded,
221 MaximumConnectTime,
222 SubscriptionIdentifiersNotSupported,
223 WildcardSubscriptionsNotSupported
224 ]
225);
226
227packet_reason_codes!(
228 PublishReasonCode,
229 [
230 Success,
231 NoMatchingSubscribers,
232 UnspecifiedError,
233 ImplementationSpecificError,
234 NotAuthorized,
235 TopicNameInvalid,
236 PacketIdentifierInUse,
237 QuotaExceeded,
238 PayloadFormatInvalid
239 ]
240);
241
242packet_reason_codes!(PubrelReasonCode, [Success, PacketIdentifierNotFound]);
243
244packet_reason_codes!(
245 SubscribeReasonCode,
246 [
247 Success,
248 GrantedQos1,
249 GrantedQos2,
250 UnspecifiedError,
251 ImplementationSpecificError,
252 NotAuthorized,
253 TopicFilterInvalid,
254 PacketIdentifierInUse,
255 QuotaExceeded,
256 SharedSubscriptionsNotSupported,
257 SubscriptionIdentifiersNotSupported,
258 WildcardSubscriptionsNotSupported
259 ]
260);
261
262packet_reason_codes!(
263 UnsubscribeReasonCode,
264 [
265 Success,
266 NoSubscriptionExisted,
267 UnspecifiedError,
268 ImplementationSpecificError,
269 NotAuthorized,
270 TopicFilterInvalid,
271 PacketIdentifierInUse
272 ]
273);
274
275packet_reason_codes!(
276 AuthReasonCode,
277 [Success, ContinueAuthentication, ReAuthenticate]
278);
279
280#[cfg(test)]
281mod tests {
282 use crate::codec::{
283 mqtt_reader::{MqttBufReader, MqttReader},
284 mqtt_writer::{MqttBufWriter, MqttWriter},
285 };
286
287 use super::*;
288
289 packet_reason_codes!(ExampleReasonCode, [UnspecifiedError, MalformedPacket]);
290
291 const DATA: [(ExampleReasonCode, u8); 2] = [
292 (
293 ExampleReasonCode::UnspecifiedError,
294 ReasonCode::UnspecifiedError as u8,
295 ),
296 (
297 ExampleReasonCode::MalformedPacket,
298 ReasonCode::MalformedPacket as u8,
299 ),
300 ];
301
302 #[test]
303 fn all_expected_codes_exist_with_expected_u8_value() {
304 for (code, value) in DATA.iter() {
305 assert_eq!(*code as u8, *value);
306 }
307 }
308
309 #[test]
310 fn can_write_codes() {
311 for (code, value) in DATA.iter() {
312 let mut buf = [0u8];
313 {
314 let mut r = MqttBufWriter::new(&mut buf);
315 r.put(code).unwrap();
316 assert_eq!(r.position(), 1);
317 assert_eq!(r.remaining(), 0);
318 }
319 assert_eq!(buf, [*value]);
320 }
321 }
322
323 #[test]
324 fn can_read_codes() {
325 for (code, value) in DATA.iter() {
326 let buf = [*value];
327 let mut r = MqttBufReader::new(&buf);
328 let read_code: ExampleReasonCode = r.get().unwrap();
329 assert_eq!(r.position(), 1);
330 assert_eq!(r.remaining(), 0);
331 assert_eq!(&read_code, code);
332 }
333 }
334
335 #[test]
336 fn can_try_to_get_packet_reason_code_from_reason_code() {
337 assert_eq!(
338 ExampleReasonCode::try_from(ReasonCode::UnspecifiedError),
339 Ok(ExampleReasonCode::UnspecifiedError)
340 );
341 assert_eq!(
342 ExampleReasonCode::try_from(ReasonCode::MalformedPacket),
343 Ok(ExampleReasonCode::MalformedPacket)
344 );
345 assert_eq!(
346 ExampleReasonCode::try_from(ReasonCode::AdministrativeAction),
347 Err(PacketReadError::UnknownReasonCode)
348 );
349 }
350
351 #[test]
352 fn can_try_to_get_packet_reason_code_from_u8() {
353 assert_eq!(
354 ExampleReasonCode::try_from(ReasonCode::UnspecifiedError as u8),
355 Ok(ExampleReasonCode::UnspecifiedError)
356 );
357 assert_eq!(
358 ExampleReasonCode::try_from(ReasonCode::MalformedPacket as u8),
359 Ok(ExampleReasonCode::MalformedPacket)
360 );
361 assert_eq!(
362 ExampleReasonCode::try_from(ReasonCode::AdministrativeAction as u8),
363 Err(PacketReadError::UnknownReasonCode)
364 );
365 }
366
367 #[test]
368 fn can_get_reason_code_from_packet_reason_code() {
369 assert_eq!(
370 ReasonCode::from(ExampleReasonCode::UnspecifiedError),
371 ReasonCode::UnspecifiedError
372 );
373 assert_eq!(
374 ReasonCode::from(ExampleReasonCode::MalformedPacket),
375 ReasonCode::MalformedPacket
376 );
377 }
378}