#[doc(hidden)]
#[macro_export]
macro_rules! _encode_tlv {
($stream: expr, $type: expr, $field: expr, (default_value, $default: expr) $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $field, required)
};
($stream: expr, $type: expr, $field: expr, (static_value, $value: expr) $(, $self: ident)?) => {
let _ = &$field; };
($stream: expr, $type: expr, $field: expr, required $(, $self: ident)?) => {
BigSize($type).write($stream)?;
BigSize($field.serialized_length() as u64).write($stream)?;
$field.write($stream)?;
};
($stream: expr, $type: expr, $field: expr, (required: $trait: ident $(, $read_arg: expr)?) $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $field, required);
};
($stream: expr, $type: expr, $field: expr, required_vec $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $crate::util::ser::WithoutLength($field), required);
};
($stream: expr, $type: expr, $field: expr, (required_vec, encoding: ($fieldty: ty, $encoding: ident)) $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $encoding($field), required);
};
($stream: expr, $optional_type: expr, $optional_field: expr, option $(, $self: ident)?) => {
if let Some(ref field) = $optional_field {
BigSize($optional_type).write($stream)?;
BigSize(field.serialized_length() as u64).write($stream)?;
field.write($stream)?;
}
};
($stream: expr, $optional_type: expr, $optional_field: expr, (legacy, $fieldty: ty, $write: expr) $(, $self: ident)?) => { {
let value: Option<_> = $write($($self)?);
#[cfg(debug_assertions)]
{
if let Some(v) = &value {
let encoded_value = v.encode();
let mut read_slice = &encoded_value[..];
let _: $fieldty = $crate::util::ser::Readable::read(&mut read_slice)
.expect("Failed to read written TLV, check types");
assert!(read_slice.is_empty(), "Reading written TLV was short, check types");
}
}
$crate::_encode_tlv!($stream, $optional_type, value, option);
} };
($stream: expr, $type: expr, $field: expr, optional_vec $(, $self: ident)?) => {
if !$field.is_empty() {
$crate::_encode_tlv!($stream, $type, $field, required_vec);
}
};
($stream: expr, $type: expr, $field: expr, upgradable_required $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $field, required);
};
($stream: expr, $type: expr, $field: expr, upgradable_option $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $field, option);
};
($stream: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident) $(, $self: ident)?)) => {
$crate::_encode_tlv!($stream, $type, $field.map(|f| $encoding(f)), option);
};
($stream: expr, $type: expr, $field: expr, (option, encoding: $fieldty: ty) $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $field, option);
};
($stream: expr, $type: expr, $field: expr, (option: $trait: ident $(, $read_arg: expr)?) $(, $self: ident)?) => {
$crate::_encode_tlv!($stream, $type, $field, option);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _check_encoded_tlv_order {
($last_type: expr, $type: expr, (static_value, $value: expr)) => {};
($last_type: expr, $type: expr, $fieldty: tt) => {
if let Some(t) = $last_type {
#[allow(unused_comparisons)]
(debug_assert!(t < $type))
}
$last_type = Some($type);
};
}
#[macro_export]
macro_rules! encode_tlv_stream {
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}) => {
$crate::_encode_tlv_stream!($stream, {$(($type, $field, $fieldty)),*})
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _encode_tlv_stream {
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt $(, $self: ident)?)),* $(,)*}) => { {
$crate::_encode_tlv_stream!($stream, { $(($type, $field, $fieldty $(, $self)?)),* }, &[])
} };
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt $(, $self: ident)?)),* $(,)*}, $extra_tlvs: expr) => { {
#[allow(unused_imports)]
use $crate::{
ln::msgs::DecodeError,
util::ser,
util::ser::BigSize,
util::ser::Writeable,
};
$(
$crate::_encode_tlv!($stream, $type, $field, $fieldty $(, $self)?);
)*
for tlv in $extra_tlvs {
let (typ, value): &(u64, Vec<u8>) = tlv;
$crate::_encode_tlv!($stream, *typ, value, required_vec);
}
#[allow(unused_mut, unused_variables, unused_assignments)]
#[cfg(debug_assertions)]
{
let mut last_seen: Option<u64> = None;
$(
$crate::_check_encoded_tlv_order!(last_seen, $type, $fieldty);
)*
for tlv in $extra_tlvs {
let (typ, _): &(u64, Vec<u8>) = tlv;
$crate::_check_encoded_tlv_order!(last_seen, *typ, required_vec);
}
}
} };
}
#[doc(hidden)]
#[macro_export]
macro_rules! _get_varint_length_prefixed_tlv_length {
($len: expr, $type: expr, $field: expr, (default_value, $default: expr) $(, $self: ident)?) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required)
};
($len: expr, $type: expr, $field: expr, (static_value, $value: expr) $(, $self: ident)?) => {};
($len: expr, $type: expr, $field: expr, required $(, $self: ident)?) => {
BigSize($type).write(&mut $len).expect("No in-memory data may fail to serialize");
let field_len = $field.serialized_length();
BigSize(field_len as u64)
.write(&mut $len)
.expect("No in-memory data may fail to serialize");
$len.0 += field_len;
};
($len: expr, $type: expr, $field: expr, (required: $trait: ident $(, $read_arg: expr)?) $(, $self: ident)?) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required);
};
($len: expr, $type: expr, $field: expr, required_vec $(, $self: ident)?) => {
let field = $crate::util::ser::WithoutLength($field);
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, field, required);
};
($len: expr, $type: expr, $field: expr, (required_vec, encoding: ($fieldty: ty, $encoding: ident)) $(, $self: ident)?) => {
let field = $encoding($field);
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, field, required);
};
($len: expr, $optional_type: expr, $optional_field: expr, option $(, $self: ident)?) => {
if let Some(ref field) = $optional_field.as_ref() {
BigSize($optional_type)
.write(&mut $len)
.expect("No in-memory data may fail to serialize");
let field_len = field.serialized_length();
BigSize(field_len as u64)
.write(&mut $len)
.expect("No in-memory data may fail to serialize");
$len.0 += field_len;
}
};
($len: expr, $optional_type: expr, $optional_field: expr, (legacy, $fieldty: ty, $write: expr) $(, $self: ident)?) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $optional_type, $write($($self)?), option);
};
($len: expr, $type: expr, $field: expr, optional_vec $(, $self: ident)?) => {
if !$field.is_empty() {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required_vec);
}
};
($len: expr, $type: expr, $field: expr, (option: $trait: ident $(, $read_arg: expr)?) $(, $self: ident)?) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, option);
};
($len: expr, $type: expr, $field: expr, (option, encoding: ($fieldty: ty, $encoding: ident)) $(, $self: ident)?) => {
let field = $field.map(|f| $encoding(f));
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, field, option);
};
($len: expr, $type: expr, $field: expr, upgradable_required $(, $self: ident)?) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required);
};
($len: expr, $type: expr, $field: expr, upgradable_option $(, $self: ident)?) => {
$crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, option);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _encode_varint_length_prefixed_tlv {
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt $(, $self: ident)?)),*}) => { {
$crate::_encode_varint_length_prefixed_tlv!($stream, {$(($type, $field, $fieldty $(, $self)?)),*}, &[])
} };
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt $(, $self: ident)?)),*}, $extra_tlvs: expr) => { {
extern crate alloc;
use $crate::util::ser::BigSize;
use alloc::vec::Vec;
let len = {
#[allow(unused_mut)]
let mut len = $crate::util::ser::LengthCalculatingWriter(0);
$(
$crate::_get_varint_length_prefixed_tlv_length!(len, $type, $field, $fieldty $(, $self)?);
)*
for tlv in $extra_tlvs {
let (typ, value): &(u64, Vec<u8>) = tlv;
$crate::_get_varint_length_prefixed_tlv_length!(len, *typ, value, required_vec);
}
len.0
};
BigSize(len as u64).write($stream)?;
$crate::_encode_tlv_stream!($stream, { $(($type, $field, $fieldty $(, $self)?)),* }, $extra_tlvs);
} };
}
#[doc(hidden)]
#[macro_export]
macro_rules! _check_decoded_tlv_order {
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (default_value, $default: expr)) => {{
#[allow(unused_comparisons)]
let invalid_order =
($last_seen_type.is_none() || $last_seen_type.unwrap() < $type) && $typ.0 > $type;
if invalid_order {
$field = $default.into();
}
}};
($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)]
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) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option, explicit_type: $fieldty: ty)) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (legacy, $fieldty: ty, $write: expr)) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (required, explicit_type: $fieldty: ty)) => {{
_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required);
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, required_vec) => {{
$crate::_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required);
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (required_vec, encoding: $encoding: tt)) => {{
$crate::_check_decoded_tlv_order!($last_seen_type, $typ, $type, $field, required);
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, optional_vec) => {{
}};
($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) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
}};
($last_seen_type: expr, $typ: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _check_missing_tlv {
($last_seen_type: expr, $type: expr, $field: ident, (default_value, $default: expr)) => {{
#[allow(unused_comparisons)]
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)]
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, required_vec) => {{
$crate::_check_missing_tlv!($last_seen_type, $type, $field, required);
}};
($last_seen_type: expr, $type: expr, $field: ident, (required_vec, encoding: $encoding: tt)) => {{
$crate::_check_missing_tlv!($last_seen_type, $type, $field, required);
}};
($last_seen_type: expr, $type: expr, $field: ident, option) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, (option, explicit_type: $fieldty: ty)) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, (legacy, $fieldty: ty, $write: expr)) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, (required, explicit_type: $fieldty: ty)) => {{
_check_missing_tlv!($last_seen_type, $type, $field, required);
}};
($last_seen_type: expr, $type: expr, $field: ident, optional_vec) => {{
}};
($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) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
}};
($last_seen_type: expr, $type: expr, $field: ident, (option, encoding: $encoding: tt)) => {{
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _decode_tlv {
($outer_reader: expr, $reader: expr, $field: ident, (default_value, $default: expr)) => {{
$crate::_decode_tlv!($outer_reader, $reader, $field, required)
}};
($outer_reader: expr, $reader: expr, $field: ident, (static_value, $value: expr)) => {{
}};
($outer_reader: expr, $reader: expr, $field: ident, required) => {{
$field = $crate::util::ser::LengthReadable::read_from_fixed_length_buffer(&mut $reader)?;
}};
($outer_reader: expr, $reader: expr, $field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {{
$field = $trait::read(&mut $reader $(, $read_arg)*)?;
}};
($outer_reader: expr, $reader: expr, $field: ident, required_vec) => {{
let f: $crate::util::ser::WithoutLength<Vec<_>> = $crate::util::ser::LengthReadable::read_from_fixed_length_buffer(&mut $reader)?;
$field = f.0;
}};
($outer_reader: expr, $reader: expr, $field: ident, (required_vec, encoding: ($fieldty: ty, $encoding: ident))) => {{
$field = {
let field: $encoding<$fieldty> = ser::LengthReadable::read_from_fixed_length_buffer(&mut $reader)?;
$crate::util::ser::RequiredWrapper(Some(field.0))
};
}};
($outer_reader: expr, $reader: expr, $field: ident, option) => {{
$field = Some($crate::util::ser::LengthReadable::read_from_fixed_length_buffer(&mut $reader)?);
}};
($outer_reader: expr, $reader: expr, $field: ident, (option, explicit_type: $fieldty: ty)) => {{
let _field: &Option<$fieldty> = &$field;
$crate::_decode_tlv!($outer_reader, $reader, $field, option);
}};
($outer_reader: expr, $reader: expr, $field: ident, (legacy, $fieldty: ty, $write: expr)) => {{
$crate::_decode_tlv!($outer_reader, $reader, $field, (option, explicit_type: $fieldty));
}};
($outer_reader: expr, $reader: expr, $field: ident, (required, explicit_type: $fieldty: ty)) => {{
let _field: &$fieldty = &$field;
_decode_tlv!($outer_reader, $reader, $field, required);
}};
($outer_reader: expr, $reader: expr, $field: ident, optional_vec) => {{
let f: $crate::util::ser::WithoutLength<Vec<_>> = $crate::util::ser::LengthReadable::read_from_fixed_length_buffer(&mut $reader)?;
$field = Some(f.0);
}};
($outer_reader: expr, $reader: expr, $field: ident, upgradable_required) => {{
$field = match $crate::util::ser::MaybeReadable::read(&mut $reader)? {
Some(res) => res,
None => {
$crate::io_extras::copy($outer_reader, &mut $crate::io_extras::sink()).unwrap();
return Ok(None)
},
};
}};
($outer_reader: expr, $reader: expr, $field: ident, upgradable_option) => {{
$field = $crate::util::ser::MaybeReadable::read(&mut $reader)?;
if $field.is_none() {
#[cfg(not(debug_assertions))] {
$reader.eat_remaining()?;
}
}
}};
($outer_reader: expr, $reader: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
$field = Some($trait::read(&mut $reader $(, $read_arg)*)?);
}};
($outer_reader: expr, $reader: expr, $field: ident, (option, encoding: ($fieldty: ty, $encoding: ident, $encoder:ty))) => {{
$crate::_decode_tlv!($outer_reader, $reader, $field, (option, encoding: ($fieldty, $encoding)));
}};
($outer_reader: expr, $reader: expr, $field: ident, (option, encoding: ($fieldty: ty, $encoding: ident))) => {{
$field = {
let field: $encoding<$fieldty> = ser::LengthReadable::read_from_fixed_length_buffer(&mut $reader)?;
Some(field.0)
};
}};
($outer_reader: expr, $reader: expr, $field: ident, (option, encoding: $fieldty: ty)) => {{
$crate::_decode_tlv!($outer_reader, $reader, $field, option);
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _decode_tlv_stream_match_check {
($val: ident, $type: expr, (static_value, $value: expr)) => {
false
};
($val: ident, $type: expr, $fieldty: tt) => {
$val == $type
};
}
#[macro_export]
macro_rules! decode_tlv_stream {
($stream: expr, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => {
let rewind = |_, _| { unreachable!() };
$crate::_decode_tlv_stream_range!($stream, .., rewind, {$(($type, $field, $fieldty)),*});
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _decode_tlv_stream_range {
($stream: expr, $range: expr, $rewind: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
$(, $decode_custom_tlv: expr)?) => { {
use $crate::ln::msgs::DecodeError;
let mut last_seen_type: Option<u64> = None;
let stream_ref = $stream;
'tlv_read: loop {
use $crate::util::ser;
let typ: ser::BigSize = {
let mut tracking_reader = ser::ReadTrackingReader::new(stream_ref);
match <$crate::util::ser::BigSize as $crate::util::ser::Readable>::read(&mut tracking_reader) {
Err(DecodeError::ShortRead) => {
if !tracking_reader.have_read {
break 'tlv_read;
} else {
return Err(DecodeError::ShortRead);
}
},
Err(e) => return Err(e),
Ok(t) => if core::ops::RangeBounds::contains(&$range, &t.0) { t } else {
drop(tracking_reader);
use $crate::util::ser::Writeable;
let bytes_read = t.serialized_length();
$rewind(stream_ref, bytes_read);
break 'tlv_read;
},
}
};
match last_seen_type {
Some(t) if typ.0 <= t => {
return Err(DecodeError::InvalidValue);
},
_ => {},
}
$({
$crate::_check_decoded_tlv_order!(last_seen_type, typ, $type, $field, $fieldty);
})*
last_seen_type = Some(typ.0);
let length: ser::BigSize = $crate::util::ser::Readable::read(stream_ref)?;
let mut s = ser::FixedLengthReader::new(stream_ref, length.0);
match typ.0 {
$(_t if $crate::_decode_tlv_stream_match_check!(_t, $type, $fieldty) => {
$crate::_decode_tlv!($stream, s, $field, $fieldty);
if s.bytes_remain() {
s.eat_remaining()?; return Err(DecodeError::InvalidValue);
}
},)*
t => {
$(
if $decode_custom_tlv(t, &mut s)? {
s.eat_remaining()?;
continue 'tlv_read;
}
)?
if t % 2 == 0 {
return Err(DecodeError::UnknownRequiredFeature);
}
}
}
s.eat_remaining()?;
}
$({
$crate::_check_missing_tlv!(last_seen_type, $type, $field, $fieldty);
})*
} }
}
#[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)?; )*
$crate::encode_tlv_stream!(w, {$(($type, self.$tlvfield.as_ref(), $fieldty)),*});
Ok(())
}
}
impl $crate::util::ser::LengthReadable for $st {
fn read_from_fixed_length_buffer<R: $crate::util::ser::LengthLimitedRead>(
r: &mut R
) -> Result<Self, $crate::ln::msgs::DecodeError> {
$(let $field = $crate::util::ser::Readable::read(r)?;)*
$($crate::_init_tlv_field_var!($tlvfield, $fieldty);)*
$crate::decode_tlv_stream!(r, {$(($type, $tlvfield, $fieldty)),*});
Ok(Self {
$($field,)*
$($tlvfield),*
})
}
}
}
}
#[macro_export]
macro_rules! write_tlv_fields {
($stream: expr, {$(($type: expr, $field: expr, $fieldty: tt)),* $(,)*}) => {
$crate::_encode_varint_length_prefixed_tlv!($stream, {$(($type, &$field, $fieldty)),*})
}
}
#[macro_export]
macro_rules! read_tlv_fields {
($stream: expr, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => { {
let tlv_len: $crate::util::ser::BigSize = $crate::util::ser::Readable::read($stream)?;
let mut rd = $crate::util::ser::FixedLengthReader::new($stream, tlv_len.0);
$crate::decode_tlv_stream!(&mut rd, {$(($type, $field, $fieldty)),*});
rd.eat_remaining().map_err(|_| $crate::ln::msgs::DecodeError::ShortRead)?;
} }
}
#[doc(hidden)]
#[macro_export]
macro_rules! _init_tlv_based_struct_field {
($field: ident, (default_value, $default: expr)) => {
$field.0.unwrap()
};
($field: ident, (static_value, $value: expr)) => {
$field
};
($field: ident, option) => {
$field
};
($field: ident, (legacy, $fieldty: ty, $write: expr)) => {
$crate::_init_tlv_based_struct_field!($field, option)
};
($field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_init_tlv_based_struct_field!($field, option)
};
($field: ident, upgradable_required) => {
$field.0.unwrap()
};
($field: ident, upgradable_option) => {
$field
};
($field: ident, required) => {
$field.0.unwrap()
};
($field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_init_tlv_based_struct_field!($field, required)
};
($field: ident, required_vec) => {
$field
};
($field: ident, (required_vec, encoding: ($fieldty: ty, $encoding: ident))) => {
$crate::_init_tlv_based_struct_field!($field, required)
};
($field: ident, optional_vec) => {
$field.unwrap()
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _init_tlv_field_var {
($field: ident, (default_value, $default: expr)) => {
let mut $field = $crate::util::ser::RequiredWrapper(None);
};
($field: ident, (static_value, $value: expr)) => {
let $field;
};
($field: ident, required) => {
let mut $field = $crate::util::ser::RequiredWrapper(None);
};
($field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_init_tlv_field_var!($field, required);
};
($field: ident, required_vec) => {
let mut $field = Vec::new();
};
($field: ident, (required_vec, encoding: ($fieldty: ty, $encoding: ident))) => {
$crate::_init_tlv_field_var!($field, required);
};
($field: ident, option) => {
let mut $field = None;
};
($field: ident, optional_vec) => {
let mut $field = Some(Vec::new());
};
($field: ident, (option, explicit_type: $fieldty: ty)) => {
let mut $field: Option<$fieldty> = None;
};
($field: ident, (legacy, $fieldty: ty, $write: expr)) => {
$crate::_init_tlv_field_var!($field, (option, explicit_type: $fieldty));
};
($field: ident, (required, explicit_type: $fieldty: ty)) => {
let mut $field = $crate::util::ser::RequiredWrapper::<$fieldty>(None);
};
($field: ident, (option, encoding: ($fieldty: ty, $encoding: ident))) => {
$crate::_init_tlv_field_var!($field, option);
};
($field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {
$crate::_init_tlv_field_var!($field, option);
};
($field: ident, upgradable_required) => {
let mut $field = $crate::util::ser::UpgradableRequired(None);
};
($field: ident, upgradable_option) => {
let mut $field = None;
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _init_and_read_len_prefixed_tlv_fields {
($reader: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => {
$(
$crate::_init_tlv_field_var!($field, $fieldty);
)*
$crate::read_tlv_fields!($reader, {
$(($type, $field, $fieldty)),*
});
}
}
macro_rules! _init_and_read_tlv_stream {
($reader: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => {
$(
$crate::_init_tlv_field_var!($field, $fieldty);
)*
$crate::decode_tlv_stream!($reader, {
$(($type, $field, $fieldty)),*
});
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _decode_and_build {
($stream: ident, $thing: path, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => { {
$crate::_init_and_read_len_prefixed_tlv_fields!($stream, {
$(($type, $field, $fieldty)),*
});
::lightning_macros::drop_legacy_field_definition!($thing {
$($field: $crate::_init_tlv_based_struct_field!($field, $fieldty)),*
})
} }
}
#[macro_export]
macro_rules! impl_writeable_tlv_based {
($st: ident, {$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}) => {
impl $crate::util::ser::Writeable for $st {
fn write<W: $crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), $crate::io::Error> {
$crate::_encode_varint_length_prefixed_tlv!(writer, {
$(($type, &self.$field, $fieldty, self)),*
});
Ok(())
}
#[inline]
fn serialized_length(&self) -> usize {
use $crate::util::ser::BigSize;
let len = {
#[allow(unused_mut)]
let mut len = $crate::util::ser::LengthCalculatingWriter(0);
$(
$crate::_get_varint_length_prefixed_tlv_length!(len, $type, &self.$field, $fieldty, self);
)*
len.0
};
let mut len_calc = $crate::util::ser::LengthCalculatingWriter(0);
BigSize(len as u64).write(&mut len_calc).expect("No in-memory data may fail to serialize");
len + len_calc.0
}
}
impl $crate::util::ser::Readable for $st {
fn read<R: $crate::io::Read>(reader: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
Ok($crate::_decode_and_build!(reader, Self, {$(($type, $field, $fieldty)),*}))
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _impl_writeable_tlv_based_enum_common {
($st: ident, $(($variant_id: expr, $variant_name: ident) =>
{$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
),* $(,)?;
$(($tuple_variant_id: expr, $tuple_variant_name: ident)),* $(,)?;
$(($length_prefixed_tuple_variant_id: expr, $length_prefixed_tuple_variant_name: ident)),* $(,)?) => {
impl $crate::util::ser::Writeable for $st {
fn write<W: $crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), $crate::io::Error> {
lightning_macros::skip_legacy_fields!(match self {
$($st::$variant_name { $(ref $field: $fieldty, )* .. } => {
let id: u8 = $variant_id;
id.write(writer)?;
$crate::_encode_varint_length_prefixed_tlv!(writer, {
$(($type, $field, $fieldty, self)),*
});
}),*
$($st::$tuple_variant_name (ref field) => {
let id: u8 = $tuple_variant_id;
id.write(writer)?;
field.write(writer)?;
}),*
$($st::$length_prefixed_tuple_variant_name (ref field) => {
let id: u8 = $length_prefixed_tuple_variant_id;
id.write(writer)?;
$crate::util::ser::BigSize(field.serialized_length() as u64).write(writer)?;
field.write(writer)?;
}),*
});
Ok(())
}
}
}
}
#[macro_export]
macro_rules! impl_writeable_tlv_based_enum {
($st: ident,
$(($variant_id: expr, $variant_name: ident) =>
{$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
),*
$($(,)? {$tuple_variant_id: expr, $tuple_variant_name: ident} => ()),*
$(,)?
) => {
$crate::_impl_writeable_tlv_based_enum_common!($st,
$(($variant_id, $variant_name) => {$(($type, $field, $fieldty)),*}),*
;;
$(($tuple_variant_id, $tuple_variant_name)),*);
impl $crate::util::ser::Readable for $st {
#[allow(unused_mut)]
fn read<R: $crate::io::Read>(mut reader: &mut R) -> Result<Self, $crate::ln::msgs::DecodeError> {
let id: u8 = $crate::util::ser::Readable::read(reader)?;
match id {
$($variant_id => {
let mut f = || {
Ok($crate::_decode_and_build!(reader, $st::$variant_name, {$(($type, $field, $fieldty)),*}))
};
f()
}),*
$($tuple_variant_id => {
let length: $crate::util::ser::BigSize = $crate::util::ser::Readable::read(reader)?;
let mut s = $crate::util::ser::FixedLengthReader::new(reader, length.0);
let res = $crate::util::ser::LengthReadable::read_from_fixed_length_buffer(&mut s)?;
if s.bytes_remain() {
s.eat_remaining()?; return Err($crate::ln::msgs::DecodeError::InvalidValue);
}
Ok($st::$tuple_variant_name(res))
}),*
_ => {
Err($crate::ln::msgs::DecodeError::UnknownRequiredFeature)
},
}
}
}
}
}
#[macro_export]
macro_rules! impl_writeable_tlv_based_enum_upgradable {
($st: ident,
$(($variant_id: expr, $variant_name: ident) =>
{$(($type: expr, $field: ident, $fieldty: tt)),* $(,)*}
),*
$(, {$tuple_variant_id: expr, $tuple_variant_name: ident} => ())*
$(, unread_variants: $($unread_variant: ident),*)?
$(,)?
) => {
$crate::_impl_writeable_tlv_based_enum_common!($st,
$(($variant_id, $variant_name) => {$(($type, $field, $fieldty)),*}),*
$(, $((255, $unread_variant) => {}),*)?
;;
$(($tuple_variant_id, $tuple_variant_name)),*);
impl $crate::util::ser::MaybeReadable for $st {
#[allow(unused_mut)]
fn read<R: $crate::io::Read>(mut reader: &mut R) -> Result<Option<Self>, $crate::ln::msgs::DecodeError> {
let id: u8 = $crate::util::ser::Readable::read(reader)?;
match id {
$($variant_id => {
let mut f = || {
Ok(Some($crate::_decode_and_build!(reader, $st::$variant_name, {$(($type, $field, $fieldty)),*})))
};
f()
}),*
$($tuple_variant_id => {
let length: $crate::util::ser::BigSize = $crate::util::ser::Readable::read(reader)?;
let mut s = $crate::util::ser::FixedLengthReader::new(reader, length.0);
let res = $crate::util::ser::Readable::read(&mut s)?;
if s.bytes_remain() {
s.eat_remaining()?; return Err($crate::ln::msgs::DecodeError::InvalidValue);
}
Ok(Some($st::$tuple_variant_name(res)))
}),*
255|_ if id % 2 == 1 => {
let tlv_len: $crate::util::ser::BigSize = $crate::util::ser::Readable::read(reader)?;
let mut rd = $crate::util::ser::FixedLengthReader::new(reader, tlv_len.0);
rd.eat_remaining().map_err(|_| $crate::ln::msgs::DecodeError::ShortRead)?;
Ok(None)
},
_ => Err($crate::ln::msgs::DecodeError::UnknownRequiredFeature),
}
}
}
}
}