278 lines
5.8 KiB
Go
278 lines
5.8 KiB
Go
package msgpack
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
var structs = newStructCache()
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type field interface {
|
|
Name() string
|
|
|
|
EncodeValue(*Encoder, reflect.Value) error
|
|
DecodeValue(*Decoder, reflect.Value) error
|
|
}
|
|
|
|
type baseField struct {
|
|
idx []int
|
|
name string
|
|
}
|
|
|
|
func (f *baseField) Name() string {
|
|
return f.name
|
|
}
|
|
|
|
func (f *baseField) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeValue(fv)
|
|
}
|
|
|
|
func (f *baseField) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.DecodeValue(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type boolField struct {
|
|
*baseField
|
|
}
|
|
|
|
func (f *boolField) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeBool(fv.Bool())
|
|
}
|
|
|
|
func (f *boolField) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.boolValue(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type float32Field struct {
|
|
*baseField
|
|
}
|
|
|
|
func (f *float32Field) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeFloat32(float32(fv.Float()))
|
|
}
|
|
|
|
func (f *float32Field) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.float32Value(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type float64Field struct {
|
|
*baseField
|
|
}
|
|
|
|
func (f *float64Field) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeFloat64(fv.Float())
|
|
}
|
|
|
|
func (f *float64Field) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.float64Value(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type stringField struct {
|
|
*baseField
|
|
}
|
|
|
|
func (f *stringField) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeString(fv.String())
|
|
}
|
|
|
|
func (f *stringField) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.stringValue(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type bytesField struct {
|
|
*baseField
|
|
}
|
|
|
|
func (f *bytesField) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeBytes(fv.Bytes())
|
|
}
|
|
|
|
func (f *bytesField) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.bytesValue(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type intField struct {
|
|
*baseField
|
|
}
|
|
|
|
func (f *intField) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeInt64(fv.Int())
|
|
}
|
|
|
|
func (f *intField) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.int64Value(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type uintField struct {
|
|
*baseField
|
|
}
|
|
|
|
func (f *uintField) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return e.EncodeUint64(fv.Uint())
|
|
}
|
|
|
|
func (f *uintField) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return d.uint64Value(fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type customField struct {
|
|
*baseField
|
|
encode encoderFunc
|
|
decode decoderFunc
|
|
}
|
|
|
|
func (f *customField) EncodeValue(e *Encoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return f.encode(e, fv)
|
|
}
|
|
|
|
func (f *customField) DecodeValue(d *Decoder, v reflect.Value) error {
|
|
fv := v.FieldByIndex(f.idx)
|
|
return f.decode(d, fv)
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
type structCache struct {
|
|
l sync.RWMutex
|
|
m map[reflect.Type][]field
|
|
}
|
|
|
|
func newStructCache() *structCache {
|
|
return &structCache{
|
|
m: make(map[reflect.Type][]field),
|
|
}
|
|
}
|
|
|
|
func (m *structCache) Fields(typ reflect.Type) []field {
|
|
m.l.RLock()
|
|
fields, ok := m.m[typ]
|
|
m.l.RUnlock()
|
|
if ok {
|
|
return fields
|
|
}
|
|
|
|
numField := typ.NumField()
|
|
fields = make([]field, 0, numField)
|
|
for i := 0; i < numField; i++ {
|
|
f := typ.Field(i)
|
|
if f.PkgPath != "" {
|
|
continue
|
|
}
|
|
finfo := m.newStructField(typ, &f)
|
|
if finfo != nil {
|
|
fields = append(fields, finfo)
|
|
}
|
|
}
|
|
|
|
m.l.Lock()
|
|
m.m[typ] = fields
|
|
m.l.Unlock()
|
|
|
|
return fields
|
|
}
|
|
|
|
func (m *structCache) newStructField(typ reflect.Type, f *reflect.StructField) field {
|
|
tokens := strings.Split(f.Tag.Get("msgpack"), ",")
|
|
name := tokens[0]
|
|
if name == "-" {
|
|
return nil
|
|
} else if name == "" {
|
|
name = f.Name
|
|
}
|
|
|
|
baseField := &baseField{
|
|
idx: f.Index,
|
|
name: name,
|
|
}
|
|
|
|
ft := typ.FieldByIndex(f.Index).Type
|
|
if encodeFunc, ok := typEncMap[ft]; ok {
|
|
decodeFunc := typDecMap[ft]
|
|
return &customField{
|
|
encode: encodeFunc,
|
|
decode: decodeFunc,
|
|
baseField: baseField,
|
|
}
|
|
}
|
|
|
|
switch ft.Kind() {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return &intField{
|
|
baseField: baseField,
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return &uintField{
|
|
baseField: baseField,
|
|
}
|
|
case reflect.Bool:
|
|
return &boolField{
|
|
baseField: baseField,
|
|
}
|
|
case reflect.Float32:
|
|
return &float32Field{
|
|
baseField: baseField,
|
|
}
|
|
case reflect.Float64:
|
|
return &float64Field{
|
|
baseField: baseField,
|
|
}
|
|
case reflect.Array, reflect.Slice:
|
|
if ft.Elem().Kind() == reflect.Uint8 {
|
|
return &bytesField{
|
|
baseField: baseField,
|
|
}
|
|
}
|
|
case reflect.String:
|
|
return &stringField{
|
|
baseField: baseField,
|
|
}
|
|
}
|
|
return baseField
|
|
}
|
|
|
|
func (m *structCache) Field(typ reflect.Type, name string) field {
|
|
// TODO(vmihailenco): binary search?
|
|
for _, f := range m.Fields(typ) {
|
|
if f.Name() == name {
|
|
return f
|
|
}
|
|
}
|
|
return nil
|
|
}
|