govendor fetch github.com/zclconf/go-cty/cty/...
The existing cty packages were already at the latest version, but we were not yet vendoring the msgpack package. This also imports some dependencies from: github.com/vmihailenco/msgpack
This commit is contained in:
parent
da17afaa85
commit
b1247bf7af
|
@ -0,0 +1,18 @@
|
|||
## v3.3
|
||||
|
||||
- `msgpack:",inline"` tag is restored to force inlining structs.
|
||||
|
||||
## v3.2
|
||||
|
||||
- Decoding extension types returns pointer to the value instead of the value. Fixes #153
|
||||
|
||||
## v3
|
||||
|
||||
- gopkg.in is not supported any more. Update import path to github.com/vmihailenco/msgpack.
|
||||
- Msgpack maps are decoded into map[string]interface{} by default.
|
||||
- EncodeSliceLen is removed in favor of EncodeArrayLen. DecodeSliceLen is removed in favor of DecodeArrayLen.
|
||||
- Embedded structs are automatically inlined where possible.
|
||||
- Time is encoded using extension as described in https://github.com/msgpack/msgpack/pull/209. Old format is supported as well.
|
||||
- EncodeInt8/16/32/64 is replaced with EncodeInt. EncodeUint8/16/32/64 is replaced with EncodeUint. There should be no performance differences.
|
||||
- DecodeInterface can now return int8/16/32 and uint8/16/32.
|
||||
- PeekCode returns codes.Code instead of byte.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2013 The github.com/vmihailenco/msgpack 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.
|
||||
|
||||
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,5 @@
|
|||
all:
|
||||
go test ./...
|
||||
env GOOS=linux GOARCH=386 go test ./...
|
||||
go test ./... -short -race
|
||||
go vet
|
|
@ -0,0 +1,69 @@
|
|||
# MessagePack encoding for Golang
|
||||
|
||||
[![Build Status](https://travis-ci.org/vmihailenco/msgpack.svg?branch=v2)](https://travis-ci.org/vmihailenco/msgpack)
|
||||
[![GoDoc](https://godoc.org/github.com/vmihailenco/msgpack?status.svg)](https://godoc.org/github.com/vmihailenco/msgpack)
|
||||
|
||||
Supports:
|
||||
- Primitives, arrays, maps, structs, time.Time and interface{}.
|
||||
- Appengine *datastore.Key and datastore.Cursor.
|
||||
- [CustomEncoder](https://godoc.org/github.com/vmihailenco/msgpack#example-CustomEncoder)/CustomDecoder interfaces for custom encoding.
|
||||
- [Extensions](https://godoc.org/github.com/vmihailenco/msgpack#example-RegisterExt) to encode type information.
|
||||
- Renaming fields via `msgpack:"my_field_name"`.
|
||||
- Omitting individual empty fields via `msgpack:",omitempty"` tag or all [empty fields in a struct](https://godoc.org/github.com/vmihailenco/msgpack#example-Marshal--OmitEmpty).
|
||||
- [Map keys sorting](https://godoc.org/github.com/vmihailenco/msgpack#Encoder.SortMapKeys).
|
||||
- Encoding/decoding all [structs as arrays](https://godoc.org/github.com/vmihailenco/msgpack#Encoder.StructAsArray) or [individual structs](https://godoc.org/github.com/vmihailenco/msgpack#example-Marshal--AsArray).
|
||||
- [Encoder.UseJSONTag](https://godoc.org/github.com/vmihailenco/msgpack#Encoder.UseJSONTag) with [Decoder.UseJSONTag](https://godoc.org/github.com/vmihailenco/msgpack#Decoder.UseJSONTag) can turn msgpack into drop-in replacement for JSON.
|
||||
- Simple but very fast and efficient [queries](https://godoc.org/github.com/vmihailenco/msgpack#example-Decoder-Query).
|
||||
|
||||
API docs: https://godoc.org/github.com/vmihailenco/msgpack.
|
||||
Examples: https://godoc.org/github.com/vmihailenco/msgpack#pkg-examples.
|
||||
|
||||
## Installation
|
||||
|
||||
Install:
|
||||
|
||||
```shell
|
||||
go get -u github.com/vmihailenco/msgpack
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
```go
|
||||
func ExampleMarshal() {
|
||||
type Item struct {
|
||||
Foo string
|
||||
}
|
||||
|
||||
b, err := msgpack.Marshal(&Item{Foo: "bar"})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var item Item
|
||||
err = msgpack.Unmarshal(b, &item)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(item.Foo)
|
||||
// Output: bar
|
||||
}
|
||||
```
|
||||
|
||||
## Benchmark
|
||||
|
||||
```
|
||||
BenchmarkStructVmihailencoMsgpack-4 200000 12814 ns/op 2128 B/op 26 allocs/op
|
||||
BenchmarkStructUgorjiGoMsgpack-4 100000 17678 ns/op 3616 B/op 70 allocs/op
|
||||
BenchmarkStructUgorjiGoCodec-4 100000 19053 ns/op 7346 B/op 23 allocs/op
|
||||
BenchmarkStructJSON-4 20000 69438 ns/op 7864 B/op 26 allocs/op
|
||||
BenchmarkStructGOB-4 10000 104331 ns/op 14664 B/op 278 allocs/op
|
||||
```
|
||||
|
||||
## Howto
|
||||
|
||||
Please go through [examples](https://godoc.org/github.com/vmihailenco/msgpack#pkg-examples) to get an idea how to use this package.
|
||||
|
||||
## See also
|
||||
|
||||
- [Golang PostgreSQL ORM](https://github.com/go-pg/pg)
|
||||
- [Golang message task queue](https://github.com/go-msgqueue/msgqueue)
|
|
@ -0,0 +1,86 @@
|
|||
package codes
|
||||
|
||||
type Code byte
|
||||
|
||||
var (
|
||||
PosFixedNumHigh Code = 0x7f
|
||||
NegFixedNumLow Code = 0xe0
|
||||
|
||||
Nil Code = 0xc0
|
||||
|
||||
False Code = 0xc2
|
||||
True Code = 0xc3
|
||||
|
||||
Float Code = 0xca
|
||||
Double Code = 0xcb
|
||||
|
||||
Uint8 Code = 0xcc
|
||||
Uint16 Code = 0xcd
|
||||
Uint32 Code = 0xce
|
||||
Uint64 Code = 0xcf
|
||||
|
||||
Int8 Code = 0xd0
|
||||
Int16 Code = 0xd1
|
||||
Int32 Code = 0xd2
|
||||
Int64 Code = 0xd3
|
||||
|
||||
FixedStrLow Code = 0xa0
|
||||
FixedStrHigh Code = 0xbf
|
||||
FixedStrMask Code = 0x1f
|
||||
Str8 Code = 0xd9
|
||||
Str16 Code = 0xda
|
||||
Str32 Code = 0xdb
|
||||
|
||||
Bin8 Code = 0xc4
|
||||
Bin16 Code = 0xc5
|
||||
Bin32 Code = 0xc6
|
||||
|
||||
FixedArrayLow Code = 0x90
|
||||
FixedArrayHigh Code = 0x9f
|
||||
FixedArrayMask Code = 0xf
|
||||
Array16 Code = 0xdc
|
||||
Array32 Code = 0xdd
|
||||
|
||||
FixedMapLow Code = 0x80
|
||||
FixedMapHigh Code = 0x8f
|
||||
FixedMapMask Code = 0xf
|
||||
Map16 Code = 0xde
|
||||
Map32 Code = 0xdf
|
||||
|
||||
FixExt1 Code = 0xd4
|
||||
FixExt2 Code = 0xd5
|
||||
FixExt4 Code = 0xd6
|
||||
FixExt8 Code = 0xd7
|
||||
FixExt16 Code = 0xd8
|
||||
Ext8 Code = 0xc7
|
||||
Ext16 Code = 0xc8
|
||||
Ext32 Code = 0xc9
|
||||
)
|
||||
|
||||
func IsFixedNum(c Code) bool {
|
||||
return c <= PosFixedNumHigh || c >= NegFixedNumLow
|
||||
}
|
||||
|
||||
func IsFixedMap(c Code) bool {
|
||||
return c >= FixedMapLow && c <= FixedMapHigh
|
||||
}
|
||||
|
||||
func IsFixedArray(c Code) bool {
|
||||
return c >= FixedArrayLow && c <= FixedArrayHigh
|
||||
}
|
||||
|
||||
func IsFixedString(c Code) bool {
|
||||
return c >= FixedStrLow && c <= FixedStrHigh
|
||||
}
|
||||
|
||||
func IsString(c Code) bool {
|
||||
return IsFixedString(c) || c == Str8 || c == Str16 || c == Str32
|
||||
}
|
||||
|
||||
func IsFixedExt(c Code) bool {
|
||||
return c >= FixExt1 && c <= FixExt16
|
||||
}
|
||||
|
||||
func IsExt(c Code) bool {
|
||||
return IsFixedExt(c) || c == Ext8 || c == Ext16 || c == Ext32
|
||||
}
|
|
@ -0,0 +1,536 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
const bytesAllocLimit = 1024 * 1024 // 1mb
|
||||
|
||||
type bufReader interface {
|
||||
io.Reader
|
||||
io.ByteScanner
|
||||
}
|
||||
|
||||
func newBufReader(r io.Reader) bufReader {
|
||||
if br, ok := r.(bufReader); ok {
|
||||
return br
|
||||
}
|
||||
return bufio.NewReader(r)
|
||||
}
|
||||
|
||||
func makeBuffer() []byte {
|
||||
return make([]byte, 0, 64)
|
||||
}
|
||||
|
||||
// Unmarshal decodes the MessagePack-encoded data and stores the result
|
||||
// in the value pointed to by v.
|
||||
func Unmarshal(data []byte, v ...interface{}) error {
|
||||
return NewDecoder(bytes.NewReader(data)).Decode(v...)
|
||||
}
|
||||
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
s io.ByteScanner
|
||||
buf []byte
|
||||
|
||||
extLen int
|
||||
rec []byte // accumulates read data if not nil
|
||||
|
||||
useLoose bool
|
||||
useJSONTag bool
|
||||
|
||||
decodeMapFunc func(*Decoder) (interface{}, error)
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder that reads from r.
|
||||
//
|
||||
// The decoder introduces its own buffering and may read data from r
|
||||
// beyond the MessagePack values requested. Buffering can be disabled
|
||||
// by passing a reader that implements io.ByteScanner interface.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
d := &Decoder{
|
||||
decodeMapFunc: decodeMap,
|
||||
|
||||
buf: makeBuffer(),
|
||||
}
|
||||
d.resetReader(r)
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Decoder) SetDecodeMapFunc(fn func(*Decoder) (interface{}, error)) {
|
||||
d.decodeMapFunc = fn
|
||||
}
|
||||
|
||||
// UseDecodeInterfaceLoose causes decoder to use DecodeInterfaceLoose
|
||||
// to decode msgpack value into Go interface{}.
|
||||
func (d *Decoder) UseDecodeInterfaceLoose(flag bool) {
|
||||
d.useLoose = flag
|
||||
}
|
||||
|
||||
// UseJSONTag causes the Decoder to use json struct tag as fallback option
|
||||
// if there is no msgpack tag.
|
||||
func (d *Decoder) UseJSONTag(v bool) *Decoder {
|
||||
d.useJSONTag = v
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Decoder) Reset(r io.Reader) error {
|
||||
d.resetReader(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) resetReader(r io.Reader) {
|
||||
reader := newBufReader(r)
|
||||
d.r = reader
|
||||
d.s = reader
|
||||
}
|
||||
|
||||
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(dst interface{}) error {
|
||||
var err error
|
||||
switch v := dst.(type) {
|
||||
case *string:
|
||||
if v != nil {
|
||||
*v, err = d.DecodeString()
|
||||
return err
|
||||
}
|
||||
case *[]byte:
|
||||
if v != nil {
|
||||
return d.decodeBytesPtr(v)
|
||||
}
|
||||
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.decodeStringSlicePtr(v)
|
||||
case *map[string]string:
|
||||
return d.decodeMapStringStringPtr(v)
|
||||
case *map[string]interface{}:
|
||||
return d.decodeMapStringInterfacePtr(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(dst)
|
||||
if !v.IsValid() {
|
||||
return errors.New("msgpack: Decode(nil)")
|
||||
}
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("msgpack: Decode(nonsettable %T)", dst)
|
||||
}
|
||||
v = v.Elem()
|
||||
if !v.IsValid() {
|
||||
return fmt.Errorf("msgpack: Decode(nonsettable %T)", dst)
|
||||
}
|
||||
return d.DecodeValue(v)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeInterface() (interface{}, error) {
|
||||
if d.useLoose {
|
||||
return d.DecodeInterfaceLoose()
|
||||
}
|
||||
return d.DecodeInterface()
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeValue(v reflect.Value) error {
|
||||
decode := getDecoder(v.Type())
|
||||
return decode(d, v)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeNil() error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != codes.Nil {
|
||||
return fmt.Errorf("msgpack: invalid code=%x decoding nil", c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeNilValue(v reflect.Value) error {
|
||||
err := d.DecodeNil()
|
||||
if v.IsNil() {
|
||||
return err
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeBool() (bool, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return d.bool(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) bool(c codes.Code) (bool, error) {
|
||||
if c == codes.False {
|
||||
return false, nil
|
||||
}
|
||||
if c == codes.True {
|
||||
return true, nil
|
||||
}
|
||||
return false, fmt.Errorf("msgpack: invalid code=%x decoding bool", c)
|
||||
}
|
||||
|
||||
// DecodeInterface decodes value into interface. It returns following types:
|
||||
// - nil,
|
||||
// - bool,
|
||||
// - int8, int16, int32, int64,
|
||||
// - uint8, uint16, uint32, uint64,
|
||||
// - float32 and float64,
|
||||
// - string,
|
||||
// - []byte,
|
||||
// - slices of any of the above,
|
||||
// - maps of any of the above.
|
||||
//
|
||||
// DecodeInterface should be used only when you don't know the type of value
|
||||
// you are decoding. For example, if you are decoding number it is better to use
|
||||
// DecodeInt64 for negative numbers and DecodeUint64 for positive numbers.
|
||||
func (d *Decoder) DecodeInterface() (interface{}, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if codes.IsFixedNum(c) {
|
||||
return int8(c), nil
|
||||
}
|
||||
if codes.IsFixedMap(c) {
|
||||
_ = d.s.UnreadByte()
|
||||
return d.DecodeMap()
|
||||
}
|
||||
if codes.IsFixedArray(c) {
|
||||
return d.decodeSlice(c)
|
||||
}
|
||||
if codes.IsFixedString(c) {
|
||||
return d.string(c)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case codes.Nil:
|
||||
return nil, nil
|
||||
case codes.False, codes.True:
|
||||
return d.bool(c)
|
||||
case codes.Float:
|
||||
return d.float32(c)
|
||||
case codes.Double:
|
||||
return d.float64(c)
|
||||
case codes.Uint8:
|
||||
return d.uint8()
|
||||
case codes.Uint16:
|
||||
return d.uint16()
|
||||
case codes.Uint32:
|
||||
return d.uint32()
|
||||
case codes.Uint64:
|
||||
return d.uint64()
|
||||
case codes.Int8:
|
||||
return d.int8()
|
||||
case codes.Int16:
|
||||
return d.int16()
|
||||
case codes.Int32:
|
||||
return d.int32()
|
||||
case codes.Int64:
|
||||
return d.int64()
|
||||
case codes.Bin8, codes.Bin16, codes.Bin32:
|
||||
return d.bytes(c, nil)
|
||||
case codes.Str8, codes.Str16, codes.Str32:
|
||||
return d.string(c)
|
||||
case codes.Array16, codes.Array32:
|
||||
return d.decodeSlice(c)
|
||||
case codes.Map16, codes.Map32:
|
||||
d.s.UnreadByte()
|
||||
return d.DecodeMap()
|
||||
case codes.FixExt1, codes.FixExt2, codes.FixExt4, codes.FixExt8, codes.FixExt16,
|
||||
codes.Ext8, codes.Ext16, codes.Ext32:
|
||||
return d.extInterface(c)
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c)
|
||||
}
|
||||
|
||||
// DecodeInterfaceLoose is like DecodeInterface except that:
|
||||
// - int8, int16, and int32 are converted to int64,
|
||||
// - uint8, uint16, and uint32 are converted to uint64,
|
||||
// - float32 is converted to float64.
|
||||
func (d *Decoder) DecodeInterfaceLoose() (interface{}, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if codes.IsFixedNum(c) {
|
||||
return int64(c), nil
|
||||
}
|
||||
if codes.IsFixedMap(c) {
|
||||
d.s.UnreadByte()
|
||||
return d.DecodeMap()
|
||||
}
|
||||
if codes.IsFixedArray(c) {
|
||||
return d.decodeSlice(c)
|
||||
}
|
||||
if codes.IsFixedString(c) {
|
||||
return d.string(c)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case codes.Nil:
|
||||
return nil, nil
|
||||
case codes.False, codes.True:
|
||||
return d.bool(c)
|
||||
case codes.Float, codes.Double:
|
||||
return d.float64(c)
|
||||
case codes.Uint8, codes.Uint16, codes.Uint32, codes.Uint64:
|
||||
return d.uint(c)
|
||||
case codes.Int8, codes.Int16, codes.Int32, codes.Int64:
|
||||
return d.int(c)
|
||||
case codes.Bin8, codes.Bin16, codes.Bin32:
|
||||
return d.bytes(c, nil)
|
||||
case codes.Str8, codes.Str16, codes.Str32:
|
||||
return d.string(c)
|
||||
case codes.Array16, codes.Array32:
|
||||
return d.decodeSlice(c)
|
||||
case codes.Map16, codes.Map32:
|
||||
d.s.UnreadByte()
|
||||
return d.DecodeMap()
|
||||
case codes.FixExt1, codes.FixExt2, codes.FixExt4, codes.FixExt8, codes.FixExt16,
|
||||
codes.Ext8, codes.Ext16, codes.Ext32:
|
||||
return d.extInterface(c)
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c)
|
||||
}
|
||||
|
||||
// Skip skips next value.
|
||||
func (d *Decoder) Skip() error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if codes.IsFixedNum(c) {
|
||||
return nil
|
||||
} else if codes.IsFixedMap(c) {
|
||||
return d.skipMap(c)
|
||||
} else if codes.IsFixedArray(c) {
|
||||
return d.skipSlice(c)
|
||||
} else if codes.IsFixedString(c) {
|
||||
return d.skipBytes(c)
|
||||
}
|
||||
|
||||
switch c {
|
||||
case codes.Nil, codes.False, codes.True:
|
||||
return nil
|
||||
case codes.Uint8, codes.Int8:
|
||||
return d.skipN(1)
|
||||
case codes.Uint16, codes.Int16:
|
||||
return d.skipN(2)
|
||||
case codes.Uint32, codes.Int32, codes.Float:
|
||||
return d.skipN(4)
|
||||
case codes.Uint64, codes.Int64, codes.Double:
|
||||
return d.skipN(8)
|
||||
case codes.Bin8, codes.Bin16, codes.Bin32:
|
||||
return d.skipBytes(c)
|
||||
case codes.Str8, codes.Str16, codes.Str32:
|
||||
return d.skipBytes(c)
|
||||
case codes.Array16, codes.Array32:
|
||||
return d.skipSlice(c)
|
||||
case codes.Map16, codes.Map32:
|
||||
return d.skipMap(c)
|
||||
case codes.FixExt1, codes.FixExt2, codes.FixExt4, codes.FixExt8, codes.FixExt16,
|
||||
codes.Ext8, codes.Ext16, codes.Ext32:
|
||||
return d.skipExt(c)
|
||||
}
|
||||
|
||||
return fmt.Errorf("msgpack: unknown code %x", c)
|
||||
}
|
||||
|
||||
// PeekCode returns the next MessagePack code without advancing the reader.
|
||||
// Subpackage msgpack/codes contains list of available codes.
|
||||
func (d *Decoder) PeekCode() (codes.Code, error) {
|
||||
c, err := d.s.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return codes.Code(c), d.s.UnreadByte()
|
||||
}
|
||||
|
||||
func (d *Decoder) hasNilCode() bool {
|
||||
code, err := d.PeekCode()
|
||||
return err == nil && code == codes.Nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readCode() (codes.Code, error) {
|
||||
d.extLen = 0
|
||||
c, err := d.s.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if d.rec != nil {
|
||||
d.rec = append(d.rec, c)
|
||||
}
|
||||
return codes.Code(c), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readFull(b []byte) error {
|
||||
_, err := io.ReadFull(d.r, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.rec != nil {
|
||||
d.rec = append(d.rec, b...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) readN(n int) ([]byte, error) {
|
||||
buf, err := readN(d.r, d.buf, n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.buf = buf
|
||||
if d.rec != nil {
|
||||
d.rec = append(d.rec, buf...)
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func readN(r io.Reader, b []byte, n int) ([]byte, error) {
|
||||
if b == nil {
|
||||
if n == 0 {
|
||||
return make([]byte, 0), nil
|
||||
}
|
||||
if n <= bytesAllocLimit {
|
||||
b = make([]byte, n)
|
||||
} else {
|
||||
b = make([]byte, bytesAllocLimit)
|
||||
}
|
||||
}
|
||||
|
||||
if n <= cap(b) {
|
||||
b = b[:n]
|
||||
_, err := io.ReadFull(r, b)
|
||||
return b, err
|
||||
}
|
||||
b = b[:cap(b)]
|
||||
|
||||
var pos int
|
||||
for {
|
||||
alloc := n - len(b)
|
||||
if alloc > bytesAllocLimit {
|
||||
alloc = bytesAllocLimit
|
||||
}
|
||||
b = append(b, make([]byte, alloc)...)
|
||||
|
||||
_, err := io.ReadFull(r, b[pos:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(b) == n {
|
||||
break
|
||||
}
|
||||
pos = len(b)
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a <= b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
const mapElemsAllocLimit = 1e4
|
||||
|
||||
var mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil))
|
||||
var mapStringStringType = mapStringStringPtrType.Elem()
|
||||
|
||||
var mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil))
|
||||
var mapStringInterfaceType = mapStringInterfacePtrType.Elem()
|
||||
|
||||
var errInvalidCode = errors.New("invalid code")
|
||||
|
||||
func decodeMapValue(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typ := v.Type()
|
||||
if n == -1 {
|
||||
v.Set(reflect.Zero(typ))
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func decodeMap(d *Decoder) (interface{}, error) {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
m := make(map[string]interface{}, min(n, mapElemsAllocLimit))
|
||||
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
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeMapLen() (int, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if codes.IsExt(c) {
|
||||
if err = d.skipExtHeader(c); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
c, err = d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return d.mapLen(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) mapLen(c codes.Code) (int, error) {
|
||||
n, err := d._mapLen(c)
|
||||
err = expandInvalidCodeMapLenError(c, err)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (d *Decoder) _mapLen(c codes.Code) (int, error) {
|
||||
if c == codes.Nil {
|
||||
return -1, nil
|
||||
}
|
||||
if c >= codes.FixedMapLow && c <= codes.FixedMapHigh {
|
||||
return int(c & codes.FixedMapMask), nil
|
||||
}
|
||||
if c == codes.Map16 {
|
||||
n, err := d.uint16()
|
||||
return int(n), err
|
||||
}
|
||||
if c == codes.Map32 {
|
||||
n, err := d.uint32()
|
||||
return int(n), err
|
||||
}
|
||||
return 0, errInvalidCode
|
||||
}
|
||||
|
||||
func expandInvalidCodeMapLenError(c codes.Code, err error) error {
|
||||
if err == errInvalidCode {
|
||||
return fmt.Errorf("msgpack: invalid code=%x decoding map length", c)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeMapStringStringValue(d *Decoder, v reflect.Value) error {
|
||||
mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string)
|
||||
return d.decodeMapStringStringPtr(mptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
*ptr = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
m := *ptr
|
||||
if m == nil {
|
||||
*ptr = make(map[string]string, min(n, mapElemsAllocLimit))
|
||||
m = *ptr
|
||||
}
|
||||
|
||||
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 decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error {
|
||||
ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{})
|
||||
return d.decodeMapStringInterfacePtr(ptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
*ptr = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
m := *ptr
|
||||
if m == nil {
|
||||
*ptr = make(map[string]interface{}, min(n, mapElemsAllocLimit))
|
||||
m = *ptr
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
mk, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mv, err := d.decodeInterface()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m[mk] = mv
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeMap() (interface{}, error) {
|
||||
return d.decodeMapFunc(d)
|
||||
}
|
||||
|
||||
func (d *Decoder) skipMap(c codes.Code) error {
|
||||
n, err := d.mapLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeStructValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var isArray bool
|
||||
|
||||
n, err := d._mapLen(c)
|
||||
if err != nil {
|
||||
var err2 error
|
||||
n, err2 = d.arrayLen(c)
|
||||
if err2 != nil {
|
||||
return expandInvalidCodeMapLenError(c, err)
|
||||
}
|
||||
isArray = true
|
||||
}
|
||||
if n == -1 {
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
var fields *fields
|
||||
if d.useJSONTag {
|
||||
fields = jsonStructs.Fields(v.Type())
|
||||
} else {
|
||||
fields = structs.Fields(v.Type())
|
||||
}
|
||||
|
||||
if isArray {
|
||||
for i, f := range fields.List {
|
||||
if i >= n {
|
||||
break
|
||||
}
|
||||
if err := f.DecodeValue(d, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Skip extra values.
|
||||
for i := len(fields.List); i < n; i++ {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
name, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f := fields.Table[name]; f != nil {
|
||||
if err := f.DecodeValue(d, v); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
func (d *Decoder) skipN(n int) error {
|
||||
_, err := d.readN(n)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint8() (uint8, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint8(c), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) int8() (int8, error) {
|
||||
n, err := d.uint8()
|
||||
return int8(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint16() (uint16, error) {
|
||||
b, err := d.readN(2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return (uint16(b[0]) << 8) | uint16(b[1]), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) int16() (int16, error) {
|
||||
n, err := d.uint16()
|
||||
return int16(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint32() (uint32, error) {
|
||||
b, err := d.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) int32() (int32, error) {
|
||||
n, err := d.uint32()
|
||||
return int32(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) uint64() (uint64, error) {
|
||||
b, err := d.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) int64() (int64, error) {
|
||||
n, err := d.uint64()
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
// DecodeUint64 decodes msgpack int8/16/32/64 and uint8/16/32/64
|
||||
// into Go uint64.
|
||||
func (d *Decoder) DecodeUint64() (uint64, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.uint(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) uint(c codes.Code) (uint64, error) {
|
||||
if c == codes.Nil {
|
||||
return 0, nil
|
||||
}
|
||||
if codes.IsFixedNum(c) {
|
||||
return uint64(int8(c)), nil
|
||||
}
|
||||
switch c {
|
||||
case codes.Uint8:
|
||||
n, err := d.uint8()
|
||||
return uint64(n), err
|
||||
case codes.Int8:
|
||||
n, err := d.int8()
|
||||
return uint64(n), err
|
||||
case codes.Uint16:
|
||||
n, err := d.uint16()
|
||||
return uint64(n), err
|
||||
case codes.Int16:
|
||||
n, err := d.int16()
|
||||
return uint64(n), err
|
||||
case codes.Uint32:
|
||||
n, err := d.uint32()
|
||||
return uint64(n), err
|
||||
case codes.Int32:
|
||||
n, err := d.int32()
|
||||
return uint64(n), err
|
||||
case codes.Uint64, codes.Int64:
|
||||
return d.uint64()
|
||||
}
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding uint64", c)
|
||||
}
|
||||
|
||||
// DecodeInt64 decodes msgpack int8/16/32/64 and uint8/16/32/64
|
||||
// into Go int64.
|
||||
func (d *Decoder) DecodeInt64() (int64, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.int(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) int(c codes.Code) (int64, error) {
|
||||
if c == codes.Nil {
|
||||
return 0, nil
|
||||
}
|
||||
if codes.IsFixedNum(c) {
|
||||
return int64(int8(c)), nil
|
||||
}
|
||||
switch c {
|
||||
case codes.Uint8:
|
||||
n, err := d.uint8()
|
||||
return int64(n), err
|
||||
case codes.Int8:
|
||||
n, err := d.uint8()
|
||||
return int64(int8(n)), err
|
||||
case codes.Uint16:
|
||||
n, err := d.uint16()
|
||||
return int64(n), err
|
||||
case codes.Int16:
|
||||
n, err := d.uint16()
|
||||
return int64(int16(n)), err
|
||||
case codes.Uint32:
|
||||
n, err := d.uint32()
|
||||
return int64(n), err
|
||||
case codes.Int32:
|
||||
n, err := d.uint32()
|
||||
return int64(int32(n)), err
|
||||
case codes.Uint64, codes.Int64:
|
||||
n, err := d.uint64()
|
||||
return int64(n), err
|
||||
}
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding int64", c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeFloat32() (float32, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.float32(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) float32(c codes.Code) (float32, error) {
|
||||
if c == codes.Float {
|
||||
n, err := d.uint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return math.Float32frombits(n), nil
|
||||
}
|
||||
|
||||
n, err := d.int(c)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c)
|
||||
}
|
||||
return float32(n), nil
|
||||
}
|
||||
|
||||
// DecodeFloat64 decodes msgpack float32/64 into Go float64.
|
||||
func (d *Decoder) DecodeFloat64() (float64, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.float64(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) float64(c codes.Code) (float64, error) {
|
||||
switch c {
|
||||
case codes.Float:
|
||||
n, err := d.float32(c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float64(n), nil
|
||||
case codes.Double:
|
||||
n, err := d.uint64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return math.Float64frombits(n), nil
|
||||
}
|
||||
|
||||
n, err := d.int(c)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c)
|
||||
}
|
||||
return float64(n), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint() (uint, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint8() (uint8, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint8(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint16() (uint16, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint16(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeUint32() (uint32, error) {
|
||||
n, err := d.DecodeUint64()
|
||||
return uint32(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt() (int, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt8() (int8, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int8(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt16() (int16, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int16(n), err
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeInt32() (int32, error) {
|
||||
n, err := d.DecodeInt64()
|
||||
return int32(n), err
|
||||
}
|
||||
|
||||
func decodeFloat32Value(d *Decoder, v reflect.Value) error {
|
||||
f, err := d.DecodeFloat32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetFloat(float64(f))
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeFloat64Value(d *Decoder, v reflect.Value) error {
|
||||
f, err := d.DecodeFloat64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetFloat(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInt64Value(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeInt64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetInt(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUint64Value(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeUint64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetUint(n)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
type queryResult struct {
|
||||
query string
|
||||
key string
|
||||
hasAsterisk bool
|
||||
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
func (q *queryResult) nextKey() {
|
||||
ind := strings.IndexByte(q.query, '.')
|
||||
if ind == -1 {
|
||||
q.key = q.query
|
||||
q.query = ""
|
||||
return
|
||||
}
|
||||
q.key = q.query[:ind]
|
||||
q.query = q.query[ind+1:]
|
||||
}
|
||||
|
||||
// Query extracts data specified by the query from the msgpack stream skipping
|
||||
// any other data. Query consists of map keys and array indexes separated with dot,
|
||||
// e.g. key1.0.key2.
|
||||
func (d *Decoder) Query(query string) ([]interface{}, error) {
|
||||
res := queryResult{
|
||||
query: query,
|
||||
}
|
||||
if err := d.query(&res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.values, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) query(q *queryResult) error {
|
||||
q.nextKey()
|
||||
if q.key == "" {
|
||||
v, err := d.decodeInterface()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
q.values = append(q.values, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
code, err := d.PeekCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case code == codes.Map16 || code == codes.Map32 || codes.IsFixedMap(code):
|
||||
err = d.queryMapKey(q)
|
||||
case code == codes.Array16 || code == codes.Array32 || codes.IsFixedArray(code):
|
||||
err = d.queryArrayIndex(q)
|
||||
default:
|
||||
err = fmt.Errorf("msgpack: unsupported code=%x decoding key=%q", code, q.key)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) queryMapKey(q *queryResult) error {
|
||||
n, err := d.DecodeMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
k, err := d.bytesNoCopy()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if string(k) == q.key {
|
||||
if err := d.query(q); err != nil {
|
||||
return err
|
||||
}
|
||||
if q.hasAsterisk {
|
||||
return d.skipNext((n - i - 1) * 2)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) queryArrayIndex(q *queryResult) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if q.key == "*" {
|
||||
q.hasAsterisk = true
|
||||
|
||||
query := q.query
|
||||
for i := 0; i < n; i++ {
|
||||
q.query = query
|
||||
if err := d.query(q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
q.hasAsterisk = false
|
||||
return nil
|
||||
}
|
||||
|
||||
ind, err := strconv.Atoi(q.key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if i == ind {
|
||||
if err := d.query(q); err != nil {
|
||||
return err
|
||||
}
|
||||
if q.hasAsterisk {
|
||||
return d.skipNext(n - i - 1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) skipNext(n int) error {
|
||||
for i := 0; i < n; i++ {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
const sliceElemsAllocLimit = 1e4
|
||||
|
||||
var sliceStringPtrType = reflect.TypeOf((*[]string)(nil))
|
||||
|
||||
func (d *Decoder) DecodeArrayLen() (int, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.arrayLen(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) arrayLen(c codes.Code) (int, error) {
|
||||
if c == codes.Nil {
|
||||
return -1, nil
|
||||
} else if c >= codes.FixedArrayLow && c <= codes.FixedArrayHigh {
|
||||
return int(c & codes.FixedArrayMask), nil
|
||||
}
|
||||
switch c {
|
||||
case codes.Array16:
|
||||
n, err := d.uint16()
|
||||
return int(n), err
|
||||
case codes.Array32:
|
||||
n, err := d.uint32()
|
||||
return int(n), err
|
||||
}
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding array length", c)
|
||||
}
|
||||
|
||||
func decodeStringSliceValue(d *Decoder, v reflect.Value) error {
|
||||
ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string)
|
||||
return d.decodeStringSlicePtr(ptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ss := setStringsCap(*ptr, n)
|
||||
for i := 0; i < n; i++ {
|
||||
s, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ss = append(ss, s)
|
||||
}
|
||||
*ptr = ss
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setStringsCap(s []string, n int) []string {
|
||||
if n > sliceElemsAllocLimit {
|
||||
n = sliceElemsAllocLimit
|
||||
}
|
||||
|
||||
if s == nil {
|
||||
return make([]string, 0, n)
|
||||
}
|
||||
|
||||
if cap(s) >= n {
|
||||
return s[:0]
|
||||
}
|
||||
|
||||
s = s[:cap(s)]
|
||||
s = append(s, make([]string, n-len(s))...)
|
||||
return s[:0]
|
||||
}
|
||||
|
||||
func decodeSliceValue(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n == -1 {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return nil
|
||||
}
|
||||
if n == 0 && v.IsNil() {
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Cap() >= n {
|
||||
v.Set(v.Slice(0, n))
|
||||
} else if v.Len() < v.Cap() {
|
||||
v.Set(v.Slice(0, v.Cap()))
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if i >= v.Len() {
|
||||
v.Set(growSliceValue(v, n))
|
||||
}
|
||||
sv := v.Index(i)
|
||||
if err := d.DecodeValue(sv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func growSliceValue(v reflect.Value, n int) reflect.Value {
|
||||
diff := n - v.Len()
|
||||
if diff > sliceElemsAllocLimit {
|
||||
diff = sliceElemsAllocLimit
|
||||
}
|
||||
v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff))
|
||||
return v
|
||||
}
|
||||
|
||||
func decodeArrayValue(d *Decoder, v reflect.Value) error {
|
||||
n, err := d.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if n > v.Len() {
|
||||
return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n)
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
sv := v.Index(i)
|
||||
if err := d.DecodeValue(sv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeSlice() ([]interface{}, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.decodeSlice(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeSlice(c codes.Code) ([]interface{}, error) {
|
||||
n, err := d.arrayLen(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
s := make([]interface{}, 0, min(n, sliceElemsAllocLimit))
|
||||
for i := 0; i < n; i++ {
|
||||
v, err := d.decodeInterface()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s = append(s, v)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) skipSlice(c codes.Code) error {
|
||||
n, err := d.arrayLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
func (d *Decoder) bytesLen(c codes.Code) (int, error) {
|
||||
if c == codes.Nil {
|
||||
return -1, nil
|
||||
} else if codes.IsFixedString(c) {
|
||||
return int(c & codes.FixedStrMask), nil
|
||||
}
|
||||
switch c {
|
||||
case codes.Str8, codes.Bin8:
|
||||
n, err := d.uint8()
|
||||
return int(n), err
|
||||
case codes.Str16, codes.Bin16:
|
||||
n, err := d.uint16()
|
||||
return int(n), err
|
||||
case codes.Str32, codes.Bin32:
|
||||
n, err := d.uint32()
|
||||
return int(n), err
|
||||
}
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding bytes length", c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeString() (string, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return d.string(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) string(c codes.Code) (string, error) {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n == -1 {
|
||||
return "", nil
|
||||
}
|
||||
b, err := d.readN(n)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
func decodeStringValue(d *Decoder, v reflect.Value) error {
|
||||
s, err := d.DecodeString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetString(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeBytesLen() (int, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d.bytesLen(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeBytes() ([]byte, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.bytes(c, nil)
|
||||
}
|
||||
|
||||
func (d *Decoder) bytes(c codes.Code, b []byte) ([]byte, error) {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
return readN(d.r, b, n)
|
||||
}
|
||||
|
||||
func (d *Decoder) bytesNoCopy() ([]byte, error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil, nil
|
||||
}
|
||||
return d.readN(n)
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeBytesPtr(ptr *[]byte) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.bytesPtr(c, ptr)
|
||||
}
|
||||
|
||||
func (d *Decoder) bytesPtr(c codes.Code, ptr *[]byte) error {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
*ptr = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
*ptr, err = readN(d.r, *ptr, n)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) skipBytes(c codes.Code) error {
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
return d.skipN(n)
|
||||
}
|
||||
|
||||
func decodeBytesValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := d.bytes(c, v.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetBytes(b)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeByteArrayValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := d.bytesLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == -1 {
|
||||
return nil
|
||||
}
|
||||
if n > v.Len() {
|
||||
return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n)
|
||||
}
|
||||
|
||||
b := v.Slice(0, n).Bytes()
|
||||
return d.readFull(b)
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
var interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
|
||||
var stringType = reflect.TypeOf((*string)(nil)).Elem()
|
||||
|
||||
var valueDecoders []decoderFunc
|
||||
|
||||
func init() {
|
||||
valueDecoders = []decoderFunc{
|
||||
reflect.Bool: decodeBoolValue,
|
||||
reflect.Int: decodeInt64Value,
|
||||
reflect.Int8: decodeInt64Value,
|
||||
reflect.Int16: decodeInt64Value,
|
||||
reflect.Int32: decodeInt64Value,
|
||||
reflect.Int64: decodeInt64Value,
|
||||
reflect.Uint: decodeUint64Value,
|
||||
reflect.Uint8: decodeUint64Value,
|
||||
reflect.Uint16: decodeUint64Value,
|
||||
reflect.Uint32: decodeUint64Value,
|
||||
reflect.Uint64: decodeUint64Value,
|
||||
reflect.Float32: decodeFloat32Value,
|
||||
reflect.Float64: decodeFloat64Value,
|
||||
reflect.Complex64: decodeUnsupportedValue,
|
||||
reflect.Complex128: decodeUnsupportedValue,
|
||||
reflect.Array: decodeArrayValue,
|
||||
reflect.Chan: decodeUnsupportedValue,
|
||||
reflect.Func: decodeUnsupportedValue,
|
||||
reflect.Interface: decodeInterfaceValue,
|
||||
reflect.Map: decodeMapValue,
|
||||
reflect.Ptr: decodeUnsupportedValue,
|
||||
reflect.Slice: decodeSliceValue,
|
||||
reflect.String: decodeStringValue,
|
||||
reflect.Struct: decodeStructValue,
|
||||
reflect.UnsafePointer: decodeUnsupportedValue,
|
||||
}
|
||||
}
|
||||
|
||||
func mustSet(v reflect.Value) error {
|
||||
if !v.CanSet() {
|
||||
return fmt.Errorf("msgpack: Decode(nonsettable %s)", v.Type())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDecoder(typ reflect.Type) decoderFunc {
|
||||
kind := typ.Kind()
|
||||
|
||||
if decoder, ok := typDecMap[typ]; ok {
|
||||
return decoder
|
||||
}
|
||||
|
||||
if typ.Implements(customDecoderType) {
|
||||
return decodeCustomValue
|
||||
}
|
||||
if typ.Implements(unmarshalerType) {
|
||||
return unmarshalValue
|
||||
}
|
||||
|
||||
// Addressable struct field value.
|
||||
if kind != reflect.Ptr {
|
||||
ptr := reflect.PtrTo(typ)
|
||||
if ptr.Implements(customDecoderType) {
|
||||
return decodeCustomValueAddr
|
||||
}
|
||||
if ptr.Implements(unmarshalerType) {
|
||||
return unmarshalValueAddr
|
||||
}
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Ptr:
|
||||
return ptrDecoderFunc(typ)
|
||||
case reflect.Slice:
|
||||
elem := typ.Elem()
|
||||
switch elem.Kind() {
|
||||
case reflect.Uint8:
|
||||
return decodeBytesValue
|
||||
}
|
||||
switch elem {
|
||||
case stringType:
|
||||
return decodeStringSliceValue
|
||||
}
|
||||
case reflect.Array:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return decodeByteArrayValue
|
||||
}
|
||||
case reflect.Map:
|
||||
if typ.Key() == stringType {
|
||||
switch typ.Elem() {
|
||||
case stringType:
|
||||
return decodeMapStringStringValue
|
||||
case interfaceType:
|
||||
return decodeMapStringInterfaceValue
|
||||
}
|
||||
}
|
||||
}
|
||||
return valueDecoders[kind]
|
||||
}
|
||||
|
||||
func ptrDecoderFunc(typ reflect.Type) decoderFunc {
|
||||
decoder := getDecoder(typ.Elem())
|
||||
return func(d *Decoder, v reflect.Value) error {
|
||||
if d.hasNilCode() {
|
||||
if err := mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return d.DecodeNil()
|
||||
}
|
||||
if v.IsNil() {
|
||||
if err := mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
return decoder(d, v.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func decodeCustomValueAddr(d *Decoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
|
||||
}
|
||||
return decodeCustomValue(d, v.Addr())
|
||||
}
|
||||
|
||||
func decodeCustomValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.PeekCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if codes.IsExt(c) {
|
||||
c, err = d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
extLen, err := d.parseExtLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err = d.PeekCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.extLen = extLen
|
||||
}
|
||||
|
||||
if c == codes.Nil {
|
||||
return d.decodeNilValue(v)
|
||||
}
|
||||
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
|
||||
decoder := v.Interface().(CustomDecoder)
|
||||
return decoder.DecodeMsgpack(d)
|
||||
}
|
||||
|
||||
func unmarshalValueAddr(d *Decoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
|
||||
}
|
||||
return unmarshalValue(d, v.Addr())
|
||||
}
|
||||
|
||||
func unmarshalValue(d *Decoder, v reflect.Value) error {
|
||||
c, err := d.PeekCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
extLen := d.extLen
|
||||
d.extLen = 0
|
||||
|
||||
if extLen == 0 && codes.IsExt(c) {
|
||||
c, err = d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
extLen, err = d.parseExtLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err = d.PeekCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c == codes.Nil {
|
||||
return d.decodeNilValue(v)
|
||||
}
|
||||
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
|
||||
if extLen != 0 {
|
||||
b, err := d.readN(extLen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.rec = b
|
||||
} else {
|
||||
d.rec = makeBuffer()
|
||||
if err := d.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
unmarshaler := v.Interface().(Unmarshaler)
|
||||
err = unmarshaler.UnmarshalMsgpack(d.rec)
|
||||
d.rec = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func decodeBoolValue(d *Decoder, v reflect.Value) error {
|
||||
flag, err := d.DecodeBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mustSet(v); err != nil {
|
||||
return err
|
||||
}
|
||||
v.SetBool(flag)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeInterfaceValue(d *Decoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return d.interfaceValue(v)
|
||||
}
|
||||
|
||||
elem := v.Elem()
|
||||
if !elem.CanAddr() {
|
||||
if d.hasNilCode() {
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
return d.DecodeNil()
|
||||
}
|
||||
}
|
||||
|
||||
return d.DecodeValue(elem)
|
||||
}
|
||||
|
||||
func (d *Decoder) interfaceValue(v reflect.Value) error {
|
||||
vv, err := d.decodeInterface()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if vv != nil {
|
||||
if v.Type() == errorType {
|
||||
if vv, ok := vv.(string); ok {
|
||||
v.Set(reflect.ValueOf(errors.New(vv)))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
v.Set(reflect.ValueOf(vv))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeUnsupportedValue(d *Decoder, v reflect.Value) error {
|
||||
return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type())
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
type writer interface {
|
||||
io.Writer
|
||||
WriteByte(byte) error
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
type byteWriter struct {
|
||||
io.Writer
|
||||
|
||||
buf []byte
|
||||
bootstrap [64]byte
|
||||
}
|
||||
|
||||
func newByteWriter(w io.Writer) *byteWriter {
|
||||
bw := &byteWriter{
|
||||
Writer: w,
|
||||
}
|
||||
bw.buf = bw.bootstrap[:]
|
||||
return bw
|
||||
}
|
||||
|
||||
func (w *byteWriter) WriteByte(c byte) error {
|
||||
w.buf = w.buf[:1]
|
||||
w.buf[0] = c
|
||||
_, err := w.Write(w.buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *byteWriter) WriteString(s string) (int, error) {
|
||||
w.buf = append(w.buf[:0], s...)
|
||||
return w.Write(w.buf)
|
||||
}
|
||||
|
||||
// Marshal returns the MessagePack encoding of v.
|
||||
func Marshal(v ...interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
err := NewEncoder(&buf).Encode(v...)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
type Encoder struct {
|
||||
w writer
|
||||
buf []byte
|
||||
|
||||
sortMapKeys bool
|
||||
structAsArray bool
|
||||
useJSONTag bool
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
bw, ok := w.(writer)
|
||||
if !ok {
|
||||
bw = newByteWriter(w)
|
||||
}
|
||||
return &Encoder{
|
||||
w: bw,
|
||||
buf: make([]byte, 9),
|
||||
}
|
||||
}
|
||||
|
||||
// SortMapKeys causes the Encoder to encode map keys in increasing order.
|
||||
// Supported map types are:
|
||||
// - map[string]string
|
||||
// - map[string]interface{}
|
||||
func (e *Encoder) SortMapKeys(v bool) *Encoder {
|
||||
e.sortMapKeys = v
|
||||
return e
|
||||
}
|
||||
|
||||
// StructAsArray causes the Encoder to encode Go structs as MessagePack arrays.
|
||||
func (e *Encoder) StructAsArray(v bool) *Encoder {
|
||||
e.structAsArray = v
|
||||
return e
|
||||
}
|
||||
|
||||
// UseJSONTag causes the Encoder to use json struct tag as fallback option
|
||||
// if there is no msgpack tag.
|
||||
func (e *Encoder) UseJSONTag(v bool) *Encoder {
|
||||
e.useJSONTag = v
|
||||
return e
|
||||
}
|
||||
|
||||
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(v interface{}) error {
|
||||
switch v := v.(type) {
|
||||
case nil:
|
||||
return e.EncodeNil()
|
||||
case string:
|
||||
return e.EncodeString(v)
|
||||
case []byte:
|
||||
return e.EncodeBytes(v)
|
||||
case int:
|
||||
return e.EncodeInt(int64(v))
|
||||
case int64:
|
||||
return e.EncodeInt(v)
|
||||
case uint:
|
||||
return e.EncodeUint(uint64(v))
|
||||
case uint64:
|
||||
return e.EncodeUint(v)
|
||||
case bool:
|
||||
return e.EncodeBool(v)
|
||||
case float32:
|
||||
return e.EncodeFloat32(v)
|
||||
case float64:
|
||||
return e.EncodeFloat64(v)
|
||||
case time.Duration:
|
||||
return e.EncodeInt(int64(v))
|
||||
case time.Time:
|
||||
return e.EncodeTime(v)
|
||||
}
|
||||
return e.EncodeValue(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeValue(v reflect.Value) error {
|
||||
encode := getEncoder(v.Type())
|
||||
return encode(e, v)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeNil() error {
|
||||
return e.writeCode(codes.Nil)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeBool(value bool) error {
|
||||
if value {
|
||||
return e.writeCode(codes.True)
|
||||
}
|
||||
return e.writeCode(codes.False)
|
||||
}
|
||||
|
||||
func (e *Encoder) writeCode(c codes.Code) error {
|
||||
return e.w.WriteByte(byte(c))
|
||||
}
|
||||
|
||||
func (e *Encoder) write(b []byte) error {
|
||||
_, err := e.w.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) writeString(s string) error {
|
||||
_, err := e.w.WriteString(s)
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
func encodeMapValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
if err := e.EncodeMapLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, key := range v.MapKeys() {
|
||||
if err := e.EncodeValue(key); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.EncodeValue(v.MapIndex(key)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeMapStringStringValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
if err := e.EncodeMapLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := v.Convert(mapStringStringType).Interface().(map[string]string)
|
||||
if e.sortMapKeys {
|
||||
return e.encodeSortedMapStringString(m)
|
||||
}
|
||||
|
||||
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 encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
|
||||
if err := e.EncodeMapLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{})
|
||||
if e.sortMapKeys {
|
||||
return e.encodeSortedMapStringInterface(m)
|
||||
}
|
||||
|
||||
for mk, mv := range m {
|
||||
if err := e.EncodeString(mk); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.Encode(mv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeSortedMapStringString(m map[string]string) error {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k, _ := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
err := e.EncodeString(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = e.EncodeString(m[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeSortedMapStringInterface(m map[string]interface{}) error {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k, _ := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, k := range keys {
|
||||
err := e.EncodeString(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = e.Encode(m[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeMapLen(l int) error {
|
||||
if l < 16 {
|
||||
return e.writeCode(codes.FixedMapLow | codes.Code(l))
|
||||
}
|
||||
if l < 65536 {
|
||||
return e.write2(codes.Map16, uint64(l))
|
||||
}
|
||||
return e.write4(codes.Map32, uint32(l))
|
||||
}
|
||||
|
||||
func encodeStructValue(e *Encoder, strct reflect.Value) error {
|
||||
var structFields *fields
|
||||
if e.useJSONTag {
|
||||
structFields = jsonStructs.Fields(strct.Type())
|
||||
} else {
|
||||
structFields = structs.Fields(strct.Type())
|
||||
}
|
||||
|
||||
if e.structAsArray || structFields.AsArray {
|
||||
return encodeStructValueAsArray(e, strct, structFields.List)
|
||||
}
|
||||
fields := structFields.OmitEmpty(strct)
|
||||
|
||||
if err := e.EncodeMapLen(len(fields)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range fields {
|
||||
if err := e.EncodeString(f.name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.EncodeValue(e, strct); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeStructValueAsArray(e *Encoder, strct reflect.Value, fields []*field) error {
|
||||
if err := e.EncodeArrayLen(len(fields)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, f := range fields {
|
||||
if err := f.EncodeValue(e, strct); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
// EncodeUint encodes an uint64 in 1, 2, 3, 5, or 9 bytes.
|
||||
func (e *Encoder) EncodeUint(v uint64) error {
|
||||
if v <= math.MaxInt8 {
|
||||
return e.w.WriteByte(byte(v))
|
||||
}
|
||||
if v <= math.MaxUint8 {
|
||||
return e.write1(codes.Uint8, v)
|
||||
}
|
||||
if v <= math.MaxUint16 {
|
||||
return e.write2(codes.Uint16, v)
|
||||
}
|
||||
if v <= math.MaxUint32 {
|
||||
return e.write4(codes.Uint32, uint32(v))
|
||||
}
|
||||
return e.write8(codes.Uint64, v)
|
||||
}
|
||||
|
||||
// EncodeInt encodes an int64 in 1, 2, 3, 5, or 9 bytes.
|
||||
func (e *Encoder) EncodeInt(v int64) error {
|
||||
if v >= 0 {
|
||||
return e.EncodeUint(uint64(v))
|
||||
}
|
||||
if v >= int64(int8(codes.NegFixedNumLow)) {
|
||||
return e.w.WriteByte(byte(v))
|
||||
}
|
||||
if v >= math.MinInt8 {
|
||||
return e.write1(codes.Int8, uint64(v))
|
||||
}
|
||||
if v >= math.MinInt16 {
|
||||
return e.write2(codes.Int16, uint64(v))
|
||||
}
|
||||
if v >= math.MinInt32 {
|
||||
return e.write4(codes.Int32, uint32(v))
|
||||
}
|
||||
return e.write8(codes.Int64, uint64(v))
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeFloat32(n float32) error {
|
||||
return e.write4(codes.Float, math.Float32bits(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeFloat64(n float64) error {
|
||||
return e.write8(codes.Double, math.Float64bits(n))
|
||||
}
|
||||
|
||||
func (e *Encoder) write1(code codes.Code, n uint64) error {
|
||||
e.buf = e.buf[:2]
|
||||
e.buf[0] = byte(code)
|
||||
e.buf[1] = byte(n)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func (e *Encoder) write2(code codes.Code, n uint64) error {
|
||||
e.buf = e.buf[:3]
|
||||
e.buf[0] = byte(code)
|
||||
e.buf[1] = byte(n >> 8)
|
||||
e.buf[2] = byte(n)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func (e *Encoder) write4(code codes.Code, n uint32) error {
|
||||
e.buf = e.buf[:5]
|
||||
e.buf[0] = byte(code)
|
||||
e.buf[1] = byte(n >> 24)
|
||||
e.buf[2] = byte(n >> 16)
|
||||
e.buf[3] = byte(n >> 8)
|
||||
e.buf[4] = byte(n)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func (e *Encoder) write8(code codes.Code, n uint64) error {
|
||||
e.buf = e.buf[:9]
|
||||
e.buf[0] = byte(code)
|
||||
e.buf[1] = byte(n >> 56)
|
||||
e.buf[2] = byte(n >> 48)
|
||||
e.buf[3] = byte(n >> 40)
|
||||
e.buf[4] = byte(n >> 32)
|
||||
e.buf[5] = byte(n >> 24)
|
||||
e.buf[6] = byte(n >> 16)
|
||||
e.buf[7] = byte(n >> 8)
|
||||
e.buf[8] = byte(n)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func encodeInt64Value(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeInt(v.Int())
|
||||
}
|
||||
|
||||
func encodeUint64Value(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeUint(v.Uint())
|
||||
}
|
||||
|
||||
func encodeFloat32Value(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeFloat32(float32(v.Float()))
|
||||
}
|
||||
|
||||
func encodeFloat64Value(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeFloat64(v.Float())
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
func encodeStringValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeString(v.String())
|
||||
}
|
||||
|
||||
func encodeByteSliceValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeBytes(v.Bytes())
|
||||
}
|
||||
|
||||
func encodeByteArrayValue(e *Encoder, v reflect.Value) error {
|
||||
if err := e.EncodeBytesLen(v.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v.CanAddr() {
|
||||
b := v.Slice(0, v.Len()).Bytes()
|
||||
return e.write(b)
|
||||
}
|
||||
|
||||
e.buf = grow(e.buf, v.Len())
|
||||
reflect.Copy(reflect.ValueOf(e.buf), v)
|
||||
return e.write(e.buf)
|
||||
}
|
||||
|
||||
func grow(b []byte, n int) []byte {
|
||||
if cap(b) >= n {
|
||||
return b[:n]
|
||||
}
|
||||
b = b[:cap(b)]
|
||||
b = append(b, make([]byte, n-len(b))...)
|
||||
return b
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeBytesLen(l int) error {
|
||||
if l < 256 {
|
||||
return e.write1(codes.Bin8, uint64(l))
|
||||
}
|
||||
if l < 65536 {
|
||||
return e.write2(codes.Bin16, uint64(l))
|
||||
}
|
||||
return e.write4(codes.Bin32, uint32(l))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeStrLen(l int) error {
|
||||
if l < 32 {
|
||||
return e.writeCode(codes.FixedStrLow | codes.Code(l))
|
||||
}
|
||||
if l < 256 {
|
||||
return e.write1(codes.Str8, uint64(l))
|
||||
}
|
||||
if l < 65536 {
|
||||
return e.write2(codes.Str16, uint64(l))
|
||||
}
|
||||
return e.write4(codes.Str32, uint32(l))
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeString(v string) error {
|
||||
if err := e.encodeStrLen(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) EncodeArrayLen(l int) error {
|
||||
if l < 16 {
|
||||
return e.writeCode(codes.FixedArrayLow | codes.Code(l))
|
||||
}
|
||||
if l < 65536 {
|
||||
return e.write2(codes.Array16, uint64(l))
|
||||
}
|
||||
return e.write4(codes.Array32, uint32(l))
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeStringSlice(s []string) error {
|
||||
if s == nil {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
if err := e.EncodeArrayLen(len(s)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range s {
|
||||
if err := e.EncodeString(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeSliceValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return encodeArrayValue(e, v)
|
||||
}
|
||||
|
||||
func encodeArrayValue(e *Encoder, v reflect.Value) error {
|
||||
l := v.Len()
|
||||
if err := e.EncodeArrayLen(l); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
if err := e.EncodeValue(v.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var valueEncoders []encoderFunc
|
||||
|
||||
func init() {
|
||||
valueEncoders = []encoderFunc{
|
||||
reflect.Bool: encodeBoolValue,
|
||||
reflect.Int: encodeInt64Value,
|
||||
reflect.Int8: encodeInt64Value,
|
||||
reflect.Int16: encodeInt64Value,
|
||||
reflect.Int32: encodeInt64Value,
|
||||
reflect.Int64: encodeInt64Value,
|
||||
reflect.Uint: encodeUint64Value,
|
||||
reflect.Uint8: encodeUint64Value,
|
||||
reflect.Uint16: encodeUint64Value,
|
||||
reflect.Uint32: encodeUint64Value,
|
||||
reflect.Uint64: encodeUint64Value,
|
||||
reflect.Float32: encodeFloat32Value,
|
||||
reflect.Float64: encodeFloat64Value,
|
||||
reflect.Complex64: encodeUnsupportedValue,
|
||||
reflect.Complex128: encodeUnsupportedValue,
|
||||
reflect.Array: encodeArrayValue,
|
||||
reflect.Chan: encodeUnsupportedValue,
|
||||
reflect.Func: encodeUnsupportedValue,
|
||||
reflect.Interface: encodeInterfaceValue,
|
||||
reflect.Map: encodeMapValue,
|
||||
reflect.Ptr: encodeUnsupportedValue,
|
||||
reflect.Slice: encodeSliceValue,
|
||||
reflect.String: encodeStringValue,
|
||||
reflect.Struct: encodeStructValue,
|
||||
reflect.UnsafePointer: encodeUnsupportedValue,
|
||||
}
|
||||
}
|
||||
|
||||
func getEncoder(typ reflect.Type) encoderFunc {
|
||||
if encoder, ok := typEncMap[typ]; ok {
|
||||
return encoder
|
||||
}
|
||||
|
||||
if typ.Implements(customEncoderType) {
|
||||
return encodeCustomValue
|
||||
}
|
||||
if typ.Implements(marshalerType) {
|
||||
return marshalValue
|
||||
}
|
||||
|
||||
kind := typ.Kind()
|
||||
|
||||
// Addressable struct field value.
|
||||
if kind != reflect.Ptr {
|
||||
ptr := reflect.PtrTo(typ)
|
||||
if ptr.Implements(customEncoderType) {
|
||||
return encodeCustomValuePtr
|
||||
}
|
||||
if ptr.Implements(marshalerType) {
|
||||
return marshalValuePtr
|
||||
}
|
||||
}
|
||||
|
||||
if typ == errorType {
|
||||
return encodeErrorValue
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Ptr:
|
||||
return ptrEncoderFunc(typ)
|
||||
case reflect.Slice:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return encodeByteSliceValue
|
||||
}
|
||||
case reflect.Array:
|
||||
if typ.Elem().Kind() == reflect.Uint8 {
|
||||
return encodeByteArrayValue
|
||||
}
|
||||
case reflect.Map:
|
||||
if typ.Key() == stringType {
|
||||
switch typ.Elem() {
|
||||
case stringType:
|
||||
return encodeMapStringStringValue
|
||||
case interfaceType:
|
||||
return encodeMapStringInterfaceValue
|
||||
}
|
||||
}
|
||||
}
|
||||
return valueEncoders[kind]
|
||||
}
|
||||
|
||||
func ptrEncoderFunc(typ reflect.Type) encoderFunc {
|
||||
encoder := getEncoder(typ.Elem())
|
||||
return func(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return encoder(e, v.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
func encodeCustomValuePtr(e *Encoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
|
||||
}
|
||||
encoder := v.Addr().Interface().(CustomEncoder)
|
||||
return encoder.EncodeMsgpack(e)
|
||||
}
|
||||
|
||||
func encodeCustomValue(e *Encoder, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
}
|
||||
|
||||
encoder := v.Interface().(CustomEncoder)
|
||||
return encoder.EncodeMsgpack(e)
|
||||
}
|
||||
|
||||
func marshalValuePtr(e *Encoder, v reflect.Value) error {
|
||||
if !v.CanAddr() {
|
||||
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
|
||||
}
|
||||
return marshalValue(e, v.Addr())
|
||||
}
|
||||
|
||||
func marshalValue(e *Encoder, v reflect.Value) error {
|
||||
switch v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
}
|
||||
|
||||
marshaler := v.Interface().(Marshaler)
|
||||
b, err := marshaler.MarshalMsgpack()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = e.w.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
func encodeBoolValue(e *Encoder, v reflect.Value) error {
|
||||
return e.EncodeBool(v.Bool())
|
||||
}
|
||||
|
||||
func encodeInterfaceValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return e.EncodeValue(v.Elem())
|
||||
}
|
||||
|
||||
func encodeErrorValue(e *Encoder, v reflect.Value) error {
|
||||
if v.IsNil() {
|
||||
return e.EncodeNil()
|
||||
}
|
||||
return e.EncodeString(v.Interface().(error).Error())
|
||||
}
|
||||
|
||||
func encodeUnsupportedValue(e *Encoder, v reflect.Value) error {
|
||||
return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type())
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
var extTypes = make(map[int8]reflect.Type)
|
||||
|
||||
var bufferPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
// RegisterExt records a type, identified by a value for that type,
|
||||
// under the provided id. That id will identify the concrete type of a value
|
||||
// sent or received as an interface variable. Only types that will be
|
||||
// transferred as implementations of interface values need to be registered.
|
||||
// Expecting to be used only during initialization, it panics if the mapping
|
||||
// between types and ids is not a bijection.
|
||||
func RegisterExt(id int8, value interface{}) {
|
||||
typ := reflect.TypeOf(value)
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
ptr := reflect.PtrTo(typ)
|
||||
|
||||
if _, ok := extTypes[id]; ok {
|
||||
panic(fmt.Errorf("msgpack: ext with id=%d is already registered", id))
|
||||
}
|
||||
|
||||
registerExt(id, ptr, getEncoder(ptr), nil)
|
||||
registerExt(id, typ, getEncoder(typ), getDecoder(typ))
|
||||
}
|
||||
|
||||
func registerExt(id int8, typ reflect.Type, enc encoderFunc, dec decoderFunc) {
|
||||
if dec != nil {
|
||||
extTypes[id] = typ
|
||||
}
|
||||
if enc != nil {
|
||||
typEncMap[typ] = makeExtEncoder(id, enc)
|
||||
}
|
||||
if dec != nil {
|
||||
typDecMap[typ] = dec
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeExtHeader(typeId int8, length int) error {
|
||||
if err := e.encodeExtLen(length); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.w.WriteByte(byte(typeId)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeExtEncoder(typeId int8, enc encoderFunc) encoderFunc {
|
||||
return func(e *Encoder, v reflect.Value) error {
|
||||
buf := bufferPool.Get().(*bytes.Buffer)
|
||||
defer bufferPool.Put(buf)
|
||||
buf.Reset()
|
||||
|
||||
oldw := e.w
|
||||
e.w = buf
|
||||
err := enc(e, v)
|
||||
e.w = oldw
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.EncodeExtHeader(typeId, buf.Len()); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.write(buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeExtLen(l int) error {
|
||||
switch l {
|
||||
case 1:
|
||||
return e.writeCode(codes.FixExt1)
|
||||
case 2:
|
||||
return e.writeCode(codes.FixExt2)
|
||||
case 4:
|
||||
return e.writeCode(codes.FixExt4)
|
||||
case 8:
|
||||
return e.writeCode(codes.FixExt8)
|
||||
case 16:
|
||||
return e.writeCode(codes.FixExt16)
|
||||
}
|
||||
if l < 256 {
|
||||
return e.write1(codes.Ext8, uint64(l))
|
||||
}
|
||||
if l < 65536 {
|
||||
return e.write2(codes.Ext16, uint64(l))
|
||||
}
|
||||
return e.write4(codes.Ext32, uint32(l))
|
||||
}
|
||||
|
||||
func (d *Decoder) parseExtLen(c codes.Code) (int, error) {
|
||||
switch c {
|
||||
case codes.FixExt1:
|
||||
return 1, nil
|
||||
case codes.FixExt2:
|
||||
return 2, nil
|
||||
case codes.FixExt4:
|
||||
return 4, nil
|
||||
case codes.FixExt8:
|
||||
return 8, nil
|
||||
case codes.FixExt16:
|
||||
return 16, nil
|
||||
case codes.Ext8:
|
||||
n, err := d.uint8()
|
||||
return int(n), err
|
||||
case codes.Ext16:
|
||||
n, err := d.uint16()
|
||||
return int(n), err
|
||||
case codes.Ext32:
|
||||
n, err := d.uint32()
|
||||
return int(n), err
|
||||
default:
|
||||
return 0, fmt.Errorf("msgpack: invalid code=%x decoding ext length", c)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeExtHeader(c codes.Code) (int8, int, error) {
|
||||
length, err := d.parseExtLen(c)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
typeId, err := d.readCode()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return int8(typeId), length, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeExtHeader() (typeId int8, length int, err error) {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return d.decodeExtHeader(c)
|
||||
}
|
||||
|
||||
func (d *Decoder) extInterface(c codes.Code) (interface{}, error) {
|
||||
extId, extLen, err := d.decodeExtHeader(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
typ, ok := extTypes[extId]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("msgpack: unregistered ext id=%d", extId)
|
||||
}
|
||||
|
||||
v := reflect.New(typ)
|
||||
|
||||
d.extLen = extLen
|
||||
err = d.DecodeValue(v.Elem())
|
||||
d.extLen = 0
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return v.Interface(), nil
|
||||
}
|
||||
|
||||
func (d *Decoder) skipExt(c codes.Code) error {
|
||||
n, err := d.parseExtLen(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.skipN(n + 1)
|
||||
}
|
||||
|
||||
func (d *Decoder) skipExtHeader(c codes.Code) error {
|
||||
// Read ext type.
|
||||
_, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Read ext body len.
|
||||
for i := 0; i < extHeaderLen(c); i++ {
|
||||
_, err := d.readCode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extHeaderLen(c codes.Code) int {
|
||||
switch c {
|
||||
case codes.Ext8:
|
||||
return 1
|
||||
case codes.Ext16:
|
||||
return 2
|
||||
case codes.Ext32:
|
||||
return 4
|
||||
}
|
||||
return 0
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package msgpack
|
||||
|
||||
type Marshaler interface {
|
||||
MarshalMsgpack() ([]byte, error)
|
||||
}
|
||||
|
||||
type Unmarshaler interface {
|
||||
UnmarshalMsgpack([]byte) error
|
||||
}
|
||||
|
||||
type CustomEncoder interface {
|
||||
EncodeMsgpack(*Encoder) error
|
||||
}
|
||||
|
||||
type CustomDecoder interface {
|
||||
DecodeMsgpack(*Decoder) error
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type tagOptions string
|
||||
|
||||
func (o tagOptions) Get(name string) (string, bool) {
|
||||
s := string(o)
|
||||
for len(s) > 0 {
|
||||
var next string
|
||||
idx := strings.IndexByte(s, ',')
|
||||
if idx >= 0 {
|
||||
s, next = s[:idx], s[idx+1:]
|
||||
}
|
||||
if strings.HasPrefix(s, name) {
|
||||
return s[len(name):], true
|
||||
}
|
||||
s = next
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (o tagOptions) Contains(name string) bool {
|
||||
_, ok := o.Get(name)
|
||||
return ok
|
||||
}
|
||||
|
||||
func parseTag(tag string) (string, tagOptions) {
|
||||
if idx := strings.IndexByte(tag, ','); idx != -1 {
|
||||
name := tag[:idx]
|
||||
if strings.IndexByte(name, ':') == -1 {
|
||||
return name, tagOptions(tag[idx+1:])
|
||||
}
|
||||
}
|
||||
|
||||
if strings.IndexByte(tag, ':') == -1 {
|
||||
return tag, ""
|
||||
}
|
||||
return "", tagOptions(tag)
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/vmihailenco/msgpack/codes"
|
||||
)
|
||||
|
||||
var timeExtId int8 = -1
|
||||
|
||||
func init() {
|
||||
timeType := reflect.TypeOf((*time.Time)(nil)).Elem()
|
||||
registerExt(timeExtId, timeType, encodeTimeValue, decodeTimeValue)
|
||||
}
|
||||
|
||||
func (e *Encoder) EncodeTime(tm time.Time) error {
|
||||
b := e.encodeTime(tm)
|
||||
if err := e.encodeExtLen(len(b)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.w.WriteByte(byte(timeExtId)); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.write(b)
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeTime(tm time.Time) []byte {
|
||||
secs := uint64(tm.Unix())
|
||||
if secs>>34 == 0 {
|
||||
data := uint64(tm.Nanosecond())<<34 | secs
|
||||
if data&0xffffffff00000000 == 0 {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, uint32(data))
|
||||
return b
|
||||
} else {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, data)
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
b := make([]byte, 12)
|
||||
binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond()))
|
||||
binary.BigEndian.PutUint64(b[4:], uint64(secs))
|
||||
return b
|
||||
}
|
||||
|
||||
func (d *Decoder) DecodeTime() (time.Time, error) {
|
||||
tm, err := d.decodeTime()
|
||||
if err != nil {
|
||||
return tm, err
|
||||
}
|
||||
|
||||
if tm.IsZero() {
|
||||
// Assume that zero time does not have timezone information.
|
||||
return tm.UTC(), nil
|
||||
}
|
||||
return tm, nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeTime() (time.Time, error) {
|
||||
extLen := d.extLen
|
||||
d.extLen = 0
|
||||
if extLen == 0 {
|
||||
c, err := d.readCode()
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
// Legacy format.
|
||||
if c == codes.FixedArrayLow|2 {
|
||||
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
|
||||
}
|
||||
|
||||
if codes.IsString(c) {
|
||||
s, err := d.string(c)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return time.Parse(time.RFC3339Nano, s)
|
||||
}
|
||||
|
||||
extLen, err = d.parseExtLen(c)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
// Skip ext id.
|
||||
_, err = d.s.ReadByte()
|
||||
if err != nil {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
b, err := d.readN(extLen)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
switch len(b) {
|
||||
case 4:
|
||||
sec := binary.BigEndian.Uint32(b)
|
||||
return time.Unix(int64(sec), 0), nil
|
||||
case 8:
|
||||
sec := binary.BigEndian.Uint64(b)
|
||||
nsec := int64(sec >> 34)
|
||||
sec &= 0x00000003ffffffff
|
||||
return time.Unix(int64(sec), nsec), nil
|
||||
case 12:
|
||||
nsec := binary.BigEndian.Uint32(b)
|
||||
sec := binary.BigEndian.Uint64(b[4:])
|
||||
return time.Unix(int64(sec), int64(nsec)), nil
|
||||
default:
|
||||
err = fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen)
|
||||
return time.Time{}, err
|
||||
}
|
||||
}
|
||||
|
||||
func encodeTimeValue(e *Encoder, v reflect.Value) error {
|
||||
tm := v.Interface().(time.Time)
|
||||
b := e.encodeTime(tm)
|
||||
return e.write(b)
|
||||
}
|
||||
|
||||
func decodeTimeValue(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,307 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
var customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem()
|
||||
var customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem()
|
||||
|
||||
var marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||
|
||||
type encoderFunc func(*Encoder, reflect.Value) error
|
||||
type decoderFunc func(*Decoder, reflect.Value) error
|
||||
|
||||
var typEncMap = make(map[reflect.Type]encoderFunc)
|
||||
var typDecMap = make(map[reflect.Type]decoderFunc)
|
||||
|
||||
// Register registers encoder and decoder functions for a value.
|
||||
// This is low level API and in most cases you should prefer implementing
|
||||
// Marshaler/CustomEncoder and Unmarshaler/CustomDecoder interfaces.
|
||||
func Register(value interface{}, enc encoderFunc, dec decoderFunc) {
|
||||
typ := reflect.TypeOf(value)
|
||||
if enc != nil {
|
||||
typEncMap[typ] = enc
|
||||
}
|
||||
if dec != nil {
|
||||
typDecMap[typ] = dec
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var structs = newStructCache(false)
|
||||
var jsonStructs = newStructCache(true)
|
||||
|
||||
type structCache struct {
|
||||
mu sync.RWMutex
|
||||
m map[reflect.Type]*fields
|
||||
|
||||
useJSONTag bool
|
||||
}
|
||||
|
||||
func newStructCache(useJSONTag bool) *structCache {
|
||||
return &structCache{
|
||||
m: make(map[reflect.Type]*fields),
|
||||
|
||||
useJSONTag: useJSONTag,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *structCache) Fields(typ reflect.Type) *fields {
|
||||
m.mu.RLock()
|
||||
fs, ok := m.m[typ]
|
||||
m.mu.RUnlock()
|
||||
if ok {
|
||||
return fs
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
fs, ok = m.m[typ]
|
||||
if !ok {
|
||||
fs = getFields(typ, m.useJSONTag)
|
||||
m.m[typ] = fs
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
return fs
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type field struct {
|
||||
name string
|
||||
index []int
|
||||
omitEmpty bool
|
||||
encoder encoderFunc
|
||||
decoder decoderFunc
|
||||
}
|
||||
|
||||
func (f *field) value(v reflect.Value) reflect.Value {
|
||||
return fieldByIndex(v, f.index)
|
||||
}
|
||||
|
||||
func (f *field) Omit(strct reflect.Value) bool {
|
||||
return f.omitEmpty && isEmptyValue(f.value(strct))
|
||||
}
|
||||
|
||||
func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error {
|
||||
return f.encoder(e, f.value(strct))
|
||||
}
|
||||
|
||||
func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error {
|
||||
return f.decoder(d, f.value(strct))
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type fields struct {
|
||||
Table map[string]*field
|
||||
List []*field
|
||||
AsArray bool
|
||||
|
||||
hasOmitEmpty bool
|
||||
}
|
||||
|
||||
func newFields(numField int) *fields {
|
||||
return &fields{
|
||||
Table: make(map[string]*field, numField),
|
||||
List: make([]*field, 0, numField),
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *fields) Add(field *field) {
|
||||
fs.Table[field.name] = field
|
||||
fs.List = append(fs.List, field)
|
||||
if field.omitEmpty {
|
||||
fs.hasOmitEmpty = true
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *fields) OmitEmpty(strct reflect.Value) []*field {
|
||||
if !fs.hasOmitEmpty {
|
||||
return fs.List
|
||||
}
|
||||
|
||||
fields := make([]*field, 0, len(fs.List))
|
||||
for _, f := range fs.List {
|
||||
if !f.Omit(strct) {
|
||||
fields = append(fields, f)
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
func getFields(typ reflect.Type, useJSONTag bool) *fields {
|
||||
numField := typ.NumField()
|
||||
fs := newFields(numField)
|
||||
|
||||
var omitEmpty bool
|
||||
for i := 0; i < numField; i++ {
|
||||
f := typ.Field(i)
|
||||
|
||||
tag := f.Tag.Get("msgpack")
|
||||
if useJSONTag && tag == "" {
|
||||
tag = f.Tag.Get("json")
|
||||
}
|
||||
|
||||
name, opt := parseTag(tag)
|
||||
if name == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
if f.Name == "_msgpack" {
|
||||
if opt.Contains("asArray") {
|
||||
fs.AsArray = true
|
||||
}
|
||||
if opt.Contains("omitempty") {
|
||||
omitEmpty = true
|
||||
}
|
||||
}
|
||||
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
continue
|
||||
}
|
||||
|
||||
field := &field{
|
||||
name: name,
|
||||
index: f.Index,
|
||||
omitEmpty: omitEmpty || opt.Contains("omitempty"),
|
||||
encoder: getEncoder(f.Type),
|
||||
decoder: getDecoder(f.Type),
|
||||
}
|
||||
|
||||
if field.name == "" {
|
||||
field.name = f.Name
|
||||
}
|
||||
|
||||
if f.Anonymous {
|
||||
if opt.Contains("inline") {
|
||||
inlineFields(fs, f.Type, field, useJSONTag)
|
||||
continue
|
||||
}
|
||||
if autoinlineFields(fs, f.Type, field, useJSONTag) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
fs.Add(field)
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
var encodeStructValuePtr uintptr
|
||||
var decodeStructValuePtr uintptr
|
||||
|
||||
func init() {
|
||||
encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer()
|
||||
decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer()
|
||||
}
|
||||
|
||||
func inlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) {
|
||||
inlinedFields := getFields(typ, useJSONTag).List
|
||||
for _, field := range inlinedFields {
|
||||
if _, ok := fs.Table[field.name]; ok {
|
||||
// Don't inline shadowed fields.
|
||||
continue
|
||||
}
|
||||
field.index = append(f.index, field.index...)
|
||||
fs.Add(field)
|
||||
}
|
||||
}
|
||||
|
||||
func autoinlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) bool {
|
||||
var encoder encoderFunc
|
||||
var decoder decoderFunc
|
||||
|
||||
if typ.Kind() == reflect.Struct {
|
||||
encoder = f.encoder
|
||||
decoder = f.decoder
|
||||
} else {
|
||||
for typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
encoder = getEncoder(typ)
|
||||
decoder = getDecoder(typ)
|
||||
}
|
||||
if typ.Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if reflect.ValueOf(encoder).Pointer() != encodeStructValuePtr {
|
||||
return false
|
||||
}
|
||||
if reflect.ValueOf(decoder).Pointer() != decodeStructValuePtr {
|
||||
return false
|
||||
}
|
||||
|
||||
inlinedFields := getFields(typ, useJSONTag).List
|
||||
for _, field := range inlinedFields {
|
||||
if _, ok := fs.Table[field.name]; ok {
|
||||
// Don't inline shadowed fields.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for _, field := range inlinedFields {
|
||||
field.index = append(f.index, field.index...)
|
||||
fs.Add(field)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fieldByIndex(v reflect.Value, index []int) reflect.Value {
|
||||
if len(index) == 1 {
|
||||
return v.Field(index[0])
|
||||
}
|
||||
for i, x := range index {
|
||||
if i > 0 {
|
||||
var ok bool
|
||||
v, ok = indirectNew(v)
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
v = v.Field(x)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func indirectNew(v reflect.Value) (reflect.Value, bool) {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
if !v.CanSet() {
|
||||
return v, false
|
||||
}
|
||||
elemType := v.Type().Elem()
|
||||
if elemType.Kind() != reflect.Struct {
|
||||
return v, false
|
||||
}
|
||||
v.Set(reflect.New(elemType))
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
return v, true
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Package msgpack provides functions for serializing cty values in the
|
||||
// msgpack encoding, and decoding them again.
|
||||
//
|
||||
// If the same type information is provided both at encoding and decoding time
|
||||
// then values can be round-tripped without loss, except for capsule types
|
||||
// which are not currently supported.
|
||||
//
|
||||
// If any unknown values are passed to Marshal then they will be represented
|
||||
// using a msgpack extension with type code zero, which is understood by
|
||||
// the Unmarshal function within this package but will not be understood by
|
||||
// a generic (non-cty-aware) msgpack decoder. Ensure that no unknown values
|
||||
// are used if interoperability with other msgpack implementations is
|
||||
// required.
|
||||
package msgpack
|
|
@ -0,0 +1,31 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/vmihailenco/msgpack"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
type dynamicVal struct {
|
||||
Value cty.Value
|
||||
Path cty.Path
|
||||
}
|
||||
|
||||
func (dv *dynamicVal) MarshalMsgpack() ([]byte, error) {
|
||||
// Rather than defining a msgpack-specific serialization of types,
|
||||
// instead we use the existing JSON serialization.
|
||||
typeJSON, err := dv.Value.Type().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, dv.Path.NewErrorf("failed to serialize type: %s", err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
enc := msgpack.NewEncoder(&buf)
|
||||
enc.EncodeArrayLen(2)
|
||||
enc.EncodeBytes(typeJSON)
|
||||
err = marshal(dv.Value, dv.Value.Type(), dv.Path, enc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
var negativeInfinity = math.Inf(-1)
|
||||
var positiveInfinity = math.Inf(1)
|
|
@ -0,0 +1,207 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
"sort"
|
||||
|
||||
"github.com/vmihailenco/msgpack"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
)
|
||||
|
||||
// Marshal produces a msgpack serialization of the given value that
|
||||
// can be decoded into the given type later using Unmarshal.
|
||||
//
|
||||
// The given value must conform to the given type, or an error will
|
||||
// be returned.
|
||||
func Marshal(val cty.Value, ty cty.Type) ([]byte, error) {
|
||||
errs := val.Type().TestConformance(ty)
|
||||
if errs != nil {
|
||||
// Attempt a conversion
|
||||
var err error
|
||||
val, err = convert.Convert(val, ty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// From this point onward, val can be assumed to be conforming to t.
|
||||
|
||||
var path cty.Path
|
||||
var buf bytes.Buffer
|
||||
enc := msgpack.NewEncoder(&buf)
|
||||
|
||||
err := marshal(val, ty, path, enc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func marshal(val cty.Value, ty cty.Type, path cty.Path, enc *msgpack.Encoder) error {
|
||||
// If we're going to decode as DynamicPseudoType then we need to save
|
||||
// dynamic type information to recover the real type.
|
||||
if ty == cty.DynamicPseudoType && val.Type() != cty.DynamicPseudoType {
|
||||
return marshalDynamic(val, path, enc)
|
||||
}
|
||||
|
||||
if !val.IsKnown() {
|
||||
err := enc.Encode(unknownVal)
|
||||
if err != nil {
|
||||
return path.NewError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if val.IsNull() {
|
||||
err := enc.EncodeNil()
|
||||
if err != nil {
|
||||
return path.NewError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// The caller should've guaranteed that the given val is conformant with
|
||||
// the given type ty, so we'll proceed under that assumption here.
|
||||
switch {
|
||||
case ty.IsPrimitiveType():
|
||||
switch ty {
|
||||
case cty.String:
|
||||
err := enc.EncodeString(val.AsString())
|
||||
if err != nil {
|
||||
return path.NewError(err)
|
||||
}
|
||||
return nil
|
||||
case cty.Number:
|
||||
var err error
|
||||
switch {
|
||||
case val.RawEquals(cty.PositiveInfinity):
|
||||
err = enc.EncodeFloat64(positiveInfinity)
|
||||
case val.RawEquals(cty.NegativeInfinity):
|
||||
err = enc.EncodeFloat64(negativeInfinity)
|
||||
default:
|
||||
bf := val.AsBigFloat()
|
||||
if iv, acc := bf.Int64(); acc == big.Exact {
|
||||
err = enc.EncodeInt(iv)
|
||||
} else if fv, acc := bf.Float64(); acc == big.Exact {
|
||||
err = enc.EncodeFloat64(fv)
|
||||
} else {
|
||||
err = enc.EncodeString(bf.Text('f', -1))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return path.NewError(err)
|
||||
}
|
||||
return nil
|
||||
case cty.Bool:
|
||||
err := enc.EncodeBool(val.True())
|
||||
if err != nil {
|
||||
return path.NewError(err)
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
panic("unsupported primitive type")
|
||||
}
|
||||
case ty.IsListType(), ty.IsSetType():
|
||||
enc.EncodeArrayLen(val.LengthInt())
|
||||
ety := ty.ElementType()
|
||||
it := val.ElementIterator()
|
||||
path := append(path, nil) // local override of 'path' with extra element
|
||||
for it.Next() {
|
||||
ek, ev := it.Element()
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: ek,
|
||||
}
|
||||
err := marshal(ev, ety, path, enc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case ty.IsMapType():
|
||||
enc.EncodeMapLen(val.LengthInt())
|
||||
ety := ty.ElementType()
|
||||
it := val.ElementIterator()
|
||||
path := append(path, nil) // local override of 'path' with extra element
|
||||
for it.Next() {
|
||||
ek, ev := it.Element()
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: ek,
|
||||
}
|
||||
var err error
|
||||
err = marshal(ek, ek.Type(), path, enc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = marshal(ev, ety, path, enc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case ty.IsTupleType():
|
||||
etys := ty.TupleElementTypes()
|
||||
it := val.ElementIterator()
|
||||
path := append(path, nil) // local override of 'path' with extra element
|
||||
i := 0
|
||||
enc.EncodeArrayLen(len(etys))
|
||||
for it.Next() {
|
||||
ety := etys[i]
|
||||
ek, ev := it.Element()
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: ek,
|
||||
}
|
||||
err := marshal(ev, ety, path, enc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i++
|
||||
}
|
||||
return nil
|
||||
case ty.IsObjectType():
|
||||
atys := ty.AttributeTypes()
|
||||
path := append(path, nil) // local override of 'path' with extra element
|
||||
|
||||
names := make([]string, 0, len(atys))
|
||||
for k := range atys {
|
||||
names = append(names, k)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
enc.EncodeMapLen(len(names))
|
||||
|
||||
for _, k := range names {
|
||||
aty := atys[k]
|
||||
av := val.GetAttr(k)
|
||||
path[len(path)-1] = cty.GetAttrStep{
|
||||
Name: k,
|
||||
}
|
||||
var err error
|
||||
err = marshal(cty.StringVal(k), cty.String, path, enc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = marshal(av, aty, path, enc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case ty.IsCapsuleType():
|
||||
return path.NewErrorf("capsule types not supported for msgpack encoding")
|
||||
default:
|
||||
// should never happen
|
||||
return path.NewErrorf("cannot msgpack-serialize %s", ty.FriendlyName())
|
||||
}
|
||||
}
|
||||
|
||||
// marshalDynamic adds an extra wrapping object containing dynamic type
|
||||
// information for the given value.
|
||||
func marshalDynamic(val cty.Value, path cty.Path, enc *msgpack.Encoder) error {
|
||||
dv := dynamicVal{
|
||||
Value: val,
|
||||
Path: path,
|
||||
}
|
||||
return enc.Encode(&dv)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package msgpack
|
||||
|
||||
type unknownType struct{}
|
||||
|
||||
var unknownVal = unknownType{}
|
||||
|
||||
// unknownValBytes is the raw bytes of the msgpack fixext1 value we
|
||||
// write to represent an unknown value. It's an extension value of
|
||||
// type zero whose value is irrelevant. Since it's irrelevant, we
|
||||
// set it to a single byte whose value is also zero, since that's
|
||||
// the most compact possible representation.
|
||||
var unknownValBytes = []byte{0xd4, 0, 0}
|
||||
|
||||
func (uv unknownType) MarshalMsgpack() ([]byte, error) {
|
||||
return unknownValBytes, nil
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
package msgpack
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/vmihailenco/msgpack"
|
||||
msgpackCodes "github.com/vmihailenco/msgpack/codes"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// Unmarshal interprets the given bytes as a msgpack-encoded cty Value of
|
||||
// the given type, returning the result.
|
||||
//
|
||||
// If an error is returned, the error is written with a hypothetical
|
||||
// end-user that wrote the msgpack file as its audience, using cty type
|
||||
// system concepts rather than Go type system concepts.
|
||||
func Unmarshal(b []byte, ty cty.Type) (cty.Value, error) {
|
||||
r := bytes.NewReader(b)
|
||||
dec := msgpack.NewDecoder(r)
|
||||
|
||||
var path cty.Path
|
||||
return unmarshal(dec, ty, path)
|
||||
}
|
||||
|
||||
func unmarshal(dec *msgpack.Decoder, ty cty.Type, path cty.Path) (cty.Value, error) {
|
||||
peek, err := dec.PeekCode()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewError(err)
|
||||
}
|
||||
if msgpackCodes.IsExt(peek) {
|
||||
// We just assume _all_ extensions are unknown values,
|
||||
// since we don't have any other extensions.
|
||||
return cty.UnknownVal(ty), nil
|
||||
}
|
||||
if ty == cty.DynamicPseudoType {
|
||||
return unmarshalDynamic(dec, path)
|
||||
}
|
||||
if peek == msgpackCodes.Nil {
|
||||
return cty.NullVal(ty), nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case ty.IsPrimitiveType():
|
||||
val, err := unmarshalPrimitive(dec, ty, path)
|
||||
if err != nil {
|
||||
return cty.NilVal, err
|
||||
}
|
||||
return val, nil
|
||||
case ty.IsListType():
|
||||
return unmarshalList(dec, ty.ElementType(), path)
|
||||
case ty.IsSetType():
|
||||
return unmarshalSet(dec, ty.ElementType(), path)
|
||||
case ty.IsMapType():
|
||||
return unmarshalMap(dec, ty.ElementType(), path)
|
||||
case ty.IsTupleType():
|
||||
return unmarshalTuple(dec, ty.TupleElementTypes(), path)
|
||||
case ty.IsObjectType():
|
||||
return unmarshalObject(dec, ty.AttributeTypes(), path)
|
||||
default:
|
||||
return cty.NilVal, path.NewErrorf("unsupported type %s", ty.FriendlyName())
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalPrimitive(dec *msgpack.Decoder, ty cty.Type, path cty.Path) (cty.Value, error) {
|
||||
switch ty {
|
||||
case cty.Bool:
|
||||
rv, err := dec.DecodeBool()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("bool is required")
|
||||
}
|
||||
return cty.BoolVal(rv), nil
|
||||
case cty.Number:
|
||||
// Marshal will try int and float first, if the value can be
|
||||
// losslessly represented in these encodings, and then fall
|
||||
// back on a string if the number is too large or too precise.
|
||||
peek, err := dec.PeekCode()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("number is required")
|
||||
}
|
||||
|
||||
fmt.Printf("peek %x\n", peek)
|
||||
|
||||
if msgpackCodes.IsFixedNum(peek) {
|
||||
rv, err := dec.DecodeInt64()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("number is required")
|
||||
}
|
||||
return cty.NumberIntVal(rv), nil
|
||||
}
|
||||
|
||||
switch peek {
|
||||
case msgpackCodes.Int8, msgpackCodes.Int16, msgpackCodes.Int32, msgpackCodes.Int64:
|
||||
rv, err := dec.DecodeInt64()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("number is required")
|
||||
}
|
||||
return cty.NumberIntVal(rv), nil
|
||||
case msgpackCodes.Uint8, msgpackCodes.Uint16, msgpackCodes.Uint32, msgpackCodes.Uint64:
|
||||
rv, err := dec.DecodeUint64()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("number is required")
|
||||
}
|
||||
return cty.NumberUIntVal(rv), nil
|
||||
case msgpackCodes.Float, msgpackCodes.Double:
|
||||
rv, err := dec.DecodeFloat64()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("number is required")
|
||||
}
|
||||
return cty.NumberFloatVal(rv), nil
|
||||
default:
|
||||
rv, err := dec.DecodeString()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("number is required")
|
||||
}
|
||||
bf := &big.Float{}
|
||||
_, _, err = bf.Parse(rv, 10)
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("number is required")
|
||||
}
|
||||
return cty.NumberVal(bf), nil
|
||||
}
|
||||
case cty.String:
|
||||
rv, err := dec.DecodeString()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("string is required")
|
||||
}
|
||||
return cty.StringVal(rv), nil
|
||||
default:
|
||||
// should never happen
|
||||
panic("unsupported primitive type")
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalList(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) {
|
||||
length, err := dec.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("a list is required")
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
return cty.ListValEmpty(ety), nil
|
||||
}
|
||||
|
||||
vals := make([]cty.Value, 0, length)
|
||||
path = append(path, nil)
|
||||
for i := 0; i < length; i++ {
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(int64(i)),
|
||||
}
|
||||
|
||||
val, err := unmarshal(dec, ety, path)
|
||||
if err != nil {
|
||||
return cty.DynamicVal, err
|
||||
}
|
||||
|
||||
vals = append(vals, val)
|
||||
}
|
||||
|
||||
return cty.ListVal(vals), nil
|
||||
}
|
||||
|
||||
func unmarshalSet(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) {
|
||||
length, err := dec.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("a set is required")
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
return cty.SetValEmpty(ety), nil
|
||||
}
|
||||
|
||||
vals := make([]cty.Value, 0, length)
|
||||
path = append(path, nil)
|
||||
for i := 0; i < length; i++ {
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(int64(i)),
|
||||
}
|
||||
|
||||
val, err := unmarshal(dec, ety, path)
|
||||
if err != nil {
|
||||
return cty.DynamicVal, err
|
||||
}
|
||||
|
||||
vals = append(vals, val)
|
||||
}
|
||||
|
||||
return cty.SetVal(vals), nil
|
||||
}
|
||||
|
||||
func unmarshalMap(dec *msgpack.Decoder, ety cty.Type, path cty.Path) (cty.Value, error) {
|
||||
length, err := dec.DecodeMapLen()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("a map is required")
|
||||
}
|
||||
|
||||
if length == 0 {
|
||||
return cty.MapValEmpty(ety), nil
|
||||
}
|
||||
|
||||
vals := make(map[string]cty.Value, length)
|
||||
path = append(path, nil)
|
||||
for i := 0; i < length; i++ {
|
||||
key, err := dec.DecodeString()
|
||||
if err != nil {
|
||||
path[:len(path)-1].NewErrorf("non-string key in map")
|
||||
}
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.StringVal(key),
|
||||
}
|
||||
|
||||
val, err := unmarshal(dec, ety, path)
|
||||
if err != nil {
|
||||
return cty.DynamicVal, err
|
||||
}
|
||||
|
||||
vals[key] = val
|
||||
}
|
||||
|
||||
return cty.MapVal(vals), nil
|
||||
}
|
||||
|
||||
func unmarshalTuple(dec *msgpack.Decoder, etys []cty.Type, path cty.Path) (cty.Value, error) {
|
||||
length, err := dec.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("a tuple is required")
|
||||
}
|
||||
|
||||
if length != len(etys) {
|
||||
return cty.DynamicVal, path.NewErrorf("a tuple of length %d is required", len(etys))
|
||||
}
|
||||
|
||||
vals := make([]cty.Value, 0, length)
|
||||
path = append(path, nil)
|
||||
for i := 0; i < length; i++ {
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.NumberIntVal(int64(i)),
|
||||
}
|
||||
ety := etys[i]
|
||||
|
||||
val, err := unmarshal(dec, ety, path)
|
||||
if err != nil {
|
||||
return cty.DynamicVal, err
|
||||
}
|
||||
|
||||
vals = append(vals, val)
|
||||
}
|
||||
|
||||
return cty.TupleVal(vals), nil
|
||||
}
|
||||
|
||||
func unmarshalObject(dec *msgpack.Decoder, atys map[string]cty.Type, path cty.Path) (cty.Value, error) {
|
||||
length, err := dec.DecodeMapLen()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewErrorf("an object is required")
|
||||
}
|
||||
|
||||
if length != len(atys) {
|
||||
return cty.DynamicVal, path.NewErrorf("an object with %d attributes is required", len(atys))
|
||||
}
|
||||
|
||||
vals := make(map[string]cty.Value, length)
|
||||
path = append(path, nil)
|
||||
for i := 0; i < length; i++ {
|
||||
key, err := dec.DecodeString()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path[:len(path)-1].NewErrorf("all keys must be strings")
|
||||
}
|
||||
|
||||
path[len(path)-1] = cty.IndexStep{
|
||||
Key: cty.StringVal(key),
|
||||
}
|
||||
aty, exists := atys[key]
|
||||
if !exists {
|
||||
return cty.DynamicVal, path.NewErrorf("unsupported attribute")
|
||||
}
|
||||
|
||||
val, err := unmarshal(dec, aty, path)
|
||||
if err != nil {
|
||||
return cty.DynamicVal, err
|
||||
}
|
||||
|
||||
vals[key] = val
|
||||
}
|
||||
|
||||
return cty.ObjectVal(vals), nil
|
||||
}
|
||||
|
||||
func unmarshalDynamic(dec *msgpack.Decoder, path cty.Path) (cty.Value, error) {
|
||||
length, err := dec.DecodeArrayLen()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewError(err)
|
||||
}
|
||||
|
||||
if length != 2 {
|
||||
return cty.DynamicVal, path.NewErrorf(
|
||||
"dynamic value array must have exactly two elements",
|
||||
)
|
||||
}
|
||||
|
||||
typeJSON, err := dec.DecodeBytes()
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewError(err)
|
||||
}
|
||||
var ty cty.Type
|
||||
err = (&ty).UnmarshalJSON(typeJSON)
|
||||
if err != nil {
|
||||
return cty.DynamicVal, path.NewError(err)
|
||||
}
|
||||
|
||||
return unmarshal(dec, ty, path)
|
||||
}
|
|
@ -2416,7 +2416,19 @@
|
|||
"revisionTime": "2017-06-05T21:53:11Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "VNhImVFfxO7x8Kp1BrM2zgp4vi0=",
|
||||
"checksumSHA1": "t9A/EE2GhHFPHzK+ksAKgKW9ZC8=",
|
||||
"path": "github.com/vmihailenco/msgpack",
|
||||
"revision": "b5e691b1eb52a28c05e67ab9df303626c095c23b",
|
||||
"revisionTime": "2018-06-13T09:15:15Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "OcTSGT2v7/2saIGq06nDhEZwm8I=",
|
||||
"path": "github.com/vmihailenco/msgpack/codes",
|
||||
"revision": "b5e691b1eb52a28c05e67ab9df303626c095c23b",
|
||||
"revisionTime": "2018-06-13T09:15:15Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "iHiMTBffQvWYlOLu3130JXuQpgQ=",
|
||||
"path": "github.com/xanzy/ssh-agent",
|
||||
"revision": "640f0ab560aeb89d523bb6ac322b1244d5c3796c",
|
||||
"revisionTime": "2018-07-03T18:17:07Z"
|
||||
|
@ -2463,6 +2475,12 @@
|
|||
"revision": "ba988ce11d9994867838957d4c40bb1ad78b433d",
|
||||
"revisionTime": "2018-05-24T00:26:36Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "55JE44+FFgAo5WZEC23gp4X5tak=",
|
||||
"path": "github.com/zclconf/go-cty/cty/msgpack",
|
||||
"revision": "ba988ce11d9994867838957d4c40bb1ad78b433d",
|
||||
"revisionTime": "2018-05-24T00:26:36Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "y5Sk+n6SOspFj8mlyb8swr4DMIs=",
|
||||
"path": "github.com/zclconf/go-cty/cty/set",
|
||||
|
|
Loading…
Reference in New Issue