mqtt/control/
packet_type.rs1use crate::qos::QualityOfService;
4
5#[derive(Debug, Eq, PartialEq, Copy, Clone)]
8pub struct PacketType(u8);
9
10#[rustfmt::skip]
12#[repr(u8)]
13#[derive(Debug, Eq, PartialEq, Copy, Clone)]
14pub enum ControlType {
15 Connect = value::CONNECT,
17
18 ConnectAcknowledgement = value::CONNACK,
20
21 Publish = value::PUBLISH,
23
24 PublishAcknowledgement = value::PUBACK,
26
27 PublishReceived = value::PUBREC,
29
30 PublishRelease = value::PUBREL,
32
33 PublishComplete = value::PUBCOMP,
35
36 Subscribe = value::SUBSCRIBE,
38
39 SubscribeAcknowledgement = value::SUBACK,
41
42 Unsubscribe = value::UNSUBSCRIBE,
44
45 UnsubscribeAcknowledgement = value::UNSUBACK,
47
48 PingRequest = value::PINGREQ,
50
51 PingResponse = value::PINGRESP,
53
54 Disconnect = value::DISCONNECT,
56}
57
58impl ControlType {
59 #[inline]
60 fn default_flags(self) -> u8 {
61 match self {
62 ControlType::Connect => 0,
63 ControlType::ConnectAcknowledgement => 0,
64
65 ControlType::Publish => 0,
66 ControlType::PublishAcknowledgement => 0,
67 ControlType::PublishReceived => 0,
68 ControlType::PublishRelease => 0b0010,
69 ControlType::PublishComplete => 0,
70
71 ControlType::Subscribe => 0b0010,
72 ControlType::SubscribeAcknowledgement => 0,
73
74 ControlType::Unsubscribe => 0b0010,
75 ControlType::UnsubscribeAcknowledgement => 0,
76
77 ControlType::PingRequest => 0,
78 ControlType::PingResponse => 0,
79
80 ControlType::Disconnect => 0,
81 }
82 }
83}
84
85impl PacketType {
86 pub fn new(t: ControlType, flags: u8) -> Result<PacketType, InvalidFlag> {
91 let flags_ok = match t {
92 ControlType::Publish => {
93 let qos = (flags & 0b0110) >> 1;
94 matches!(qos, 0 | 1 | 2)
95 }
96 _ => t.default_flags() == flags,
97 };
98 if flags_ok {
99 Ok(PacketType::new_unchecked(t, flags))
100 } else {
101 Err(InvalidFlag(t, flags))
102 }
103 }
104
105 #[inline]
106 fn new_unchecked(t: ControlType, flags: u8) -> PacketType {
107 let byte = (t as u8) << 4 | (flags & 0x0F);
108 #[allow(unused_unsafe)]
109 unsafe {
110 PacketType(byte)
112 }
113 }
114
115 #[inline]
119 pub fn with_default(t: ControlType) -> PacketType {
120 let flags = t.default_flags();
121 PacketType::new_unchecked(t, flags)
122 }
123
124 pub(crate) fn publish(qos: QualityOfService) -> PacketType {
125 PacketType::new_unchecked(ControlType::Publish, (qos as u8) << 1)
126 }
127
128 #[inline]
129 pub(crate) fn update_flags(&mut self, upd: impl FnOnce(u8) -> u8) {
130 let flags = upd(self.flags());
131 self.0 = (self.0 & !0x0F) | (flags & 0x0F)
132 }
133
134 #[inline]
136 pub fn to_u8(self) -> u8 {
137 self.0
138 }
139
140 pub fn from_u8(val: u8) -> Result<PacketType, PacketTypeError> {
142 let type_val = val >> 4;
143 let flags = val & 0x0F;
144
145 let control_type = get_control_type(type_val).ok_or(PacketTypeError::ReservedType(type_val, flags))?;
146 Ok(PacketType::new(control_type, flags)?)
147 }
148
149 #[inline]
150 pub fn control_type(self) -> ControlType {
151 get_control_type(self.0 >> 4).unwrap_or_else(|| {
152 unsafe { std::hint::unreachable_unchecked() }
154 })
155 }
156
157 #[inline]
158 pub fn flags(self) -> u8 {
159 self.0 & 0x0F
160 }
161}
162
163#[inline]
164fn get_control_type(val: u8) -> Option<ControlType> {
165 let typ = match val {
166 value::CONNECT => ControlType::Connect,
167 value::CONNACK => ControlType::ConnectAcknowledgement,
168
169 value::PUBLISH => ControlType::Publish,
170 value::PUBACK => ControlType::PublishAcknowledgement,
171 value::PUBREC => ControlType::PublishReceived,
172 value::PUBREL => ControlType::PublishRelease,
173 value::PUBCOMP => ControlType::PublishComplete,
174
175 value::SUBSCRIBE => ControlType::Subscribe,
176 value::SUBACK => ControlType::SubscribeAcknowledgement,
177
178 value::UNSUBSCRIBE => ControlType::Unsubscribe,
179 value::UNSUBACK => ControlType::UnsubscribeAcknowledgement,
180
181 value::PINGREQ => ControlType::PingRequest,
182 value::PINGRESP => ControlType::PingResponse,
183
184 value::DISCONNECT => ControlType::Disconnect,
185
186 _ => return None,
187 };
188 Some(typ)
189}
190
191#[derive(Debug, thiserror::Error)]
193pub enum PacketTypeError {
194 #[error("reserved type {0:?} (flags {1:#X})")]
195 ReservedType(u8, u8),
196 #[error(transparent)]
197 InvalidFlag(#[from] InvalidFlag),
198}
199
200#[derive(Debug, thiserror::Error)]
201#[error("invalid flag for {0:?} ({1:#X})")]
202pub struct InvalidFlag(pub ControlType, pub u8);
203
204#[rustfmt::skip]
205mod value {
206 pub const CONNECT: u8 = 1;
207 pub const CONNACK: u8 = 2;
208 pub const PUBLISH: u8 = 3;
209 pub const PUBACK: u8 = 4;
210 pub const PUBREC: u8 = 5;
211 pub const PUBREL: u8 = 6;
212 pub const PUBCOMP: u8 = 7;
213 pub const SUBSCRIBE: u8 = 8;
214 pub const SUBACK: u8 = 9;
215 pub const UNSUBSCRIBE: u8 = 10;
216 pub const UNSUBACK: u8 = 11;
217 pub const PINGREQ: u8 = 12;
218 pub const PINGRESP: u8 = 13;
219 pub const DISCONNECT: u8 = 14;
220}