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}