Skip to main content

rust_mqtt/types/
reason_code.rs

1use crate::{
2    eio::{Read, Write},
3    io::{
4        err::{ReadError, WriteError},
5        read::Readable,
6        write::Writable,
7    },
8};
9
10/// A Reason Code is a variable byte integer encoded value that indicates the result of an operation.
11///
12/// The CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, DISCONNECT and AUTH Control Packets have
13/// a single Reason Code as part of the Variable Header. The SUBACK and UNSUBACK packets
14/// contain a list of one or more Reason Codes in the Payload.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[repr(u8)]
18pub enum ReasonCode {
19    /// # aka `GrantedQoS0`, `NormalDisconnection`
20    ///
21    /// CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, AUTH, DISCONNECT
22    Success = 0x00,
23
24    /// SUBACK
25    GrantedQoS1 = 0x01,
26
27    /// SUBACK
28    GrantedQoS2 = 0x02,
29
30    /// DISCONNECT
31    DisconnectWithWillMessage = 0x04,
32
33    /// PUBACK, PUBREC
34    NoMatchingSubscribers = 0x10,
35
36    /// UNSUBACK
37    NoSubscriptionExisted = 0x11,
38
39    /// AUTH
40    ContinueAuthentication = 0x18,
41
42    /// AUTH
43    ReAuthenticate = 0x19,
44
45    #[default]
46    /// CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT
47    UnspecifiedError = 0x80,
48
49    /// CONNACK, DISCONNECT
50    MalformedPacket = 0x81,
51
52    /// CONNACK, DISCONNECT
53    ProtocolError = 0x82,
54
55    /// CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT
56    ImplementationSpecificError = 0x83,
57
58    /// CONNACK
59    UnsupportedProtocolVersion = 0x84,
60
61    /// CONNACK
62    ClientIdentifierNotValid = 0x85,
63
64    /// CONNACK
65    BadUserNameOrPassword = 0x86,
66
67    /// CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT
68    NotAuthorized = 0x87,
69
70    /// CONNACK
71    ServerUnavailable = 0x88,
72
73    /// CONNACK, DISCONNECT
74    ServerBusy = 0x89,
75
76    /// CONNACK
77    Banned = 0x8A,
78
79    /// DISCONNECT
80    ServerShuttingDown = 0x8B,
81
82    /// CONNACK, DISCONNECT
83    BadAuthenticationMethod = 0x8C,
84
85    /// DISCONNECT
86    KeepAliveTimeout = 0x8D,
87
88    /// DISCONNECT
89    SessionTakenOver = 0x8E,
90
91    /// SUBACK, UNSUBACK, DISCONNECT
92    TopicFilterInvalid = 0x8F,
93
94    /// CONNACK, PUBACK, PUBREC, DISCONNECT
95    TopicNameInvalid = 0x90,
96
97    /// PUBACK, PUBREC, SUBACK, UNSUBACK
98    PacketIdentifierInUse = 0x91,
99
100    /// PUBREL, PUBCOMP
101    PacketIdentifierNotFound = 0x92,
102
103    /// DISCONNECT
104    ReceiveMaximumExceeded = 0x93,
105
106    /// DISCONNECT
107    TopicAliasInvalid = 0x94,
108
109    /// CONNACK, DISCONNECT
110    PacketTooLarge = 0x95,
111
112    /// DISCONNECT
113    MessageRateTooHigh = 0x96,
114
115    /// CONNACK, PUBACK, PUBREC, SUBACK, DISCONNECT
116    QuotaExceeded = 0x97,
117
118    /// DISCONNECT
119    AdministrativeAction = 0x98,
120
121    /// CONNACK, PUBACK, PUBREC, DISCONNECT
122    PayloadFormatInvalid = 0x99,
123
124    /// CONNACK, DISCONNECT
125    RetainNotSupported = 0x9A,
126
127    /// CONNACK, DISCONNECT
128    QoSNotSupported = 0x9B,
129
130    /// CONNACK, DISCONNECT
131    UseAnotherServer = 0x9C,
132
133    /// CONNACK, DISCONNECT
134    ServerMoved = 0x9D,
135
136    /// SUBACK, DISCONNECT
137    SharedSubscriptionsNotSupported = 0x9E,
138
139    /// CONNACK, DISCONNECT
140    ConnectionRateExceeded = 0x9F,
141
142    /// DISCONNECT
143    MaximumConnectTime = 0xA0,
144
145    /// SUBACK, DISCONNECT
146    SubscriptionIdentifiersNotSupported = 0xA1,
147
148    /// SUBACK, DISCONNECT
149    WildcardSubscriptionsNotSupported = 0xA2,
150}
151
152impl ReasonCode {
153    /// Returns the numeric value of the reason code.
154    #[must_use]
155    pub const fn value(self) -> u8 {
156        self as u8
157    }
158
159    /// Returns whether the reason code is successful.
160    /// This is the case if the reason code's numeric value is less than 0x80.
161    #[must_use]
162    pub const fn is_success(&self) -> bool {
163        self.value() < 0x80
164    }
165
166    /// Returns whether the reason code indicates an error.
167    /// This is the case if the reason code's numeric value is greater than or equal to 0x80.
168    #[must_use]
169    pub const fn is_erroneous(&self) -> bool {
170        self.value() >= 0x80
171    }
172}
173
174impl<R: Read> Readable<R> for ReasonCode {
175    async fn read(net: &mut R) -> Result<Self, ReadError<R::Error>> {
176        let value = u8::read(net).await?;
177        Ok(match value {
178            0x00 => Self::Success, // Note: This is ambiguous - context determines the specific variant
179            0x01 => Self::GrantedQoS1,
180            0x02 => Self::GrantedQoS2,
181            0x04 => Self::DisconnectWithWillMessage,
182            0x10 => Self::NoMatchingSubscribers,
183            0x11 => Self::NoSubscriptionExisted,
184            0x18 => Self::ContinueAuthentication,
185            0x19 => Self::ReAuthenticate,
186            0x80 => Self::UnspecifiedError,
187            0x81 => Self::MalformedPacket,
188            0x82 => Self::ProtocolError,
189            0x83 => Self::ImplementationSpecificError,
190            0x84 => Self::UnsupportedProtocolVersion,
191            0x85 => Self::ClientIdentifierNotValid,
192            0x86 => Self::BadUserNameOrPassword,
193            0x87 => Self::NotAuthorized,
194            0x88 => Self::ServerUnavailable,
195            0x89 => Self::ServerBusy,
196            0x8A => Self::Banned,
197            0x8B => Self::ServerShuttingDown,
198            0x8C => Self::BadAuthenticationMethod,
199            0x8D => Self::KeepAliveTimeout,
200            0x8E => Self::SessionTakenOver,
201            0x8F => Self::TopicFilterInvalid,
202            0x90 => Self::TopicNameInvalid,
203            0x91 => Self::PacketIdentifierInUse,
204            0x92 => Self::PacketIdentifierNotFound,
205            0x93 => Self::ReceiveMaximumExceeded,
206            0x94 => Self::TopicAliasInvalid,
207            0x95 => Self::PacketTooLarge,
208            0x96 => Self::MessageRateTooHigh,
209            0x97 => Self::QuotaExceeded,
210            0x98 => Self::AdministrativeAction,
211            0x99 => Self::PayloadFormatInvalid,
212            0x9A => Self::RetainNotSupported,
213            0x9B => Self::QoSNotSupported,
214            0x9C => Self::UseAnotherServer,
215            0x9D => Self::ServerMoved,
216            0x9E => Self::SharedSubscriptionsNotSupported,
217            0x9F => Self::ConnectionRateExceeded,
218            0xA0 => Self::MaximumConnectTime,
219            0xA1 => Self::SubscriptionIdentifiersNotSupported,
220            0xA2 => Self::WildcardSubscriptionsNotSupported,
221            _ => return Err(ReadError::ProtocolError),
222        })
223    }
224}
225
226impl Writable for ReasonCode {
227    fn written_len(&self) -> usize {
228        1
229    }
230
231    async fn write<W: Write>(&self, write: &mut W) -> Result<(), WriteError<W::Error>> {
232        self.value().write(write).await
233    }
234}