diff options
Diffstat (limited to 'rlp/decode.go')
-rw-r--r-- | rlp/decode.go | 51 |
1 files changed, 34 insertions, 17 deletions
diff --git a/rlp/decode.go b/rlp/decode.go index c4d42c6fc..c4e5869cc 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -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 { |