rlp: add support for optional struct fields (#22832)
This adds support for a new struct tag "optional". Using this tag, structs used for RLP encoding/decoding can be extended in a backwards-compatible way, by adding new fields at the end.
This commit is contained in:
@ -229,7 +229,7 @@ func decodeBigInt(s *Stream, val reflect.Value) error {
|
||||
i = new(big.Int)
|
||||
val.Set(reflect.ValueOf(i))
|
||||
}
|
||||
// Reject leading zero bytes
|
||||
// Reject leading zero bytes.
|
||||
if len(b) > 0 && b[0] == 0 {
|
||||
return wrapStreamError(ErrCanonInt, val.Type())
|
||||
}
|
||||
@ -394,9 +394,16 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) {
|
||||
if _, err := s.List(); err != nil {
|
||||
return wrapStreamError(err, typ)
|
||||
}
|
||||
for _, f := range fields {
|
||||
for i, f := range fields {
|
||||
err := f.info.decoder(s, val.Field(f.index))
|
||||
if err == EOL {
|
||||
if f.optional {
|
||||
// The field is optional, so reaching the end of the list before
|
||||
// reaching the last field is acceptable. All remaining undecoded
|
||||
// fields are zeroed.
|
||||
zeroFields(val, fields[i:])
|
||||
break
|
||||
}
|
||||
return &decodeError{msg: "too few elements", typ: typ}
|
||||
} else if err != nil {
|
||||
return addErrorContext(err, "."+typ.Field(f.index).Name)
|
||||
@ -407,6 +414,13 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) {
|
||||
return dec, nil
|
||||
}
|
||||
|
||||
func zeroFields(structval reflect.Value, fields []field) {
|
||||
for _, f := range fields {
|
||||
fv := structval.Field(f.index)
|
||||
fv.Set(reflect.Zero(fv.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
// makePtrDecoder creates a decoder that decodes into the pointer's element type.
|
||||
func makePtrDecoder(typ reflect.Type, tag tags) (decoder, error) {
|
||||
etype := typ.Elem()
|
||||
|
Reference in New Issue
Block a user