initial commit
This commit is contained in:
commit
f8719a06fa
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2013 The msgpack for Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,87 @@
|
||||||
|
Msgpack implementation for Golang
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Supports:
|
||||||
|
- Primitives, arrays, maps, structs and interface{}.
|
||||||
|
- time.Time.
|
||||||
|
- Appengine *datastore.Key and datastore.Cursor.
|
||||||
|
- Extensions for user defined types.
|
||||||
|
- Tags.
|
||||||
|
|
||||||
|
API docs: http://godoc.org/github.com/vmihailenco/msgpack
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
Install:
|
||||||
|
|
||||||
|
go get github.com/vmihailenco/msgpack
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
func ExampleEncode() {
|
||||||
|
b, err := msgpack.Marshal(true)
|
||||||
|
fmt.Printf("%v %#v\n", err, b)
|
||||||
|
// Output: <nil> []byte{0xc3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode() {
|
||||||
|
var out bool
|
||||||
|
err := msgpack.Unmarshal([]byte{0xc3}, &out)
|
||||||
|
fmt.Println(err, out)
|
||||||
|
// Output: <nil> true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleMapStringInterface() {
|
||||||
|
in := map[string]interface{}{"foo": 1, "hello": "world"}
|
||||||
|
b, err := msgpack.Marshal(in)
|
||||||
|
_ = err
|
||||||
|
|
||||||
|
var out map[string]interface{}
|
||||||
|
err = msgpack.Unmarshal(b, &out)
|
||||||
|
fmt.Printf("%v %#v\n", err, out)
|
||||||
|
// Output: <nil> map[string]interface {}{"foo":1, "hello":"world"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRecursiveMapStringInterface() {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
enc := msgpack.NewEncoder(buf)
|
||||||
|
in := map[string]interface{}{"foo": map[string]interface{}{"hello": "world"}}
|
||||||
|
_ = enc.Encode(in)
|
||||||
|
|
||||||
|
dec := msgpack.NewDecoder(buf)
|
||||||
|
dec.DecodeMapFunc = func(d *msgpack.Decoder) (interface{}, error) {
|
||||||
|
n, err := d.DecodeMapLen()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]interface{}, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
mk, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mv, err := d.DecodeInterface()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m[mk] = mv
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
out, err := dec.DecodeInterface()
|
||||||
|
fmt.Printf("%v %#v\n", err, out)
|
||||||
|
// Output: <nil> map[string]interface {}{"foo":map[string]interface {}{"hello":"world"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
Extensions
|
||||||
|
----------
|
||||||
|
|
||||||
|
Look at [appengine.go](https://github.com/vmihailenco/msgpack/blob/master/appengine.go) for example.
|
|
@ -0,0 +1,69 @@
|
||||||
|
// +build appengine
|
||||||
|
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
ds "appengine/datastore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
keyPtrType = reflect.TypeOf((*ds.Key)(nil))
|
||||||
|
cursorType = reflect.TypeOf((*ds.Cursor)(nil)).Elem()
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(keyPtrType, encodeDatastoreKeyValue, decodeDatastoreKeyValue)
|
||||||
|
Register(cursorType, encodeDatastoreCursorValue, decodeDatastoreCursorValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncodeDatastoreKey(e *Encoder, key *ds.Key) error {
|
||||||
|
if key == nil {
|
||||||
|
return e.EncodeNil()
|
||||||
|
}
|
||||||
|
return e.EncodeString(key.Encode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeDatastoreKeyValue(e *Encoder, v reflect.Value) error {
|
||||||
|
key := v.Interface().(*ds.Key)
|
||||||
|
return EncodeDatastoreKey(e, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeDatastoreKey(d *Decoder) (*ds.Key, error) {
|
||||||
|
v, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if v == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return ds.DecodeKey(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeDatastoreKeyValue(d *Decoder, v reflect.Value) error {
|
||||||
|
key, err := DecodeDatastoreKey(d)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(key))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeDatastoreCursorValue(e *Encoder, v reflect.Value) error {
|
||||||
|
cursor := v.Interface().(ds.Cursor)
|
||||||
|
return e.Encode(cursor.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeDatastoreCursorValue(d *Decoder, v reflect.Value) error {
|
||||||
|
s, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cursor, err := ds.DecodeCursor(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(cursor))
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
const (
|
||||||
|
posFixNumHighCode = 0x7f
|
||||||
|
negFixNumLowCode = 0xe0
|
||||||
|
|
||||||
|
nilCode = 0xc0
|
||||||
|
|
||||||
|
falseCode = 0xc2
|
||||||
|
trueCode = 0xc3
|
||||||
|
|
||||||
|
floatCode = 0xca
|
||||||
|
doubleCode = 0xcb
|
||||||
|
|
||||||
|
uint8Code = 0xcc
|
||||||
|
uint16Code = 0xcd
|
||||||
|
uint32Code = 0xce
|
||||||
|
uint64Code = 0xcf
|
||||||
|
|
||||||
|
int8Code = 0xd0
|
||||||
|
int16Code = 0xd1
|
||||||
|
int32Code = 0xd2
|
||||||
|
int64Code = 0xd3
|
||||||
|
|
||||||
|
fixRawLowCode = 0xa0
|
||||||
|
fixRawHighCode = 0xbf
|
||||||
|
fixRawMask = 0x1f
|
||||||
|
raw16Code = 0xda
|
||||||
|
raw32Code = 0xdb
|
||||||
|
|
||||||
|
fixArrayLowCode = 0x90
|
||||||
|
fixArrayHighCode = 0x9f
|
||||||
|
fixArrayMask = 0xf
|
||||||
|
array16Code = 0xdc
|
||||||
|
array32Code = 0xdd
|
||||||
|
|
||||||
|
fixMapLowCode = 0x80
|
||||||
|
fixMapHighCode = 0x8f
|
||||||
|
fixMapMask = 0xf
|
||||||
|
map16Code = 0xde
|
||||||
|
map32Code = 0xdf
|
||||||
|
)
|
|
@ -0,0 +1,19 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
typEncMap = make(map[reflect.Type]encoderFunc)
|
||||||
|
typDecMap = make(map[reflect.Type]decoderFunc)
|
||||||
|
)
|
||||||
|
|
||||||
|
type encoderFunc func(*Encoder, reflect.Value) error
|
||||||
|
|
||||||
|
type decoderFunc func(*Decoder, reflect.Value) error
|
||||||
|
|
||||||
|
func Register(typ reflect.Type, enc encoderFunc, dec decoderFunc) {
|
||||||
|
typEncMap[typ] = enc
|
||||||
|
typDecMap[typ] = dec
|
||||||
|
}
|
|
@ -0,0 +1,807 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/vmihailenco/bufio"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bufReader interface {
|
||||||
|
Read([]byte) (int, error)
|
||||||
|
ReadByte() (byte, error)
|
||||||
|
UnreadByte() error
|
||||||
|
Peek(int) ([]byte, error)
|
||||||
|
ReadN(int) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Unmarshal(data []byte, v ...interface{}) error {
|
||||||
|
buf := bufio.NewBuffer(data)
|
||||||
|
return NewDecoder(buf).Decode(v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Decoder struct {
|
||||||
|
R bufReader
|
||||||
|
DecodeMapFunc func(*Decoder) (interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDecoder(rd io.Reader) *Decoder {
|
||||||
|
brd, ok := rd.(bufReader)
|
||||||
|
if !ok {
|
||||||
|
brd = bufio.NewReader(rd)
|
||||||
|
}
|
||||||
|
return &Decoder{
|
||||||
|
R: brd,
|
||||||
|
DecodeMapFunc: decodeMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Decode(v ...interface{}) error {
|
||||||
|
for _, vv := range v {
|
||||||
|
if err := d.decode(vv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) decode(iv interface{}) error {
|
||||||
|
var err error
|
||||||
|
switch v := iv.(type) {
|
||||||
|
case *string:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeString()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *[]byte:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeBytes()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *int:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeInt()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *int8:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeInt8()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *int16:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeInt16()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *int32:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeInt32()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *int64:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeInt64()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *uint:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeUint()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *uint8:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeUint8()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *uint16:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeUint16()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *uint32:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeUint32()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *uint64:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeUint64()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *bool:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeBool()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *float32:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeFloat32()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *float64:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeFloat64()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *[]string:
|
||||||
|
return d.decodeIntoStrings(v)
|
||||||
|
case *map[string]string:
|
||||||
|
return d.decodeIntoMapStringString(v)
|
||||||
|
case *time.Duration:
|
||||||
|
if v != nil {
|
||||||
|
vv, err := d.DecodeInt64()
|
||||||
|
*v = time.Duration(vv)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case *time.Time:
|
||||||
|
if v != nil {
|
||||||
|
*v, err = d.DecodeTime()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v := reflect.ValueOf(iv)
|
||||||
|
if !v.IsValid() {
|
||||||
|
return errors.New("msgpack: Decode(" + v.String() + ")")
|
||||||
|
}
|
||||||
|
if v.Kind() != reflect.Ptr {
|
||||||
|
return errors.New("msgpack: pointer expected")
|
||||||
|
}
|
||||||
|
return d.DecodeValue(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeValue(v reflect.Value) error {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c == nilCode {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := d.R.UnreadByte(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return d.boolValue(v)
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return d.uint64Value(v)
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return d.int64Value(v)
|
||||||
|
case reflect.Float32:
|
||||||
|
return d.float32Value(v)
|
||||||
|
case reflect.Float64:
|
||||||
|
return d.float64Value(v)
|
||||||
|
case reflect.String:
|
||||||
|
return d.stringValue(v)
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
return d.sliceValue(v)
|
||||||
|
case reflect.Map:
|
||||||
|
return d.mapValue(v)
|
||||||
|
case reflect.Struct:
|
||||||
|
typ := v.Type()
|
||||||
|
if dec, ok := typDecMap[typ]; ok {
|
||||||
|
return dec(d, v)
|
||||||
|
}
|
||||||
|
if dec, ok := v.Interface().(decoder); ok {
|
||||||
|
return dec.DecodeMsgpack(d.R)
|
||||||
|
}
|
||||||
|
return d.structValue(v)
|
||||||
|
case reflect.Ptr:
|
||||||
|
typ := v.Type()
|
||||||
|
if v.IsNil() {
|
||||||
|
v.Set(reflect.New(typ.Elem()))
|
||||||
|
}
|
||||||
|
if dec, ok := typDecMap[typ]; ok {
|
||||||
|
return dec(d, v)
|
||||||
|
}
|
||||||
|
if dec, ok := v.Interface().(decoder); ok {
|
||||||
|
return dec.DecodeMsgpack(d.R)
|
||||||
|
}
|
||||||
|
return d.DecodeValue(v.Elem())
|
||||||
|
case reflect.Interface:
|
||||||
|
if v.IsNil() {
|
||||||
|
return d.interfaceValue(v)
|
||||||
|
} else {
|
||||||
|
return d.DecodeValue(v.Elem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("msgpack: unsupported type %v", v.Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeBool() (bool, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case falseCode:
|
||||||
|
return false, nil
|
||||||
|
case trueCode:
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("msgpack: invalid code %x decoding bool", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) boolValue(value reflect.Value) error {
|
||||||
|
v, err := d.DecodeBool()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.SetBool(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) uint16() (uint16, error) {
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return (uint16(b[0]) << 8) | uint16(b[1]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) uint32() (uint32, error) {
|
||||||
|
b, err := d.R.ReadN(4)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
n := (uint32(b[0]) << 24) |
|
||||||
|
(uint32(b[1]) << 16) |
|
||||||
|
(uint32(b[2]) << 8) |
|
||||||
|
uint32(b[3])
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) uint64() (uint64, error) {
|
||||||
|
b, err := d.R.ReadN(8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
n := (uint64(b[0]) << 56) |
|
||||||
|
(uint64(b[1]) << 48) |
|
||||||
|
(uint64(b[2]) << 40) |
|
||||||
|
(uint64(b[3]) << 32) |
|
||||||
|
(uint64(b[4]) << 24) |
|
||||||
|
(uint64(b[5]) << 16) |
|
||||||
|
(uint64(b[6]) << 8) |
|
||||||
|
uint64(b[7])
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeUint64() (uint64, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode {
|
||||||
|
return uint64(c), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case uint8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint64(c), nil
|
||||||
|
case uint16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return (uint64(b[0]) << 8) | uint64(b[1]), nil
|
||||||
|
case uint32Code:
|
||||||
|
b, err := d.R.ReadN(4)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := (uint64(b[0]) << 24) |
|
||||||
|
(uint64(b[1]) << 16) |
|
||||||
|
(uint64(b[2]) << 8) |
|
||||||
|
uint64(b[3])
|
||||||
|
return v, nil
|
||||||
|
case uint64Code:
|
||||||
|
b, err := d.R.ReadN(8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := (uint64(b[0]) << 56) |
|
||||||
|
(uint64(b[1]) << 48) |
|
||||||
|
(uint64(b[2]) << 40) |
|
||||||
|
(uint64(b[3]) << 32) |
|
||||||
|
(uint64(b[4]) << 24) |
|
||||||
|
(uint64(b[5]) << 16) |
|
||||||
|
(uint64(b[6]) << 8) |
|
||||||
|
uint64(b[7])
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding uint64", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) uint64Value(value reflect.Value) error {
|
||||||
|
v, err := d.DecodeUint64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.SetUint(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeInt64() (int64, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode || c >= negFixNumLowCode {
|
||||||
|
return int64(int8(c)), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case int8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int64(int8(c)), nil
|
||||||
|
case int16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int64((int16(b[0]) << 8) | int16(b[1])), nil
|
||||||
|
case int32Code:
|
||||||
|
b, err := d.R.ReadN(4)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := int64((int32(b[0]) << 24) |
|
||||||
|
(int32(b[1]) << 16) |
|
||||||
|
(int32(b[2]) << 8) |
|
||||||
|
int32(b[3]))
|
||||||
|
return v, nil
|
||||||
|
case int64Code:
|
||||||
|
b, err := d.R.ReadN(8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := (int64(b[0]) << 56) |
|
||||||
|
(int64(b[1]) << 48) |
|
||||||
|
(int64(b[2]) << 40) |
|
||||||
|
(int64(b[3]) << 32) |
|
||||||
|
(int64(b[4]) << 24) |
|
||||||
|
(int64(b[5]) << 16) |
|
||||||
|
(int64(b[6]) << 8) |
|
||||||
|
int64(b[7])
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding int64", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) int64Value(value reflect.Value) error {
|
||||||
|
v, err := d.DecodeInt64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.SetInt(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeFloat32() (float32, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c != floatCode {
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding float32", c)
|
||||||
|
}
|
||||||
|
b, err := d.uint32()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return math.Float32frombits(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) float32Value(value reflect.Value) error {
|
||||||
|
v, err := d.DecodeFloat32()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.SetFloat(float64(v))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeFloat64() (float64, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c != doubleCode {
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding float64", c)
|
||||||
|
}
|
||||||
|
b, err := d.uint64()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return math.Float64frombits(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) float64Value(value reflect.Value) error {
|
||||||
|
v, err := d.DecodeFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.SetFloat(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) structLen() (int, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c >= fixMapLowCode && c <= fixMapHighCode {
|
||||||
|
return int(c & fixMapMask), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case map16Code:
|
||||||
|
n, err := d.uint16()
|
||||||
|
return int(n), err
|
||||||
|
case map32Code:
|
||||||
|
n, err := d.uint32()
|
||||||
|
return int(n), err
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding struct length", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) structValue(v reflect.Value) error {
|
||||||
|
n, err := d.structLen()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := v.Type()
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
name, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f := structs.Field(typ, name)
|
||||||
|
if f != nil {
|
||||||
|
if err := f.DecodeValue(d, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := d.DecodeInterface()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeUint() (uint, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode {
|
||||||
|
return uint(c), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case uint8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint(c), nil
|
||||||
|
case uint16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return (uint(b[0]) << 8) | uint(b[1]), nil
|
||||||
|
case uint32Code:
|
||||||
|
b, err := d.R.ReadN(4)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := (uint(b[0]) << 24) |
|
||||||
|
(uint(b[1]) << 16) |
|
||||||
|
(uint(b[2]) << 8) |
|
||||||
|
uint(b[3])
|
||||||
|
return v, nil
|
||||||
|
case uint64Code:
|
||||||
|
b, err := d.R.ReadN(8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := (uint(b[0]) << 56) |
|
||||||
|
(uint(b[1]) << 48) |
|
||||||
|
(uint(b[2]) << 40) |
|
||||||
|
(uint(b[3]) << 32) |
|
||||||
|
(uint(b[4]) << 24) |
|
||||||
|
(uint(b[5]) << 16) |
|
||||||
|
(uint(b[6]) << 8) |
|
||||||
|
uint(b[7])
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding uint", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeUint8() (uint8, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode {
|
||||||
|
return uint8(c), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case uint8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint8(c), nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding uint8", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeUint16() (uint16, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode {
|
||||||
|
return uint16(c), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case uint8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint16(c), nil
|
||||||
|
case uint16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return (uint16(b[0]) << 8) | uint16(b[1]), nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding uint16", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeUint32() (uint32, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode {
|
||||||
|
return uint32(c), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case uint8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint32(c), nil
|
||||||
|
case uint16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return (uint32(b[0]) << 8) | uint32(b[1]), nil
|
||||||
|
case uint32Code:
|
||||||
|
b, err := d.R.ReadN(4)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := (uint32(b[0]) << 24) |
|
||||||
|
(uint32(b[1]) << 16) |
|
||||||
|
(uint32(b[2]) << 8) |
|
||||||
|
uint32(b[3])
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding uint32", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeInt() (int, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode || c >= negFixNumLowCode {
|
||||||
|
return int(int8(c)), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case int8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(int8(c)), nil
|
||||||
|
case int16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int((int16(b[0]) << 8) | int16(b[1])), nil
|
||||||
|
case int32Code:
|
||||||
|
b, err := d.R.ReadN(4)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := int((int32(b[0]) << 24) |
|
||||||
|
(int32(b[1]) << 16) |
|
||||||
|
(int32(b[2]) << 8) |
|
||||||
|
int32(b[3]))
|
||||||
|
return v, nil
|
||||||
|
case int64Code:
|
||||||
|
b, err := d.R.ReadN(8)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := int((int64(b[0]) << 56) |
|
||||||
|
(int64(b[1]) << 48) |
|
||||||
|
(int64(b[2]) << 40) |
|
||||||
|
(int64(b[3]) << 32) |
|
||||||
|
(int64(b[4]) << 24) |
|
||||||
|
(int64(b[5]) << 16) |
|
||||||
|
(int64(b[6]) << 8) |
|
||||||
|
int64(b[7]))
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding int64", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeInt8() (int8, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode || c >= negFixNumLowCode {
|
||||||
|
return int8(c), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case int8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int8(c), nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding int8", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeInt16() (int16, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode || c >= negFixNumLowCode {
|
||||||
|
return int16(int8(c)), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case int8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int16(int8(c)), nil
|
||||||
|
case int16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return (int16(b[0]) << 8) | int16(b[1]), nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding int16", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeInt32() (int32, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c <= posFixNumHighCode || c >= negFixNumLowCode {
|
||||||
|
return int32(int8(c)), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case int8Code:
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int32(int8(c)), nil
|
||||||
|
case int16Code:
|
||||||
|
b, err := d.R.ReadN(2)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int32((int16(b[0]) << 8) | int16(b[1])), nil
|
||||||
|
case int32Code:
|
||||||
|
b, err := d.R.ReadN(4)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
v := (int32(b[0]) << 24) |
|
||||||
|
(int32(b[1]) << 16) |
|
||||||
|
(int32(b[2]) << 8) |
|
||||||
|
int32(b[3])
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding int32", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (d *Decoder) interfaceValue(v reflect.Value) error {
|
||||||
|
iface, err := d.DecodeInterface()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(iface))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decodes value into interface. Possible value types are:
|
||||||
|
// - nil,
|
||||||
|
// - int64,
|
||||||
|
// - uint64,
|
||||||
|
// - bool,
|
||||||
|
// - float32 and float64,
|
||||||
|
// - string,
|
||||||
|
// - slices of any of the above,
|
||||||
|
// - maps of any of the above.
|
||||||
|
func (d *Decoder) DecodeInterface() (interface{}, error) {
|
||||||
|
b, err := d.R.Peek(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := b[0]
|
||||||
|
|
||||||
|
if c <= posFixNumHighCode || c >= negFixNumLowCode {
|
||||||
|
return d.DecodeInt64()
|
||||||
|
} else if c >= fixMapLowCode && c <= fixMapHighCode {
|
||||||
|
return d.DecodeMap()
|
||||||
|
} else if c >= fixArrayLowCode && c <= fixArrayHighCode {
|
||||||
|
return d.DecodeSlice()
|
||||||
|
} else if c >= fixRawLowCode && c <= fixRawHighCode {
|
||||||
|
return d.DecodeString()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case nilCode:
|
||||||
|
_, err := d.R.ReadByte()
|
||||||
|
return nil, err
|
||||||
|
case falseCode, trueCode:
|
||||||
|
return d.DecodeBool()
|
||||||
|
case floatCode:
|
||||||
|
return d.DecodeFloat32()
|
||||||
|
case doubleCode:
|
||||||
|
return d.DecodeFloat64()
|
||||||
|
case uint8Code, uint16Code, uint32Code, uint64Code:
|
||||||
|
return d.DecodeUint64()
|
||||||
|
case int8Code, int16Code, int32Code, int64Code:
|
||||||
|
return d.DecodeInt64()
|
||||||
|
case raw16Code, raw32Code:
|
||||||
|
return d.DecodeString()
|
||||||
|
case array16Code, array32Code:
|
||||||
|
return d.DecodeSlice()
|
||||||
|
case map16Code, map32Code:
|
||||||
|
return d.DecodeMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding interface{}", c)
|
||||||
|
}
|
|
@ -0,0 +1,343 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type writer interface {
|
||||||
|
io.Writer
|
||||||
|
WriteByte(byte) error
|
||||||
|
WriteString(string) (int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type writeByte struct {
|
||||||
|
io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeByte) WriteByte(b byte) error {
|
||||||
|
n, err := w.Write([]byte{b})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n != 1 {
|
||||||
|
return io.ErrShortWrite
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeByte) WriteString(s string) (int, error) {
|
||||||
|
return w.Write([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Marshal(v ...interface{}) ([]byte, error) {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := NewEncoder(buf).Encode(v...)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Encoder struct {
|
||||||
|
W writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
|
ww, ok := w.(writer)
|
||||||
|
if !ok {
|
||||||
|
ww = &writeByte{Writer: w}
|
||||||
|
}
|
||||||
|
return &Encoder{
|
||||||
|
W: ww,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) Encode(v ...interface{}) error {
|
||||||
|
for _, vv := range v {
|
||||||
|
if err := e.encode(vv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encode(iv interface{}) error {
|
||||||
|
if iv == nil {
|
||||||
|
return e.EncodeNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := iv.(type) {
|
||||||
|
case string:
|
||||||
|
return e.EncodeString(v)
|
||||||
|
case []byte:
|
||||||
|
return e.EncodeBytes(v)
|
||||||
|
case int:
|
||||||
|
return e.EncodeInt64(int64(v))
|
||||||
|
case int64:
|
||||||
|
return e.EncodeInt64(v)
|
||||||
|
case uint:
|
||||||
|
return e.EncodeUint64(uint64(v))
|
||||||
|
case uint64:
|
||||||
|
return e.EncodeUint64(v)
|
||||||
|
case bool:
|
||||||
|
return e.EncodeBool(v)
|
||||||
|
case float32:
|
||||||
|
return e.EncodeFloat32(v)
|
||||||
|
case float64:
|
||||||
|
return e.EncodeFloat64(v)
|
||||||
|
case []string:
|
||||||
|
return e.encodeStringSlice(v)
|
||||||
|
case map[string]string:
|
||||||
|
return e.encodeMapStringString(v)
|
||||||
|
case time.Duration:
|
||||||
|
return e.EncodeInt64(int64(v))
|
||||||
|
case time.Time:
|
||||||
|
return e.EncodeTime(v)
|
||||||
|
case encoder:
|
||||||
|
return v.EncodeMsgpack(e.W)
|
||||||
|
}
|
||||||
|
return e.EncodeValue(reflect.ValueOf(iv))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeValue(v reflect.Value) error {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return e.EncodeString(v.String())
|
||||||
|
case reflect.Bool:
|
||||||
|
return e.EncodeBool(v.Bool())
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
|
return e.EncodeUint64(v.Uint())
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||||
|
return e.EncodeInt64(v.Int())
|
||||||
|
case reflect.Float32:
|
||||||
|
return e.EncodeFloat32(float32(v.Float()))
|
||||||
|
case reflect.Float64:
|
||||||
|
return e.EncodeFloat64(v.Float())
|
||||||
|
case reflect.Array:
|
||||||
|
return e.encodeSlice(v)
|
||||||
|
case reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
return e.EncodeNil()
|
||||||
|
}
|
||||||
|
return e.encodeSlice(v)
|
||||||
|
case reflect.Map:
|
||||||
|
return e.encodeMap(v)
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
if v.IsNil() {
|
||||||
|
return e.EncodeNil()
|
||||||
|
}
|
||||||
|
if enc, ok := typEncMap[v.Type()]; ok {
|
||||||
|
return enc(e, v)
|
||||||
|
}
|
||||||
|
if enc, ok := v.Interface().(encoder); ok {
|
||||||
|
return enc.EncodeMsgpack(e.W)
|
||||||
|
}
|
||||||
|
return e.EncodeValue(v.Elem())
|
||||||
|
case reflect.Struct:
|
||||||
|
typ := v.Type()
|
||||||
|
if enc, ok := typEncMap[typ]; ok {
|
||||||
|
return enc(e, v)
|
||||||
|
}
|
||||||
|
if enc, ok := v.Interface().(encoder); ok {
|
||||||
|
return enc.EncodeMsgpack(e.W)
|
||||||
|
}
|
||||||
|
return e.encodeStruct(v)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("msgpack: unsupported type %v", v.Type().String())
|
||||||
|
}
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeNil() error {
|
||||||
|
return e.W.WriteByte(nilCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeUint(v uint) error {
|
||||||
|
return e.EncodeUint64(uint64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeUint8(v uint8) error {
|
||||||
|
return e.EncodeUint64(uint64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeUint16(v uint16) error {
|
||||||
|
return e.EncodeUint64(uint64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeUint32(v uint32) error {
|
||||||
|
return e.EncodeUint64(uint64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeUint64(v uint64) error {
|
||||||
|
switch {
|
||||||
|
case v < 128:
|
||||||
|
return e.W.WriteByte(byte(v))
|
||||||
|
case v < 256:
|
||||||
|
return e.write([]byte{uint8Code, byte(v)})
|
||||||
|
case v < 65536:
|
||||||
|
return e.write([]byte{uint16Code, byte(v >> 8), byte(v)})
|
||||||
|
case v < 4294967296:
|
||||||
|
return e.write([]byte{
|
||||||
|
uint32Code,
|
||||||
|
byte(v >> 24),
|
||||||
|
byte(v >> 16),
|
||||||
|
byte(v >> 8),
|
||||||
|
byte(v),
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return e.write([]byte{
|
||||||
|
uint64Code,
|
||||||
|
byte(v >> 56),
|
||||||
|
byte(v >> 48),
|
||||||
|
byte(v >> 40),
|
||||||
|
byte(v >> 32),
|
||||||
|
byte(v >> 24),
|
||||||
|
byte(v >> 16),
|
||||||
|
byte(v >> 8),
|
||||||
|
byte(v),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeInt(v int) error {
|
||||||
|
return e.EncodeInt64(int64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeInt8(v int8) error {
|
||||||
|
return e.EncodeInt64(int64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeInt16(v int16) error {
|
||||||
|
return e.EncodeInt64(int64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeInt32(v int32) error {
|
||||||
|
return e.EncodeInt64(int64(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeInt64(v int64) error {
|
||||||
|
switch {
|
||||||
|
case v < -2147483648 || v >= 2147483648:
|
||||||
|
return e.write([]byte{
|
||||||
|
int64Code,
|
||||||
|
byte(v >> 56),
|
||||||
|
byte(v >> 48),
|
||||||
|
byte(v >> 40),
|
||||||
|
byte(v >> 32),
|
||||||
|
byte(v >> 24),
|
||||||
|
byte(v >> 16),
|
||||||
|
byte(v >> 8),
|
||||||
|
byte(v),
|
||||||
|
})
|
||||||
|
case v < -32768 || v >= 32768:
|
||||||
|
return e.write([]byte{
|
||||||
|
int32Code,
|
||||||
|
byte(v >> 24),
|
||||||
|
byte(v >> 16),
|
||||||
|
byte(v >> 8),
|
||||||
|
byte(v),
|
||||||
|
})
|
||||||
|
case v < -128 || v >= 128:
|
||||||
|
return e.write([]byte{int16Code, byte(v >> 8), byte(v)})
|
||||||
|
case v < -32:
|
||||||
|
return e.write([]byte{int8Code, byte(v)})
|
||||||
|
default:
|
||||||
|
return e.W.WriteByte(byte(v))
|
||||||
|
}
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeBool(value bool) error {
|
||||||
|
if value {
|
||||||
|
return e.W.WriteByte(trueCode)
|
||||||
|
}
|
||||||
|
return e.W.WriteByte(falseCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeFloat32(value float32) error {
|
||||||
|
v := math.Float32bits(value)
|
||||||
|
return e.write([]byte{
|
||||||
|
floatCode,
|
||||||
|
byte(v >> 24),
|
||||||
|
byte(v >> 16),
|
||||||
|
byte(v >> 8),
|
||||||
|
byte(v),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeFloat64(value float64) error {
|
||||||
|
v := math.Float64bits(value)
|
||||||
|
return e.write([]byte{
|
||||||
|
doubleCode,
|
||||||
|
byte(v >> 56),
|
||||||
|
byte(v >> 48),
|
||||||
|
byte(v >> 40),
|
||||||
|
byte(v >> 32),
|
||||||
|
byte(v >> 24),
|
||||||
|
byte(v >> 16),
|
||||||
|
byte(v >> 8),
|
||||||
|
byte(v),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeStruct(v reflect.Value) error {
|
||||||
|
fields := structs.Fields(v.Type())
|
||||||
|
switch l := len(fields); {
|
||||||
|
case l < 16:
|
||||||
|
if err := e.W.WriteByte(fixMapLowCode | byte(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case l < 65536:
|
||||||
|
if err := e.write([]byte{
|
||||||
|
map16Code,
|
||||||
|
byte(l >> 8),
|
||||||
|
byte(l),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if err := e.write([]byte{
|
||||||
|
map32Code,
|
||||||
|
byte(l >> 24),
|
||||||
|
byte(l >> 16),
|
||||||
|
byte(l >> 8),
|
||||||
|
byte(l),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, f := range fields {
|
||||||
|
if err := e.EncodeString(f.Name()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := f.EncodeValue(e, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) write(data []byte) error {
|
||||||
|
n, err := e.W.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n < len(data) {
|
||||||
|
return io.ErrShortWrite
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) writeString(s string) error {
|
||||||
|
n, err := e.W.WriteString(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n < len(s) {
|
||||||
|
return io.ErrShortWrite
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package msgpack_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.bit5.ru/backend/msgpack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleMarshal() {
|
||||||
|
b, err := msgpack.Marshal(true)
|
||||||
|
fmt.Printf("%v %#v\n", err, b)
|
||||||
|
// Output: <nil> []byte{0xc3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleUnmarshal() {
|
||||||
|
var out bool
|
||||||
|
err := msgpack.Unmarshal([]byte{0xc3}, &out)
|
||||||
|
fmt.Println(err, out)
|
||||||
|
// Output: <nil> true
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_mapStringInterface() {
|
||||||
|
in := map[string]interface{}{"foo": 1, "hello": "world"}
|
||||||
|
b, err := msgpack.Marshal(in)
|
||||||
|
_ = err
|
||||||
|
|
||||||
|
var out map[string]interface{}
|
||||||
|
err = msgpack.Unmarshal(b, &out)
|
||||||
|
fmt.Printf("%v %#v\n", err, out)
|
||||||
|
// Output: <nil> map[string]interface {}{"foo":1, "hello":"world"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_recursiveMapStringInterface() {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
enc := msgpack.NewEncoder(buf)
|
||||||
|
in := map[string]interface{}{"foo": map[string]interface{}{"hello": "world"}}
|
||||||
|
_ = enc.Encode(in)
|
||||||
|
|
||||||
|
dec := msgpack.NewDecoder(buf)
|
||||||
|
dec.DecodeMapFunc = func(d *msgpack.Decoder) (interface{}, error) {
|
||||||
|
n, err := d.DecodeMapLen()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]interface{}, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
mk, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mv, err := d.DecodeInterface()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m[mk] = mv
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
out, err := dec.DecodeInterface()
|
||||||
|
fmt.Printf("%v %#v\n", err, out)
|
||||||
|
// Output: <nil> map[string]interface {}{"foo":map[string]interface {}{"hello":"world"}}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
module git.bit5.ru/backend/msgpack
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/ugorji/go/codec v1.2.7
|
||||||
|
github.com/vmihailenco/bufio v0.0.0-20140618134113-fe7b595919de
|
||||||
|
gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect
|
||||||
|
launchpad.net/gocheck v0.0.0-20140225173054-000000000087
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||||
|
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||||
|
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||||
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
|
github.com/vmihailenco/bufio v0.0.0-20140618134113-fe7b595919de h1:U+I4zEVstMdfNES/2UO8iqkIf214SDMRhdaFTE3A5rA=
|
||||||
|
github.com/vmihailenco/bufio v0.0.0-20140618134113-fe7b595919de/go.mod h1:ghSGoeEoFFkXNguSget72dMA0+OLq3AGZiqRohVojxI=
|
||||||
|
gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e h1:wGA78yza6bu/mWcc4QfBuIEHEtc06xdiU0X8sY36yUU=
|
||||||
|
gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e/go.mod h1:xsQCaysVCudhrYTfzYWe577fCe7Ceci+6qjO2Rdc0Z4=
|
||||||
|
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
|
||||||
|
launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
|
|
@ -0,0 +1,175 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Encoder) encodeMapLen(l int) error {
|
||||||
|
switch {
|
||||||
|
case l < 16:
|
||||||
|
if err := e.W.WriteByte(fixMapLowCode | byte(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case l < 65536:
|
||||||
|
if err := e.write([]byte{
|
||||||
|
map16Code,
|
||||||
|
byte(l >> 8),
|
||||||
|
byte(l),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if err := e.write([]byte{
|
||||||
|
map32Code,
|
||||||
|
byte(l >> 24),
|
||||||
|
byte(l >> 16),
|
||||||
|
byte(l >> 8),
|
||||||
|
byte(l),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeMapStringString(m map[string]string) error {
|
||||||
|
if err := e.encodeMapLen(len(m)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for mk, mv := range m {
|
||||||
|
if err := e.EncodeString(mk); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := e.EncodeString(mv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeMap(value reflect.Value) error {
|
||||||
|
if err := e.encodeMapLen(value.Len()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
keys := value.MapKeys()
|
||||||
|
for _, k := range keys {
|
||||||
|
if err := e.EncodeValue(k); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := e.EncodeValue(value.MapIndex(k)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeMap(d *Decoder) (interface{}, error) {
|
||||||
|
n, err := d.DecodeMapLen()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[interface{}]interface{}, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
mk, err := d.DecodeInterface()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mv, err := d.DecodeInterface()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m[mk] = mv
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeMapLen() (int, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c == nilCode {
|
||||||
|
return -1, nil
|
||||||
|
} else if c >= fixMapLowCode && c <= fixMapHighCode {
|
||||||
|
return int(c & fixMapMask), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case map16Code:
|
||||||
|
n, err := d.uint16()
|
||||||
|
return int(n), err
|
||||||
|
case map32Code:
|
||||||
|
n, err := d.uint32()
|
||||||
|
return int(n), err
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding map length", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) decodeIntoMapStringString(mp *map[string]string) error {
|
||||||
|
n, err := d.DecodeMapLen()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(vmihailenco): simpler way?
|
||||||
|
m := *mp
|
||||||
|
if m == nil {
|
||||||
|
*mp = make(map[string]string, n)
|
||||||
|
m = *mp
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
mk, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mv, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m[mk] = mv
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeMap() (interface{}, error) {
|
||||||
|
return d.DecodeMapFunc(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) mapValue(v reflect.Value) error {
|
||||||
|
n, err := d.DecodeMapLen()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := v.Type()
|
||||||
|
if v.IsNil() {
|
||||||
|
v.Set(reflect.MakeMap(typ))
|
||||||
|
}
|
||||||
|
keyType := typ.Key()
|
||||||
|
valueType := typ.Elem()
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
mk := reflect.New(keyType).Elem()
|
||||||
|
if err := d.DecodeValue(mk); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mv := reflect.New(valueType).Elem()
|
||||||
|
if err := d.DecodeValue(mv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.SetMapIndex(mk, mv)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type encoder interface {
|
||||||
|
EncodeMsgpack(io.Writer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type decoder interface {
|
||||||
|
DecodeMsgpack(io.Reader) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Coder interface {
|
||||||
|
encoder
|
||||||
|
decoder
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,285 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/vmihailenco/bufio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Encoder) encodeBytesLen(l int) error {
|
||||||
|
switch {
|
||||||
|
case l < 32:
|
||||||
|
if err := e.W.WriteByte(fixRawLowCode | uint8(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case l < 65536:
|
||||||
|
if err := e.write([]byte{
|
||||||
|
raw16Code,
|
||||||
|
byte(l >> 8),
|
||||||
|
byte(l),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if err := e.write([]byte{
|
||||||
|
raw32Code,
|
||||||
|
byte(l >> 24),
|
||||||
|
byte(l >> 16),
|
||||||
|
byte(l >> 8),
|
||||||
|
byte(l),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeString(v string) error {
|
||||||
|
if err := e.encodeBytesLen(len(v)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.writeString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeBytes(v []byte) error {
|
||||||
|
if v == nil {
|
||||||
|
return e.EncodeNil()
|
||||||
|
}
|
||||||
|
if err := e.encodeBytesLen(len(v)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.write(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeSliceLen(l int) error {
|
||||||
|
switch {
|
||||||
|
case l < 16:
|
||||||
|
if err := e.W.WriteByte(fixArrayLowCode | byte(l)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case l < 65536:
|
||||||
|
if err := e.write([]byte{array16Code, byte(l >> 8), byte(l)}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if err := e.write([]byte{
|
||||||
|
array32Code,
|
||||||
|
byte(l >> 24),
|
||||||
|
byte(l >> 16),
|
||||||
|
byte(l >> 8),
|
||||||
|
byte(l),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeStringSlice(s []string) error {
|
||||||
|
if s == nil {
|
||||||
|
return e.EncodeNil()
|
||||||
|
}
|
||||||
|
if err := e.encodeSliceLen(len(s)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, v := range s {
|
||||||
|
if err := e.EncodeString(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) encodeSlice(v reflect.Value) error {
|
||||||
|
switch v.Type().Elem().Kind() {
|
||||||
|
case reflect.Uint8:
|
||||||
|
return e.EncodeBytes(v.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
l := v.Len()
|
||||||
|
if err := e.encodeSliceLen(l); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
if err := e.EncodeValue(v.Index(i)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeBytesLen() (int, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c == nilCode {
|
||||||
|
return -1, nil
|
||||||
|
} else if c >= fixRawLowCode && c <= fixRawHighCode {
|
||||||
|
return int(c & fixRawMask), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case raw16Code:
|
||||||
|
n, err := d.uint16()
|
||||||
|
return int(n), err
|
||||||
|
case raw32Code:
|
||||||
|
n, err := d.uint32()
|
||||||
|
return int(n), err
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding bytes length", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeBytes() ([]byte, error) {
|
||||||
|
n, err := d.DecodeBytesLen()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n == -1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
b := make([]byte, n)
|
||||||
|
_, err = io.ReadFull(d.R, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) bytesValue(value reflect.Value) error {
|
||||||
|
v, err := d.DecodeBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.SetBytes(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeString() (string, error) {
|
||||||
|
n, err := d.DecodeBytesLen()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if n == -1 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
b, err := d.R.ReadN(n)
|
||||||
|
if err == bufio.ErrBufferFull {
|
||||||
|
newB := make([]byte, n)
|
||||||
|
n := copy(newB, b)
|
||||||
|
b = newB
|
||||||
|
|
||||||
|
_, err := io.ReadFull(d.R, newB[n:])
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) stringValue(value reflect.Value) error {
|
||||||
|
v, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.SetString(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeSliceLen() (int, error) {
|
||||||
|
c, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c == nilCode {
|
||||||
|
return -1, nil
|
||||||
|
} else if c >= fixArrayLowCode && c <= fixArrayHighCode {
|
||||||
|
return int(c & fixArrayMask), nil
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case array16Code:
|
||||||
|
n, err := d.uint16()
|
||||||
|
return int(n), err
|
||||||
|
case array32Code:
|
||||||
|
n, err := d.uint32()
|
||||||
|
return int(n), err
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("msgpack: invalid code %x decoding array length", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) decodeIntoStrings(sp *[]string) error {
|
||||||
|
n, err := d.DecodeSliceLen()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s := *sp
|
||||||
|
if s == nil || len(s) < n {
|
||||||
|
s = make([]string, n)
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
v, err := d.DecodeString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s[i] = v
|
||||||
|
}
|
||||||
|
*sp = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeSlice() ([]interface{}, error) {
|
||||||
|
n, err := d.DecodeSliceLen()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n == -1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
s := make([]interface{}, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
v, err := d.DecodeInterface()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s[i] = v
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) sliceValue(v reflect.Value) error {
|
||||||
|
elemType := v.Type().Elem()
|
||||||
|
switch elemType.Kind() {
|
||||||
|
case reflect.Uint8:
|
||||||
|
b, err := d.DecodeBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.SetBytes(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := d.DecodeSliceLen()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Len() < n || (v.Kind() == reflect.Slice && v.IsNil()) {
|
||||||
|
v.Set(reflect.MakeSlice(v.Type(), n, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
sv := v.Index(i)
|
||||||
|
if err := d.DecodeValue(sv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package msgpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(timeType, encodeTime, decodeTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Encoder) EncodeTime(tm time.Time) error {
|
||||||
|
if err := e.W.WriteByte(0x92); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := e.EncodeInt64(tm.Unix()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.EncodeInt(tm.Nanosecond())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) DecodeTime() (time.Time, error) {
|
||||||
|
b, err := d.R.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
if b != 0x92 {
|
||||||
|
return time.Time{}, fmt.Errorf("msgpack: invalid code %x decoding time", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
sec, err := d.DecodeInt64()
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
nsec, err := d.DecodeInt64()
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
return time.Unix(sec, nsec), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeTime(e *Encoder, v reflect.Value) error {
|
||||||
|
tm := v.Interface().(time.Time)
|
||||||
|
return e.EncodeTime(tm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeTime(d *Decoder, v reflect.Value) error {
|
||||||
|
tm, err := d.DecodeTime()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set(reflect.ValueOf(tm))
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,277 @@
|
||||||
|
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
|
||||||
|
}
|
Loading…
Reference in New Issue