2020-03-10 12:20:34 -07:00
|
|
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
|
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
|
|
|
|
package codec
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2020-06-10 13:20:40 -07:00
|
|
|
"math"
|
2020-03-10 12:20:34 -07:00
|
|
|
"reflect"
|
|
|
|
"unicode"
|
2020-06-12 07:41:02 -07:00
|
|
|
|
|
|
|
"github.com/ava-labs/gecko/utils/wrappers"
|
2020-03-10 12:20:34 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-03-12 09:11:45 -07:00
|
|
|
defaultMaxSize = 1 << 18 // default max size, in bytes, of something being marshalled by Marshal()
|
2020-06-12 13:52:58 -07:00
|
|
|
defaultMaxSliceLength = 1 << 18 // default max length of a slice being marshalled by Marshal(). Should be <= math.MaxUint32.
|
2020-06-12 07:41:02 -07:00
|
|
|
maxStringLen = math.MaxUint16
|
2020-03-10 12:20:34 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// ErrBadCodec is returned when one tries to perform an operation
|
|
|
|
// using an unknown codec
|
|
|
|
var (
|
|
|
|
errBadCodec = errors.New("wrong or unknown codec used")
|
2020-06-10 13:20:40 -07:00
|
|
|
errNil = errors.New("can't marshal/unmarshal nil value")
|
2020-03-10 12:20:34 -07:00
|
|
|
errNeedPointer = errors.New("must unmarshal into a pointer")
|
|
|
|
errMarshalUnregisteredType = errors.New("can't marshal an unregistered type")
|
|
|
|
errUnmarshalUnregisteredType = errors.New("can't unmarshal an unregistered type")
|
|
|
|
errUnknownType = errors.New("don't know how to marshal/unmarshal this type")
|
|
|
|
errMarshalUnexportedField = errors.New("can't serialize an unexported field")
|
|
|
|
errUnmarshalUnexportedField = errors.New("can't deserialize into an unexported field")
|
|
|
|
errOutOfMemory = errors.New("out of memory")
|
|
|
|
errSliceTooLarge = errors.New("slice too large")
|
|
|
|
)
|
|
|
|
|
|
|
|
// Codec handles marshaling and unmarshaling of structs
|
|
|
|
type codec struct {
|
|
|
|
maxSize int
|
|
|
|
maxSliceLen int
|
|
|
|
|
|
|
|
typeIDToType map[uint32]reflect.Type
|
|
|
|
typeToTypeID map[reflect.Type]uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// Codec marshals and unmarshals
|
|
|
|
type Codec interface {
|
|
|
|
RegisterType(interface{}) error
|
|
|
|
Marshal(interface{}) ([]byte, error)
|
|
|
|
Unmarshal([]byte, interface{}) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// New returns a new codec
|
|
|
|
func New(maxSize, maxSliceLen int) Codec {
|
|
|
|
return codec{
|
|
|
|
maxSize: maxSize,
|
|
|
|
maxSliceLen: maxSliceLen,
|
|
|
|
typeIDToType: map[uint32]reflect.Type{},
|
|
|
|
typeToTypeID: map[reflect.Type]uint32{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewDefault returns a new codec with reasonable default values
|
|
|
|
func NewDefault() Codec { return New(defaultMaxSize, defaultMaxSliceLength) }
|
|
|
|
|
2020-06-10 13:20:40 -07:00
|
|
|
// RegisterType is used to register types that may be unmarshaled into an interface
|
2020-03-10 12:20:34 -07:00
|
|
|
// [val] is a value of the type being registered
|
|
|
|
func (c codec) RegisterType(val interface{}) error {
|
|
|
|
valType := reflect.TypeOf(val)
|
|
|
|
if _, exists := c.typeToTypeID[valType]; exists {
|
|
|
|
return fmt.Errorf("type %v has already been registered", valType)
|
|
|
|
}
|
|
|
|
c.typeIDToType[uint32(len(c.typeIDToType))] = reflect.TypeOf(val)
|
|
|
|
c.typeToTypeID[valType] = uint32(len(c.typeIDToType) - 1)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// A few notes:
|
|
|
|
// 1) See codec_test.go for examples of usage
|
|
|
|
// 2) We use "marshal" and "serialize" interchangeably, and "unmarshal" and "deserialize" interchangeably
|
|
|
|
// 3) To include a field of a struct in the serialized form, add the tag `serialize:"true"` to it
|
|
|
|
// 4) These typed members of a struct may be serialized:
|
2020-06-10 13:20:40 -07:00
|
|
|
// bool, string, uint[8,16,32,64], int[8,16,32,64],
|
2020-03-10 12:20:34 -07:00
|
|
|
// structs, slices, arrays, interface.
|
2020-06-10 13:20:40 -07:00
|
|
|
// structs, slices and arrays can only be serialized if their constituent values can be.
|
|
|
|
// 5) To marshal an interface, you must pass a pointer to the value
|
|
|
|
// 6) To unmarshal an interface, you must call codec.RegisterType([instance of the type that fulfills the interface]).
|
2020-06-12 07:41:02 -07:00
|
|
|
// 7) Serialized fields must be exported
|
2020-06-12 13:52:58 -07:00
|
|
|
// 8) nil slices are marshaled as empty slices
|
2020-03-10 12:20:34 -07:00
|
|
|
|
2020-06-10 13:20:40 -07:00
|
|
|
// To marshal an interface, [value] must be a pointer to the interface
|
2020-03-10 12:20:34 -07:00
|
|
|
func (c codec) Marshal(value interface{}) ([]byte, error) {
|
|
|
|
if value == nil {
|
|
|
|
return nil, errNil
|
|
|
|
}
|
2020-06-12 16:03:08 -07:00
|
|
|
|
|
|
|
funcs := make([]func(*wrappers.Packer) error, 512, 512)
|
|
|
|
size, _, err := c.marshal(reflect.ValueOf(value), 0, &funcs)
|
2020-06-11 15:16:21 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
|
2020-06-12 07:41:02 -07:00
|
|
|
p := &wrappers.Packer{MaxSize: size, Bytes: make([]byte, 0, size)}
|
2020-06-12 16:03:08 -07:00
|
|
|
for _, f := range funcs {
|
|
|
|
if f == nil {
|
|
|
|
break
|
|
|
|
} else if err := f(p); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 16:03:08 -07:00
|
|
|
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Bytes, nil
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
|
2020-06-11 15:16:21 -07:00
|
|
|
// marshal returns:
|
|
|
|
// 1) The size, in bytes, of the byte representation of [value]
|
|
|
|
// 2) A slice of functions, where each function writes bytes to its argument
|
|
|
|
// and returns the number of bytes it wrote.
|
|
|
|
// When these functions are called in order, they write [value] to a byte slice.
|
|
|
|
// 3) An error
|
2020-06-12 16:03:08 -07:00
|
|
|
func (c codec) marshal(value reflect.Value, index int, funcs *[]func(*wrappers.Packer) error) (size int, funcsWritten int, err error) {
|
2020-03-10 12:20:34 -07:00
|
|
|
valueKind := value.Kind()
|
2020-06-10 13:20:40 -07:00
|
|
|
|
|
|
|
// Case: Value can't be marshalled
|
2020-03-10 12:20:34 -07:00
|
|
|
switch valueKind {
|
2020-06-11 15:16:21 -07:00
|
|
|
case reflect.Interface, reflect.Ptr, reflect.Invalid:
|
|
|
|
if value.IsNil() { // Can't marshal nil or nil pointers
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, errNil
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-10 13:20:40 -07:00
|
|
|
// Case: Value is of known size; return its byte repr.
|
2020-03-10 12:20:34 -07:00
|
|
|
switch valueKind {
|
|
|
|
case reflect.Uint8:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 1
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asByte := byte(value.Uint())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackByte(asByte)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int8:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 1
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asByte := byte(value.Int())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackByte(asByte)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Uint16:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 2
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asShort := uint16(value.Uint())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackShort(asShort)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int16:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 2
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asShort := uint16(value.Int())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackShort(asShort)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Uint32:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 4
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asInt := uint32(value.Uint())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackInt(asInt)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int32:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 4
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asInt := uint32(value.Int())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackInt(asInt)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Uint64:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 8
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asInt := uint64(value.Uint())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackLong(asInt)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int64:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 8
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asInt := uint64(value.Int())
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackLong(asInt)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.String:
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-10 13:20:40 -07:00
|
|
|
asStr := value.String()
|
2020-06-12 16:03:08 -07:00
|
|
|
size = len(asStr) + wrappers.ShortLen
|
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 07:41:02 -07:00
|
|
|
p.PackStr(asStr)
|
|
|
|
return p.Err
|
2020-06-10 13:20:40 -07:00
|
|
|
}
|
2020-06-11 15:16:21 -07:00
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Bool:
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 1
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1
|
2020-06-12 16:26:03 -07:00
|
|
|
asBool := value.Bool()
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackBool(asBool)
|
2020-06-12 07:41:02 -07:00
|
|
|
return p.Err
|
2020-06-10 13:20:40 -07:00
|
|
|
}
|
2020-06-11 15:16:21 -07:00
|
|
|
return
|
|
|
|
case reflect.Uintptr, reflect.Ptr:
|
2020-06-12 16:03:08 -07:00
|
|
|
return c.marshal(value.Elem(), index, funcs)
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Interface:
|
|
|
|
typeID, ok := c.typeToTypeID[reflect.TypeOf(value.Interface())] // Get the type ID of the value being marshaled
|
|
|
|
if !ok {
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, fmt.Errorf("can't marshal unregistered type '%v'", reflect.TypeOf(value.Interface()).String())
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-06-11 15:16:21 -07:00
|
|
|
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = nil
|
|
|
|
subsize, subFuncsWritten, subErr := c.marshal(reflect.ValueOf(value.Interface()), index+1, funcs)
|
2020-06-11 15:16:21 -07:00
|
|
|
if subErr != nil {
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, subErr
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
size = 4 + subsize // 4 because we pack the type ID, a uint32
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 07:41:02 -07:00
|
|
|
p.PackInt(typeID)
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 16:03:08 -07:00
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 1 + subFuncsWritten
|
2020-06-11 15:16:21 -07:00
|
|
|
return
|
|
|
|
case reflect.Slice:
|
2020-06-12 13:52:58 -07:00
|
|
|
numElts := value.Len() // # elements in the slice/array. 0 if this slice is nil.
|
2020-06-11 15:16:21 -07:00
|
|
|
if numElts > c.maxSliceLen {
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, fmt.Errorf("slice length, %d, exceeds maximum length, %d", numElts, c.maxSliceLen)
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-06-11 15:16:21 -07:00
|
|
|
|
2020-06-12 16:03:08 -07:00
|
|
|
size = wrappers.IntLen // for # elements
|
|
|
|
subFuncsWritten := 0
|
2020-06-12 13:52:58 -07:00
|
|
|
for i := 0; i < numElts; i++ { // Process each element in the slice
|
2020-06-12 16:03:08 -07:00
|
|
|
subSize, n, subErr := c.marshal(value.Index(i), index+subFuncsWritten+1, funcs)
|
2020-06-11 15:16:21 -07:00
|
|
|
if subErr != nil {
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, subErr
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
size += subSize
|
2020-06-12 16:03:08 -07:00
|
|
|
subFuncsWritten += n
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
|
2020-06-12 16:26:03 -07:00
|
|
|
numEltsAsUint32 := uint32(numElts)
|
2020-06-12 16:03:08 -07:00
|
|
|
(*funcs)[index] = func(p *wrappers.Packer) error {
|
2020-06-12 16:26:03 -07:00
|
|
|
p.PackInt(numEltsAsUint32) // pack # elements
|
2020-06-12 13:52:58 -07:00
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
|
|
|
}
|
2020-06-11 15:16:21 -07:00
|
|
|
return nil
|
|
|
|
}
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = subFuncsWritten + 1
|
2020-06-11 15:16:21 -07:00
|
|
|
return
|
|
|
|
case reflect.Array:
|
2020-06-12 13:52:58 -07:00
|
|
|
numElts := value.Len()
|
|
|
|
if numElts > c.maxSliceLen {
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, fmt.Errorf("array length, %d, exceeds maximum length, %d", numElts, c.maxSliceLen)
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
size = 0
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten = 0
|
2020-06-11 15:16:21 -07:00
|
|
|
for i := 0; i < numElts; i++ { // Process each element in the array
|
2020-06-12 16:03:08 -07:00
|
|
|
subSize, n, subErr := c.marshal(value.Index(i), index+funcsWritten, funcs)
|
2020-06-11 15:16:21 -07:00
|
|
|
if subErr != nil {
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, subErr
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
size += subSize
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten += n
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Struct:
|
2020-06-11 15:16:21 -07:00
|
|
|
t := value.Type()
|
|
|
|
numFields := t.NumField()
|
2020-06-12 13:52:58 -07:00
|
|
|
|
2020-06-11 15:16:21 -07:00
|
|
|
size = 0
|
2020-06-12 16:03:08 -07:00
|
|
|
fieldsMarshalled := 0
|
|
|
|
funcsWritten = 0
|
2020-06-11 15:16:21 -07:00
|
|
|
for i := 0; i < numFields; i++ { // Go through all fields of this struct
|
2020-03-10 12:20:34 -07:00
|
|
|
field := t.Field(i)
|
|
|
|
if !shouldSerialize(field) { // Skip fields we don't need to serialize
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if unicode.IsLower(rune(field.Name[0])) { // Can only marshal exported fields
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, fmt.Errorf("can't marshal unexported field %s", field.Name)
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-06-12 16:03:08 -07:00
|
|
|
fieldVal := value.Field(i) // The field we're serializing
|
|
|
|
subSize, n, err := c.marshal(fieldVal, index+funcsWritten, funcs) // Serialize the field
|
2020-03-10 12:20:34 -07:00
|
|
|
if err != nil {
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 16:03:08 -07:00
|
|
|
fieldsMarshalled++
|
2020-06-11 15:16:21 -07:00
|
|
|
size += subSize
|
2020-06-12 16:03:08 -07:00
|
|
|
funcsWritten += n
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
|
|
|
return
|
2020-03-10 12:20:34 -07:00
|
|
|
default:
|
2020-06-12 16:03:08 -07:00
|
|
|
return 0, 0, errUnknownType
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unmarshal unmarshals [bytes] into [dest], where
|
|
|
|
// [dest] must be a pointer or interface
|
|
|
|
func (c codec) Unmarshal(bytes []byte, dest interface{}) error {
|
2020-06-11 15:16:21 -07:00
|
|
|
switch {
|
|
|
|
case len(bytes) > c.maxSize:
|
2020-03-10 12:20:34 -07:00
|
|
|
return errSliceTooLarge
|
2020-06-11 15:16:21 -07:00
|
|
|
case dest == nil:
|
2020-03-10 12:20:34 -07:00
|
|
|
return errNil
|
|
|
|
}
|
|
|
|
|
|
|
|
destPtr := reflect.ValueOf(dest)
|
|
|
|
if destPtr.Kind() != reflect.Ptr {
|
|
|
|
return errNeedPointer
|
|
|
|
}
|
|
|
|
|
2020-06-12 07:41:02 -07:00
|
|
|
p := &wrappers.Packer{MaxSize: c.maxSize, Bytes: bytes}
|
2020-03-10 12:20:34 -07:00
|
|
|
destVal := destPtr.Elem()
|
2020-06-12 07:41:02 -07:00
|
|
|
if err := c.unmarshal(p, destVal); err != nil {
|
2020-03-10 12:20:34 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-11 15:16:21 -07:00
|
|
|
// Unmarshal bytes from [bytes] into [field]
|
2020-03-10 12:20:34 -07:00
|
|
|
// [field] must be addressable
|
2020-06-12 07:41:02 -07:00
|
|
|
func (c codec) unmarshal(p *wrappers.Packer, field reflect.Value) error {
|
2020-03-10 12:20:34 -07:00
|
|
|
kind := field.Kind()
|
|
|
|
switch kind {
|
|
|
|
case reflect.Uint8:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackByte()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetUint(uint64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int8:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackByte()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetInt(int64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Uint16:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackShort()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetUint(uint64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int16:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackShort()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetInt(int64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Uint32:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackInt()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetUint(uint64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int32:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackInt()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetInt(int64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Uint64:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackLong()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetUint(uint64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Int64:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackLong()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetInt(int64(b))
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Bool:
|
2020-06-12 07:41:02 -07:00
|
|
|
b := p.UnpackBool()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetBool(b)
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Slice:
|
2020-06-12 13:52:58 -07:00
|
|
|
numElts := int(p.UnpackInt())
|
2020-06-12 07:41:02 -07:00
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-06-11 15:16:21 -07:00
|
|
|
// set [field] to be a slice of the appropriate type/capacity (right now [field] is nil)
|
|
|
|
slice := reflect.MakeSlice(field.Type(), numElts, numElts)
|
2020-03-10 12:20:34 -07:00
|
|
|
field.Set(slice)
|
|
|
|
// Unmarshal each element into the appropriate index of the slice
|
2020-06-11 15:16:21 -07:00
|
|
|
for i := 0; i < numElts; i++ {
|
2020-06-12 07:41:02 -07:00
|
|
|
if err := c.unmarshal(p, field.Index(i)); err != nil {
|
|
|
|
return err
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Array:
|
|
|
|
for i := 0; i < field.Len(); i++ {
|
2020-06-12 07:41:02 -07:00
|
|
|
if err := c.unmarshal(p, field.Index(i)); err != nil {
|
|
|
|
return err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.String:
|
2020-06-12 07:41:02 -07:00
|
|
|
str := p.UnpackStr()
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field.SetString(str)
|
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Interface:
|
2020-06-12 07:41:02 -07:00
|
|
|
typeID := p.UnpackInt() // Get the type ID
|
|
|
|
if p.Err != nil {
|
|
|
|
return p.Err
|
2020-06-11 15:16:21 -07:00
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
// Get a struct that implements the interface
|
|
|
|
typ, ok := c.typeIDToType[typeID]
|
|
|
|
if !ok {
|
2020-06-12 07:41:02 -07:00
|
|
|
return errUnmarshalUnregisteredType
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-03-26 12:14:45 -07:00
|
|
|
// Ensure struct actually does implement the interface
|
|
|
|
fieldType := field.Type()
|
|
|
|
if !typ.Implements(fieldType) {
|
2020-06-12 07:41:02 -07:00
|
|
|
return fmt.Errorf("%s does not implement interface %s", typ, fieldType)
|
2020-03-26 12:14:45 -07:00
|
|
|
}
|
2020-03-10 12:20:34 -07:00
|
|
|
concreteInstancePtr := reflect.New(typ) // instance of the proper type
|
|
|
|
// Unmarshal into the struct
|
2020-06-12 07:41:02 -07:00
|
|
|
if err := c.unmarshal(p, concreteInstancePtr.Elem()); err != nil {
|
|
|
|
return err
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
// And assign the filled struct to the field
|
|
|
|
field.Set(concreteInstancePtr.Elem())
|
2020-06-12 07:41:02 -07:00
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Struct:
|
|
|
|
// Type of this struct
|
|
|
|
structType := reflect.TypeOf(field.Interface())
|
|
|
|
// Go through all the fields and umarshal into each
|
|
|
|
for i := 0; i < structType.NumField(); i++ {
|
|
|
|
structField := structType.Field(i)
|
|
|
|
if !shouldSerialize(structField) { // Skip fields we don't need to unmarshal
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if unicode.IsLower(rune(structField.Name[0])) { // Only unmarshal into exported field
|
2020-06-12 07:41:02 -07:00
|
|
|
return errUnmarshalUnexportedField
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
field := field.Field(i) // Get the field
|
|
|
|
if err := c.unmarshal(p, field); err != nil { // Unmarshal into the field
|
|
|
|
return err
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 07:41:02 -07:00
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Ptr:
|
|
|
|
// Get the type this pointer points to
|
|
|
|
underlyingType := field.Type().Elem()
|
|
|
|
// Create a new pointer to a new value of the underlying type
|
|
|
|
underlyingValue := reflect.New(underlyingType)
|
|
|
|
// Fill the value
|
2020-06-12 07:41:02 -07:00
|
|
|
if err := c.unmarshal(p, underlyingValue.Elem()); err != nil {
|
|
|
|
return err
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
// Assign to the top-level struct's member
|
|
|
|
field.Set(underlyingValue)
|
2020-06-12 07:41:02 -07:00
|
|
|
return nil
|
2020-03-10 12:20:34 -07:00
|
|
|
case reflect.Invalid:
|
2020-06-12 07:41:02 -07:00
|
|
|
return errNil
|
2020-03-10 12:20:34 -07:00
|
|
|
default:
|
2020-06-12 07:41:02 -07:00
|
|
|
return errUnknownType
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true iff [field] should be serialized
|
|
|
|
func shouldSerialize(field reflect.StructField) bool {
|
2020-04-24 14:47:05 -07:00
|
|
|
return field.Tag.Get("serialize") == "true"
|
2020-03-10 12:20:34 -07:00
|
|
|
}
|