minimq/
properties.rs

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/// All of the possible properties that MQTT version 5 supports.
73#[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}