1use super::*;
2use bytes::{Buf, BufMut, Bytes, BytesMut};
3
4#[derive(Debug, Clone, Copy, PartialEq)]
6#[repr(u8)]
7pub enum PubRelReason {
8 Success = 0,
9 PacketIdentifierNotFound = 146,
10}
11
12#[derive(Debug, Clone, PartialEq)]
14pub struct PubRel {
15 pub pkid: u16,
16 pub reason: PubRelReason,
17 pub properties: Option<PubRelProperties>,
18}
19
20impl PubRel {
21 pub fn new(pkid: u16) -> PubRel {
22 PubRel {
23 pkid,
24 reason: PubRelReason::Success,
25 properties: None,
26 }
27 }
28
29 fn len(&self) -> usize {
30 let mut len = 2 + 1; if self.reason == PubRelReason::Success && self.properties.is_none() {
34 return 2;
35 }
36
37 if let Some(properties) = &self.properties {
38 let properties_len = properties.len();
39 let properties_len_len = len_len(properties_len);
40 len += properties_len_len + properties_len;
41 }
42
43 len
44 }
45
46 pub fn read(fixed_header: FixedHeader, mut bytes: Bytes) -> Result<Self, Error> {
47 let variable_header_index = fixed_header.fixed_header_len;
48 bytes.advance(variable_header_index);
49 let pkid = read_u16(&mut bytes)?;
50 if fixed_header.remaining_len == 2 {
51 return Ok(PubRel {
52 pkid,
53 reason: PubRelReason::Success,
54 properties: None,
55 });
56 }
57
58 let ack_reason = read_u8(&mut bytes)?;
59 if fixed_header.remaining_len < 4 {
60 return Ok(PubRel {
61 pkid,
62 reason: reason(ack_reason)?,
63 properties: None,
64 });
65 }
66
67 let puback = PubRel {
68 pkid,
69 reason: reason(ack_reason)?,
70 properties: PubRelProperties::extract(&mut bytes)?,
71 };
72
73 Ok(puback)
74 }
75
76 pub fn write(&self, buffer: &mut BytesMut) -> Result<usize, Error> {
77 let len = self.len();
78 buffer.put_u8(0x62);
79 let count = write_remaining_length(buffer, len)?;
80 buffer.put_u16(self.pkid);
81
82 if self.reason == PubRelReason::Success && self.properties.is_none() {
84 return Ok(4);
85 }
86
87 buffer.put_u8(self.reason as u8);
88
89 if let Some(properties) = &self.properties {
90 properties.write(buffer)?;
91 }
92
93 Ok(1 + count + len)
94 }
95}
96
97#[derive(Debug, Clone, PartialEq)]
98pub struct PubRelProperties {
99 pub reason_string: Option<String>,
100 pub user_properties: Vec<(String, String)>,
101}
102
103impl PubRelProperties {
104 pub fn len(&self) -> usize {
105 let mut len = 0;
106
107 if let Some(reason) = &self.reason_string {
108 len += 1 + 2 + reason.len();
109 }
110
111 for (key, value) in self.user_properties.iter() {
112 len += 1 + 2 + key.len() + 2 + value.len();
113 }
114
115 len
116 }
117
118 pub fn extract(mut bytes: &mut Bytes) -> Result<Option<PubRelProperties>, Error> {
119 let mut reason_string = None;
120 let mut user_properties = Vec::new();
121
122 let (properties_len_len, properties_len) = length(bytes.iter())?;
123 bytes.advance(properties_len_len);
124 if properties_len == 0 {
125 return Ok(None);
126 }
127
128 let mut cursor = 0;
129 while cursor < properties_len {
131 let prop = read_u8(&mut bytes)?;
132 cursor += 1;
133
134 match property(prop)? {
135 PropertyType::ReasonString => {
136 let reason = read_mqtt_string(&mut bytes)?;
137 cursor += 2 + reason.len();
138 reason_string = Some(reason);
139 }
140 PropertyType::UserProperty => {
141 let key = read_mqtt_string(&mut bytes)?;
142 let value = read_mqtt_string(&mut bytes)?;
143 cursor += 2 + key.len() + 2 + value.len();
144 user_properties.push((key, value));
145 }
146 _ => return Err(Error::InvalidPropertyType(prop)),
147 }
148 }
149
150 Ok(Some(PubRelProperties {
151 reason_string,
152 user_properties,
153 }))
154 }
155
156 fn write(&self, buffer: &mut BytesMut) -> Result<(), Error> {
157 let len = self.len();
158 write_remaining_length(buffer, len)?;
159
160 if let Some(reason) = &self.reason_string {
161 buffer.put_u8(PropertyType::ReasonString as u8);
162 write_mqtt_string(buffer, reason);
163 }
164
165 for (key, value) in self.user_properties.iter() {
166 buffer.put_u8(PropertyType::UserProperty as u8);
167 write_mqtt_string(buffer, key);
168 write_mqtt_string(buffer, value);
169 }
170
171 Ok(())
172 }
173}
174fn reason(num: u8) -> Result<PubRelReason, Error> {
176 let code = match num {
177 0 => PubRelReason::Success,
178 146 => PubRelReason::PacketIdentifierNotFound,
179 num => return Err(Error::InvalidConnectReturnCode(num)),
180 };
181
182 Ok(code)
183}
184
185#[cfg(test)]
186mod test {
187 use super::*;
188 use alloc::vec;
189 use bytes::BytesMut;
190 use pretty_assertions::assert_eq;
191
192 fn sample() -> PubRel {
193 let properties = PubRelProperties {
194 reason_string: Some("test".to_owned()),
195 user_properties: vec![("test".to_owned(), "test".to_owned())],
196 };
197
198 PubRel {
199 pkid: 42,
200 reason: PubRelReason::PacketIdentifierNotFound,
201 properties: Some(properties),
202 }
203 }
204
205 fn sample_bytes() -> Vec<u8> {
206 vec![
207 0x62, 0x18, 0x00, 0x2a, 0x92, 0x14, 0x1f, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x26, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x04, 0x74, 0x65, 0x73,
214 0x74, ]
216 }
217
218 #[test]
219 fn pubrel_parsing_works() {
220 let mut stream = bytes::BytesMut::new();
221 let packetstream = &sample_bytes();
222 stream.extend_from_slice(&packetstream[..]);
223
224 let fixed_header = parse_fixed_header(stream.iter()).unwrap();
225 let pubrel_bytes = stream.split_to(fixed_header.frame_length()).freeze();
226 let pubrel = PubRel::read(fixed_header, pubrel_bytes).unwrap();
227 assert_eq!(pubrel, sample());
228 }
229
230 #[test]
231 fn pubrel_encoding_works() {
232 let pubrel = sample();
233 let mut buf = BytesMut::new();
234 pubrel.write(&mut buf).unwrap();
235 assert_eq!(&buf[..], sample_bytes());
236 }
237}