8
8
// licenses.
9
9
10
10
macro_rules! encode_tlv {
11
- ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* } ) => { {
11
+ ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* } , { $ ( ( $optional_type : expr , $optional_field : expr ) ) , * } ) => { {
12
12
#[ allow( unused_imports) ]
13
13
use util:: ser:: { BigSize , LengthCalculatingWriter } ;
14
+ // Fields must be serialized in order, so we have to potentially switch between optional
15
+ // fields and normal fields while serializing. Thus, we end up having to loop over the type
16
+ // counts.
17
+ // Sadly, while LLVM does appear smart enough to make `max_field` a constant, it appears to
18
+ // refuse to unroll the loop. If we have enough entries that this is slow we can revisit
19
+ // this design in the future.
20
+ #[ allow( unused_mut) ]
21
+ let mut max_field: u64 = 0 ;
22
+ $(
23
+ if $type >= max_field { max_field = $type + 1 ; }
24
+ ) *
14
25
$(
15
- BigSize ( $type) . write( $stream) ?;
16
- let mut len_calc = LengthCalculatingWriter ( 0 ) ;
17
- $field. write( & mut len_calc) ?;
18
- BigSize ( len_calc. 0 as u64 ) . write( $stream) ?;
19
- $field. write( $stream) ?;
26
+ if $optional_type >= max_field { max_field = $optional_type + 1 ; }
20
27
) *
28
+ #[ allow( unused_variables) ]
29
+ for i in 0 ..max_field {
30
+ $(
31
+ if i == $type {
32
+ BigSize ( $type) . write( $stream) ?;
33
+ let mut len_calc = LengthCalculatingWriter ( 0 ) ;
34
+ $field. write( & mut len_calc) ?;
35
+ BigSize ( len_calc. 0 as u64 ) . write( $stream) ?;
36
+ $field. write( $stream) ?;
37
+ }
38
+ ) *
39
+ $(
40
+ if i == $optional_type {
41
+ if let Some ( ref field) = $optional_field {
42
+ BigSize ( $optional_type) . write( $stream) ?;
43
+ let mut len_calc = LengthCalculatingWriter ( 0 ) ;
44
+ field. write( & mut len_calc) ?;
45
+ BigSize ( len_calc. 0 as u64 ) . write( $stream) ?;
46
+ field. write( $stream) ?;
47
+ }
48
+ }
49
+ ) *
50
+ }
21
51
} }
22
52
}
23
53
24
54
macro_rules! encode_varint_length_prefixed_tlv {
25
- ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* } ) => { {
55
+ ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* } , { $ ( ( $optional_type : expr , $optional_field : expr ) ) , * } ) => { {
26
56
use util:: ser:: { BigSize , LengthCalculatingWriter } ;
27
57
#[ allow( unused_mut) ]
28
58
let mut len = LengthCalculatingWriter ( 0 ) ;
@@ -34,12 +64,19 @@ macro_rules! encode_varint_length_prefixed_tlv {
34
64
BigSize ( field_len. 0 as u64 ) . write( & mut len) ?;
35
65
len. 0 += field_len. 0 ;
36
66
) *
67
+ $(
68
+ if let Some ( ref field) = $optional_field {
69
+ BigSize ( $optional_type) . write( & mut len) ?;
70
+ let mut field_len = LengthCalculatingWriter ( 0 ) ;
71
+ field. write( & mut field_len) ?;
72
+ BigSize ( field_len. 0 as u64 ) . write( & mut len) ?;
73
+ len. 0 += field_len. 0 ;
74
+ }
75
+ ) *
37
76
}
38
77
39
78
BigSize ( len. 0 as u64 ) . write( $stream) ?;
40
- encode_tlv!( $stream, {
41
- $( ( $type, $field) ) ,*
42
- } ) ;
79
+ encode_tlv!( $stream, { $( ( $type, $field) ) ,* } , { $( ( $optional_type, $optional_field) ) ,* } ) ;
43
80
} }
44
81
}
45
82
@@ -209,8 +246,8 @@ macro_rules! write_ver_prefix {
209
246
/// This is the preferred method of adding new fields that old nodes can ignore and still function
210
247
/// correctly.
211
248
macro_rules! write_tlv_fields {
212
- ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* } ) => {
213
- encode_varint_length_prefixed_tlv!( $stream, { $( ( $type, $field) ) ,* } ) ;
249
+ ( $stream: expr, { $( ( $type: expr, $field: expr) ) ,* } , { $ ( ( $optional_type : expr , $optional_field : expr ) ) , * } ) => {
250
+ encode_varint_length_prefixed_tlv!( $stream, { $( ( $type, $field) ) ,* } , { $ ( ( $optional_type , $optional_field ) ) , * } ) ;
214
251
}
215
252
}
216
253
@@ -435,19 +472,27 @@ mod tests {
435
472
let mut stream = VecWriter ( Vec :: new ( ) ) ;
436
473
437
474
stream. 0 . clear ( ) ;
438
- encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 1 , 1u8 ) } ) ;
475
+ encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 1 , 1u8 ) } , { ( 42 , None :: < u64 > ) } ) ;
439
476
assert_eq ! ( stream. 0 , :: hex:: decode( "03010101" ) . unwrap( ) ) ;
440
477
441
478
stream. 0 . clear ( ) ;
442
- encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 4 , 0xabcdu16 ) } ) ;
479
+ encode_varint_length_prefixed_tlv ! ( & mut stream, { } , { ( 1 , Some ( 1u8 ) ) } ) ;
480
+ assert_eq ! ( stream. 0 , :: hex:: decode( "03010101" ) . unwrap( ) ) ;
481
+
482
+ stream. 0 . clear ( ) ;
483
+ encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 4 , 0xabcdu16 ) } , { ( 42 , None :: <u64 >) } ) ;
443
484
assert_eq ! ( stream. 0 , :: hex:: decode( "040402abcd" ) . unwrap( ) ) ;
444
485
445
486
stream. 0 . clear ( ) ;
446
- encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 0xff , 0xabcdu16 ) } ) ;
487
+ encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 0xff , 0xabcdu16 ) } , { ( 42 , None :: < u64 > ) } ) ;
447
488
assert_eq ! ( stream. 0 , :: hex:: decode( "06fd00ff02abcd" ) . unwrap( ) ) ;
448
489
449
490
stream. 0 . clear ( ) ;
450
- encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 0 , 1u64 ) , ( 0xff , HighZeroBytesDroppedVarInt ( 0u64 ) ) } ) ;
491
+ encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 0 , 1u64 ) , ( 0xff , HighZeroBytesDroppedVarInt ( 0u64 ) ) } , { ( 42 , None :: <u64 >) } ) ;
492
+ assert_eq ! ( stream. 0 , :: hex:: decode( "0e00080000000000000001fd00ff00" ) . unwrap( ) ) ;
493
+
494
+ stream. 0 . clear ( ) ;
495
+ encode_varint_length_prefixed_tlv ! ( & mut stream, { ( 0xff , HighZeroBytesDroppedVarInt ( 0u64 ) ) } , { ( 0 , Some ( 1u64 ) ) } ) ;
451
496
assert_eq ! ( stream. 0 , :: hex:: decode( "0e00080000000000000001fd00ff00" ) . unwrap( ) ) ;
452
497
453
498
Ok ( ( ) )
0 commit comments