@@ -115,6 +115,9 @@ macro_rules! check_tlv_order {
115
115
( $last_seen_type: expr, $typ: expr, $type: expr, $field: ident, vec_type) => { {
116
116
// no-op
117
117
} } ;
118
+ ( $last_seen_type: expr, $typ: expr, $type: expr, $field: ident, ignorable) => { {
119
+ // no-op
120
+ } } ;
118
121
}
119
122
120
123
macro_rules! check_missing_tlv {
@@ -138,6 +141,9 @@ macro_rules! check_missing_tlv {
138
141
( $last_seen_type: expr, $type: expr, $field: ident, option) => { {
139
142
// no-op
140
143
} } ;
144
+ ( $last_seen_type: expr, $type: expr, $field: ident, ignorable) => { {
145
+ // no-op
146
+ } } ;
141
147
}
142
148
143
149
macro_rules! decode_tlv {
@@ -153,6 +159,9 @@ macro_rules! decode_tlv {
153
159
( $reader: expr, $field: ident, option) => { {
154
160
$field = Some ( ser:: Readable :: read( & mut $reader) ?) ;
155
161
} } ;
162
+ ( $reader: expr, $field: ident, ignorable) => { {
163
+ $field = ser:: MaybeReadable :: read( & mut $reader) ?;
164
+ } } ;
156
165
}
157
166
158
167
macro_rules! decode_tlv_stream {
@@ -371,7 +380,7 @@ macro_rules! read_ver_prefix {
371
380
/// Reads a suffix added by write_tlv_fields.
372
381
macro_rules! read_tlv_fields {
373
382
( $stream: expr, { $( ( $type: expr, $field: ident, $fieldty: tt) ) ,* $( , ) * } ) => { {
374
- let tlv_len = :: util:: ser:: BigSize :: read( $stream) ?;
383
+ let tlv_len: :: util :: ser :: BigSize = :: util:: ser:: Readable :: read( $stream) ?;
375
384
let mut rd = :: util:: ser:: FixedLengthReader :: new( $stream, tlv_len. 0 ) ;
376
385
decode_tlv_stream!( & mut rd, { $( ( $type, $field, $fieldty) ) ,* } ) ;
377
386
rd. eat_remaining( ) . map_err( |_| :: ln:: msgs:: DecodeError :: ShortRead ) ?;
@@ -405,7 +414,7 @@ macro_rules! init_tlv_field_var {
405
414
} ;
406
415
( $field: ident, option) => {
407
416
let mut $field = None ;
408
- }
417
+ } ;
409
418
}
410
419
411
420
/// Implements Readable/Writeable for a struct storing it as a set of TLVs
@@ -458,17 +467,7 @@ macro_rules! impl_writeable_tlv_based {
458
467
}
459
468
}
460
469
461
- /// Implement Readable and Writeable for an enum, with struct variants stored as TLVs and tuple
462
- /// variants stored directly.
463
- /// The format is, for example
464
- /// impl_writeable_tlv_based_enum!(EnumName,
465
- /// (0, StructVariantA) => {(0, required_variant_field, required), (1, optional_variant_field, option)},
466
- /// (1, StructVariantB) => {(0, variant_field_a, required), (1, variant_field_b, required), (2, variant_vec_field, vec_type)};
467
- /// (2, TupleVariantA), (3, TupleVariantB),
468
- /// );
469
- /// The type is written as a single byte, followed by any variant data.
470
- /// Attempts to read an unknown type byte result in DecodeError::UnknownRequiredFeature.
471
- macro_rules! impl_writeable_tlv_based_enum {
470
+ macro_rules! _impl_writeable_tlv_based_enum_common {
472
471
( $st: ident, $( ( $variant_id: expr, $variant_name: ident) =>
473
472
{ $( ( $type: expr, $field: ident, $fieldty: tt) ) ,* $( , ) * }
474
473
) ,* $( , ) * ;
@@ -492,6 +491,72 @@ macro_rules! impl_writeable_tlv_based_enum {
492
491
Ok ( ( ) )
493
492
}
494
493
}
494
+ }
495
+ }
496
+
497
+ /// Implement MaybeReadable and Writeable for an enum, with struct variants stored as TLVs and
498
+ /// tuple variants stored directly.
499
+ ///
500
+ /// This is largely identical to `impl_writeable_tlv_based_enum`, except that odd variants will
501
+ /// return `Ok(None)` instead of `Err(UnknownRequiredFeature)`. It should generally be preferred
502
+ /// when `MaybeReadable` is practical instead of just `Readable` as it provides an upgrade path for
503
+ /// new variants to be added which are simply ignored by existing clients.
504
+ macro_rules! impl_writeable_tlv_based_enum_upgradable {
505
+ ( $st: ident, $( ( $variant_id: expr, $variant_name: ident) =>
506
+ { $( ( $type: expr, $field: ident, $fieldty: tt) ) ,* $( , ) * }
507
+ ) ,* $( , ) * ) => {
508
+ _impl_writeable_tlv_based_enum_common!( $st,
509
+ $( ( $variant_id, $variant_name) => { $( ( $type, $field, $fieldty) ) ,* } ) ,* ; ) ;
510
+
511
+ impl :: util:: ser:: MaybeReadable for $st {
512
+ fn read<R : $crate:: io:: Read >( reader: & mut R ) -> Result <Option <Self >, :: ln:: msgs:: DecodeError > {
513
+ let id: u8 = :: util:: ser:: Readable :: read( reader) ?;
514
+ match id {
515
+ $( $variant_id => {
516
+ // Because read_tlv_fields creates a labeled loop, we cannot call it twice
517
+ // in the same function body. Instead, we define a closure and call it.
518
+ let f = || {
519
+ $(
520
+ init_tlv_field_var!( $field, $fieldty) ;
521
+ ) *
522
+ read_tlv_fields!( reader, {
523
+ $( ( $type, $field, $fieldty) ) ,*
524
+ } ) ;
525
+ Ok ( Some ( $st:: $variant_name {
526
+ $(
527
+ $field: init_tlv_based_struct_field!( $field, $fieldty)
528
+ ) ,*
529
+ } ) )
530
+ } ;
531
+ f( )
532
+ } ) ,*
533
+ _ if id % 2 == 1 => Ok ( None ) ,
534
+ _ => Err ( DecodeError :: UnknownRequiredFeature ) ,
535
+ }
536
+ }
537
+ }
538
+
539
+ }
540
+ }
541
+
542
+ /// Implement Readable and Writeable for an enum, with struct variants stored as TLVs and tuple
543
+ /// variants stored directly.
544
+ /// The format is, for example
545
+ /// impl_writeable_tlv_based_enum!(EnumName,
546
+ /// (0, StructVariantA) => {(0, required_variant_field, required), (1, optional_variant_field, option)},
547
+ /// (1, StructVariantB) => {(0, variant_field_a, required), (1, variant_field_b, required), (2, variant_vec_field, vec_type)};
548
+ /// (2, TupleVariantA), (3, TupleVariantB),
549
+ /// );
550
+ /// The type is written as a single byte, followed by any variant data.
551
+ /// Attempts to read an unknown type byte result in DecodeError::UnknownRequiredFeature.
552
+ macro_rules! impl_writeable_tlv_based_enum {
553
+ ( $st: ident, $( ( $variant_id: expr, $variant_name: ident) =>
554
+ { $( ( $type: expr, $field: ident, $fieldty: tt) ) ,* $( , ) * }
555
+ ) ,* $( , ) * ;
556
+ $( ( $tuple_variant_id: expr, $tuple_variant_name: ident) ) ,* $( , ) * ) => {
557
+ _impl_writeable_tlv_based_enum_common!( $st,
558
+ $( ( $variant_id, $variant_name) => { $( ( $type, $field, $fieldty) ) ,* } ) ,* ;
559
+ $( ( $tuple_variant_id, $tuple_variant_name) ) ,* ) ;
495
560
496
561
impl :: util:: ser:: Readable for $st {
497
562
fn read<R : $crate:: io:: Read >( reader: & mut R ) -> Result <Self , :: ln:: msgs:: DecodeError > {
0 commit comments