Merge pull request #2008 from valentinewallace/2023-02-remove-manual-retries
[rust-lightning] / lightning / src / util / ser_macros.rs
index 8d74a83a37365fc490ccf089449aad42bcb955ea..0aefaf383062b3d8ddcafbeb1465242ccf802e95 100644 (file)
@@ -39,6 +39,9 @@ macro_rules! _encode_tlv {
                        field.write($stream)?;
                }
        };
+       ($stream: expr, $type: expr, $field: expr, ignorable) => {
+               $crate::_encode_tlv!($stream, $type, $field, required);
+       };
        ($stream: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident))) => {
                $crate::_encode_tlv!($stream, $type, $field.map(|f| $encoding(f)), option);
        };
@@ -155,6 +158,9 @@ macro_rules! _get_varint_length_prefixed_tlv_length {
                        $len.0 += field_len;
                }
        };
+       ($len: expr, $type: expr, $field: expr, ignorable) => {
+               $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required);
+       };
 }
 
 /// See the documentation of [`write_tlv_fields`].
@@ -280,6 +286,9 @@ macro_rules! _decode_tlv {
        ($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)?;
@@ -451,20 +460,50 @@ macro_rules! _decode_tlv_stream_range {
        } }
 }
 
+/// Implements [`Readable`]/[`Writeable`] for a message struct that may include non-TLV and
+/// TLV-encoded parts.
+///
+/// This is useful to implement a [`CustomMessageReader`].
+///
+/// Currently `$fieldty` may only be `option`, i.e., `$tlvfield` is optional field.
+///
+/// For example,
+/// ```
+/// # use lightning::impl_writeable_msg;
+/// struct MyCustomMessage {
+///    pub field_1: u32,
+///    pub field_2: bool,
+///    pub field_3: String,
+///    pub tlv_optional_integer: Option<u32>,
+/// }
+///
+/// impl_writeable_msg!(MyCustomMessage, {
+///    field_1,
+///    field_2,
+///    field_3
+/// }, {
+///    (1, tlv_optional_integer, option),
+/// });
+/// ```
+///
+/// [`Readable`]: crate::util::ser::Readable
+/// [`Writeable`]: crate::util::ser::Writeable
+/// [`CustomMessageReader`]: crate::ln::wire::CustomMessageReader
+#[macro_export]
 macro_rules! impl_writeable_msg {
        ($st:ident, {$($field:ident),* $(,)*}, {$(($type: expr, $tlvfield: ident, $fieldty: tt)),* $(,)*}) => {
                impl $crate::util::ser::Writeable for $st {
                        fn write<W: $crate::util::ser::Writer>(&self, w: &mut W) -> Result<(), $crate::io::Error> {
                                $( self.$field.write(w)?; )*
-                               encode_tlv_stream!(w, {$(($type, self.$tlvfield, $fieldty)),*});
+                               $crate::encode_tlv_stream!(w, {$(($type, self.$tlvfield, $fieldty)),*});
                                Ok(())
                        }
                }
                impl $crate::util::ser::Readable for $st {
                        fn read<R: $crate::io::Read>(r: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
                                $(let $field = $crate::util::ser::Readable::read(r)?;)*
-                               $(_init_tlv_field_var!($tlvfield, $fieldty);)*
-                               decode_tlv_stream!(r, {$(($type, $tlvfield, $fieldty)),*});
+                               $($crate::_init_tlv_field_var!($tlvfield, $fieldty);)*
+                               $crate::decode_tlv_stream!(r, {$(($type, $tlvfield, $fieldty)),*});
                                Ok(Self {
                                        $($field),*,
                                        $($tlvfield),*
@@ -581,6 +620,9 @@ macro_rules! _init_tlv_based_struct_field {
        ($field: ident, option) => {
                $field
        };
+       ($field: ident, ignorable) => {
+               if $field.is_none() { return Ok(None); } else { $field.unwrap() }
+       };
        ($field: ident, required) => {
                $field.0.unwrap()
        };
@@ -610,6 +652,9 @@ macro_rules! _init_tlv_field_var {
        ($field: ident, option) => {
                let mut $field = None;
        };
+       ($field: ident, ignorable) => {
+               let mut $field = None;
+       };
 }
 
 /// Equivalent to running [`_init_tlv_field_var`] then [`read_tlv_fields`].
@@ -630,10 +675,10 @@ macro_rules! _init_and_read_tlv_fields {
 }
 
 /// Implements [`Readable`]/[`Writeable`] for a struct storing it as a set of TLVs
-/// If `$fieldty` is `required`, then `$field` is a required field that is not an Option nor a Vec.
+/// If `$fieldty` is `required`, then `$field` is a required field that is not an [`Option`] nor a [`Vec`].
 /// If `$fieldty` is `(default_value, $default)`, then `$field` will be set to `$default` if not present.
 /// If `$fieldty` is `option`, then `$field` is optional field.
-/// If `$fieldty` is `vec_type`, then `$field` is a Vec, which needs to have its individual elements serialized.
+/// If `$fieldty` is `vec_type`, then `$field` is a [`Vec`], which needs to have its individual elements serialized.
 ///
 /// For example,
 /// ```
@@ -718,7 +763,8 @@ macro_rules! tlv_stream {
                        )*
                }
 
-               #[derive(Debug, PartialEq)]
+               #[cfg_attr(test, derive(PartialEq))]
+               #[derive(Debug)]
                pub(super) struct $nameref<'a> {
                        $(
                                pub(super) $field: Option<tlv_record_ref_type!($fieldty)>,
@@ -758,6 +804,7 @@ macro_rules! tlv_stream {
 
 macro_rules! tlv_record_type {
        (($type:ty, $wrapper:ident)) => { $type };
+       (($type:ty, $wrapper:ident, $encoder:ty)) => { $type };
        ($type:ty) => { $type };
 }
 
@@ -768,6 +815,7 @@ macro_rules! tlv_record_ref_type {
        ((u32, $wrapper: ident)) => { u32 };
        ((u64, $wrapper: ident)) => { u64 };
        (($type:ty, $wrapper:ident)) => { &'a $type };
+       (($type:ty, $wrapper:ident, $encoder:ty)) => { $encoder };
        ($type:ty) => { &'a $type };
 }