@@ -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,86 @@ 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 blow, 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) ,* ,
299
+ $( $vecfield: $vecfield. unwrap( ) . 0 ) ,*
300
+ } )
301
+ } ;
302
+ ( { $( $reqfield: ident) ,* } , { $( $field: ident) ,* } , { } ) => {
303
+ Ok ( Self {
304
+ $( $reqfield) ,* ,
305
+ $( $field) ,*
306
+ } )
307
+ } ;
308
+ ( { $( $reqfield: ident) ,* } , { $( $field: ident) ,* } , { $( $vecfield: ident) ,* } ) => {
309
+ Ok ( Self {
310
+ $( $reqfield) ,* ,
311
+ $( $field) ,* ,
312
+ $( $vecfield: $vecfield. unwrap( ) . 0 ) ,*
313
+ } )
314
+ }
315
+ }
316
+
317
+ /// Implements Readable/Writeable for a struct storing it as a set of TLVs
318
+ /// First block includes all the required fields including a dummy value which is used during
319
+ /// deserialization but which will never be exposed to other code.
320
+ /// The second block includes optional fields.
321
+ macro_rules! impl_writeable_tlv_based {
322
+ ( $st: ident, { $( ( $reqtype: expr, $reqfield: ident, $reqdefault: expr) ) ,* $( , ) ?} , { $( ( $type: expr, $field: ident) ) ,* $( , ) ?} , { $( ( $vectype: expr, $vecfield: ident) ) ,* $( , ) ?} ) => {
323
+ impl :: util:: ser:: Writeable for $st {
324
+ fn write<W : :: util:: ser:: Writer >( & self , writer: & mut W ) -> Result <( ) , :: std:: io:: Error > {
325
+ write_tlv_fields!( writer, {
326
+ $( ( $reqtype, self . $reqfield) ) ,*
327
+ } , {
328
+ $( ( $type, self . $field) ) ,* ,
329
+ $( ( $vectype, Some ( :: util:: ser:: VecWriteWrapper ( & self . $vecfield) ) ) ) ,*
330
+ } ) ;
331
+ Ok ( ( ) )
332
+ }
333
+ }
334
+
335
+ impl :: util:: ser:: Readable for $st {
336
+ fn read<R : :: std:: io:: Read >( reader: & mut R ) -> Result <Self , :: ln:: msgs:: DecodeError > {
337
+ $(
338
+ let mut $reqfield = $reqdefault;
339
+ ) *
340
+ $(
341
+ let mut $field = None ;
342
+ ) *
343
+ $(
344
+ let mut $vecfield = Some ( :: util:: ser:: VecReadWrapper ( Vec :: new( ) ) ) ;
345
+ ) *
346
+ read_tlv_fields!( reader, {
347
+ $( ( $reqtype, $reqfield) ) ,*
348
+ } , {
349
+ $( ( $type, $field) ) ,* ,
350
+ $( ( $vectype, $vecfield) ) ,*
351
+ } ) ;
352
+ _init_tlv_based_struct!( { $( $reqfield) ,* } , { $( $field) ,* } , { $( $vecfield) ,* } )
353
+ }
354
+ }
355
+ }
356
+ }
357
+
286
358
#[ cfg( test) ]
287
359
mod tests {
288
360
use std:: io:: { Cursor , Read } ;
0 commit comments