1use crate::MqttString;
2
3use super::{
4 len_len, length, property, read_mqtt_string, read_u16, read_u8, write_mqtt_string,
5 write_remaining_length, Debug, Error, FixedHeader, PropertyType,
6};
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[repr(u8)]
12pub enum PubRelReason {
13 Success,
14 PacketIdentifierNotFound,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct PubRel {
20 pub pkid: u16,
21 pub reason: PubRelReason,
22 pub properties: Option<PubRelProperties>,
23}
24
25impl PubRel {
26 #[must_use]
27 pub fn new(pkid: u16, properties: Option<PubRelProperties>) -> Self {
28 Self {
29 pkid,
30 reason: PubRelReason::Success,
31 properties,
32 }
33 }
34
35 #[must_use]
36 pub fn size(&self) -> usize {
37 if self.reason == PubRelReason::Success && self.properties.is_none() {
39 return 4;
40 }
41
42 let len = self.len();
43 let remaining_len_size = len_len(len);
44
45 1 + remaining_len_size + len
46 }
47
48 fn len(&self) -> usize {
49 let mut len = 2 + 1; if self.reason == PubRelReason::Success && self.properties.is_none() {
55 return 2;
56 }
57
58 if let Some(p) = &self.properties {
59 let properties_len = p.len();
60 let properties_len_len = len_len(properties_len);
61 len += properties_len_len + properties_len;
62 } else {
63 len += 1;
64 }
65
66 len
67 }
68
69 pub fn read(fixed_header: FixedHeader, mut bytes: Bytes) -> Result<PubRel, Error> {
70 let variable_header_index = fixed_header.fixed_header_len;
71 bytes.advance(variable_header_index);
72 let pkid = read_u16(&mut bytes)?;
73 if fixed_header.remaining_len == 2 {
74 return Ok(PubRel {
75 pkid,
76 reason: PubRelReason::Success,
77 properties: None,
78 });
79 }
80
81 let ack_reason = read_u8(&mut bytes)?;
82 if fixed_header.remaining_len < 4 {
83 return Ok(PubRel {
84 pkid,
85 reason: reason(ack_reason)?,
86 properties: None,
87 });
88 }
89
90 let properties = PubRelProperties::read(&mut bytes)?;
91 let puback = PubRel {
92 pkid,
93 reason: reason(ack_reason)?,
94 properties,
95 };
96
97 Ok(puback)
98 }
99
100 pub fn write(&self, buffer: &mut BytesMut) -> Result<usize, Error> {
101 let len = self.len();
102 buffer.put_u8(0x62);
103 let count = write_remaining_length(buffer, len)?;
104 buffer.put_u16(self.pkid);
105
106 if self.reason == PubRelReason::Success && self.properties.is_none() {
108 return Ok(4);
109 }
110
111 buffer.put_u8(code(self.reason));
112
113 if let Some(p) = &self.properties {
114 p.write(buffer)?;
115 } else {
116 write_remaining_length(buffer, 0)?;
117 }
118
119 Ok(1 + count + len)
120 }
121}
122
123#[derive(Debug, Clone, PartialEq, Eq)]
124pub struct PubRelProperties {
125 pub reason_string: Option<MqttString>,
126 pub user_properties: Vec<(MqttString, MqttString)>,
127}
128
129impl PubRelProperties {
130 fn len(&self) -> usize {
131 let mut len = 0;
132
133 if let Some(reason) = &self.reason_string {
134 len += 1 + 2 + reason.len();
135 }
136
137 for (key, value) in &self.user_properties {
138 len += 1 + 2 + key.len() + 2 + value.len();
139 }
140
141 len
142 }
143
144 pub fn read(bytes: &mut Bytes) -> Result<Option<PubRelProperties>, Error> {
145 let mut reason_string = None;
146 let mut user_properties = Vec::new();
147
148 let (properties_len_len, properties_len) = length(bytes.iter())?;
149 bytes.advance(properties_len_len);
150 if properties_len == 0 {
151 return Ok(None);
152 }
153
154 let mut cursor = 0;
155 while cursor < properties_len {
157 let prop = read_u8(bytes)?;
158 cursor += 1;
159
160 match property(prop)? {
161 PropertyType::ReasonString => {
162 let reason = read_mqtt_string(bytes)?;
163 cursor += 2 + reason.len();
164 reason_string = Some(reason);
165 }
166 PropertyType::UserProperty => {
167 let key = read_mqtt_string(bytes)?;
168 let value = read_mqtt_string(bytes)?;
169 cursor += 2 + key.len() + 2 + value.len();
170 user_properties.push((key, value));
171 }
172 _ => return Err(Error::InvalidPropertyType(prop)),
173 }
174 }
175
176 Ok(Some(PubRelProperties {
177 reason_string,
178 user_properties,
179 }))
180 }
181
182 pub fn write(&self, buffer: &mut BytesMut) -> Result<(), Error> {
183 let len = self.len();
184 write_remaining_length(buffer, len)?;
185
186 if let Some(reason) = &self.reason_string {
187 buffer.put_u8(PropertyType::ReasonString as u8);
188 write_mqtt_string(buffer, reason)?;
189 }
190
191 for (key, value) in &self.user_properties {
192 buffer.put_u8(PropertyType::UserProperty as u8);
193 write_mqtt_string(buffer, key)?;
194 write_mqtt_string(buffer, value)?;
195 }
196
197 Ok(())
198 }
199}
200
201fn reason(num: u8) -> Result<PubRelReason, Error> {
203 let code = match num {
204 0 => PubRelReason::Success,
205 146 => PubRelReason::PacketIdentifierNotFound,
206 num => return Err(Error::InvalidConnectReturnCode(num)),
207 };
208
209 Ok(code)
210}
211
212fn code(reason: PubRelReason) -> u8 {
213 match reason {
214 PubRelReason::Success => 0,
215 PubRelReason::PacketIdentifierNotFound => 146,
216 }
217}
218
219#[cfg(test)]
220mod test {
221 use crate::test::read_write_packets;
222 use crate::Packet;
223
224 use super::super::test::{USER_PROP_KEY, USER_PROP_VAL};
225 use super::*;
226 use bytes::BytesMut;
227 use pretty_assertions::assert_eq;
228
229 #[test]
230 fn length_calculation() {
231 let mut dummy_bytes = BytesMut::new();
232 let pubrel_props = PubRelProperties {
235 reason_string: None,
236 user_properties: vec![(USER_PROP_KEY.into(), USER_PROP_VAL.into())],
237 };
238
239 let pubrel_pkt = PubRel::new(1, Some(pubrel_props));
240
241 let size_from_size = pubrel_pkt.size();
242 let size_from_write = pubrel_pkt.write(&mut dummy_bytes).unwrap();
243 let size_from_bytes = dummy_bytes.len();
244
245 assert_eq!(size_from_write, size_from_bytes);
246 assert_eq!(size_from_size, size_from_bytes);
247 }
248
249 #[test]
250 fn test_write_read() {
251 read_write_packets(write_read_provider());
252 }
253
254 fn write_read_provider() -> Vec<Packet> {
255 vec![
256 Packet::PubRel(PubRel {
257 pkid: 42,
258 reason: PubRelReason::Success,
259 properties: None,
260 }),
261 Packet::PubRel(PubRel {
262 pkid: 42,
263 reason: PubRelReason::Success,
264 properties: Some(PubRelProperties {
265 reason_string: Some("hello".into()),
266 user_properties: vec![(USER_PROP_KEY.into(), USER_PROP_VAL.into())],
267 }),
268 }),
269 ]
270 }
271}