mqttrs/
encoder.rs

1use crate::{Error, Packet};
2
3/// Encode a [Packet] enum into a [BufMut] buffer.
4///
5/// ```
6/// # use mqttrs::*;
7/// # use bytes::*;
8/// // Instantiate a `Packet` to encode.
9/// let packet = Publish {
10///    dup: false,
11///    qospid: QosPid::AtMostOnce,
12///    retain: false,
13///    topic_name: "test",
14///    payload: b"hello",
15/// }.into();
16///
17/// // Allocate buffer (should be appropriately-sized or able to grow as needed).
18/// let mut buf = [0u8; 1024];
19///
20/// // Write bytes corresponding to `&Packet` into the `BytesMut`.
21/// let len = encode_slice(&packet, &mut buf).expect("failed encoding");
22/// assert_eq!(&buf[..len], &[0b00110000, 11,
23///                     0, 4, 't' as u8, 'e' as u8, 's' as u8, 't' as u8,
24///                    'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8]);
25/// ```
26///
27/// [Packet]: ../enum.Packet.html
28/// [BufMut]: https://docs.rs/bytes/1.0.0/bytes/trait.BufMut.html
29// #[cfg(feature = "std")]
30// pub fn encode_slice(packet: &Packet, buf: impl BufMut) -> Result<usize, Error> {
31//     let mut offset = 0;
32//     encode_slice(packet, buf.bytes_mut(), &mut offset)
33// }
34
35pub fn encode_slice(packet: &Packet, buf: &mut [u8]) -> Result<usize, Error> {
36    let mut offset = 0;
37
38    match packet {
39        Packet::Connect(connect) => connect.to_buffer(buf, &mut offset),
40        Packet::Connack(connack) => connack.to_buffer(buf, &mut offset),
41        Packet::Publish(publish) => publish.to_buffer(buf, &mut offset),
42        Packet::Puback(pid) => {
43            check_remaining(buf, &mut offset, 4)?;
44            let header: u8 = 0b01000000;
45            let length: u8 = 2;
46            write_u8(buf, &mut offset, header)?;
47            write_u8(buf, &mut offset, length)?;
48            pid.to_buffer(buf, &mut offset)?;
49            Ok(4)
50        }
51        Packet::Pubrec(pid) => {
52            check_remaining(buf, &mut offset, 4)?;
53            let header: u8 = 0b01010000;
54            let length: u8 = 2;
55            write_u8(buf, &mut offset, header)?;
56            write_u8(buf, &mut offset, length)?;
57            pid.to_buffer(buf, &mut offset)?;
58            Ok(4)
59        }
60        Packet::Pubrel(pid) => {
61            check_remaining(buf, &mut offset, 4)?;
62            let header: u8 = 0b01100010;
63            let length: u8 = 2;
64            write_u8(buf, &mut offset, header)?;
65            write_u8(buf, &mut offset, length)?;
66            pid.to_buffer(buf, &mut offset)?;
67            Ok(4)
68        }
69        Packet::Pubcomp(pid) => {
70            check_remaining(buf, &mut offset, 4)?;
71            let header: u8 = 0b01110000;
72            let length: u8 = 2;
73            write_u8(buf, &mut offset, header)?;
74            write_u8(buf, &mut offset, length)?;
75            pid.to_buffer(buf, &mut offset)?;
76            Ok(4)
77        }
78        Packet::Subscribe(subscribe) => subscribe.to_buffer(buf, &mut offset),
79        Packet::Suback(suback) => suback.to_buffer(buf, &mut offset),
80        Packet::Unsubscribe(unsub) => unsub.to_buffer(buf, &mut offset),
81        Packet::Unsuback(pid) => {
82            check_remaining(buf, &mut offset, 4)?;
83            let header: u8 = 0b10110000;
84            let length: u8 = 2;
85            write_u8(buf, &mut offset, header)?;
86            write_u8(buf, &mut offset, length)?;
87            pid.to_buffer(buf, &mut offset)?;
88            Ok(4)
89        }
90        Packet::Pingreq => {
91            check_remaining(buf, &mut offset, 2)?;
92            let header: u8 = 0b11000000;
93            let length: u8 = 0;
94            write_u8(buf, &mut offset, header)?;
95            write_u8(buf, &mut offset, length)?;
96            Ok(2)
97        }
98        Packet::Pingresp => {
99            check_remaining(buf, &mut offset, 2)?;
100            let header: u8 = 0b11010000;
101            let length: u8 = 0;
102            write_u8(buf, &mut offset, header)?;
103            write_u8(buf, &mut offset, length)?;
104            Ok(2)
105        }
106        Packet::Disconnect => {
107            check_remaining(buf, &mut offset, 2)?;
108            let header: u8 = 0b11100000;
109            let length: u8 = 0;
110            write_u8(buf, &mut offset, header)?;
111            write_u8(buf, &mut offset, length)?;
112            Ok(2)
113        }
114    }
115}
116
117/// Check wether buffer has `len` bytes of write capacity left. Use this to return a clean
118/// Result::Err instead of panicking.
119pub(crate) fn check_remaining(buf: &mut [u8], offset: &mut usize, len: usize) -> Result<(), Error> {
120    if buf[*offset..].len() < len {
121        Err(Error::WriteZero)
122    } else {
123        Ok(())
124    }
125}
126
127/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718023
128pub(crate) fn write_length(buf: &mut [u8], offset: &mut usize, len: usize) -> Result<usize, Error> {
129    let write_len = match len {
130        0..=127 => {
131            check_remaining(buf, offset, len + 1)?;
132            len + 1
133        }
134        128..=16383 => {
135            check_remaining(buf, offset, len + 2)?;
136            len + 2
137        }
138        16384..=2097151 => {
139            check_remaining(buf, offset, len + 3)?;
140            len + 3
141        }
142        2097152..=268435455 => {
143            check_remaining(buf, offset, len + 4)?;
144            len + 4
145        }
146        _ => return Err(Error::InvalidLength),
147    };
148    let mut done = false;
149    let mut x = len;
150    while !done {
151        let mut byte = (x % 128) as u8;
152        x = x / 128;
153        if x > 0 {
154            byte = byte | 128;
155        }
156        write_u8(buf, offset, byte)?;
157        done = x <= 0;
158    }
159    Ok(write_len)
160}
161
162pub(crate) fn write_u8(buf: &mut [u8], offset: &mut usize, val: u8) -> Result<(), Error> {
163    buf[*offset] = val;
164    *offset += 1;
165    Ok(())
166}
167
168pub(crate) fn write_u16(buf: &mut [u8], offset: &mut usize, val: u16) -> Result<(), Error> {
169    write_u8(buf, offset, (val >> 8) as u8)?;
170    write_u8(buf, offset, (val & 0xFF) as u8)
171}
172
173pub(crate) fn write_bytes(buf: &mut [u8], offset: &mut usize, bytes: &[u8]) -> Result<(), Error> {
174    write_u16(buf, offset, bytes.len() as u16)?;
175
176    for &byte in bytes {
177        write_u8(buf, offset, byte)?;
178    }
179    Ok(())
180}
181
182pub(crate) fn write_string(buf: &mut [u8], offset: &mut usize, string: &str) -> Result<(), Error> {
183    write_bytes(buf, offset, string.as_bytes())
184}