1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum ReasonCode {
3 Success = 0x00, GrantedQoS1 = 0x01,
6 GrantedQoS2 = 0x02,
7 DisconnectWithWillMessage = 0x04,
8 NoMatchingSubscribers = 0x10,
9 NoSubscriptionExisted = 0x11,
10 ContinueAuthentication = 0x18,
11 ReAuthenticate = 0x19,
12
13 UnspecifiedError = 0x80,
15 MalformedPacket = 0x81,
16 ProtocolError = 0x82,
17 ImplementationSpecificError = 0x83,
18 UnsupportedProtocolVersion = 0x84,
19 ClientIdentifierNotValid = 0x85,
20 BadUsernameOrPassword = 0x86,
21 NotAuthorized = 0x87,
22 ServerUnavailable = 0x88,
23 ServerBusy = 0x89,
24 Banned = 0x8A,
25 ServerShuttingDown = 0x8B,
26 BadAuthenticationMethod = 0x8C,
27 KeepAliveTimeout = 0x8D,
28 SessionTakenOver = 0x8E,
29 TopicFilterInvalid = 0x8F,
30 TopicNameInvalid = 0x90,
31 PacketIdentifierInUse = 0x91,
32 PacketIdentifierNotFound = 0x92,
33 ReceiveMaximumExceeded = 0x93,
34 TopicAliasInvalid = 0x94,
35 PacketTooLarge = 0x95,
36 MessageRateTooHigh = 0x96,
37 QuotaExceeded = 0x97,
38 AdministrativeAction = 0x98,
39 PayloadFormatInvalid = 0x99,
40 RetainNotSupported = 0x9A,
41 QoSNotSupported = 0x9B,
42 UseAnotherServer = 0x9C,
43 ServerMoved = 0x9D,
44 SharedSubscriptionsNotSupported = 0x9E,
45 ConnectionRateExceeded = 0x9F,
46 MaximumConnectTime = 0xA0,
47 SubscriptionIdentifiersNotSupported = 0xA1,
48 WildcardSubscriptionsNotSupported = 0xA2,
49
50 MqoqNoFlowState = 0xB3,
52 MqoqProtocolError = 0xB4,
53 MqoqStreamTypeError = 0xB5,
54 MqoqBadFlowId = 0xB6,
55 MqoqPersistentSubError = 0xB8,
56 MqoqIncompletePacket = 0xBA,
57 MqoqFlowOpenIdle = 0xBB,
58 MqoqFlowCancelled = 0xBC,
59}
60
61pub const NORMAL_DISCONNECTION: ReasonCode = ReasonCode::Success;
63pub const GRANTED_QOS_0: ReasonCode = ReasonCode::Success;
64
65impl From<ReasonCode> for u8 {
66 fn from(code: ReasonCode) -> Self {
67 code as u8
68 }
69}
70
71impl ReasonCode {
72 #[must_use]
73 pub fn is_success(&self) -> bool {
74 u8::from(*self) < 0x80
75 }
76
77 #[must_use]
78 pub fn is_error(&self) -> bool {
79 u8::from(*self) >= 0x80
80 }
81
82 #[must_use]
83 pub fn is_mqoq_error(&self) -> bool {
84 matches!(
85 self,
86 Self::MqoqNoFlowState
87 | Self::MqoqProtocolError
88 | Self::MqoqStreamTypeError
89 | Self::MqoqBadFlowId
90 | Self::MqoqPersistentSubError
91 | Self::MqoqIncompletePacket
92 | Self::MqoqFlowOpenIdle
93 | Self::MqoqFlowCancelled
94 )
95 }
96
97 #[must_use]
98 pub fn mqoq_error_level(&self) -> Option<u8> {
99 match self {
100 Self::MqoqNoFlowState | Self::MqoqProtocolError => Some(0),
101 Self::MqoqStreamTypeError | Self::MqoqBadFlowId | Self::MqoqPersistentSubError => {
102 Some(1)
103 }
104 Self::MqoqIncompletePacket | Self::MqoqFlowOpenIdle | Self::MqoqFlowCancelled => {
105 Some(2)
106 }
107 _ => None,
108 }
109 }
110
111 #[must_use]
112 pub fn from_u8(value: u8) -> Option<Self> {
113 match value {
114 0x00 => Some(Self::Success),
115 0x01 => Some(Self::GrantedQoS1),
116 0x02 => Some(Self::GrantedQoS2),
117 0x04 => Some(Self::DisconnectWithWillMessage),
118 0x10 => Some(Self::NoMatchingSubscribers),
119 0x11 => Some(Self::NoSubscriptionExisted),
120 0x18 => Some(Self::ContinueAuthentication),
121 0x19 => Some(Self::ReAuthenticate),
122 0x80 => Some(Self::UnspecifiedError),
123 0x81 => Some(Self::MalformedPacket),
124 0x82 => Some(Self::ProtocolError),
125 0x83 => Some(Self::ImplementationSpecificError),
126 0x84 => Some(Self::UnsupportedProtocolVersion),
127 0x85 => Some(Self::ClientIdentifierNotValid),
128 0x86 => Some(Self::BadUsernameOrPassword),
129 0x87 => Some(Self::NotAuthorized),
130 0x88 => Some(Self::ServerUnavailable),
131 0x89 => Some(Self::ServerBusy),
132 0x8A => Some(Self::Banned),
133 0x8B => Some(Self::ServerShuttingDown),
134 0x8C => Some(Self::BadAuthenticationMethod),
135 0x8D => Some(Self::KeepAliveTimeout),
136 0x8E => Some(Self::SessionTakenOver),
137 0x8F => Some(Self::TopicFilterInvalid),
138 0x90 => Some(Self::TopicNameInvalid),
139 0x91 => Some(Self::PacketIdentifierInUse),
140 0x92 => Some(Self::PacketIdentifierNotFound),
141 0x93 => Some(Self::ReceiveMaximumExceeded),
142 0x94 => Some(Self::TopicAliasInvalid),
143 0x95 => Some(Self::PacketTooLarge),
144 0x96 => Some(Self::MessageRateTooHigh),
145 0x97 => Some(Self::QuotaExceeded),
146 0x98 => Some(Self::AdministrativeAction),
147 0x99 => Some(Self::PayloadFormatInvalid),
148 0x9A => Some(Self::RetainNotSupported),
149 0x9B => Some(Self::QoSNotSupported),
150 0x9C => Some(Self::UseAnotherServer),
151 0x9D => Some(Self::ServerMoved),
152 0x9E => Some(Self::SharedSubscriptionsNotSupported),
153 0x9F => Some(Self::ConnectionRateExceeded),
154 0xA0 => Some(Self::MaximumConnectTime),
155 0xA1 => Some(Self::SubscriptionIdentifiersNotSupported),
156 0xA2 => Some(Self::WildcardSubscriptionsNotSupported),
157 0xB3 => Some(Self::MqoqNoFlowState),
158 0xB4 => Some(Self::MqoqProtocolError),
159 0xB5 => Some(Self::MqoqStreamTypeError),
160 0xB6 => Some(Self::MqoqBadFlowId),
161 0xB8 => Some(Self::MqoqPersistentSubError),
162 0xBA => Some(Self::MqoqIncompletePacket),
163 0xBB => Some(Self::MqoqFlowOpenIdle),
164 0xBC => Some(Self::MqoqFlowCancelled),
165 _ => None,
166 }
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn test_reason_code_success_check() {
176 assert!(ReasonCode::Success.is_success());
177 assert!(ReasonCode::GrantedQoS1.is_success());
178 assert!(ReasonCode::GrantedQoS2.is_success());
179 assert!(ReasonCode::NoMatchingSubscribers.is_success());
180
181 assert!(!ReasonCode::UnspecifiedError.is_success());
182 assert!(!ReasonCode::MalformedPacket.is_success());
183 assert!(!ReasonCode::NotAuthorized.is_success());
184 }
185
186 #[test]
187 fn test_reason_code_error_check() {
188 assert!(!ReasonCode::Success.is_error());
189 assert!(!ReasonCode::GrantedQoS1.is_error());
190
191 assert!(ReasonCode::UnspecifiedError.is_error());
192 assert!(ReasonCode::MalformedPacket.is_error());
193 assert!(ReasonCode::ProtocolError.is_error());
194 assert!(ReasonCode::ServerBusy.is_error());
195 }
196
197 #[test]
198 fn test_reason_code_from_u8() {
199 assert_eq!(ReasonCode::from_u8(0x00), Some(ReasonCode::Success));
200 assert_eq!(ReasonCode::from_u8(0x01), Some(ReasonCode::GrantedQoS1));
201 assert_eq!(ReasonCode::from_u8(0x02), Some(ReasonCode::GrantedQoS2));
202 assert_eq!(
203 ReasonCode::from_u8(0x80),
204 Some(ReasonCode::UnspecifiedError)
205 );
206 assert_eq!(ReasonCode::from_u8(0x81), Some(ReasonCode::MalformedPacket));
207 assert_eq!(ReasonCode::from_u8(0x87), Some(ReasonCode::NotAuthorized));
208 assert_eq!(
209 ReasonCode::from_u8(0xA2),
210 Some(ReasonCode::WildcardSubscriptionsNotSupported)
211 );
212
213 assert_eq!(ReasonCode::from_u8(0x03), None);
215 assert_eq!(ReasonCode::from_u8(0x05), None);
216 assert_eq!(ReasonCode::from_u8(0xFF), None);
217 }
218
219 #[test]
220 fn test_reason_code_aliases() {
221 assert_eq!(NORMAL_DISCONNECTION, ReasonCode::Success);
222 assert_eq!(GRANTED_QOS_0, ReasonCode::Success);
223 assert_eq!(NORMAL_DISCONNECTION as u8, 0x00);
224 assert_eq!(GRANTED_QOS_0 as u8, 0x00);
225 }
226
227 #[test]
228 fn test_reason_code_values() {
229 assert_eq!(ReasonCode::Success as u8, 0x00);
230 assert_eq!(ReasonCode::DisconnectWithWillMessage as u8, 0x04);
231 assert_eq!(ReasonCode::NoMatchingSubscribers as u8, 0x10);
232 assert_eq!(ReasonCode::UnspecifiedError as u8, 0x80);
233 assert_eq!(ReasonCode::ClientIdentifierNotValid as u8, 0x85);
234 assert_eq!(ReasonCode::ServerBusy as u8, 0x89);
235 assert_eq!(ReasonCode::QuotaExceeded as u8, 0x97);
236 assert_eq!(ReasonCode::WildcardSubscriptionsNotSupported as u8, 0xA2);
237 }
238
239 #[test]
240 fn test_mqoq_error_codes() {
241 assert_eq!(ReasonCode::MqoqNoFlowState as u8, 0xB3);
242 assert_eq!(ReasonCode::MqoqProtocolError as u8, 0xB4);
243 assert_eq!(ReasonCode::MqoqStreamTypeError as u8, 0xB5);
244 assert_eq!(ReasonCode::MqoqBadFlowId as u8, 0xB6);
245 assert_eq!(ReasonCode::MqoqPersistentSubError as u8, 0xB8);
246 assert_eq!(ReasonCode::MqoqIncompletePacket as u8, 0xBA);
247 assert_eq!(ReasonCode::MqoqFlowOpenIdle as u8, 0xBB);
248 assert_eq!(ReasonCode::MqoqFlowCancelled as u8, 0xBC);
249 }
250
251 #[test]
252 fn test_mqoq_error_from_u8() {
253 assert_eq!(ReasonCode::from_u8(0xB3), Some(ReasonCode::MqoqNoFlowState));
254 assert_eq!(
255 ReasonCode::from_u8(0xB4),
256 Some(ReasonCode::MqoqProtocolError)
257 );
258 assert_eq!(
259 ReasonCode::from_u8(0xB5),
260 Some(ReasonCode::MqoqStreamTypeError)
261 );
262 assert_eq!(ReasonCode::from_u8(0xB6), Some(ReasonCode::MqoqBadFlowId));
263 assert_eq!(
264 ReasonCode::from_u8(0xB8),
265 Some(ReasonCode::MqoqPersistentSubError)
266 );
267 assert_eq!(
268 ReasonCode::from_u8(0xBA),
269 Some(ReasonCode::MqoqIncompletePacket)
270 );
271 assert_eq!(
272 ReasonCode::from_u8(0xBB),
273 Some(ReasonCode::MqoqFlowOpenIdle)
274 );
275 assert_eq!(
276 ReasonCode::from_u8(0xBC),
277 Some(ReasonCode::MqoqFlowCancelled)
278 );
279 assert_eq!(ReasonCode::from_u8(0xB7), None);
280 assert_eq!(ReasonCode::from_u8(0xB9), None);
281 }
282
283 #[test]
284 fn test_mqoq_error_detection() {
285 assert!(ReasonCode::MqoqNoFlowState.is_mqoq_error());
286 assert!(ReasonCode::MqoqProtocolError.is_mqoq_error());
287 assert!(ReasonCode::MqoqStreamTypeError.is_mqoq_error());
288 assert!(ReasonCode::MqoqBadFlowId.is_mqoq_error());
289 assert!(ReasonCode::MqoqPersistentSubError.is_mqoq_error());
290 assert!(ReasonCode::MqoqIncompletePacket.is_mqoq_error());
291 assert!(ReasonCode::MqoqFlowOpenIdle.is_mqoq_error());
292 assert!(ReasonCode::MqoqFlowCancelled.is_mqoq_error());
293 assert!(!ReasonCode::Success.is_mqoq_error());
294 assert!(!ReasonCode::ProtocolError.is_mqoq_error());
295 }
296
297 #[test]
298 fn test_mqoq_error_levels() {
299 assert_eq!(ReasonCode::MqoqNoFlowState.mqoq_error_level(), Some(0));
300 assert_eq!(ReasonCode::MqoqProtocolError.mqoq_error_level(), Some(0));
301 assert_eq!(ReasonCode::MqoqStreamTypeError.mqoq_error_level(), Some(1));
302 assert_eq!(ReasonCode::MqoqBadFlowId.mqoq_error_level(), Some(1));
303 assert_eq!(
304 ReasonCode::MqoqPersistentSubError.mqoq_error_level(),
305 Some(1)
306 );
307 assert_eq!(ReasonCode::MqoqIncompletePacket.mqoq_error_level(), Some(2));
308 assert_eq!(ReasonCode::MqoqFlowOpenIdle.mqoq_error_level(), Some(2));
309 assert_eq!(ReasonCode::MqoqFlowCancelled.mqoq_error_level(), Some(2));
310 assert_eq!(ReasonCode::Success.mqoq_error_level(), None);
311 assert_eq!(ReasonCode::ProtocolError.mqoq_error_level(), None);
312 }
313}