@@ -26,6 +26,12 @@ macro_rules! encode_tlv {
2626 field.write($stream)?;
2727 }
2828 };
29+ ($stream: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident))) => {
30+ encode_tlv!($stream, $type, $field.map(|f| $encoding(f)), option);
31+ };
32+ ($stream: expr, $type: expr, $field: expr, (option, encoding: $fieldty: ty)) => {
33+ encode_tlv!($stream, $type, $field, option);
34+ };
2935}
3036
3137macro_rules! encode_tlv_stream {
@@ -121,6 +127,9 @@ macro_rules! check_tlv_order {
121127 ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
122128 // no-op
123129 }};
130+ ($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
131+ // no-op
132+ }};
124133}
125134
126135macro_rules! check_missing_tlv {
@@ -150,6 +159,9 @@ macro_rules! check_missing_tlv {
150159 ($last_seen_type: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
151160 // no-op
152161 }};
162+ ($last_seen_type: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
163+ // no-op
164+ }};
153165}
154166
155167macro_rules! decode_tlv {
@@ -172,6 +184,15 @@ macro_rules! decode_tlv {
172184 ($reader: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
173185 $field = Some($trait::read(&mut $reader $(, $read_arg)*)?);
174186 }};
187+ ($reader: expr, $field: ident, (option, encoding: ($fieldty: ty, $encoding: ident))) => {{
188+ $field = {
189+ let field: $encoding<$fieldty> = ser::Readable::read(&mut $reader)?;
190+ Some(field.0)
191+ };
192+ }};
193+ ($reader: expr, $field: ident, (option, encoding: $fieldty: ty)) => {{
194+ decode_tlv!($reader, $field, option);
195+ }};
175196}
176197
177198// `$decode_custom_tlv` is a closure that may be optionally provided to handle custom message types.
@@ -441,6 +462,75 @@ macro_rules! impl_writeable_tlv_based {
441462 }
442463}
443464
465+ /// Defines a struct for a TLV stream and a similar struct using references for non-primitive types,
466+ /// implementing [`Readable`] for the former and [`Writeable`] for the latter. Useful as an
467+ /// intermediary format when reading or writing a type encoded as a TLV stream. Note that each field
468+ /// representing a TLV record has its type wrapped with an [`Option`]. A tuple consisting of a type
469+ /// and a serialization wrapper may be given in place of a type when custom serialization is
470+ /// required.
471+ ///
472+ /// [`Readable`]: crate::util::ser::Readable
473+ /// [`Writeable`]: crate::util::ser::Writeable
474+ macro_rules! tlv_stream {
475+ ($name:ident, $nameref:ident, {
476+ $(($type:expr, $field:ident : $fieldty:tt)),* $(,)*
477+ }) => {
478+ #[derive(Debug)]
479+ struct $name {
480+ $(
481+ $field: Option<tlv_record_type!($fieldty)>,
482+ )*
483+ }
484+
485+ pub(crate) struct $nameref<'a> {
486+ $(
487+ pub(crate) $field: Option<tlv_record_ref_type!($fieldty)>,
488+ )*
489+ }
490+
491+ impl<'a> $crate::util::ser::Writeable for $nameref<'a> {
492+ fn write<W: $crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), $crate::io::Error> {
493+ encode_tlv_stream!(writer, {
494+ $(($type, self.$field, (option, encoding: $fieldty))),*
495+ });
496+ Ok(())
497+ }
498+ }
499+
500+ impl $crate::util::ser::Readable for $name {
501+ fn read<R: $crate::io::Read>(reader: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
502+ $(
503+ init_tlv_field_var!($field, option);
504+ )*
505+ decode_tlv_stream!(reader, {
506+ $(($type, $field, (option, encoding: $fieldty))),*
507+ });
508+
509+ Ok(Self {
510+ $(
511+ $field: $field
512+ ),*
513+ })
514+ }
515+ }
516+ }
517+ }
518+
519+ macro_rules! tlv_record_type {
520+ (($type:ty, $wrapper:ident)) => { $type };
521+ ($type:ty) => { $type };
522+ }
523+
524+ macro_rules! tlv_record_ref_type {
525+ (char) => { char };
526+ (u8) => { u8 };
527+ ((u16, $wrapper: ident)) => { u16 };
528+ ((u32, $wrapper: ident)) => { u32 };
529+ ((u64, $wrapper: ident)) => { u64 };
530+ (($type:ty, $wrapper:ident)) => { &'a $type };
531+ ($type:ty) => { &'a $type };
532+ }
533+
444534macro_rules! _impl_writeable_tlv_based_enum_common {
445535 ($st: ident, $(($variant_id: expr, $variant_name: ident) =>
446536 {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
0 commit comments