1use crate::{
2 types::{BinaryData, Utf8String},
3 varint::Varint,
4};
5
6use core::convert::TryFrom;
7use num_enum::TryFromPrimitive;
8use serde::ser::SerializeSeq;
9
10#[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)]
11#[repr(u32)]
12pub(crate) enum PropertyIdentifier {
13 Invalid = u32::MAX,
14
15 PayloadFormatIndicator = 0x01,
16 MessageExpiryInterval = 0x02,
17 ContentType = 0x03,
18
19 ResponseTopic = 0x08,
20 CorrelationData = 0x09,
21
22 SubscriptionIdentifier = 0x0B,
23
24 SessionExpiryInterval = 0x11,
25 AssignedClientIdentifier = 0x12,
26 ServerKeepAlive = 0x13,
27 AuthenticationMethod = 0x15,
28 AuthenticationData = 0x16,
29 RequestProblemInformation = 0x17,
30 WillDelayInterval = 0x18,
31 RequestResponseInformation = 0x19,
32
33 ResponseInformation = 0x1A,
34
35 ServerReference = 0x1C,
36
37 ReasonString = 0x1F,
38
39 ReceiveMaximum = 0x21,
40 TopicAliasMaximum = 0x22,
41 TopicAlias = 0x23,
42 MaximumQoS = 0x24,
43 RetainAvailable = 0x25,
44 UserProperty = 0x26,
45 MaximumPacketSize = 0x27,
46 WildcardSubscriptionAvailable = 0x28,
47 SubscriptionIdentifierAvailable = 0x29,
48 SharedSubscriptionAvailable = 0x2A,
49}
50
51struct PropertyIdVisitor;
52
53impl serde::de::Visitor<'_> for PropertyIdVisitor {
54 type Value = PropertyIdentifier;
55
56 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
57 write!(formatter, "PropertyIdentifier")
58 }
59
60 fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> {
61 PropertyIdentifier::try_from(v).map_err(|_| E::custom("Invalid PropertyIdentifier"))
62 }
63}
64
65impl<'de> serde::de::Deserialize<'de> for PropertyIdentifier {
66 fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
67 let result = deserializer.deserialize_u32(PropertyIdVisitor)?;
68 Ok(result)
69 }
70}
71
72#[derive(Debug, Copy, Clone, PartialEq)]
74pub enum Property<'a> {
75 PayloadFormatIndicator(u8),
76 MessageExpiryInterval(u32),
77 ContentType(Utf8String<'a>),
78 ResponseTopic(Utf8String<'a>),
79 CorrelationData(BinaryData<'a>),
80 SubscriptionIdentifier(Varint),
81 SessionExpiryInterval(u32),
82 AssignedClientIdentifier(Utf8String<'a>),
83 ServerKeepAlive(u16),
84 AuthenticationMethod(Utf8String<'a>),
85 AuthenticationData(BinaryData<'a>),
86 RequestProblemInformation(u8),
87 WillDelayInterval(u32),
88 RequestResponseInformation(u8),
89 ResponseInformation(Utf8String<'a>),
90 ServerReference(Utf8String<'a>),
91 ReasonString(Utf8String<'a>),
92 ReceiveMaximum(u16),
93 TopicAliasMaximum(u16),
94 TopicAlias(u16),
95 MaximumQoS(u8),
96 RetainAvailable(u8),
97 UserProperty(Utf8String<'a>, Utf8String<'a>),
98 MaximumPacketSize(u32),
99 WildcardSubscriptionAvailable(u8),
100 SubscriptionIdentifierAvailable(u8),
101 SharedSubscriptionAvailable(u8),
102}
103
104struct UserPropertyVisitor<'a> {
105 _data: core::marker::PhantomData<&'a ()>,
106}
107
108impl<'a, 'de: 'a> serde::de::Visitor<'de> for UserPropertyVisitor<'a> {
109 type Value = (Utf8String<'a>, Utf8String<'a>);
110
111 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
112 write!(formatter, "UserProperty")
113 }
114
115 fn visit_seq<A: serde::de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
116 use serde::de::Error;
117 let key = seq
118 .next_element()?
119 .ok_or_else(|| A::Error::custom("No key present"))?;
120 let value = seq
121 .next_element()?
122 .ok_or_else(|| A::Error::custom("No value present"))?;
123 Ok((key, value))
124 }
125}
126
127struct PropertyVisitor<'a> {
128 _data: core::marker::PhantomData<&'a ()>,
129}
130
131impl<'a, 'de: 'a> serde::de::Visitor<'de> for PropertyVisitor<'a> {
132 type Value = Property<'a>;
133
134 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
135 write!(formatter, "enum Property")
136 }
137
138 fn visit_enum<A: serde::de::EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> {
139 use serde::de::{Error, VariantAccess};
140
141 let (field, variant) = data.variant::<PropertyIdentifier>()?;
142 crate::trace!("Deserializing {:?}", field);
143
144 let property = match field {
145 PropertyIdentifier::ResponseTopic => {
146 Property::ResponseTopic(variant.newtype_variant()?)
147 }
148 PropertyIdentifier::PayloadFormatIndicator => {
149 Property::PayloadFormatIndicator(variant.newtype_variant()?)
150 }
151 PropertyIdentifier::MessageExpiryInterval => {
152 Property::MessageExpiryInterval(variant.newtype_variant()?)
153 }
154 PropertyIdentifier::ContentType => Property::ContentType(variant.newtype_variant()?),
155 PropertyIdentifier::CorrelationData => {
156 Property::CorrelationData(variant.newtype_variant()?)
157 }
158 PropertyIdentifier::SubscriptionIdentifier => {
159 Property::SubscriptionIdentifier(variant.newtype_variant()?)
160 }
161 PropertyIdentifier::SessionExpiryInterval => {
162 Property::SessionExpiryInterval(variant.newtype_variant()?)
163 }
164 PropertyIdentifier::AssignedClientIdentifier => {
165 Property::AssignedClientIdentifier(variant.newtype_variant()?)
166 }
167 PropertyIdentifier::ServerKeepAlive => {
168 Property::ServerKeepAlive(variant.newtype_variant()?)
169 }
170 PropertyIdentifier::AuthenticationMethod => {
171 Property::AuthenticationMethod(variant.newtype_variant()?)
172 }
173 PropertyIdentifier::AuthenticationData => {
174 Property::AuthenticationData(variant.newtype_variant()?)
175 }
176 PropertyIdentifier::RequestProblemInformation => {
177 Property::RequestProblemInformation(variant.newtype_variant()?)
178 }
179 PropertyIdentifier::WillDelayInterval => {
180 Property::WillDelayInterval(variant.newtype_variant()?)
181 }
182 PropertyIdentifier::RequestResponseInformation => {
183 Property::RequestResponseInformation(variant.newtype_variant()?)
184 }
185 PropertyIdentifier::ResponseInformation => {
186 Property::ResponseInformation(variant.newtype_variant()?)
187 }
188 PropertyIdentifier::ServerReference => {
189 Property::ServerReference(variant.newtype_variant()?)
190 }
191 PropertyIdentifier::ReasonString => Property::ReasonString(variant.newtype_variant()?),
192 PropertyIdentifier::ReceiveMaximum => {
193 Property::ReceiveMaximum(variant.newtype_variant()?)
194 }
195 PropertyIdentifier::TopicAliasMaximum => {
196 Property::TopicAliasMaximum(variant.newtype_variant()?)
197 }
198 PropertyIdentifier::TopicAlias => Property::TopicAlias(variant.newtype_variant()?),
199 PropertyIdentifier::MaximumQoS => Property::MaximumQoS(variant.newtype_variant()?),
200 PropertyIdentifier::RetainAvailable => {
201 Property::RetainAvailable(variant.newtype_variant()?)
202 }
203 PropertyIdentifier::UserProperty => {
204 let (key, value) = variant.tuple_variant(
205 2,
206 UserPropertyVisitor {
207 _data: core::marker::PhantomData,
208 },
209 )?;
210 Property::UserProperty(key, value)
211 }
212 PropertyIdentifier::MaximumPacketSize => {
213 Property::MaximumPacketSize(variant.newtype_variant()?)
214 }
215 PropertyIdentifier::WildcardSubscriptionAvailable => {
216 Property::WildcardSubscriptionAvailable(variant.newtype_variant()?)
217 }
218 PropertyIdentifier::SubscriptionIdentifierAvailable => {
219 Property::SubscriptionIdentifierAvailable(variant.newtype_variant()?)
220 }
221 PropertyIdentifier::SharedSubscriptionAvailable => {
222 Property::SharedSubscriptionAvailable(variant.newtype_variant()?)
223 }
224
225 _ => return Err(A::Error::custom("Invalid property identifier")),
226 };
227
228 Ok(property)
229 }
230}
231
232impl<'a, 'de: 'a> serde::de::Deserialize<'de> for Property<'a> {
233 fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
234 let prop = deserializer.deserialize_enum(
235 "Property",
236 &[],
237 PropertyVisitor {
238 _data: core::marker::PhantomData,
239 },
240 )?;
241 crate::debug!("Deserialized {:?}", prop);
242 Ok(prop)
243 }
244}
245
246impl serde::Serialize for Property<'_> {
247 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
248 let mut serializer = serializer.serialize_seq(None)?;
249
250 let id: PropertyIdentifier = self.into();
251 serializer.serialize_element(&Varint(id as u32))?;
252
253 match self {
254 Property::PayloadFormatIndicator(value) => serializer.serialize_element(value)?,
255 Property::MessageExpiryInterval(value) => serializer.serialize_element(value)?,
256 Property::ContentType(content_type) => serializer.serialize_element(content_type)?,
257 Property::ResponseTopic(topic) => serializer.serialize_element(topic)?,
258 Property::CorrelationData(data) => serializer.serialize_element(data)?,
259 Property::SubscriptionIdentifier(data) => serializer.serialize_element(data)?,
260 Property::SessionExpiryInterval(data) => serializer.serialize_element(data)?,
261 Property::AssignedClientIdentifier(data) => serializer.serialize_element(data)?,
262 Property::ServerKeepAlive(data) => serializer.serialize_element(data)?,
263 Property::AuthenticationMethod(data) => serializer.serialize_element(data)?,
264 Property::AuthenticationData(data) => serializer.serialize_element(data)?,
265 Property::RequestProblemInformation(data) => serializer.serialize_element(data)?,
266 Property::WillDelayInterval(data) => serializer.serialize_element(data)?,
267 Property::RequestResponseInformation(data) => serializer.serialize_element(data)?,
268 Property::ResponseInformation(data) => serializer.serialize_element(data)?,
269 Property::ServerReference(data) => serializer.serialize_element(data)?,
270 Property::ReasonString(data) => serializer.serialize_element(data)?,
271 Property::ReceiveMaximum(data) => serializer.serialize_element(data)?,
272 Property::TopicAliasMaximum(data) => serializer.serialize_element(data)?,
273 Property::TopicAlias(data) => serializer.serialize_element(data)?,
274 Property::MaximumQoS(data) => serializer.serialize_element(data)?,
275 Property::RetainAvailable(data) => serializer.serialize_element(data)?,
276 Property::UserProperty(key, value) => {
277 serializer.serialize_element(key)?;
278 serializer.serialize_element(value)?;
279 }
280 Property::MaximumPacketSize(data) => serializer.serialize_element(data)?,
281 Property::WildcardSubscriptionAvailable(data) => serializer.serialize_element(data)?,
282 Property::SubscriptionIdentifierAvailable(data) => {
283 serializer.serialize_element(data)?
284 }
285 Property::SharedSubscriptionAvailable(data) => serializer.serialize_element(data)?,
286 }
287
288 serializer.end()
289 }
290}
291
292impl<'a> From<&Property<'a>> for PropertyIdentifier {
293 fn from(prop: &Property<'a>) -> PropertyIdentifier {
294 match prop {
295 Property::PayloadFormatIndicator(_) => PropertyIdentifier::PayloadFormatIndicator,
296 Property::MessageExpiryInterval(_) => PropertyIdentifier::MessageExpiryInterval,
297 Property::ContentType(_) => PropertyIdentifier::ContentType,
298 Property::ResponseTopic(_) => PropertyIdentifier::ResponseTopic,
299 Property::CorrelationData(_) => PropertyIdentifier::CorrelationData,
300 Property::SubscriptionIdentifier(_) => PropertyIdentifier::SubscriptionIdentifier,
301 Property::SessionExpiryInterval(_) => PropertyIdentifier::SessionExpiryInterval,
302 Property::AssignedClientIdentifier(_) => PropertyIdentifier::AssignedClientIdentifier,
303 Property::ServerKeepAlive(_) => PropertyIdentifier::ServerKeepAlive,
304 Property::AuthenticationMethod(_) => PropertyIdentifier::AuthenticationMethod,
305 Property::AuthenticationData(_) => PropertyIdentifier::AuthenticationData,
306 Property::RequestProblemInformation(_) => PropertyIdentifier::RequestProblemInformation,
307 Property::WillDelayInterval(_) => PropertyIdentifier::WillDelayInterval,
308 Property::RequestResponseInformation(_) => {
309 PropertyIdentifier::RequestResponseInformation
310 }
311 Property::ResponseInformation(_) => PropertyIdentifier::ResponseInformation,
312 Property::ServerReference(_) => PropertyIdentifier::ServerReference,
313 Property::ReasonString(_) => PropertyIdentifier::ReasonString,
314 Property::ReceiveMaximum(_) => PropertyIdentifier::ReceiveMaximum,
315 Property::TopicAliasMaximum(_) => PropertyIdentifier::TopicAliasMaximum,
316 Property::TopicAlias(_) => PropertyIdentifier::TopicAlias,
317 Property::MaximumQoS(_) => PropertyIdentifier::MaximumQoS,
318 Property::RetainAvailable(_) => PropertyIdentifier::RetainAvailable,
319 Property::UserProperty(_, _) => PropertyIdentifier::UserProperty,
320 Property::MaximumPacketSize(_) => PropertyIdentifier::MaximumPacketSize,
321 Property::WildcardSubscriptionAvailable(_) => {
322 PropertyIdentifier::WildcardSubscriptionAvailable
323 }
324 Property::SubscriptionIdentifierAvailable(_) => {
325 PropertyIdentifier::SubscriptionIdentifierAvailable
326 }
327 Property::SharedSubscriptionAvailable(_) => {
328 PropertyIdentifier::SharedSubscriptionAvailable
329 }
330 }
331 }
332}
333
334impl Property<'_> {
335 pub(crate) fn size(&self) -> usize {
336 let identifier: PropertyIdentifier = self.into();
337 let identifier_length = Varint(identifier as u32).len();
338
339 match self {
340 Property::ContentType(data)
341 | Property::ResponseTopic(data)
342 | Property::AuthenticationMethod(data)
343 | Property::ResponseInformation(data)
344 | Property::ServerReference(data)
345 | Property::ReasonString(data)
346 | Property::AssignedClientIdentifier(data) => data.0.len() + 2 + identifier_length,
347 Property::UserProperty(key, value) => {
348 (value.0.len() + 2) + (key.0.len() + 2) + identifier_length
349 }
350 Property::CorrelationData(data) | Property::AuthenticationData(data) => {
351 data.0.len() + 2 + identifier_length
352 }
353 Property::SubscriptionIdentifier(id) => id.len() + identifier_length,
354
355 Property::MessageExpiryInterval(_)
356 | Property::SessionExpiryInterval(_)
357 | Property::WillDelayInterval(_)
358 | Property::MaximumPacketSize(_) => 4 + identifier_length,
359 Property::ServerKeepAlive(_)
360 | Property::ReceiveMaximum(_)
361 | Property::TopicAliasMaximum(_)
362 | Property::TopicAlias(_) => 2 + identifier_length,
363 Property::PayloadFormatIndicator(_)
364 | Property::RequestProblemInformation(_)
365 | Property::RequestResponseInformation(_)
366 | Property::MaximumQoS(_)
367 | Property::RetainAvailable(_)
368 | Property::WildcardSubscriptionAvailable(_)
369 | Property::SubscriptionIdentifierAvailable(_)
370 | Property::SharedSubscriptionAvailable(_) => 1 + identifier_length,
371 }
372 }
373}