Commit 2a5d6348 authored by Martin Atkins's avatar Martin Atkins
Browse files

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
parent 40816dcd
Showing with 3156 additions and 0 deletions
+3156 -0
## 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.
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.
all:
go test ./...
env GOOS=linux GOARCH=386 go test ./...
go test ./... -short -race
go vet
# 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)
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
}
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
}
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
}
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
}
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
}
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
}
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)
}
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())
}
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
}
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
}
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())
}
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
}
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())
}
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
}
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
}
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)
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment