mqttrust/encoding/v4/
packet.rs

1use super::*;
2
3/// https://docs.solace.com/MQTT-311-Prtl-Conformance-Spec/MQTT%20Control%20Packets.htm#_Toc430864901
4const FIXED_HEADER_LEN: usize = 5;
5const PID_LEN: usize = 2;
6
7/// Base enum for all MQTT packet types.
8///
9/// This is the main type you'll be interacting with, as an output of [`decode_slice()`] and an input of
10/// [`encode()`]. Most variants can be constructed directly without using methods.
11///
12/// ```
13/// # use mqttrust::encoding::v4::*;
14/// # use core::convert::TryFrom;
15/// // Simplest form
16/// let pkt = Packet::Connack(Connack { session_present: false,
17///                                     code: ConnectReturnCode::Accepted });
18/// // Using `Into` trait
19/// let publish = Publish { dup: false,
20///                         qos: QoS::AtMostOnce,
21///                         retain: false,
22///                         pid: None,
23///                         topic_name: "to/pic",
24///                         payload: b"payload" };
25/// let pkt: Packet = publish.into();
26/// // Identifyer-only packets
27/// let pkt = Packet::Puback(Pid::try_from(42).unwrap());
28/// ```
29///
30/// [`encode()`]: fn.encode.html
31/// [`decode_slice()`]: fn.decode_slice.html
32#[derive(Debug, Clone, PartialEq)]
33pub enum Packet<'a> {
34    /// [MQTT 3.1](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028)
35    Connect(Connect<'a>),
36    /// [MQTT 3.2](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033)
37    Connack(Connack),
38    /// [MQTT 3.3](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037)
39    Publish(Publish<'a>),
40    /// [MQTT 3.4](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043)
41    Puback(Pid),
42    /// [MQTT 3.5](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718048)
43    Pubrec(Pid),
44    /// [MQTT 3.6](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053)
45    Pubrel(Pid),
46    /// [MQTT 3.7](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718058)
47    Pubcomp(Pid),
48    /// [MQTT 3.8](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718063)
49    Subscribe(Subscribe<'a>),
50    /// [MQTT 3.9](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718068)
51    Suback(Suback<'a>),
52    /// [MQTT 3.10](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718072)
53    Unsubscribe(Unsubscribe<'a>),
54    /// [MQTT 3.11](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718077)
55    Unsuback(Pid),
56    /// [MQTT 3.12](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718081)
57    Pingreq,
58    /// [MQTT 3.13](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718086)
59    Pingresp,
60    /// [MQTT 3.14](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718090)
61    Disconnect,
62}
63
64impl<'a> Packet<'a> {
65    /// Return the packet type variant.
66    ///
67    /// This can be used for matching, categorising, debuging, etc. Most users will match directly
68    /// on `Packet` instead.
69    pub fn get_type(&self) -> PacketType {
70        match self {
71            Packet::Connect(_) => PacketType::Connect,
72            Packet::Connack(_) => PacketType::Connack,
73            Packet::Publish(_) => PacketType::Publish,
74            Packet::Puback(_) => PacketType::Puback,
75            Packet::Pubrec(_) => PacketType::Pubrec,
76            Packet::Pubrel(_) => PacketType::Pubrel,
77            Packet::Pubcomp(_) => PacketType::Pubcomp,
78            Packet::Subscribe(_) => PacketType::Subscribe,
79            Packet::Suback(_) => PacketType::Suback,
80            Packet::Unsubscribe(_) => PacketType::Unsubscribe,
81            Packet::Unsuback(_) => PacketType::Unsuback,
82            Packet::Pingreq => PacketType::Pingreq,
83            Packet::Pingresp => PacketType::Pingresp,
84            Packet::Disconnect => PacketType::Disconnect,
85        }
86    }
87
88    pub fn len(&self) -> usize {
89        let variable_len = match self {
90            Packet::Connect(c) => c.len(),
91            Packet::Connack(_) => 2,
92            Packet::Publish(p) => p.len(),
93            Packet::Puback(_)
94            | Packet::Pubrec(_)
95            | Packet::Pubrel(_)
96            | Packet::Pubcomp(_)
97            | Packet::Unsuback(_) => PID_LEN,
98            Packet::Suback(_) => PID_LEN + 1,
99            Packet::Subscribe(s) => s.len(),
100            Packet::Unsubscribe(u) => u.len(),
101            Packet::Pingreq | Packet::Pingresp | Packet::Disconnect => 0,
102        };
103
104        FIXED_HEADER_LEN + variable_len
105    }
106}
107
108macro_rules! packet_from_borrowed {
109    ($($t:ident),+) => {
110        $(
111            impl<'a> From<$t<'a>> for Packet<'a> {
112                fn from(p: $t<'a>) -> Self {
113                    Packet::$t(p)
114                }
115            }
116        )+
117    }
118}
119macro_rules! packet_from {
120    ($($t:ident),+) => {
121        $(
122            impl<'a> From<$t> for Packet<'a> {
123                fn from(p: $t) -> Self {
124                    Packet::$t(p)
125                }
126            }
127        )+
128    }
129}
130
131packet_from_borrowed!(Suback, Connect, Publish, Subscribe, Unsubscribe);
132packet_from!(Connack);
133
134/// Packet type variant, without the associated data.
135#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
136#[cfg_attr(feature = "defmt-impl", derive(defmt::Format))]
137pub enum PacketType {
138    Connect,
139    Connack,
140    Publish,
141    Puback,
142    Pubrec,
143    Pubrel,
144    Pubcomp,
145    Subscribe,
146    Suback,
147    Unsubscribe,
148    Unsuback,
149    Pingreq,
150    Pingresp,
151    Disconnect,
152}