rlp: add "tail" struct tag

This commit is contained in:
Felix Lange
2015-12-21 21:05:20 +01:00
parent fdb936ee95
commit bb07ce3eed
6 changed files with 163 additions and 26 deletions

View File

@ -17,7 +17,9 @@
package rlp
import (
"fmt"
"reflect"
"strings"
"sync"
)
@ -33,7 +35,13 @@ type typeinfo struct {
// represents struct tags
type tags struct {
// rlp:"nil" controls whether empty input results in a nil pointer.
nilOK bool
// rlp:"tail" controls whether this field swallows additional list
// elements. It can only be set for the last field, which must be
// of slice type.
tail bool
}
type typekey struct {
@ -89,7 +97,10 @@ type field struct {
func structFields(typ reflect.Type) (fields []field, err error) {
for i := 0; i < typ.NumField(); i++ {
if f := typ.Field(i); f.PkgPath == "" { // exported
tags := parseStructTag(f.Tag.Get("rlp"))
tags, err := parseStructTag(typ, i)
if err != nil {
return nil, err
}
info, err := cachedTypeInfo1(f.Type, tags)
if err != nil {
return nil, err
@ -100,8 +111,27 @@ func structFields(typ reflect.Type) (fields []field, err error) {
return fields, nil
}
func parseStructTag(tag string) tags {
return tags{nilOK: tag == "nil"}
func parseStructTag(typ reflect.Type, fi int) (tags, error) {
f := typ.Field(fi)
var ts tags
for _, t := range strings.Split(f.Tag.Get("rlp"), ",") {
switch t = strings.TrimSpace(t); t {
case "":
case "nil":
ts.nilOK = true
case "tail":
ts.tail = true
if fi != typ.NumField()-1 {
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 {
return ts, fmt.Errorf(`rlp: invalid struct tag "tail" for %v.%s (field type is not slice)`, typ, f.Name)
}
default:
return ts, fmt.Errorf("rlp: unknown struct tag %q on %v.%s", t, typ, f.Name)
}
}
return ts, nil
}
func genTypeInfo(typ reflect.Type, tags tags) (info *typeinfo, err error) {
@ -109,7 +139,7 @@ func genTypeInfo(typ reflect.Type, tags tags) (info *typeinfo, err error) {
if info.decoder, err = makeDecoder(typ, tags); err != nil {
return nil, err
}
if info.writer, err = makeWriter(typ); err != nil {
if info.writer, err = makeWriter(typ, tags); err != nil {
return nil, err
}
return info, nil