mqtt_protocol_core/mqtt/packet/
enum_packet.rs

1/**
2 * MIT License
3 *
4 * Copyright (c) 2025 Takatoshi Kondo
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24use crate::mqtt::packet::v3_1_1;
25use crate::mqtt::packet::v5_0;
26use crate::mqtt::packet::IsPacketId;
27use crate::mqtt::packet::PacketType;
28use crate::mqtt::Version;
29use alloc::vec::Vec;
30use enum_dispatch::enum_dispatch;
31use serde::Serialize;
32#[cfg(feature = "std")]
33use std::io::IoSlice;
34
35#[enum_dispatch]
36pub trait GenericPacketTrait {
37    fn size(&self) -> usize;
38
39    /// Create a continuous buffer containing the complete packet data
40    ///
41    /// Returns a vector containing all packet bytes in a single continuous buffer.
42    /// This method is compatible with no-std environments.
43    ///
44    /// The returned buffer contains the complete packet serialized according
45    /// to the MQTT protocol specification.
46    ///
47    /// # Returns
48    ///
49    /// A vector containing the complete packet data
50    fn to_continuous_buffer(&self) -> Vec<u8>;
51
52    #[cfg(feature = "std")]
53    fn to_buffers(&self) -> Vec<IoSlice<'_>>;
54}
55
56#[enum_dispatch]
57pub trait GenericPacketDisplay {
58    fn fmt_debug(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
59    fn fmt_display(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
60}
61
62#[enum_dispatch(GenericPacketTrait, GenericPacketDisplay)]
63#[derive(Serialize, Clone, PartialEq, Eq)]
64pub enum GenericPacket<PacketIdType>
65where
66    PacketIdType: IsPacketId + Serialize,
67{
68    V3_1_1Connect(v3_1_1::Connect),
69    V3_1_1Connack(v3_1_1::Connack),
70    V3_1_1Subscribe(v3_1_1::GenericSubscribe<PacketIdType>),
71    V3_1_1Suback(v3_1_1::GenericSuback<PacketIdType>),
72    V3_1_1Unsubscribe(v3_1_1::GenericUnsubscribe<PacketIdType>),
73    V3_1_1Unsuback(v3_1_1::GenericUnsuback<PacketIdType>),
74    V3_1_1Publish(v3_1_1::GenericPublish<PacketIdType>),
75    V3_1_1Puback(v3_1_1::GenericPuback<PacketIdType>),
76    V3_1_1Pubrec(v3_1_1::GenericPubrec<PacketIdType>),
77    V3_1_1Pubrel(v3_1_1::GenericPubrel<PacketIdType>),
78    V3_1_1Pubcomp(v3_1_1::GenericPubcomp<PacketIdType>),
79    V3_1_1Disconnect(v3_1_1::Disconnect),
80    V3_1_1Pingreq(v3_1_1::Pingreq),
81    V3_1_1Pingresp(v3_1_1::Pingresp),
82
83    V5_0Connect(v5_0::Connect),
84    V5_0Connack(v5_0::Connack),
85    V5_0Subscribe(v5_0::GenericSubscribe<PacketIdType>),
86    V5_0Suback(v5_0::GenericSuback<PacketIdType>),
87    V5_0Unsubscribe(v5_0::GenericUnsubscribe<PacketIdType>),
88    V5_0Unsuback(v5_0::GenericUnsuback<PacketIdType>),
89    V5_0Publish(v5_0::GenericPublish<PacketIdType>),
90    V5_0Puback(v5_0::GenericPuback<PacketIdType>),
91    V5_0Pubrec(v5_0::GenericPubrec<PacketIdType>),
92    V5_0Pubrel(v5_0::GenericPubrel<PacketIdType>),
93    V5_0Pubcomp(v5_0::GenericPubcomp<PacketIdType>),
94    V5_0Disconnect(v5_0::Disconnect),
95    V5_0Pingreq(v5_0::Pingreq),
96    V5_0Pingresp(v5_0::Pingresp),
97    V5_0Auth(v5_0::Auth),
98}
99
100// Type alias for commonly used u16 PacketIdType
101pub type Packet = GenericPacket<u16>;
102
103impl<PacketIdType> core::fmt::Debug for GenericPacket<PacketIdType>
104where
105    PacketIdType: IsPacketId + Serialize,
106{
107    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108        self.fmt_debug(f)
109    }
110}
111
112impl<PacketIdType> core::fmt::Display for GenericPacket<PacketIdType>
113where
114    PacketIdType: IsPacketId + Serialize,
115{
116    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
117        self.fmt_display(f)
118    }
119}
120
121impl<PacketIdType> GenericPacket<PacketIdType>
122where
123    PacketIdType: IsPacketId + Serialize,
124{
125    /// Get the packet type
126    pub fn packet_type(&self) -> PacketType {
127        match self {
128            GenericPacket::V3_1_1Connect(_) => PacketType::Connect,
129            GenericPacket::V3_1_1Connack(_) => PacketType::Connack,
130            GenericPacket::V3_1_1Subscribe(_) => PacketType::Subscribe,
131            GenericPacket::V3_1_1Suback(_) => PacketType::Suback,
132            GenericPacket::V3_1_1Unsubscribe(_) => PacketType::Unsubscribe,
133            GenericPacket::V3_1_1Unsuback(_) => PacketType::Unsuback,
134            GenericPacket::V3_1_1Publish(_) => PacketType::Publish,
135            GenericPacket::V3_1_1Puback(_) => PacketType::Puback,
136            GenericPacket::V3_1_1Pubrec(_) => PacketType::Pubrec,
137            GenericPacket::V3_1_1Pubrel(_) => PacketType::Pubrel,
138            GenericPacket::V3_1_1Pubcomp(_) => PacketType::Pubcomp,
139            GenericPacket::V3_1_1Disconnect(_) => PacketType::Disconnect,
140            GenericPacket::V3_1_1Pingreq(_) => PacketType::Pingreq,
141            GenericPacket::V3_1_1Pingresp(_) => PacketType::Pingresp,
142
143            GenericPacket::V5_0Connect(_) => PacketType::Connect,
144            GenericPacket::V5_0Connack(_) => PacketType::Connack,
145            GenericPacket::V5_0Subscribe(_) => PacketType::Subscribe,
146            GenericPacket::V5_0Suback(_) => PacketType::Suback,
147            GenericPacket::V5_0Unsubscribe(_) => PacketType::Unsubscribe,
148            GenericPacket::V5_0Unsuback(_) => PacketType::Unsuback,
149            GenericPacket::V5_0Publish(_) => PacketType::Publish,
150            GenericPacket::V5_0Puback(_) => PacketType::Puback,
151            GenericPacket::V5_0Pubrec(_) => PacketType::Pubrec,
152            GenericPacket::V5_0Pubrel(_) => PacketType::Pubrel,
153            GenericPacket::V5_0Pubcomp(_) => PacketType::Pubcomp,
154            GenericPacket::V5_0Disconnect(_) => PacketType::Disconnect,
155            GenericPacket::V5_0Pingreq(_) => PacketType::Pingreq,
156            GenericPacket::V5_0Pingresp(_) => PacketType::Pingresp,
157            GenericPacket::V5_0Auth(_) => PacketType::Auth,
158        }
159    }
160
161    /// Get the MQTT protocol version of this packet
162    pub fn protocol_version(&self) -> Version {
163        match self {
164            GenericPacket::V3_1_1Connect(_) => Version::V3_1_1,
165            GenericPacket::V3_1_1Connack(_) => Version::V3_1_1,
166            GenericPacket::V3_1_1Subscribe(_) => Version::V3_1_1,
167            GenericPacket::V3_1_1Suback(_) => Version::V3_1_1,
168            GenericPacket::V3_1_1Unsubscribe(_) => Version::V3_1_1,
169            GenericPacket::V3_1_1Unsuback(_) => Version::V3_1_1,
170            GenericPacket::V3_1_1Publish(_) => Version::V3_1_1,
171            GenericPacket::V3_1_1Puback(_) => Version::V3_1_1,
172            GenericPacket::V3_1_1Pubrec(_) => Version::V3_1_1,
173            GenericPacket::V3_1_1Pubrel(_) => Version::V3_1_1,
174            GenericPacket::V3_1_1Pubcomp(_) => Version::V3_1_1,
175            GenericPacket::V3_1_1Disconnect(_) => Version::V3_1_1,
176            GenericPacket::V3_1_1Pingreq(_) => Version::V3_1_1,
177            GenericPacket::V3_1_1Pingresp(_) => Version::V3_1_1,
178
179            GenericPacket::V5_0Connect(_) => Version::V5_0,
180            GenericPacket::V5_0Connack(_) => Version::V5_0,
181            GenericPacket::V5_0Subscribe(_) => Version::V5_0,
182            GenericPacket::V5_0Suback(_) => Version::V5_0,
183            GenericPacket::V5_0Unsubscribe(_) => Version::V5_0,
184            GenericPacket::V5_0Unsuback(_) => Version::V5_0,
185            GenericPacket::V5_0Publish(_) => Version::V5_0,
186            GenericPacket::V5_0Puback(_) => Version::V5_0,
187            GenericPacket::V5_0Pubrec(_) => Version::V5_0,
188            GenericPacket::V5_0Pubrel(_) => Version::V5_0,
189            GenericPacket::V5_0Pubcomp(_) => Version::V5_0,
190            GenericPacket::V5_0Disconnect(_) => Version::V5_0,
191            GenericPacket::V5_0Pingreq(_) => Version::V5_0,
192            GenericPacket::V5_0Pingresp(_) => Version::V5_0,
193            GenericPacket::V5_0Auth(_) => Version::V5_0,
194        }
195    }
196}