mqtt/packet/
suback.rs

1//! SUBACK
2
3use std::cmp::Ordering;
4
5use std::io::{self, Read, Write};
6
7use byteorder::{ReadBytesExt, WriteBytesExt};
8
9use crate::control::variable_header::PacketIdentifier;
10use crate::control::{ControlType, FixedHeader, PacketType};
11use crate::packet::{DecodablePacket, PacketError};
12use crate::qos::QualityOfService;
13use crate::{Decodable, Encodable};
14
15/// Subscribe code
16#[repr(u8)]
17#[derive(Debug, Eq, PartialEq, Copy, Clone)]
18pub enum SubscribeReturnCode {
19    MaximumQoSLevel0 = 0x00,
20    MaximumQoSLevel1 = 0x01,
21    MaximumQoSLevel2 = 0x02,
22    Failure = 0x80,
23}
24
25impl PartialOrd for SubscribeReturnCode {
26    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
27        use self::SubscribeReturnCode::*;
28        match (self, other) {
29            (&Failure, _) => None,
30            (_, &Failure) => None,
31            (&MaximumQoSLevel0, &MaximumQoSLevel0) => Some(Ordering::Equal),
32            (&MaximumQoSLevel1, &MaximumQoSLevel1) => Some(Ordering::Equal),
33            (&MaximumQoSLevel2, &MaximumQoSLevel2) => Some(Ordering::Equal),
34            (&MaximumQoSLevel0, _) => Some(Ordering::Less),
35            (&MaximumQoSLevel1, &MaximumQoSLevel0) => Some(Ordering::Greater),
36            (&MaximumQoSLevel1, &MaximumQoSLevel2) => Some(Ordering::Less),
37            (&MaximumQoSLevel2, _) => Some(Ordering::Greater),
38        }
39    }
40}
41
42impl From<QualityOfService> for SubscribeReturnCode {
43    fn from(qos: QualityOfService) -> Self {
44        match qos {
45            QualityOfService::Level0 => SubscribeReturnCode::MaximumQoSLevel0,
46            QualityOfService::Level1 => SubscribeReturnCode::MaximumQoSLevel1,
47            QualityOfService::Level2 => SubscribeReturnCode::MaximumQoSLevel2,
48        }
49    }
50}
51
52/// `SUBACK` packet
53#[derive(Debug, Eq, PartialEq, Clone)]
54pub struct SubackPacket {
55    fixed_header: FixedHeader,
56    packet_identifier: PacketIdentifier,
57    payload: SubackPacketPayload,
58}
59
60encodable_packet!(SubackPacket(packet_identifier, payload));
61
62impl SubackPacket {
63    pub fn new(pkid: u16, subscribes: Vec<SubscribeReturnCode>) -> SubackPacket {
64        let mut pk = SubackPacket {
65            fixed_header: FixedHeader::new(PacketType::with_default(ControlType::SubscribeAcknowledgement), 0),
66            packet_identifier: PacketIdentifier(pkid),
67            payload: SubackPacketPayload::new(subscribes),
68        };
69        pk.fix_header_remaining_len();
70        pk
71    }
72
73    pub fn packet_identifier(&self) -> u16 {
74        self.packet_identifier.0
75    }
76
77    pub fn set_packet_identifier(&mut self, pkid: u16) {
78        self.packet_identifier.0 = pkid;
79    }
80
81    pub fn subscribes(&self) -> &[SubscribeReturnCode] {
82        &self.payload.subscribes[..]
83    }
84}
85
86impl DecodablePacket for SubackPacket {
87    type DecodePacketError = SubackPacketError;
88
89    fn decode_packet<R: Read>(reader: &mut R, fixed_header: FixedHeader) -> Result<Self, PacketError<Self>> {
90        let packet_identifier = PacketIdentifier::decode(reader)?;
91        let payload: SubackPacketPayload = SubackPacketPayload::decode_with(
92            reader,
93            fixed_header.remaining_length - packet_identifier.encoded_length(),
94        )
95        .map_err(PacketError::PayloadError)?;
96        Ok(SubackPacket {
97            fixed_header,
98            packet_identifier,
99            payload,
100        })
101    }
102}
103
104#[derive(Debug, Eq, PartialEq, Clone)]
105struct SubackPacketPayload {
106    subscribes: Vec<SubscribeReturnCode>,
107}
108
109impl SubackPacketPayload {
110    pub fn new(subs: Vec<SubscribeReturnCode>) -> SubackPacketPayload {
111        SubackPacketPayload { subscribes: subs }
112    }
113}
114
115impl Encodable for SubackPacketPayload {
116    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
117        for code in self.subscribes.iter() {
118            writer.write_u8(*code as u8)?;
119        }
120
121        Ok(())
122    }
123
124    fn encoded_length(&self) -> u32 {
125        self.subscribes.len() as u32
126    }
127}
128
129impl Decodable for SubackPacketPayload {
130    type Error = SubackPacketError;
131    type Cond = u32;
132
133    fn decode_with<R: Read>(reader: &mut R, payload_len: u32) -> Result<SubackPacketPayload, SubackPacketError> {
134        let mut subs = Vec::new();
135
136        for _ in 0..payload_len {
137            let retcode = match reader.read_u8()? {
138                0x00 => SubscribeReturnCode::MaximumQoSLevel0,
139                0x01 => SubscribeReturnCode::MaximumQoSLevel1,
140                0x02 => SubscribeReturnCode::MaximumQoSLevel2,
141                0x80 => SubscribeReturnCode::Failure,
142                code => return Err(SubackPacketError::InvalidSubscribeReturnCode(code)),
143            };
144
145            subs.push(retcode);
146        }
147
148        Ok(SubackPacketPayload::new(subs))
149    }
150}
151
152#[derive(Debug, thiserror::Error)]
153pub enum SubackPacketError {
154    #[error(transparent)]
155    IoError(#[from] io::Error),
156    #[error("invalid subscribe return code {0}")]
157    InvalidSubscribeReturnCode(u8),
158}