rlp: allow private fields after "tail" struct tag

This commit is contained in:
Felix Lange 2019-05-03 14:28:56 +02:00
parent d059c60a63
commit f0d231fe6f
2 changed files with 25 additions and 3 deletions

View file

@ -347,6 +347,12 @@ type tailUint struct {
Tail []uint `rlp:"tail"`
}
type tailPrivateFields struct {
A uint
Tail []uint `rlp:"tail"`
x, y bool
}
var (
veryBigInt = big.NewInt(0).Add(
big.NewInt(0).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16),
@ -510,6 +516,11 @@ var decodeTests = []decodeTest{
ptr: new(tailRaw),
value: tailRaw{A: 1, Tail: []RawValue{}},
},
{
input: "C3010203",
ptr: new(tailPrivateFields),
value: tailPrivateFields{A: 1, Tail: []uint{2, 3}},
},
// struct tag "-"
{

View file

@ -96,9 +96,10 @@ type field struct {
}
func structFields(typ reflect.Type) (fields []field, err error) {
lastPublic := lastPublicField(typ)
for i := 0; i < typ.NumField(); i++ {
if f := typ.Field(i); f.PkgPath == "" { // exported
tags, err := parseStructTag(typ, i)
tags, err := parseStructTag(typ, i, lastPublic)
if err != nil {
return nil, err
}
@ -115,7 +116,7 @@ func structFields(typ reflect.Type) (fields []field, err error) {
return fields, nil
}
func parseStructTag(typ reflect.Type, fi int) (tags, error) {
func parseStructTag(typ reflect.Type, fi, lastPublic int) (tags, error) {
f := typ.Field(fi)
var ts tags
for _, t := range strings.Split(f.Tag.Get("rlp"), ",") {
@ -127,7 +128,7 @@ func parseStructTag(typ reflect.Type, fi int) (tags, error) {
ts.nilOK = true
case "tail":
ts.tail = true
if fi != typ.NumField()-1 {
if fi != lastPublic {
return ts, fmt.Errorf(`rlp: invalid struct tag "tail" for %v.%s (must be on last field)`, typ, f.Name)
}
if f.Type.Kind() != reflect.Slice {
@ -140,6 +141,16 @@ func parseStructTag(typ reflect.Type, fi int) (tags, error) {
return ts, nil
}
func lastPublicField(typ reflect.Type) int {
last := 0
for i := 0; i < typ.NumField(); i++ {
if typ.Field(i).PkgPath == "" {
last = i
}
}
return last
}
func genTypeInfo(typ reflect.Type, tags tags) (info *typeinfo, err error) {
info = new(typeinfo)
if info.decoder, err = makeDecoder(typ, tags); err != nil {