embedded_mqtt/variable_header/
connack.rs

1use core::{
2    fmt::Debug,
3    convert::{TryFrom, TryInto},
4    result::Result,
5};
6
7use crate::{
8    fixed_header::PacketFlags,
9    codec::{self, Encodable},
10    status::Status,
11    error::{DecodeError, EncodeError},
12};
13
14use super::HeaderDecode;
15
16#[derive(PartialEq, Clone, Copy)]
17pub struct Flags(u8);
18
19bitfield_bitrange! {
20    struct Flags(u8)
21}
22
23impl Flags {
24    bitfield_fields! {
25        bool;
26        pub session_present, _ : 1;
27    }
28}
29
30impl Debug for Flags {
31    bitfield_debug! {
32        struct Flags;
33        pub session_present, _ : 1;
34    }
35}
36
37impl TryFrom<u8> for Flags {
38    type Error = ();
39    fn try_from(from: u8) -> Result<Flags, ()> {
40        if 0b11111110 & from != 0 {
41            Err(())
42        } else {
43            Ok(Flags(from))
44        }
45    }
46}
47
48impl Encodable for Flags {
49    fn encoded_len(&self) -> usize {
50        1
51    }
52
53    fn encode(&self, bytes: &mut [u8]) -> Result<usize, EncodeError> {
54        if bytes.len() < 1 {
55            return Err(EncodeError::OutOfSpace)
56        }
57
58        bytes[0] = self.0;
59
60        Ok(1)
61    }
62}
63
64#[derive(PartialEq, Eq, Debug, Clone, Copy)]
65pub enum ReturnCode {
66    Accepted,
67    RefusedProtocolVersion,
68    RefusedClientIdentifier,
69    RefusedServerUnavailable,
70    RefusedUsernameOrPassword,
71    RefusedNotAuthorized,
72}
73
74impl TryFrom<u8> for ReturnCode {
75    type Error = ();
76    fn try_from(from: u8) -> Result<ReturnCode, ()> {
77        Ok(match from {
78            0 => ReturnCode::Accepted,
79            1 => ReturnCode::RefusedProtocolVersion,
80            2 => ReturnCode::RefusedClientIdentifier,
81            3 => ReturnCode::RefusedServerUnavailable,
82            4 => ReturnCode::RefusedUsernameOrPassword,
83            5 => ReturnCode::RefusedNotAuthorized,
84            _ => return Err(()),
85        })
86    }
87}
88
89impl Encodable for ReturnCode {
90    fn encoded_len(&self) -> usize {
91        1
92    }
93
94    fn encode(&self, bytes: &mut [u8]) -> Result<usize, EncodeError> {
95        if bytes.len() < 1 {
96            return Err(EncodeError::OutOfSpace)
97        }
98
99        let val = match self {
100            &ReturnCode::Accepted => 0,
101            &ReturnCode::RefusedProtocolVersion => 1,
102            &ReturnCode::RefusedClientIdentifier => 2,
103            &ReturnCode::RefusedServerUnavailable => 3,
104            &ReturnCode::RefusedUsernameOrPassword => 4,
105            &ReturnCode::RefusedNotAuthorized => 5,
106        };
107
108        bytes[0] = val;
109
110        Ok(1)
111    }
112}
113
114// VariableHeader for Connack packet
115#[derive(PartialEq, Debug)]
116pub struct Connack {
117    flags: Flags,
118    return_code: ReturnCode,
119}
120
121impl Connack {
122    pub fn flags(&self) -> Flags {
123        self.flags
124    }
125
126    pub fn return_code(&self) -> ReturnCode {
127        self.return_code
128    }
129}
130
131impl<'buf> HeaderDecode<'buf> for Connack {
132    fn decode(_flags: PacketFlags, bytes: &[u8]) -> Result<Status<(usize, Self)>, DecodeError> {
133        if bytes.len() < 2 {
134            return Ok(Status::Partial(2 - bytes.len()));
135        }
136
137        let offset = 0;
138
139        // read connack flags
140        let (offset, flags) = read!(codec::values::parse_u8, bytes, offset);
141        let flags = flags.try_into().map_err(|_| DecodeError::InvalidConnackFlag)?;
142
143        // read return code
144        let (offset, return_code) = read!(codec::values::parse_u8, bytes, offset);
145        let return_code = return_code.try_into().map_err(|_| DecodeError::InvalidConnackReturnCode)?;
146
147        Ok(Status::Complete((offset, Connack {
148            flags,
149            return_code,
150        })))
151    }
152}
153
154impl Encodable for Connack {
155    fn encoded_len(&self) -> usize {
156        2
157    }
158
159    fn encode(&self, bytes: &mut [u8]) -> Result<usize, EncodeError> {
160        self.flags.encode(&mut bytes[0..])?;
161        self.return_code.encode(&mut bytes[1..])?;
162        Ok(2)
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    
169}