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