use crate::{
eio::Write,
fmt::unreachable,
io::{
err::WriteError,
write::{Writable, wlen},
},
types::VarByteInt,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FixedHeader {
pub(crate) type_and_flags: u8,
pub(crate) remaining_len: VarByteInt,
}
impl Writable for FixedHeader {
fn written_len(&self) -> usize {
wlen!(u8) + self.remaining_len.written_len()
}
async fn write<W: Write>(&self, write: &mut W) -> Result<(), WriteError<W::Error>> {
self.type_and_flags.write(write).await?;
self.remaining_len.write(write).await?;
Ok(())
}
}
impl FixedHeader {
pub(crate) fn new(packet_type: PacketType, flags: u8, remaining_len: VarByteInt) -> Self {
let packet_type = (packet_type as u8) << 4;
Self {
type_and_flags: packet_type | flags,
remaining_len,
}
}
#[must_use]
pub fn flags(&self) -> u8 {
self.type_and_flags & 0x0F
}
pub fn packet_type(&self) -> Result<PacketType, Reserved> {
PacketType::from_type_and_flags(self.type_and_flags)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Reserved;
#[allow(missing_docs)]
#[derive(PartialEq, Eq)]
pub enum PacketType {
Connect = 1,
Connack = 2,
Publish = 3,
Puback = 4,
Pubrec = 5,
Pubrel = 6,
Pubcomp = 7,
Subscribe = 8,
Suback = 9,
Unsubscribe = 10,
Unsuback = 11,
Pingreq = 12,
Pingresp = 13,
Disconnect = 14,
#[cfg(feature = "v5")]
Auth = 15,
}
impl core::fmt::Debug for PacketType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Connect => write!(f, "CONNECT"),
Self::Connack => write!(f, "CONNACK"),
Self::Publish => write!(f, "PUBLISH"),
Self::Puback => write!(f, "PUBACK"),
Self::Pubrec => write!(f, "PUBREC"),
Self::Pubrel => write!(f, "PUBREL"),
Self::Pubcomp => write!(f, "PUBCOMP"),
Self::Subscribe => write!(f, "SUBSCRIBE"),
Self::Suback => write!(f, "SUBACK"),
Self::Unsubscribe => write!(f, "UNSUBSCRIBE"),
Self::Unsuback => write!(f, "UNSUBACK"),
Self::Pingreq => write!(f, "PINGREQ"),
Self::Pingresp => write!(f, "PINGRESP"),
Self::Disconnect => write!(f, "DISCONNECT"),
#[cfg(feature = "v5")]
Self::Auth => write!(f, "AUTH"),
}
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for PacketType {
fn format(&self, fmt: defmt::Formatter) {
match self {
Self::Connect => defmt::write!(fmt, "CONNECT"),
Self::Connack => defmt::write!(fmt, "CONNACK"),
Self::Publish => defmt::write!(fmt, "PUBLISH"),
Self::Puback => defmt::write!(fmt, "PUBACK"),
Self::Pubrec => defmt::write!(fmt, "PUBREC"),
Self::Pubrel => defmt::write!(fmt, "PUBREL"),
Self::Pubcomp => defmt::write!(fmt, "PUBCOMP"),
Self::Subscribe => defmt::write!(fmt, "SUBSCRIBE"),
Self::Suback => defmt::write!(fmt, "SUBACK"),
Self::Unsubscribe => defmt::write!(fmt, "UNSUBSCRIBE"),
Self::Unsuback => defmt::write!(fmt, "UNSUBACK"),
Self::Pingreq => defmt::write!(fmt, "PINGREQ"),
Self::Pingresp => defmt::write!(fmt, "PINGRESP"),
Self::Disconnect => defmt::write!(fmt, "DISCONNECT"),
#[cfg(feature = "v5")]
Self::Auth => defmt::write!(fmt, "AUTH"),
}
}
}
impl PacketType {
pub(crate) fn from_type_and_flags(type_and_flags: u8) -> Result<Self, Reserved> {
match type_and_flags >> 4 {
0 => Err(Reserved),
1 => Ok(PacketType::Connect),
2 => Ok(PacketType::Connack),
3 => Ok(PacketType::Publish),
4 => Ok(PacketType::Puback),
5 => Ok(PacketType::Pubrec),
6 => Ok(PacketType::Pubrel),
7 => Ok(PacketType::Pubcomp),
8 => Ok(PacketType::Subscribe),
9 => Ok(PacketType::Suback),
10 => Ok(PacketType::Unsubscribe),
11 => Ok(PacketType::Unsuback),
12 => Ok(PacketType::Pingreq),
13 => Ok(PacketType::Pingresp),
14 => Ok(PacketType::Disconnect),
#[cfg(feature = "v3")]
15 => Err(Reserved),
#[cfg(feature = "v5")]
15 => Ok(PacketType::Auth),
0x10.. => unreachable!("u8 shifted 4 bits: all values 0x0..=0xF are covered"),
}
}
}