Skip to main content

mountain_mqtt/data/
packet_type.rs

1use crate::{error::PacketReadError, packets::publish::is_valid_publish_first_header_byte};
2
3#[derive(Debug, PartialEq)]
4#[repr(u8)]
5pub enum PacketType {
6    /// Connection request
7    /// Client to Server
8    Connect = 1,
9    /// Connect acknowledgment
10    /// Server to Client
11    Connack = 2,
12    /// Publish message
13    /// Client to Server or Server to Client
14    Publish = 3,
15    /// Publish acknowledgment (quality of service 1)
16    /// Client to Server or Server to Client
17    Puback = 4,
18    /// Publish received (quality of service 2 delivery part 1)
19    /// Client to Server or Server to Client
20    Pubrec = 5,
21    /// Publish release (quality of service 2 delivery part 2)
22    /// Client to Server or Server to Client
23    Pubrel = 6,
24    /// Publish complete (quality of service 2 delivery part 3)
25    /// Client to Server or Server to Client
26    Pubcomp = 7,
27    /// Subscribe request
28    /// Client to Server
29    Subscribe = 8,
30    /// Subscribe acknowledgment
31    /// Server to Client
32    Suback = 9,
33    /// Unsubscribe request
34    /// Client to Server
35    Unsubscribe = 10,
36    /// Unsubscribe acknowledgment
37    /// Server to Client
38    Unsuback = 11,
39    /// PING request
40    /// Client to Server
41    Pingreq = 12,
42    /// PING response
43    /// Server to Client
44    Pingresp = 13,
45    /// Disconnect notification
46    /// Client to Server or Server to Client
47    Disconnect = 14,
48    /// Authentication exchange
49    /// Client to Server or Server to Client
50    Auth = 15,
51}
52
53impl PacketType {
54    /// Check whether a u8 value is a valid first header byte of a packet
55    pub fn is_valid_first_header_byte(encoded: u8) -> bool {
56        if let Ok(packet_type) = PacketType::try_from(encoded) {
57            match packet_type {
58                PacketType::Publish => is_valid_publish_first_header_byte(encoded),
59                _ => encoded == packet_type.into(),
60            }
61        } else {
62            false
63        }
64    }
65}
66
67/// Note this only provides the "base" representation, with no
68/// additional flags set for [PacketType::Publish], but does
69/// include the fixed additional bits that some packets require.
70impl From<PacketType> for u8 {
71    fn from(value: PacketType) -> Self {
72        match value {
73            PacketType::Connect => 0x10,
74            PacketType::Connack => 0x20,
75            PacketType::Publish => 0x30,
76            PacketType::Puback => 0x40,
77            PacketType::Pubrec => 0x50,
78            PacketType::Pubrel => 0x62,
79            PacketType::Pubcomp => 0x70,
80            PacketType::Subscribe => 0x82,
81            PacketType::Suback => 0x90,
82            PacketType::Unsubscribe => 0xA2,
83            PacketType::Unsuback => 0xB0,
84            PacketType::Pingreq => 0xC0,
85            PacketType::Pingresp => 0xD0,
86            PacketType::Disconnect => 0xE0,
87            PacketType::Auth => 0xF0,
88        }
89    }
90}
91
92/// Parse the [PacketType] from a [u8], using only the upper 4 bits
93/// and ignoring any additional flags set for [PacketType::Publish]
94impl TryFrom<u8> for PacketType {
95    type Error = PacketReadError;
96
97    fn try_from(value: u8) -> Result<Self, Self::Error> {
98        match value & 0xF0 {
99            0x10 => Ok(PacketType::Connect),
100            0x20 => Ok(PacketType::Connack),
101            0x30 => Ok(PacketType::Publish),
102            0x40 => Ok(PacketType::Puback),
103            0x50 => Ok(PacketType::Pubrec),
104            0x60 => Ok(PacketType::Pubrel),
105            0x70 => Ok(PacketType::Pubcomp),
106            0x80 => Ok(PacketType::Subscribe),
107            0x90 => Ok(PacketType::Suback),
108            0xA0 => Ok(PacketType::Unsubscribe),
109            0xB0 => Ok(PacketType::Unsuback),
110            0xC0 => Ok(PacketType::Pingreq),
111            0xD0 => Ok(PacketType::Pingresp),
112            0xE0 => Ok(PacketType::Disconnect),
113            0xF0 => Ok(PacketType::Auth),
114            _ => Err(PacketReadError::InvalidPacketType),
115        }
116    }
117}