1use crate::{
4 eio::Write,
5 fmt::unreachable,
6 io::{
7 err::WriteError,
8 write::{Writable, wlen},
9 },
10 types::VarByteInt,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct FixedHeader {
18 pub(crate) type_and_flags: u8,
19 pub(crate) remaining_len: VarByteInt,
20}
21
22impl Writable for FixedHeader {
23 fn written_len(&self) -> usize {
24 wlen!(u8) + self.remaining_len.written_len()
25 }
26
27 async fn write<W: Write>(&self, write: &mut W) -> Result<(), WriteError<W::Error>> {
28 self.type_and_flags.write(write).await?;
29 self.remaining_len.write(write).await?;
30
31 Ok(())
32 }
33}
34
35impl FixedHeader {
36 pub(crate) fn new(packet_type: PacketType, flags: u8, remaining_len: VarByteInt) -> Self {
37 let packet_type = (packet_type as u8) << 4;
38 Self {
39 type_and_flags: packet_type | flags,
40 remaining_len,
41 }
42 }
43
44 #[must_use]
47 pub fn flags(&self) -> u8 {
48 self.type_and_flags & 0x0F
49 }
50
51 pub fn packet_type(&self) -> Result<PacketType, Reserved> {
57 PacketType::from_type_and_flags(self.type_and_flags)
58 }
59}
60
61#[derive(Debug)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub struct Reserved;
65
66#[allow(missing_docs)]
68#[derive(PartialEq, Eq)]
69pub enum PacketType {
70 Connect = 1,
71 Connack = 2,
72 Publish = 3,
73 Puback = 4,
74 Pubrec = 5,
75 Pubrel = 6,
76 Pubcomp = 7,
77 Subscribe = 8,
78 Suback = 9,
79 Unsubscribe = 10,
80 Unsuback = 11,
81 Pingreq = 12,
82 Pingresp = 13,
83 Disconnect = 14,
84
85 #[cfg(feature = "v5")]
86 Auth = 15,
87}
88
89impl core::fmt::Debug for PacketType {
90 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91 match self {
92 Self::Connect => write!(f, "CONNECT"),
93 Self::Connack => write!(f, "CONNACK"),
94 Self::Publish => write!(f, "PUBLISH"),
95 Self::Puback => write!(f, "PUBACK"),
96 Self::Pubrec => write!(f, "PUBREC"),
97 Self::Pubrel => write!(f, "PUBREL"),
98 Self::Pubcomp => write!(f, "PUBCOMP"),
99 Self::Subscribe => write!(f, "SUBSCRIBE"),
100 Self::Suback => write!(f, "SUBACK"),
101 Self::Unsubscribe => write!(f, "UNSUBSCRIBE"),
102 Self::Unsuback => write!(f, "UNSUBACK"),
103 Self::Pingreq => write!(f, "PINGREQ"),
104 Self::Pingresp => write!(f, "PINGRESP"),
105 Self::Disconnect => write!(f, "DISCONNECT"),
106
107 #[cfg(feature = "v5")]
108 Self::Auth => write!(f, "AUTH"),
109 }
110 }
111}
112
113#[cfg(feature = "defmt")]
114impl defmt::Format for PacketType {
115 fn format(&self, fmt: defmt::Formatter) {
116 match self {
117 Self::Connect => defmt::write!(fmt, "CONNECT"),
118 Self::Connack => defmt::write!(fmt, "CONNACK"),
119 Self::Publish => defmt::write!(fmt, "PUBLISH"),
120 Self::Puback => defmt::write!(fmt, "PUBACK"),
121 Self::Pubrec => defmt::write!(fmt, "PUBREC"),
122 Self::Pubrel => defmt::write!(fmt, "PUBREL"),
123 Self::Pubcomp => defmt::write!(fmt, "PUBCOMP"),
124 Self::Subscribe => defmt::write!(fmt, "SUBSCRIBE"),
125 Self::Suback => defmt::write!(fmt, "SUBACK"),
126 Self::Unsubscribe => defmt::write!(fmt, "UNSUBSCRIBE"),
127 Self::Unsuback => defmt::write!(fmt, "UNSUBACK"),
128 Self::Pingreq => defmt::write!(fmt, "PINGREQ"),
129 Self::Pingresp => defmt::write!(fmt, "PINGRESP"),
130 Self::Disconnect => defmt::write!(fmt, "DISCONNECT"),
131
132 #[cfg(feature = "v5")]
133 Self::Auth => defmt::write!(fmt, "AUTH"),
134 }
135 }
136}
137
138impl PacketType {
139 pub(crate) fn from_type_and_flags(type_and_flags: u8) -> Result<Self, Reserved> {
140 match type_and_flags >> 4 {
141 0 => Err(Reserved),
142 1 => Ok(PacketType::Connect),
143 2 => Ok(PacketType::Connack),
144 3 => Ok(PacketType::Publish),
145 4 => Ok(PacketType::Puback),
146 5 => Ok(PacketType::Pubrec),
147 6 => Ok(PacketType::Pubrel),
148 7 => Ok(PacketType::Pubcomp),
149 8 => Ok(PacketType::Subscribe),
150 9 => Ok(PacketType::Suback),
151 10 => Ok(PacketType::Unsubscribe),
152 11 => Ok(PacketType::Unsuback),
153 12 => Ok(PacketType::Pingreq),
154 13 => Ok(PacketType::Pingresp),
155 14 => Ok(PacketType::Disconnect),
156
157 #[cfg(feature = "v3")]
158 15 => Err(Reserved),
159
160 #[cfg(feature = "v5")]
161 15 => Ok(PacketType::Auth),
162
163 0x10.. => unreachable!("u8 shifted 4 bits: all values 0x0..=0xF are covered"),
164 }
165 }
166}