aboutsummaryrefslogtreecommitdiffstats
path: root/rlp/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'rlp/decode.go')
-rw-r--r--rlp/decode.go51
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 {