[release/1.3.4] rlp: add "tail" struct tag
This commit is contained in:
committed by
Jeffrey Wilcke
parent
8cb69b9e9b
commit
93077941d3
@ -63,11 +63,12 @@ type Decoder interface {
|
||||
// must contain an element for each decoded field. Decode returns an
|
||||
// error if there are too few or too many elements.
|
||||
//
|
||||
// The decoding of struct fields honours one particular struct tag,
|
||||
// "nil". This tag applies to pointer-typed fields and changes the
|
||||
// The decoding of struct fields honours two struct tags, "tail" and
|
||||
// "nil". For an explanation of "tail", see the example.
|
||||
// The "nil" tag applies to pointer-typed fields and changes the
|
||||
// decoding rules for the field such that input values of size zero
|
||||
// decode as a nil pointer. This tag can be useful when decoding recursive
|
||||
// types.
|
||||
// decode as a nil pointer. This tag can be useful when decoding
|
||||
// recursive types.
|
||||
//
|
||||
// type StructWithEmptyOK struct {
|
||||
// Foo *[20]byte `rlp:"nil"`
|
||||
@ -190,7 +191,7 @@ func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
|
||||
case kind == reflect.String:
|
||||
return decodeString, nil
|
||||
case kind == reflect.Slice || kind == reflect.Array:
|
||||
return makeListDecoder(typ)
|
||||
return makeListDecoder(typ, tags)
|
||||
case kind == reflect.Struct:
|
||||
return makeStructDecoder(typ)
|
||||
case kind == reflect.Ptr:
|
||||
@ -264,7 +265,7 @@ func decodeBigInt(s *Stream, val reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeListDecoder(typ reflect.Type) (decoder, error) {
|
||||
func makeListDecoder(typ reflect.Type, tag tags) (decoder, error) {
|
||||
etype := typ.Elem()
|
||||
if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) {
|
||||
if typ.Kind() == reflect.Array {
|
||||
@ -277,15 +278,26 @@ func makeListDecoder(typ reflect.Type) (decoder, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isArray := typ.Kind() == reflect.Array
|
||||
return func(s *Stream, val reflect.Value) error {
|
||||
if isArray {
|
||||
var dec decoder
|
||||
switch {
|
||||
case typ.Kind() == reflect.Array:
|
||||
dec = func(s *Stream, val reflect.Value) error {
|
||||
return decodeListArray(s, val, etypeinfo.decoder)
|
||||
} else {
|
||||
}
|
||||
case tag.tail:
|
||||
// A slice with "tail" tag can occur as the last field
|
||||
// of a struct and is upposed to swallow all remaining
|
||||
// list elements. The struct decoder already called s.List,
|
||||
// proceed directly to decoding the elements.
|
||||
dec = func(s *Stream, val reflect.Value) error {
|
||||
return decodeSliceElems(s, val, etypeinfo.decoder)
|
||||
}
|
||||
default:
|
||||
dec = func(s *Stream, val reflect.Value) error {
|
||||
return decodeListSlice(s, val, etypeinfo.decoder)
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
return dec, nil
|
||||
}
|
||||
|
||||
func decodeListSlice(s *Stream, val reflect.Value, elemdec decoder) error {
|
||||
@ -297,7 +309,13 @@ func decodeListSlice(s *Stream, val reflect.Value, elemdec decoder) error {
|
||||
val.Set(reflect.MakeSlice(val.Type(), 0, 0))
|
||||
return s.ListEnd()
|
||||
}
|
||||
if err := decodeSliceElems(s, val, elemdec); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.ListEnd()
|
||||
}
|
||||
|
||||
func decodeSliceElems(s *Stream, val reflect.Value, elemdec decoder) error {
|
||||
i := 0
|
||||
for ; ; i++ {
|
||||
// grow slice if necessary
|
||||
@ -323,12 +341,11 @@ func decodeListSlice(s *Stream, val reflect.Value, elemdec decoder) error {
|
||||
if i < val.Len() {
|
||||
val.SetLen(i)
|
||||
}
|
||||
return s.ListEnd()
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeListArray(s *Stream, val reflect.Value, elemdec decoder) error {
|
||||
_, err := s.List()
|
||||
if err != nil {
|
||||
if _, err := s.List(); err != nil {
|
||||
return wrapStreamError(err, val.Type())
|
||||
}
|
||||
vlen := val.Len()
|
||||
@ -398,11 +415,11 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) {
|
||||
return nil, err
|
||||
}
|
||||
dec := func(s *Stream, val reflect.Value) (err error) {
|
||||
if _, err = s.List(); err != nil {
|
||||
if _, err := s.List(); err != nil {
|
||||
return wrapStreamError(err, typ)
|
||||
}
|
||||
for _, f := range fields {
|
||||
err = f.info.decoder(s, val.Field(f.index))
|
||||
err := f.info.decoder(s, val.Field(f.index))
|
||||
if err == EOL {
|
||||
return &decodeError{msg: "too few elements", typ: typ}
|
||||
} else if err != nil {
|
||||
|
Reference in New Issue
Block a user