mqtt_tiny/packets/
connack.rs

1//! MQTT [`CONNACK`](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033)
2
3use crate::coding::encoder::{PacketLenIter, U8Iter, Unit};
4use crate::coding::{Decoder, Encoder};
5use crate::err;
6use crate::error::{Data, DecoderError};
7use crate::packets::TryFromIterator;
8use core::iter::Chain;
9
10/// An MQTT [`CONNACK` packet](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033)
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct Connack {
13    /// Whether a previous session is present or not
14    session_present: bool,
15    /// The return code
16    return_code: u8,
17}
18impl Connack {
19    /// The packet type constant
20    pub const TYPE: u8 = 2;
21
22    /// The expected body length
23    const BODY_LEN: usize = 2;
24
25    /// Creates a new packet
26    pub const fn new(session_present: bool, return_code: u8) -> Self {
27        Self { session_present, return_code }
28    }
29
30    /// Whether a previous session is present or not
31    pub const fn session_present(&self) -> bool {
32        self.session_present
33    }
34    /// The return code
35    pub const fn return_code(&self) -> u8 {
36        self.return_code
37    }
38}
39impl TryFromIterator for Connack {
40    fn try_from_iter<T>(iter: T) -> Result<Self, DecoderError>
41    where
42        T: IntoIterator<Item = u8>,
43    {
44        // Read packet:
45        //  - header type and `0` flags
46        //  - packet len
47        //  - ACK flags
48        //  - return code
49        let mut decoder = Decoder::new(iter);
50        let (Self::TYPE, _flags) = decoder.header()? else {
51            return Err(err!(Data::SpecViolation, "invalid packet type"))?;
52        };
53        let Self::BODY_LEN = decoder.packetlen()? else {
54            return Err(err!(Data::SpecViolation, "invalid packet length"))?;
55        };
56
57        // Read fields
58        let [_, _, _, _, _, _, _, session_present] = decoder.bitmap()?;
59        let return_code = decoder.u8()?;
60
61        // Init self
62        Ok(Self { session_present, return_code })
63    }
64}
65impl IntoIterator for Connack {
66    type Item = u8;
67    #[rustfmt::skip]
68    type IntoIter =
69        // Complex iterator built out of the individual message fields
70        Chain<Chain<Chain<Chain<
71            // - header type and `0` flags
72            Unit, U8Iter>,
73            // - packet len
74            PacketLenIter>,
75            // - ACK flags
76            U8Iter>,
77            // - return code
78            U8Iter>;
79
80    fn into_iter(self) -> Self::IntoIter {
81        // Write packet:
82        //  - header type and `0` flags
83        //  - packet len
84        //  - ACK flags
85        //  - return code
86        Encoder::default()
87            .header(Self::TYPE, [false, false, false, false])
88            .packetlen(Self::BODY_LEN)
89            .bitmap([false, false, false, false, false, false, false, self.session_present])
90            .u8(self.return_code)
91            .into_iter()
92    }
93}