rlp: fixes for two corner cases and documentation (#19527)

These changes fix two corner cases related to internal handling of types
in package rlp: The "tail" struct tag can only be applied to the last field.
The check for this was wrong and didn't allow for private fields after the
field with the tag. Unsupported types (e.g. structs containing int) which
implement either the Encoder or Decoder interface but not both 
couldn't be encoded/decoded.

Also fixes #19367
This commit is contained in:
Felix Lange
2019-05-14 15:09:56 +02:00
committed by GitHub
parent 184af72e4e
commit 8deec2e45a
5 changed files with 111 additions and 57 deletions

View File

@ -73,10 +73,12 @@ type Encoder interface {
// An unsigned integer value is encoded as an RLP string. Zero always
// encodes as an empty RLP string. Encode also supports *big.Int.
//
// Boolean values are encoded as unsigned integers zero (false) and one (true).
//
// An interface value encodes as the value contained in the interface.
//
// Boolean values are not supported, nor are signed integers, floating
// point numbers, maps, channels and functions.
// Signed integers are not supported, nor are floating point numbers, maps,
// channels and functions.
func Encode(w io.Writer, val interface{}) error {
if outer, ok := w.(*encbuf); ok {
// Encode was called by some type's EncodeRLP.
@ -180,11 +182,11 @@ func (w *encbuf) Write(b []byte) (int, error) {
func (w *encbuf) encode(val interface{}) error {
rval := reflect.ValueOf(val)
ti, err := cachedTypeInfo(rval.Type(), tags{})
writer, err := cachedWriter(rval.Type())
if err != nil {
return err
}
return ti.writer(rval, w)
return writer(rval, w)
}
func (w *encbuf) encodeStringHeader(size int) {
@ -497,17 +499,17 @@ func writeInterface(val reflect.Value, w *encbuf) error {
return nil
}
eval := val.Elem()
ti, err := cachedTypeInfo(eval.Type(), tags{})
writer, err := cachedWriter(eval.Type())
if err != nil {
return err
}
return ti.writer(eval, w)
return writer(eval, w)
}
func makeSliceWriter(typ reflect.Type, ts tags) (writer, error) {
etypeinfo, err := cachedTypeInfo1(typ.Elem(), tags{})
if err != nil {
return nil, err
etypeinfo := cachedTypeInfo1(typ.Elem(), tags{})
if etypeinfo.writerErr != nil {
return nil, etypeinfo.writerErr
}
writer := func(val reflect.Value, w *encbuf) error {
if !ts.tail {
@ -543,9 +545,9 @@ func makeStructWriter(typ reflect.Type) (writer, error) {
}
func makePtrWriter(typ reflect.Type) (writer, error) {
etypeinfo, err := cachedTypeInfo1(typ.Elem(), tags{})
if err != nil {
return nil, err
etypeinfo := cachedTypeInfo1(typ.Elem(), tags{})
if etypeinfo.writerErr != nil {
return nil, etypeinfo.writerErr
}
// determine nil pointer handler
@ -577,7 +579,7 @@ func makePtrWriter(typ reflect.Type) (writer, error) {
}
return etypeinfo.writer(val.Elem(), w)
}
return writer, err
return writer, nil
}
// putint writes i to the beginning of b in big endian byte