@@ -254,7 +254,7 @@ macro_rules! write_ver_prefix {
254
254
/// This is the preferred method of adding new fields that old nodes can ignore and still function
255
255
/// correctly.
256
256
macro_rules! write_tlv_fields {
257
- ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* } , { $( ( $optional_type: expr, $optional_field: expr) ) ,* } ) => {
257
+ ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* $ ( , ) * } , { $( ( $optional_type: expr, $optional_field: expr) ) ,* $ ( , ) * } ) => {
258
258
encode_varint_length_prefixed_tlv!( $stream, { $( ( $type, $field) ) ,* } , { $( ( $optional_type, $optional_field) ) ,* } ) ;
259
259
}
260
260
}
@@ -275,14 +275,109 @@ macro_rules! read_ver_prefix {
275
275
276
276
/// Reads a suffix added by write_tlv_fields.
277
277
macro_rules! read_tlv_fields {
278
- ( $stream: expr, { $( ( $reqtype: expr, $reqfield: ident) ) ,* } , { $( ( $type: expr, $field: ident) ) ,* } ) => { {
278
+ ( $stream: expr, { $( ( $reqtype: expr, $reqfield: ident) ) ,* $ ( , ) * } , { $( ( $type: expr, $field: ident) ) ,* $ ( , ) * } ) => { {
279
279
let tlv_len = :: util:: ser:: BigSize :: read( $stream) ?;
280
280
let mut rd = :: util:: ser:: FixedLengthReader :: new( $stream, tlv_len. 0 ) ;
281
281
decode_tlv!( & mut rd, { $( ( $reqtype, $reqfield) ) ,* } , { $( ( $type, $field) ) ,* } ) ;
282
282
rd. eat_remaining( ) . map_err( |_| DecodeError :: ShortRead ) ?;
283
283
} }
284
284
}
285
285
286
+ // If we naively create a struct in impl_writeable_tlv_based below, we may end up returning
287
+ // `Self { ,,vecfield: vecfield }` which is obviously incorrect. Instead, we have to match here to
288
+ // detect at least one empty field set and skip the potentially-extra comma.
289
+ macro_rules! _init_tlv_based_struct {
290
+ ( { } , { $( $field: ident) ,* } , { $( $vecfield: ident) ,* } ) => {
291
+ Ok ( Self {
292
+ $( $field) ,* ,
293
+ $( $vecfield: $vecfield. unwrap( ) . 0 ) ,*
294
+ } )
295
+ } ;
296
+ ( { $( $reqfield: ident) ,* } , { } , { $( $vecfield: ident) ,* } ) => {
297
+ Ok ( Self {
298
+ $( $reqfield: $reqfield. 0 . unwrap( ) ) ,* ,
299
+ $( $vecfield: $vecfield. unwrap( ) . 0 ) ,*
300
+ } )
301
+ } ;
302
+ ( { $( $reqfield: ident) ,* } , { $( $field: ident) ,* } , { } ) => {
303
+ Ok ( Self {
304
+ $( $reqfield: $reqfield. 0 . unwrap( ) ) ,* ,
305
+ $( $field) ,*
306
+ } )
307
+ } ;
308
+ ( { $( $reqfield: ident) ,* } , { $( $field: ident) ,* } , { $( $vecfield: ident) ,* } ) => {
309
+ Ok ( Self {
310
+ $( $reqfield: $reqfield. 0 . unwrap( ) ) ,* ,
311
+ $( $field) ,* ,
312
+ $( $vecfield: $vecfield. unwrap( ) . 0 ) ,*
313
+ } )
314
+ }
315
+ }
316
+
317
+ // If we don't have any optional types below, but do have some vec types, we end up calling
318
+ // `write_tlv_field!($stream, {..}, {, (vec_ty, vec_val)})`, which is obviously broken.
319
+ // Instead, for write and read we match the missing values and skip the extra comma.
320
+ macro_rules! _write_tlv_fields {
321
+ ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* $( , ) * } , { } , { $( ( $optional_type: expr, $optional_field: expr) ) ,* $( , ) * } ) => {
322
+ write_tlv_fields!( $stream, { $( ( $type, $field) ) ,* } , { $( ( $optional_type, $optional_field) ) ,* } ) ;
323
+ } ;
324
+ ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* $( , ) * } , { $( ( $optional_type: expr, $optional_field: expr) ) ,* $( , ) * } , { $( ( $optional_type_2: expr, $optional_field_2: expr) ) ,* $( , ) * } ) => {
325
+ write_tlv_fields!( $stream, { $( ( $type, $field) ) ,* } , { $( ( $optional_type, $optional_field) ) ,* , $( ( $optional_type_2, $optional_field_2) ) ,* } ) ;
326
+ }
327
+ }
328
+ macro_rules! _read_tlv_fields {
329
+ ( $stream: expr, { $( ( $reqtype: expr, $reqfield: ident) ) ,* $( , ) * } , { } , { $( ( $type: expr, $field: ident) ) ,* $( , ) * } ) => {
330
+ read_tlv_fields!( $stream, { $( ( $reqtype, $reqfield) ) ,* } , { $( ( $type, $field) ) ,* } ) ;
331
+ } ;
332
+ ( $stream: expr, { $( ( $reqtype: expr, $reqfield: ident) ) ,* $( , ) * } , { $( ( $type: expr, $field: ident) ) ,* $( , ) * } , { $( ( $type_2: expr, $field_2: ident) ) ,* $( , ) * } ) => {
333
+ read_tlv_fields!( $stream, { $( ( $reqtype, $reqfield) ) ,* } , { $( ( $type, $field) ) ,* , $( ( $type_2, $field_2) ) ,* } ) ;
334
+ }
335
+ }
336
+
337
+ /// Implements Readable/Writeable for a struct storing it as a set of TLVs
338
+ /// First block includes all the required fields including a dummy value which is used during
339
+ /// deserialization but which will never be exposed to other code.
340
+ /// The second block includes optional fields.
341
+ /// The third block includes any Vecs which need to have their individual elements serialized.
342
+ macro_rules! impl_writeable_tlv_based {
343
+ ( $st: ident, { $( ( $reqtype: expr, $reqfield: ident) ) ,* $( , ) * } , { $( ( $type: expr, $field: ident) ) ,* $( , ) * } , { $( ( $vectype: expr, $vecfield: ident) ) ,* $( , ) * } ) => {
344
+ impl :: util:: ser:: Writeable for $st {
345
+ fn write<W : :: util:: ser:: Writer >( & self , writer: & mut W ) -> Result <( ) , :: std:: io:: Error > {
346
+ _write_tlv_fields!( writer, {
347
+ $( ( $reqtype, self . $reqfield) ) ,*
348
+ } , {
349
+ $( ( $type, self . $field) ) ,*
350
+ } , {
351
+ $( ( $vectype, Some ( :: util:: ser:: VecWriteWrapper ( & self . $vecfield) ) ) ) ,*
352
+ } ) ;
353
+ Ok ( ( ) )
354
+ }
355
+ }
356
+
357
+ impl :: util:: ser:: Readable for $st {
358
+ fn read<R : :: std:: io:: Read >( reader: & mut R ) -> Result <Self , :: ln:: msgs:: DecodeError > {
359
+ $(
360
+ let mut $reqfield = :: util:: ser:: OptionDeserWrapper ( None ) ;
361
+ ) *
362
+ $(
363
+ let mut $field = None ;
364
+ ) *
365
+ $(
366
+ let mut $vecfield = Some ( :: util:: ser:: VecReadWrapper ( Vec :: new( ) ) ) ;
367
+ ) *
368
+ _read_tlv_fields!( reader, {
369
+ $( ( $reqtype, $reqfield) ) ,*
370
+ } , {
371
+ $( ( $type, $field) ) ,*
372
+ } , {
373
+ $( ( $vectype, $vecfield) ) ,*
374
+ } ) ;
375
+ _init_tlv_based_struct!( { $( $reqfield) ,* } , { $( $field) ,* } , { $( $vecfield) ,* } )
376
+ }
377
+ }
378
+ }
379
+ }
380
+
286
381
#[ cfg( test) ]
287
382
mod tests {
288
383
use std:: io:: { Cursor , Read } ;
0 commit comments