mqtt4bytes/packets/
suback.rs

1use super::*;
2use crate::*;
3use alloc::vec::Vec;
4use bytes::{Buf, BufMut, Bytes, BytesMut};
5
6/// Acknowledgement to subscribe
7#[derive(Debug, Clone, PartialEq)]
8pub struct SubAck {
9    pub pkid: u16,
10    pub return_codes: Vec<SubscribeReturnCodes>,
11}
12
13impl SubAck {
14    pub fn new(pkid: u16, return_codes: Vec<SubscribeReturnCodes>) -> SubAck {
15        SubAck { pkid, return_codes }
16    }
17
18    pub(crate) fn assemble(fixed_header: FixedHeader, mut bytes: Bytes) -> Result<Self, Error> {
19        let variable_header_index = fixed_header.fixed_len;
20        bytes.advance(variable_header_index);
21
22        let pkid = bytes.get_u16();
23        let mut payload_bytes = fixed_header.remaining_len - 2;
24        let mut return_codes = Vec::with_capacity(payload_bytes);
25
26        while payload_bytes > 0 {
27            let return_code = bytes.get_u8();
28            if return_code >> 7 == 1 {
29                return_codes.push(SubscribeReturnCodes::Failure)
30            } else {
31                return_codes.push(SubscribeReturnCodes::Success(qos(return_code & 0x3)?));
32            }
33            payload_bytes -= 1
34        }
35        let suback = SubAck { pkid, return_codes };
36
37        Ok(suback)
38    }
39
40    pub fn write(&self, payload: &mut BytesMut) -> Result<usize, Error> {
41        payload.put_u8(0x90);
42        let remaining_len = self.return_codes.len() + 2;
43        let remaining_len_bytes = write_remaining_length(payload, remaining_len)?;
44        payload.put_u16(self.pkid);
45        let p: Vec<u8> = self
46            .return_codes
47            .iter()
48            .map(|&code| match code {
49                SubscribeReturnCodes::Success(qos) => qos as u8,
50                SubscribeReturnCodes::Failure => 0x80,
51            })
52            .collect();
53
54        payload.extend_from_slice(&p);
55        Ok(1 + remaining_len_bytes + remaining_len)
56    }
57}
58
59/// Subscription return code
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum SubscribeReturnCodes {
62    Success(QoS),
63    Failure,
64}
65
66#[cfg(test)]
67mod test {
68    use super::*;
69    use alloc::vec;
70    use bytes::BytesMut;
71    use pretty_assertions::assert_eq;
72
73    #[test]
74    fn suback_stitching_works_correctly() {
75        let stream = vec![
76            0x90, 4, // packet type, flags and remaining len
77            0x00, 0x0F, // variable header. pkid = 15
78            0x01, 0x80, // payload. return codes [success qos1, failure]
79            0xDE, 0xAD, 0xBE, 0xEF, // extra packets in the stream
80        ];
81        let mut stream = BytesMut::from(&stream[..]);
82
83        let packet = mqtt_read(&mut stream, 100).unwrap();
84        let packet = match packet {
85            Packet::SubAck(packet) => packet,
86            packet => panic!("Invalid packet = {:?}", packet),
87        };
88
89        assert_eq!(
90            packet,
91            SubAck {
92                pkid: 15,
93                return_codes: vec![
94                    SubscribeReturnCodes::Success(QoS::AtLeastOnce),
95                    SubscribeReturnCodes::Failure
96                ]
97            }
98        );
99    }
100}