+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (static_value, $value: expr)) => {
+ };
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, required) => {{
+ #[allow(unused_comparisons)] // Note that $type may be 0 making the second comparison always false
+ let invalid_order = ($last_seen_type.is_none() || $last_seen_type.unwrap() < $type) && $typ.0 > $type;
+ if invalid_order {
+ return Err(DecodeError::InvalidValue);
+ }
+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
+ $crate::_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required);
+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, option) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, vec_type) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, upgradable_required) => {{
+ _check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required)
+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, upgradable_option) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
+ // no-op
+ }};
+}
+
+/// Errors if there are missing required TLV types after the last seen type.
+/// This is exported for use by other exported macros, do not use directly.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! _check_missing_tlv {
+ ($last_seen_type: expr, $type: expr, $field: ident, (default_value, $default: expr)) => {{
+ #[allow(unused_comparisons)] // Note that $type may be 0 making the second comparison always false
+ let missing_req_type = $last_seen_type.is_none() || $last_seen_type.unwrap() < $type;
+ if missing_req_type {
+ $field = $default.into();
+ }
+ }};
+ ($last_seen_type: expr, $type: expr, $field: expr, (static_value, $value: expr)) => {
+ $field = $value;
+ };
+ ($last_seen_type: expr, $type: expr, $field: ident, required) => {{
+ #[allow(unused_comparisons)] // Note that $type may be 0 making the second comparison always false
+ let missing_req_type = $last_seen_type.is_none() || $last_seen_type.unwrap() < $type;
+ if missing_req_type {
+ return Err(DecodeError::InvalidValue);
+ }
+ }};
+ ($last_seen_type: expr, $type: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
+ $crate::_check_missing_tlv!($last_seen_type, $type, $field, required);
+ }};
+ ($last_seen_type: expr, $type: expr, $field: ident, vec_type) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $type: expr, $field: ident, option) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $type: expr, $field: ident, upgradable_required) => {{
+ _check_missing_tlv!($last_seen_type, $type, $field, required)
+ }};
+ ($last_seen_type: expr, $type: expr, $field: ident, upgradable_option) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
+ // no-op
+ }};
+ ($last_seen_type: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
+ // no-op
+ }};
+}
+
+/// Implements deserialization for a single TLV record.
+/// This is exported for use by other exported macros, do not use directly.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! _decode_tlv {
+ ($reader: expr, $field: ident, (default_value, $default: expr)) => {{
+ $crate::_decode_tlv!($reader, $field, required)
+ }};
+ ($reader: expr, $field: ident, (static_value, $value: expr)) => {{
+ }};
+ ($reader: expr, $field: ident, required) => {{
+ $field = $crate::util::ser::Readable::read(&mut $reader)?;
+ }};
+ ($reader: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
+ $field = $trait::read(&mut $reader $(, $read_arg)*)?;
+ }};
+ ($reader: expr, $field: ident, vec_type) => {{
+ let f: $crate::util::ser::WithoutLength<Vec<_>> = $crate::util::ser::Readable::read(&mut $reader)?;
+ $field = Some(f.0);
+ }};
+ ($reader: expr, $field: ident, option) => {{
+ $field = Some($crate::util::ser::Readable::read(&mut $reader)?);
+ }};
+ // `upgradable_required` indicates we're reading a required TLV that may have been upgraded
+ // without backwards compat. We'll error if the field is missing, and return `Ok(None)` if the
+ // field is present but we can no longer understand it.
+ // Note that this variant can only be used within a `MaybeReadable` read.
+ ($reader: expr, $field: ident, upgradable_required) => {{
+ $field = match $crate::util::ser::MaybeReadable::read(&mut $reader)? {
+ Some(res) => res,
+ _ => return Ok(None)
+ };
+ }};
+ // `upgradable_option` indicates we're reading an Option-al TLV that may have been upgraded
+ // without backwards compat. $field will be None if the TLV is missing or if the field is present
+ // but we can no longer understand it.
+ ($reader: expr, $field: ident, upgradable_option) => {{
+ $field = $crate::util::ser::MaybeReadable::read(&mut $reader)?;
+ }};
+ ($reader: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
+ $field = Some($trait::read(&mut $reader $(, $read_arg)*)?);
+ }};
+ ($reader: expr, $field: ident, (option, encoding: ($fieldty: ty, $encoding: ident, $encoder:ty))) => {{
+ $crate::_decode_tlv!($reader, $field, (option, encoding: ($fieldty, $encoding)));
+ }};
+ ($reader: expr, $field: ident, (option, encoding: ($fieldty: ty, $encoding: ident))) => {{
+ $field = {
+ let field: $encoding<$fieldty> = ser::Readable::read(&mut $reader)?;
+ Some(field.0)
+ };
+ }};
+ ($reader: expr, $field: ident, (option, encoding: $fieldty: ty)) => {{
+ $crate::_decode_tlv!($reader, $field, option);
+ }};
+}