1use core::convert::TryFrom;
2
3use alloc::string::String;
4use alloc::sync::Arc;
5
6use bytes::Bytes;
7
8use crate::{read_bytes, read_string, read_u16, read_u32, read_u8, AsyncRead, Error, TopicName};
9
10use super::ErrorV5;
11
12#[repr(u8)]
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum PropertyId {
49 PayloadFormatIndicator = 0x01,
50 MessageExpiryInterval = 0x02,
51 ContentType = 0x03,
52 ResponseTopic = 0x08,
53 CorrelationData = 0x09,
54 SubscriptionIdentifier = 0x0B,
55 SessionExpiryInterval = 0x11,
56 AssignedClientIdentifier = 0x12,
57 ServerKeepAlive = 0x13,
58 AuthenticationMethod = 0x15,
59 AuthenticationData = 0x16,
60 RequestProblemInformation = 0x17,
61 WillDelayInterval = 0x18,
62 RequestResponseInformation = 0x19,
63 ResponseInformation = 0x1A,
64 ServerReference = 0x1C,
65 ReasonString = 0x1F,
66 ReceiveMaximum = 0x21,
67 TopicAliasMaximum = 0x22,
68 TopicAlias = 0x23,
69 MaximumQoS = 0x24,
70 RetainAvailable = 0x25,
71 UserProperty = 0x26,
72 MaximumPacketSize = 0x27,
73 WildcardSubscriptionAvailable = 0x28,
74 SubscriptionIdentifierAvailable = 0x29,
75 SharedSubscriptionAvailable = 0x2A,
76}
77
78impl PropertyId {
79 pub fn from_u8(value: u8) -> Result<Self, ErrorV5> {
80 let typ = match value {
81 0x01 => Self::PayloadFormatIndicator,
82 0x02 => Self::MessageExpiryInterval,
83 0x03 => Self::ContentType,
84 0x08 => Self::ResponseTopic,
85 0x09 => Self::CorrelationData,
86 0x0B => Self::SubscriptionIdentifier,
87 0x11 => Self::SessionExpiryInterval,
88 0x12 => Self::AssignedClientIdentifier,
89 0x13 => Self::ServerKeepAlive,
90 0x15 => Self::AuthenticationMethod,
91 0x16 => Self::AuthenticationData,
92 0x17 => Self::RequestProblemInformation,
93 0x18 => Self::WillDelayInterval,
94 0x19 => Self::RequestResponseInformation,
95 0x1A => Self::ResponseInformation,
96 0x1C => Self::ServerReference,
97 0x1F => Self::ReasonString,
98 0x21 => Self::ReceiveMaximum,
99 0x22 => Self::TopicAliasMaximum,
100 0x23 => Self::TopicAlias,
101 0x24 => Self::MaximumQoS,
102 0x25 => Self::RetainAvailable,
103 0x26 => Self::UserProperty,
104 0x27 => Self::MaximumPacketSize,
105 0x28 => Self::WildcardSubscriptionAvailable,
106 0x29 => Self::SubscriptionIdentifierAvailable,
107 0x2A => Self::SharedSubscriptionAvailable,
108 _ => return Err(ErrorV5::InvalidPropertyId(value)),
109 };
110 Ok(typ)
111 }
112}
113
114impl core::fmt::Display for PropertyId {
115 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116 write!(f, "{self:?}")
117 }
118}
119
120pub(crate) struct PropertyValue;
122
123impl PropertyValue {
124 #[inline]
125 pub(crate) async fn decode_bool<T: AsyncRead + Unpin>(
126 reader: &mut T,
127 property_id: PropertyId,
128 target: &mut Option<bool>,
129 ) -> Result<(), ErrorV5> {
130 if target.is_some() {
131 return Err(ErrorV5::DuplicatedProperty(property_id));
132 }
133 let value = read_u8(reader).await?;
134 if value > 1 {
135 Err(ErrorV5::InvalidByteProperty(property_id, value))
136 } else {
137 *target = Some(value == 1);
138 Ok(())
139 }
140 }
141
142 #[inline]
143 pub(crate) async fn decode_u16<T: AsyncRead + Unpin>(
144 reader: &mut T,
145 property_id: PropertyId,
146 target: &mut Option<u16>,
147 ) -> Result<(), ErrorV5> {
148 if target.is_some() {
149 return Err(ErrorV5::DuplicatedProperty(property_id));
150 }
151 *target = Some(read_u16(reader).await?);
152 Ok(())
153 }
154
155 #[inline]
156 pub(crate) async fn decode_u32<T: AsyncRead + Unpin>(
157 reader: &mut T,
158 property_id: PropertyId,
159 target: &mut Option<u32>,
160 ) -> Result<(), ErrorV5> {
161 if target.is_some() {
162 return Err(ErrorV5::DuplicatedProperty(property_id));
163 }
164 *target = Some(read_u32(reader).await?);
165 Ok(())
166 }
167
168 #[inline]
169 pub(crate) async fn decode_string<T: AsyncRead + Unpin>(
170 reader: &mut T,
171 property_id: PropertyId,
172 target: &mut Option<Arc<String>>,
173 ) -> Result<(), ErrorV5> {
174 if target.is_some() {
175 return Err(ErrorV5::DuplicatedProperty(property_id));
176 }
177 *target = Some(Arc::new(read_string(reader).await?));
178 Ok(())
179 }
180
181 #[inline]
182 pub(crate) async fn decode_topic_name<T: AsyncRead + Unpin>(
183 reader: &mut T,
184 property_id: PropertyId,
185 target: &mut Option<TopicName>,
186 ) -> Result<(), ErrorV5> {
187 if target.is_some() {
188 return Err(ErrorV5::DuplicatedProperty(property_id));
189 }
190 let content = read_string(reader).await?;
191 *target = Some(TopicName::try_from(content)?);
192 Ok(())
193 }
194
195 #[inline]
196 pub(crate) async fn decode_bytes<T: AsyncRead + Unpin>(
197 reader: &mut T,
198 property_id: PropertyId,
199 target: &mut Option<Bytes>,
200 ) -> Result<(), ErrorV5> {
201 if target.is_some() {
202 return Err(ErrorV5::DuplicatedProperty(property_id));
203 }
204 *target = Some(Bytes::from(read_bytes(reader).await?));
205 Ok(())
206 }
207
208 #[inline]
209 pub(crate) async fn decode_user_property<T: AsyncRead + Unpin>(
210 reader: &mut T,
211 ) -> Result<UserProperty, ErrorV5> {
212 let name = read_string(reader).await?;
213 let value = read_string(reader).await?;
214 Ok(UserProperty {
215 name: Arc::new(name),
216 value: Arc::new(value),
217 })
218 }
219}
220
221#[derive(Debug, Clone, PartialEq, Eq, Hash)]
223#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
224pub struct UserProperty {
225 pub name: Arc<String>,
227 pub value: Arc<String>,
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
233pub struct VarByteInt(u32);
234
235#[cfg(feature = "arbitrary")]
236impl<'a> arbitrary::Arbitrary<'a> for VarByteInt {
237 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
238 let value: u32 = u.arbitrary()?;
239 Ok(VarByteInt(value % 268435456))
240 }
241}
242
243impl VarByteInt {
244 pub fn value(self) -> u32 {
245 self.0
246 }
247}
248
249impl TryFrom<u32> for VarByteInt {
250 type Error = ErrorV5;
251 fn try_from(value: u32) -> Result<Self, ErrorV5> {
252 if value < 268435456 {
253 Ok(VarByteInt(value))
254 } else {
255 Err(Error::InvalidVarByteInt.into())
256 }
257 }
258}
259
260macro_rules! decode_property {
261 (PayloadFormatIndicator, $properties:expr, $reader:expr, $property_id:expr) => {
262 crate::v5::PropertyValue::decode_bool(
263 $reader,
264 $property_id,
265 &mut $properties.payload_is_utf8,
266 )
267 .await?;
268 };
269 (MessageExpiryInterval, $properties:expr, $reader:expr, $property_id:expr) => {
270 crate::v5::PropertyValue::decode_u32(
271 $reader,
272 $property_id,
273 &mut $properties.message_expiry_interval,
274 )
275 .await?;
276 };
277 (ContentType, $properties:expr, $reader:expr, $property_id:expr) => {
278 crate::v5::PropertyValue::decode_string(
279 $reader,
280 $property_id,
281 &mut $properties.content_type,
282 )
283 .await?;
284 };
285 (ResponseTopic, $properties:expr, $reader:expr, $property_id:expr) => {
286 crate::v5::PropertyValue::decode_topic_name(
287 $reader,
288 $property_id,
289 &mut $properties.response_topic,
290 )
291 .await
292 .map_err(|err| match err {
293 crate::v5::ErrorV5::Common(crate::Error::InvalidTopicName(_)) => {
294 crate::v5::ErrorV5::InvalidResponseTopic
295 }
296 err => err,
297 })?;
298 };
299 (CorrelationData, $properties:expr, $reader:expr, $property_id:expr) => {
300 crate::v5::PropertyValue::decode_bytes(
301 $reader,
302 $property_id,
303 &mut $properties.correlation_data,
304 )
305 .await?;
306 };
307 (SubscriptionIdentifier, $properties:expr, $reader:expr, $property_id:expr) => {
308 if $properties.subscription_id.is_some() {
309 return Err(crate::v5::ErrorV5::DuplicatedProperty($property_id));
310 }
311 let (value, _bytes) = crate::decode_var_int($reader).await?;
312 $properties.subscription_id = Some(crate::v5::VarByteInt::try_from(value)?);
313 };
314 (SessionExpiryInterval, $properties:expr, $reader:expr, $property_id:expr) => {
315 crate::v5::PropertyValue::decode_u32(
316 $reader,
317 $property_id,
318 &mut $properties.session_expiry_interval,
319 )
320 .await?;
321 };
322 (AssignedClientIdentifier, $properties:expr, $reader:expr, $property_id:expr) => {
323 crate::v5::PropertyValue::decode_string(
324 $reader,
325 $property_id,
326 &mut $properties.assigned_client_id,
327 )
328 .await?;
329 };
330 (ServerKeepAlive, $properties:expr, $reader:expr, $property_id:expr) => {
331 crate::v5::PropertyValue::decode_u16(
332 $reader,
333 $property_id,
334 &mut $properties.server_keep_alive,
335 )
336 .await?;
337 };
338 (AuthenticationMethod, $properties:expr, $reader:expr, $property_id:expr) => {
339 crate::v5::PropertyValue::decode_string(
340 $reader,
341 $property_id,
342 &mut $properties.auth_method,
343 )
344 .await?;
345 };
346 (AuthenticationData, $properties:expr, $reader:expr, $property_id:expr) => {
347 crate::v5::PropertyValue::decode_bytes($reader, $property_id, &mut $properties.auth_data)
348 .await?;
349 };
350 (RequestProblemInformation, $properties:expr, $reader:expr, $property_id:expr) => {
351 crate::v5::PropertyValue::decode_bool(
352 $reader,
353 $property_id,
354 &mut $properties.request_problem_info,
355 )
356 .await?;
357 };
358 (WillDelayInterval, $properties:expr, $reader:expr, $property_id:expr) => {
359 crate::v5::PropertyValue::decode_u32(
360 $reader,
361 $property_id,
362 &mut $properties.delay_interval,
363 )
364 .await?;
365 };
366 (RequestResponseInformation, $properties:expr, $reader:expr, $property_id:expr) => {
367 crate::v5::PropertyValue::decode_bool(
368 $reader,
369 $property_id,
370 &mut $properties.request_response_info,
371 )
372 .await?;
373 };
374 (ResponseInformation, $properties:expr, $reader:expr, $property_id:expr) => {
375 crate::v5::PropertyValue::decode_string(
376 $reader,
377 $property_id,
378 &mut $properties.response_info,
379 )
380 .await?;
381 };
382 (ServerReference, $properties:expr, $reader:expr, $property_id:expr) => {
383 crate::v5::PropertyValue::decode_string(
384 $reader,
385 $property_id,
386 &mut $properties.server_reference,
387 )
388 .await?;
389 };
390 (ReasonString, $properties:expr, $reader:expr, $property_id:expr) => {
391 crate::v5::PropertyValue::decode_string(
392 $reader,
393 $property_id,
394 &mut $properties.reason_string,
395 )
396 .await?;
397 };
398 (ReceiveMaximum, $properties:expr, $reader:expr, $property_id:expr) => {
399 crate::v5::PropertyValue::decode_u16($reader, $property_id, &mut $properties.receive_max)
400 .await?;
401 };
402 (TopicAliasMaximum, $properties:expr, $reader:expr, $property_id:expr) => {
403 crate::v5::PropertyValue::decode_u16(
404 $reader,
405 $property_id,
406 &mut $properties.topic_alias_max,
407 )
408 .await?;
409 };
410 (TopicAlias, $properties:expr, $reader:expr, $property_id:expr) => {
411 crate::v5::PropertyValue::decode_u16($reader, $property_id, &mut $properties.topic_alias)
412 .await?;
413 };
414 (MaximumQoS, $properties:expr, $reader:expr, $property_id:expr) => {
415 if $properties.max_qos.is_some() {
416 return Err(crate::v5::ErrorV5::DuplicatedProperty($property_id));
417 }
418 let value = crate::read_u8($reader).await?;
419 if value > 1 {
420 return Err(crate::v5::ErrorV5::InvalidByteProperty($property_id, value));
421 } else {
422 $properties.max_qos = Some(crate::QoS::from_u8(value).expect("0/1 qos"));
423 }
424 };
425 (RetainAvailable, $properties:expr, $reader:expr, $property_id:expr) => {
426 crate::v5::PropertyValue::decode_bool(
427 $reader,
428 $property_id,
429 &mut $properties.retain_available,
430 )
431 .await?;
432 };
433 (UserProperty, $properties:expr, $reader:expr, $property_id:expr) => {
434 let user_property = crate::v5::PropertyValue::decode_user_property($reader).await?;
435 $properties.user_properties.push(user_property);
436 };
437 (MaximumPacketSize, $properties:expr, $reader:expr, $property_id:expr) => {
438 crate::v5::PropertyValue::decode_u32(
439 $reader,
440 $property_id,
441 &mut $properties.max_packet_size,
442 )
443 .await?;
444 };
445 (WildcardSubscriptionAvailable, $properties:expr, $reader:expr, $property_id:expr) => {
446 crate::v5::PropertyValue::decode_bool(
447 $reader,
448 $property_id,
449 &mut $properties.wildcard_subscription_available,
450 )
451 .await?;
452 };
453 (SubscriptionIdentifierAvailable, $properties:expr, $reader:expr, $property_id:expr) => {
454 crate::v5::PropertyValue::decode_bool(
455 $reader,
456 $property_id,
457 &mut $properties.subscription_id_available,
458 )
459 .await?;
460 };
461 (SharedSubscriptionAvailable, $properties:expr, $reader:expr, $property_id:expr) => {
462 crate::v5::PropertyValue::decode_bool(
463 $reader,
464 $property_id,
465 &mut $properties.shared_subscription_available,
466 )
467 .await?;
468 };
469}
470
471macro_rules! decode_properties {
472 (LastWill, $properties:expr, $reader:expr, $($t:ident,)*) => {
473 let (property_len, _bytes) = crate::decode_var_int($reader).await?;
474 let mut len = 0;
475 while property_len as usize > len {
476 let property_id = crate::v5::PropertyId::from_u8(crate::read_u8($reader).await?)?;
477 match property_id {
478 $(
479 crate::v5::PropertyId::$t => {
480 crate::v5::decode_property!($t, $properties, $reader, property_id);
481 crate::v5::encode_property_len!($t, $properties, len);
482 }
483 )*
484 crate::v5::PropertyId::UserProperty => {
485 crate::v5::decode_property!(UserProperty, $properties, $reader, property_id);
486 let last = $properties.user_properties.last().expect("user property exists");
487 len += 1 + 4 + last.name.len() + last.value.len();
488 }
489 _ => return Err(crate::v5::ErrorV5::InvalidWillProperty(property_id)),
490 }
491 }
492 if property_len as usize != len {
493 return Err(crate::v5::ErrorV5::InvalidPropertyLength(property_len));
494 }
495 };
496 ($packet_type:expr, $properties:expr, $reader:expr, $($t:ident,)*) => {
497 let (property_len, _bytes) = crate::decode_var_int($reader).await?;
498 let mut len = 0;
499 while property_len as usize > len {
500 let property_id = crate::v5::PropertyId::from_u8(crate::read_u8($reader).await?)?;
501 match property_id {
502 $(
503 crate::v5::PropertyId::$t => {
504 crate::v5::decode_property!($t, $properties, $reader, property_id);
505 crate::v5::encode_property_len!($t, $properties, len);
506 }
507 )*
508 crate::v5::PropertyId::UserProperty => {
509 crate::v5::decode_property!(UserProperty, $properties, $reader, property_id);
510 let last = $properties.user_properties.last().expect("user property exists");
511 len += 1 + 4 + last.name.len() + last.value.len();
512 }
513 _ => return Err(crate::v5::ErrorV5::InvalidProperty($packet_type, property_id)),
514 }
515 }
516 if property_len as usize != len {
517 return Err(crate::v5::ErrorV5::InvalidPropertyLength(property_len));
518 }
519 };
520}
521
522pub(crate) use decode_properties;
523pub(crate) use decode_property;
524
525macro_rules! encode_property {
526 (PayloadFormatIndicator, $properties:expr, $writer: expr) => {
527 if let Some(value) = $properties.payload_is_utf8 {
528 crate::write_u8($writer, crate::v5::PropertyId::PayloadFormatIndicator as u8)?;
529 crate::write_u8($writer, u8::from(value))?;
530 }
531 };
532 (MessageExpiryInterval, $properties:expr, $writer: expr) => {
533 if let Some(value) = $properties.message_expiry_interval {
534 crate::write_u8($writer, crate::v5::PropertyId::MessageExpiryInterval as u8)?;
535 crate::write_u32($writer, value)?;
536 }
537 };
538 (ContentType, $properties:expr, $writer: expr) => {
539 if let Some(value) = $properties.content_type.as_ref() {
540 crate::write_u8($writer, crate::v5::PropertyId::ContentType as u8)?;
541 crate::write_bytes($writer, value.as_bytes())?;
542 }
543 };
544 (ResponseTopic, $properties:expr, $writer: expr) => {
545 if let Some(value) = $properties.response_topic.as_ref() {
546 crate::write_u8($writer, crate::v5::PropertyId::ResponseTopic as u8)?;
547 crate::write_bytes($writer, value.as_bytes())?;
548 }
549 };
550 (CorrelationData, $properties:expr, $writer: expr) => {
551 if let Some(value) = $properties.correlation_data.as_ref() {
552 crate::write_u8($writer, crate::v5::PropertyId::CorrelationData as u8)?;
553 crate::write_bytes($writer, value.as_ref())?;
554 }
555 };
556 (SubscriptionIdentifier, $properties:expr, $writer: expr) => {
557 if let Some(value) = $properties.subscription_id {
558 crate::write_u8($writer, crate::v5::PropertyId::SubscriptionIdentifier as u8)?;
559 crate::write_var_int($writer, value.value() as usize)?;
560 }
561 };
562 (SessionExpiryInterval, $properties:expr, $writer: expr) => {
563 if let Some(value) = $properties.session_expiry_interval {
564 crate::write_u8($writer, crate::v5::PropertyId::SessionExpiryInterval as u8)?;
565 crate::write_u32($writer, value)?;
566 }
567 };
568 (AssignedClientIdentifier, $properties:expr, $writer: expr) => {
569 if let Some(value) = $properties.assigned_client_id.as_ref() {
570 crate::write_u8(
571 $writer,
572 crate::v5::PropertyId::AssignedClientIdentifier as u8,
573 )?;
574 crate::write_bytes($writer, value.as_bytes())?;
575 }
576 };
577 (ServerKeepAlive, $properties:expr, $writer: expr) => {
578 if let Some(value) = $properties.server_keep_alive {
579 crate::write_u8($writer, crate::v5::PropertyId::ServerKeepAlive as u8)?;
580 crate::write_u16($writer, value)?;
581 }
582 };
583 (AuthenticationMethod, $properties:expr, $writer: expr) => {
584 if let Some(value) = $properties.auth_method.as_ref() {
585 crate::write_u8($writer, crate::v5::PropertyId::AuthenticationMethod as u8)?;
586 crate::write_bytes($writer, value.as_bytes())?;
587 }
588 };
589 (AuthenticationData, $properties:expr, $writer: expr) => {
590 if let Some(value) = $properties.auth_data.as_ref() {
591 crate::write_u8($writer, crate::v5::PropertyId::AuthenticationData as u8)?;
592 crate::write_bytes($writer, value.as_ref())?;
593 }
594 };
595 (RequestProblemInformation, $properties:expr, $writer: expr) => {
596 if let Some(value) = $properties.request_problem_info {
597 crate::write_u8(
598 $writer,
599 crate::v5::PropertyId::RequestProblemInformation as u8,
600 )?;
601 crate::write_u8($writer, u8::from(value))?;
602 }
603 };
604 (WillDelayInterval, $properties:expr, $writer: expr) => {
605 if let Some(value) = $properties.delay_interval {
606 crate::write_u8($writer, crate::v5::PropertyId::WillDelayInterval as u8)?;
607 crate::write_u32($writer, value)?;
608 }
609 };
610 (RequestResponseInformation, $properties:expr, $writer: expr) => {
611 if let Some(value) = $properties.request_response_info {
612 crate::write_u8(
613 $writer,
614 crate::v5::PropertyId::RequestResponseInformation as u8,
615 )?;
616 crate::write_u8($writer, u8::from(value))?;
617 }
618 };
619 (ResponseInformation, $properties:expr, $writer: expr) => {
620 if let Some(value) = $properties.response_info.as_ref() {
621 crate::write_u8($writer, crate::v5::PropertyId::ResponseInformation as u8)?;
622 crate::write_bytes($writer, value.as_bytes())?;
623 }
624 };
625 (ServerReference, $properties:expr, $writer: expr) => {
626 if let Some(value) = $properties.server_reference.as_ref() {
627 crate::write_u8($writer, crate::v5::PropertyId::ServerReference as u8)?;
628 crate::write_bytes($writer, value.as_bytes())?;
629 }
630 };
631 (ReasonString, $properties:expr, $writer: expr) => {
632 if let Some(value) = $properties.reason_string.as_ref() {
633 crate::write_u8($writer, crate::v5::PropertyId::ReasonString as u8)?;
634 crate::write_bytes($writer, value.as_bytes())?;
635 }
636 };
637 (ReceiveMaximum, $properties:expr, $writer: expr) => {
638 if let Some(value) = $properties.receive_max {
639 crate::write_u8($writer, crate::v5::PropertyId::ReceiveMaximum as u8)?;
640 crate::write_u16($writer, value)?;
641 }
642 };
643 (TopicAliasMaximum, $properties:expr, $writer: expr) => {
644 if let Some(value) = $properties.topic_alias_max {
645 crate::write_u8($writer, crate::v5::PropertyId::TopicAliasMaximum as u8)?;
646 crate::write_u16($writer, value)?;
647 }
648 };
649 (TopicAlias, $properties:expr, $writer: expr) => {
650 if let Some(value) = $properties.topic_alias {
651 crate::write_u8($writer, crate::v5::PropertyId::TopicAlias as u8)?;
652 crate::write_u16($writer, value)?;
653 }
654 };
655 (MaximumQoS, $properties:expr, $writer: expr) => {
656 if let Some(value) = $properties.max_qos {
657 crate::write_u8($writer, crate::v5::PropertyId::MaximumQoS as u8)?;
658 crate::write_u8($writer, value as u8)?;
659 }
660 };
661 (RetainAvailable, $properties:expr, $writer: expr) => {
662 if let Some(value) = $properties.retain_available {
663 crate::write_u8($writer, crate::v5::PropertyId::RetainAvailable as u8)?;
664 crate::write_u8($writer, u8::from(value))?;
665 }
666 };
667 (MaximumPacketSize, $properties:expr, $writer: expr) => {
668 if let Some(value) = $properties.max_packet_size {
669 crate::write_u8($writer, crate::v5::PropertyId::MaximumPacketSize as u8)?;
670 crate::write_u32($writer, value)?;
671 }
672 };
673 (WildcardSubscriptionAvailable, $properties:expr, $writer: expr) => {
674 if let Some(value) = $properties.wildcard_subscription_available {
675 crate::write_u8(
676 $writer,
677 crate::v5::PropertyId::WildcardSubscriptionAvailable as u8,
678 )?;
679 crate::write_u8($writer, u8::from(value))?;
680 }
681 };
682 (SubscriptionIdentifierAvailable, $properties:expr, $writer: expr) => {
683 if let Some(value) = $properties.subscription_id_available {
684 crate::write_u8(
685 $writer,
686 crate::v5::PropertyId::SubscriptionIdentifierAvailable as u8,
687 )?;
688 crate::write_u8($writer, u8::from(value))?;
689 }
690 };
691 (SharedSubscriptionAvailable, $properties:expr, $writer: expr) => {
692 if let Some(value) = $properties.shared_subscription_available {
693 crate::write_u8(
694 $writer,
695 crate::v5::PropertyId::SharedSubscriptionAvailable as u8,
696 )?;
697 crate::write_u8($writer, u8::from(value))?;
698 }
699 };
700}
701
702macro_rules! encode_properties {
703 ($properties:expr, $writer:expr) => {
704 let property_len = $properties.user_properties.len() + $properties
705 .user_properties
706 .iter()
707 .map(|property| 4 + property.name.len() + property.value.len())
708 .sum::<usize>();
709 crate::write_var_int($writer, property_len)?;
710 for UserProperty { name, value } in $properties.user_properties.iter() {
711 crate::write_u8($writer, crate::v5::PropertyId::UserProperty as u8)?;
712 crate::write_bytes($writer, name.as_bytes())?;
713 crate::write_bytes($writer, value.as_bytes())?;
714 }
715 };
716 ($properties:expr, $writer:expr, $($t:ident,)+) => {
717 let mut property_len = $properties.user_properties.len() + $properties
718 .user_properties
719 .iter()
720 .map(|property| 4 + property.name.len() + property.value.len())
721 .sum::<usize>();
722 $(
723 crate::v5::encode_property_len!($t, $properties, property_len);
724 )+
725
726 crate::write_var_int($writer, property_len)?;
727 $(
728 crate::v5::encode_property!($t, $properties, $writer);
729 )*
730
731 for UserProperty { name, value } in $properties.user_properties.iter() {
732 crate::write_u8($writer, crate::v5::PropertyId::UserProperty as u8)?;
733 crate::write_bytes($writer, name.as_bytes())?;
734 crate::write_bytes($writer, value.as_bytes())?;
735 }
736 };
737}
738
739pub(crate) use encode_properties;
740pub(crate) use encode_property;
741
742macro_rules! encode_property_len {
743 (PayloadFormatIndicator, $properties:expr, $property_len:expr) => {
744 if $properties.payload_is_utf8.is_some() {
745 $property_len += 1 + 1;
746 }
747 };
748 (MessageExpiryInterval, $properties:expr, $property_len:expr) => {
749 if $properties.message_expiry_interval.is_some() {
750 $property_len += 1 + 4;
751 }
752 };
753 (ContentType, $properties:expr, $property_len:expr) => {
754 if let Some(value) = $properties.content_type.as_ref() {
755 $property_len += 1 + 2 + value.len();
756 }
757 };
758 (ResponseTopic, $properties:expr, $property_len:expr) => {
759 if let Some(value) = $properties.response_topic.as_ref() {
760 $property_len += 1 + 2 + value.len();
761 }
762 };
763 (CorrelationData, $properties:expr, $property_len:expr) => {
764 if let Some(value) = $properties.correlation_data.as_ref() {
765 $property_len += 1 + 2 + value.len();
766 }
767 };
768 (SubscriptionIdentifier, $properties:expr, $property_len:expr) => {
769 if let Some(value) = $properties.subscription_id {
770 $property_len += 1 + crate::var_int_len(value.value() as usize)
771 .expect("subscription id exceed 268,435,455");
772 }
773 };
774 (SessionExpiryInterval, $properties:expr, $property_len:expr) => {
775 if $properties.session_expiry_interval.is_some() {
776 $property_len += 1 + 4;
777 }
778 };
779 (AssignedClientIdentifier, $properties:expr, $property_len:expr) => {
780 if let Some(value) = $properties.assigned_client_id.as_ref() {
781 $property_len += 1 + 2 + value.len();
782 }
783 };
784 (ServerKeepAlive, $properties:expr, $property_len:expr) => {
785 if $properties.server_keep_alive.is_some() {
786 $property_len += 1 + 2;
787 }
788 };
789 (AuthenticationMethod, $properties:expr, $property_len:expr) => {
790 if let Some(value) = $properties.auth_method.as_ref() {
791 $property_len += 1 + 2 + value.len();
792 }
793 };
794 (AuthenticationData, $properties:expr, $property_len:expr) => {
795 if let Some(value) = $properties.auth_data.as_ref() {
796 $property_len += 1 + 2 + value.len();
797 }
798 };
799 (RequestProblemInformation, $properties:expr, $property_len:expr) => {
800 if $properties.request_problem_info.is_some() {
801 $property_len += 1 + 1;
802 }
803 };
804 (WillDelayInterval, $properties:expr, $property_len:expr) => {
805 if $properties.delay_interval.is_some() {
806 $property_len += 1 + 4;
807 }
808 };
809 (RequestResponseInformation, $properties:expr, $property_len:expr) => {
810 if $properties.request_response_info.is_some() {
811 $property_len += 1 + 1;
812 }
813 };
814 (ResponseInformation, $properties:expr, $property_len:expr) => {
815 if let Some(value) = $properties.response_info.as_ref() {
816 $property_len += 1 + 2 + value.len();
817 }
818 };
819 (ServerReference, $properties:expr, $property_len:expr) => {
820 if let Some(value) = $properties.server_reference.as_ref() {
821 $property_len += 1 + 2 + value.len();
822 }
823 };
824 (ReasonString, $properties:expr, $property_len:expr) => {
825 if let Some(value) = $properties.reason_string.as_ref() {
826 $property_len += 1 + 2 + value.len();
827 }
828 };
829 (ReceiveMaximum, $properties:expr, $property_len:expr) => {
830 if $properties.receive_max.is_some() {
831 $property_len += 1 + 2;
832 }
833 };
834 (TopicAliasMaximum, $properties:expr, $property_len:expr) => {
835 if $properties.topic_alias_max.is_some() {
836 $property_len += 1 + 2;
837 }
838 };
839 (TopicAlias, $properties:expr, $property_len:expr) => {
840 if $properties.topic_alias.is_some() {
841 $property_len += 1 + 2;
842 }
843 };
844 (MaximumQoS, $properties:expr, $property_len:expr) => {
845 if $properties.max_qos.is_some() {
846 $property_len += 1 + 1;
847 }
848 };
849 (RetainAvailable, $properties:expr, $property_len:expr) => {
850 if $properties.retain_available.is_some() {
851 $property_len += 1 + 1;
852 }
853 };
854 (MaximumPacketSize, $properties:expr, $property_len:expr) => {
855 if $properties.max_packet_size.is_some() {
856 $property_len += 1 + 4;
857 }
858 };
859 (WildcardSubscriptionAvailable, $properties:expr, $property_len:expr) => {
860 if $properties.wildcard_subscription_available.is_some() {
861 $property_len += 1 + 1;
862 }
863 };
864 (SubscriptionIdentifierAvailable, $properties:expr, $property_len:expr) => {
865 if $properties.subscription_id_available.is_some() {
866 $property_len += 1 + 1;
867 }
868 };
869 (SharedSubscriptionAvailable, $properties:expr, $property_len:expr) => {
870 if $properties.shared_subscription_available.is_some() {
871 $property_len += 1 + 1;
872 }
873 };
874}
875
876macro_rules! encode_properties_len {
877 ($properties:expr, $len:expr) => {
878 let property_len: usize = $properties.user_properties.len() + $properties
880 .user_properties
881 .iter()
882 .map(|property| 4 + property.name.len() + property.value.len())
883 .sum::<usize>();
884 $len += property_len + crate::var_int_len(property_len).expect("total properties length exceed 268,435,455");
885 };
886 ($properties:expr, $len:expr, $($t:ident,)+) => {
887 let mut property_len: usize = $properties.user_properties.len() + $properties
889 .user_properties
890 .iter()
891 .map(|property| 4 + property.name.len() + property.value.len())
892 .sum::<usize>();
893 $(
894 crate::v5::encode_property_len!($t, $properties, property_len);
895 )+
896
897 $len += property_len + crate::var_int_len(property_len).expect("total properties length exceed 268,435,455");
898 };
899}
900
901pub(crate) use encode_properties_len;
902pub(crate) use encode_property_len;