@@ -63,6 +63,9 @@ macro_rules! _encode_tlv {
6363 }
6464 $crate:: _encode_tlv!( $stream, $optional_type, value, option) ;
6565 } } ;
66+ ( $stream: expr, $optional_type: expr, $optional_field: expr, ( custom, $fieldty: ty, $read: expr, $write: expr) $( , $self: ident) ?) => { {
67+ $crate:: _encode_tlv!( $stream, $optional_type, $optional_field, ( legacy, $fieldty, $write) $( , $self) ?) ;
68+ } } ;
6669 ( $stream: expr, $type: expr, $field: expr, optional_vec $( , $self: ident) ?) => {
6770 if !$field. is_empty( ) {
6871 $crate:: _encode_tlv!( $stream, $type, $field, required_vec) ;
@@ -232,6 +235,9 @@ macro_rules! _get_varint_length_prefixed_tlv_length {
232235 ( $len: expr, $optional_type: expr, $optional_field: expr, ( legacy, $fieldty: ty, $write: expr) $( , $self: ident) ?) => {
233236 $crate:: _get_varint_length_prefixed_tlv_length!( $len, $optional_type, $write( $( $self) ?) , option) ;
234237 } ;
238+ ( $len: expr, $optional_type: expr, $optional_field: expr, ( custom, $fieldty: ty, $read: expr, $write: expr) $( , $self: ident) ?) => {
239+ $crate:: _get_varint_length_prefixed_tlv_length!( $len, $optional_type, $optional_field, ( legacy, $fieldty, $write) $( , $self) ?) ;
240+ } ;
235241 ( $len: expr, $type: expr, $field: expr, optional_vec $( , $self: ident) ?) => {
236242 if !$field. is_empty( ) {
237243 $crate:: _get_varint_length_prefixed_tlv_length!( $len, $type, $field, required_vec) ;
@@ -317,6 +323,16 @@ macro_rules! _check_decoded_tlv_order {
317323 ( $last_seen_type: expr, $typ: expr, $type: expr, $field: ident, ( legacy, $fieldty: ty, $write: expr) ) => { {
318324 // no-op
319325 } } ;
326+ ( $last_seen_type: expr, $typ: expr, $type: expr, $field: ident, ( custom, $fieldty: ty, $read: expr, $write: expr) $( , $self: ident) ?) => { {
327+ // Note that $type may be 0 making the second comparison always false
328+ #[ allow( unused_comparisons) ]
329+ let invalid_order =
330+ ( $last_seen_type. is_none( ) || $last_seen_type. unwrap( ) < $type) && $typ. 0 > $type;
331+ if invalid_order {
332+ let read_result: Result <_, DecodeError > = $read( None ) ;
333+ $field = read_result?. into( ) ;
334+ }
335+ } } ;
320336 ( $last_seen_type: expr, $typ: expr, $type: expr, $field: ident, ( required, explicit_type: $fieldty: ty) ) => { {
321337 _check_decoded_tlv_order!( $last_seen_type, $typ, $type, $field, required) ;
322338 } } ;
@@ -385,6 +401,15 @@ macro_rules! _check_missing_tlv {
385401 ( $last_seen_type: expr, $type: expr, $field: ident, ( legacy, $fieldty: ty, $write: expr) ) => { {
386402 // no-op
387403 } } ;
404+ ( $last_seen_type: expr, $type: expr, $field: ident, ( custom, $fieldty: ty, $read: expr, $write: expr) ) => { {
405+ // Note that $type may be 0 making the second comparison always false
406+ #[ allow( unused_comparisons) ]
407+ let missing_req_type = $last_seen_type. is_none( ) || $last_seen_type. unwrap( ) < $type;
408+ if missing_req_type {
409+ let read_result: Result <_, DecodeError > = $read( None ) ;
410+ $field = read_result?. into( ) ;
411+ }
412+ } } ;
388413 ( $last_seen_type: expr, $type: expr, $field: ident, ( required, explicit_type: $fieldty: ty) ) => { {
389414 _check_missing_tlv!( $last_seen_type, $type, $field, required) ;
390415 } } ;
@@ -441,6 +466,12 @@ macro_rules! _decode_tlv {
441466 ( $outer_reader: expr, $reader: expr, $field: ident, ( legacy, $fieldty: ty, $write: expr) ) => { {
442467 $crate:: _decode_tlv!( $outer_reader, $reader, $field, ( option, explicit_type: $fieldty) ) ;
443468 } } ;
469+ ( $outer_reader: expr, $reader: expr, $field: ident, ( custom, $fieldty: ty, $read: expr, $write: expr) ) => { {
470+ let read_field: $fieldty;
471+ $crate:: _decode_tlv!( $outer_reader, $reader, read_field, required) ;
472+ let read_result: Result <_, DecodeError > = $read( Some ( read_field) ) ;
473+ $field = read_result?. into( ) ;
474+ } } ;
444475 ( $outer_reader: expr, $reader: expr, $field: ident, ( required, explicit_type: $fieldty: ty) ) => { {
445476 let _field: & $fieldty = & $field;
446477 _decode_tlv!( $outer_reader, $reader, $field, required) ;
@@ -830,6 +861,9 @@ macro_rules! _init_tlv_based_struct_field {
830861 ( $field: ident, ( legacy, $fieldty: ty, $write: expr) ) => {
831862 $crate:: _init_tlv_based_struct_field!( $field, option)
832863 } ;
864+ ( $field: ident, ( custom, $fieldty: ty, $read: expr, $write: expr) ) => {
865+ $crate:: _init_tlv_based_struct_field!( $field, required)
866+ } ;
833867 ( $field: ident, ( option: $trait: ident $( , $read_arg: expr) ?) ) => {
834868 $crate:: _init_tlv_based_struct_field!( $field, option)
835869 } ;
@@ -896,6 +930,9 @@ macro_rules! _init_tlv_field_var {
896930 ( $field: ident, ( legacy, $fieldty: ty, $write: expr) ) => {
897931 $crate:: _init_tlv_field_var!( $field, ( option, explicit_type: $fieldty) ) ;
898932 } ;
933+ ( $field: ident, ( custom, $fieldty: ty, $read: expr, $write: expr) ) => {
934+ $crate:: _init_tlv_field_var!( $field, required) ;
935+ } ;
899936 ( $field: ident, ( required, explicit_type: $fieldty: ty) ) => {
900937 let mut $field = $crate:: util:: ser:: RequiredWrapper :: <$fieldty>( None ) ;
901938 } ;
@@ -979,6 +1016,12 @@ macro_rules! _decode_and_build {
9791016/// called with the object being serialized and a returned `Option` and is written as a TLV if
9801017/// `Some`. When reading, an optional field of type `$ty` is read (which can be used in later
9811018/// `default_value` or `static_value` fields by referring to the value by name).
1019+ /// If `$fieldty` is `(custom, $ty, $read, $write)` then, when writing, the same behavior as
1020+ /// `legacy`, above is used. When reading, if a TLV is present, it is read as `$ty` and the
1021+ /// `$read` method is called with `Some(decoded_$ty_object)`. If no TLV is present, the field
1022+ /// will be initialized by calling `$read(None)`. `$read` should return a
1023+ /// `Result<field type, DecodeError>` (note that the processed field type may differ from `$ty`;
1024+ /// `$ty` is the type as de/serialized, not necessarily the actual field type).
9821025///
9831026/// For example,
9841027/// ```
0 commit comments