mqtt4bytes/
lib.rs

1//! This is a low level (no_std) crate with the ability to assemble and disassemble MQTT 3.1.1
2//! packets and is used by both client and broker. Uses 'bytes' crate internally
3#![no_std]
4
5extern crate alloc;
6
7mod packets;
8mod read;
9mod topic;
10
11use bytes::Buf;
12use core::fmt;
13use core::fmt::{Display, Formatter};
14pub use packets::*;
15pub use read::*;
16pub use topic::*;
17
18/// Serialization/Deserialization errors
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum Error {
21    InvalidConnectReturnCode(u8),
22    InvalidProtocol,
23    InvalidProtocolLevel(u8),
24    IncorrectPacketFormat,
25    InvalidPacketType(u8),
26    InvalidQoS(u8),
27    PacketIdZero,
28    PayloadSizeIncorrect,
29    PayloadTooLong,
30    PayloadSizeLimitExceeded,
31    PayloadRequired,
32    TopicNotUtf8,
33    BoundaryCrossed,
34    MalformedRemainingLength,
35    InsufficientBytes(usize),
36}
37
38/// Encapsulates all MQTT packet types
39#[derive(Debug, Clone, PartialEq)]
40pub enum Packet {
41    Connect(Connect),
42    ConnAck(ConnAck),
43    Publish(Publish),
44    PubAck(PubAck),
45    PubRec(PubRec),
46    PubRel(PubRel),
47    PubComp(PubComp),
48    Subscribe(Subscribe),
49    SubAck(SubAck),
50    Unsubscribe(Unsubscribe),
51    UnsubAck(UnsubAck),
52    PingReq,
53    PingResp,
54    Disconnect,
55}
56
57/// MQTT packet type
58#[repr(u8)]
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum PacketType {
61    Connect = 1,
62    ConnAck,
63    Publish,
64    PubAck,
65    PubRec,
66    PubRel,
67    PubComp,
68    Subscribe,
69    SubAck,
70    Unsubscribe,
71    UnsubAck,
72    PingReq,
73    PingResp,
74    Disconnect,
75}
76
77/// Protocol type
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum Protocol {
80    MQTT(u8),
81}
82
83/// Quality of service
84#[repr(u8)]
85#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
86pub enum QoS {
87    AtMostOnce = 0,
88    AtLeastOnce = 1,
89    ExactlyOnce = 2,
90}
91
92/// Packet type from a byte
93///
94/// ```ignore
95///          7                          3                          0
96///          +--------------------------+--------------------------+
97/// byte 1   | MQTT Control Packet Type | Flags for each type      |
98///          +--------------------------+--------------------------+
99///          |         Remaining Bytes Len  (1/2/3/4 bytes)        |
100///          +-----------------------------------------------------+
101///
102/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Figure_2.2_-
103/// ```
104pub struct FixedHeader {
105    /// First byte of the stream. Used to identify packet types and
106    /// several flags
107    byte1: u8,
108    /// Length of fixed header. Byte 1 + (1..4) bytes. So fixed header
109    /// len can vary from 2 bytes to 5 bytes
110    /// 1..4 bytes are variable length encoded to represent remaining length
111    fixed_len: usize,
112    /// Remaining length of the packet. Doesn't include fixed header bytes
113    /// Represents variable header + payload size
114    remaining_len: usize,
115}
116
117impl FixedHeader {
118    pub fn new(byte1: u8, remaining_len_len: usize, remaining_len: usize) -> FixedHeader {
119        FixedHeader {
120            byte1,
121            fixed_len: remaining_len_len + 1,
122            remaining_len,
123        }
124    }
125
126    pub fn packet_type(&self) -> Result<PacketType, Error> {
127        let num = self.byte1 >> 4;
128        match num {
129            1 => Ok(PacketType::Connect),
130            2 => Ok(PacketType::ConnAck),
131            3 => Ok(PacketType::Publish),
132            4 => Ok(PacketType::PubAck),
133            5 => Ok(PacketType::PubRec),
134            6 => Ok(PacketType::PubRel),
135            7 => Ok(PacketType::PubComp),
136            8 => Ok(PacketType::Subscribe),
137            9 => Ok(PacketType::SubAck),
138            10 => Ok(PacketType::Unsubscribe),
139            11 => Ok(PacketType::UnsubAck),
140            12 => Ok(PacketType::PingReq),
141            13 => Ok(PacketType::PingResp),
142            14 => Ok(PacketType::Disconnect),
143            _ => Err(Error::InvalidPacketType(num)),
144        }
145    }
146
147    /// Returns the size of full packet (fixed header + variable header + payload)
148    /// Fixed header is enough to get the size of a frame in the stream
149    pub fn frame_length(&self) -> usize {
150        self.fixed_len + self.remaining_len
151    }
152}
153
154/// Maps a number to QoS
155pub fn qos(num: u8) -> Result<QoS, Error> {
156    match num {
157        0 => Ok(QoS::AtMostOnce),
158        1 => Ok(QoS::AtLeastOnce),
159        2 => Ok(QoS::ExactlyOnce),
160        qos => Err(Error::InvalidQoS(qos)),
161    }
162}
163
164impl Display for Error {
165    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
166        write!(f, "Error = {:?}", self)
167    }
168}