Unverified Commit e6e35f20 authored by Kristin Laemmert's avatar Kristin Laemmert Committed by GitHub
Browse files

deps: bump go-cty version (#26079)

go-cty v1.6.1 fixes a panic in the `element` function when called with a negative offset.
parent b4017f69
Showing with 546 additions and 184 deletions
+546 -184
......@@ -120,11 +120,10 @@ require (
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect
github.com/tombuildsstuff/giovanni v0.12.0
github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 // indirect
github.com/vmihailenco/msgpack v4.0.1+incompatible // indirect
github.com/xanzy/ssh-agent v0.2.1
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
github.com/zclconf/go-cty v1.5.1
github.com/zclconf/go-cty v1.6.1
github.com/zclconf/go-cty-yaml v1.0.2
go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect
......
......@@ -486,9 +486,12 @@ github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 h1:cMjKdf4PxEBN9K5HaD9UM
github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU=
github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 h1:MPPkRncZLN9Kh4MEFmbnK4h3BD7AUmskWv2+EeZJCCs=
......@@ -498,8 +501,8 @@ github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6Ut
github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.5.1 h1:oALUZX+aJeEBUe2a1+uD2+UTaYfEjnKFDEMRydkGvWE=
github.com/zclconf/go-cty v1.5.1/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
github.com/zclconf/go-cty v1.6.1 h1:wHtZ+LSSQVwUSb+XIJ5E9hgAQxyWATZsAWT+ESJ9dQ0=
github.com/zclconf/go-cty v1.6.1/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o=
github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0=
github.com/zclconf/go-cty-yaml v1.0.2/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
......@@ -556,6 +559,7 @@ golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -630,6 +634,8 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
......
sudo: false
language: go
go:
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- tip
matrix:
allow_failures:
- go: tip
install:
- go get gopkg.in/check.v1
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)
}
run:
concurrency: 8
deadline: 5m
tests: false
linters:
enable-all: true
disable:
- gochecknoglobals
- gocognit
- godox
- wsl
- funlen
sudo: false
language: go
go:
- 1.11.x
- 1.12.x
- 1.13.x
- 1.14.x
- tip
matrix:
allow_failures:
- go: tip
env:
- GO111MODULE=on
go_import_path: github.com/vmihailenco/msgpack
before_install:
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.21.0
## 3.4
## v4
- Encode, Decode, Marshal, and Unmarshal are changed to accept single argument. EncodeMulti and DecodeMulti are added as replacement.
- Added EncodeInt8/16/32/64 and EncodeUint8/16/32/64.
......
all:
go test ./...
env GOOS=linux GOARCH=386 go test ./...
go test ./... -short -race
go vet
go test ./... -run=NONE -bench=. -benchmem
env GOOS=linux GOARCH=386 go test ./...
golangci-lint run
......@@ -8,10 +8,10 @@ Supports:
- 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"`.
- Renaming fields via `msgpack:"my_field_name"` and alias via `msgpack:"alias:another_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).
- Encoding/decoding all [structs as arrays](https://godoc.org/github.com/vmihailenco/msgpack#Encoder.UseArrayForStructs) 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).
......@@ -20,15 +20,18 @@ Examples: https://godoc.org/github.com/vmihailenco/msgpack#pkg-examples.
## Installation
Install:
This project uses [Go Modules](https://github.com/golang/go/wiki/Modules) and semantic import versioning since v4:
```shell
go get -u github.com/vmihailenco/msgpack
``` shell
go mod init github.com/my/repo
go get github.com/vmihailenco/msgpack/v4
```
## Quickstart
```go
``` go
import "github.com/vmihailenco/msgpack/v4"
func ExampleMarshal() {
type Item struct {
Foo string
......@@ -66,4 +69,4 @@ Please go through [examples](https://godoc.org/github.com/vmihailenco/msgpack#pk
## See also
- [Golang PostgreSQL ORM](https://github.com/go-pg/pg)
- [Golang message task queue](https://github.com/go-msgqueue/msgqueue)
- [Golang message task queue](https://github.com/vmihailenco/taskq)
......@@ -77,6 +77,10 @@ func IsString(c Code) bool {
return IsFixedString(c) || c == Str8 || c == Str16 || c == Str32
}
func IsBin(c Code) bool {
return c == Bin8 || c == Bin16 || c == Bin32
}
func IsFixedExt(c Code) bool {
return c >= FixExt1 && c <= FixExt16
}
......
......@@ -7,35 +7,55 @@ import (
"fmt"
"io"
"reflect"
"sync"
"time"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
const bytesAllocLimit = 1024 * 1024 // 1mb
const (
looseIfaceFlag uint32 = 1 << iota
decodeUsingJSONFlag
disallowUnknownFieldsFlag
)
const (
bytesAllocLimit = 1e6 // 1mb
sliceAllocLimit = 1e4
maxMapSize = 1e6
)
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)
var decPool = sync.Pool{
New: func() interface{} {
return NewDecoder(nil)
},
}
// 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)
dec := decPool.Get().(*Decoder)
if r, ok := dec.r.(*bytes.Reader); ok {
r.Reset(data)
} else {
dec.Reset(bytes.NewReader(data))
}
err := dec.Decode(v)
decPool.Put(dec)
return err
}
// A Decoder reads and decodes MessagePack values from an input stream.
type Decoder struct {
r io.Reader
s io.ByteScanner
......@@ -44,9 +64,8 @@ type Decoder struct {
extLen int
rec []byte // accumulates read data if not nil
useLoose bool
useJSONTag bool
intern []string
flags uint32
decodeMapFunc func(*Decoder) (interface{}, error)
}
......@@ -56,41 +75,80 @@ type Decoder struct {
// 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{
buf: makeBuffer(),
}
d.resetReader(r)
d := new(Decoder)
d.Reset(r)
return d
}
// Reset discards any buffered data, resets all state, and switches the buffered
// reader to read from r.
func (d *Decoder) Reset(r io.Reader) {
if br, ok := r.(bufReader); ok {
d.r = br
d.s = br
} else if br, ok := d.r.(*bufio.Reader); ok {
br.Reset(r)
} else {
br := bufio.NewReader(r)
d.r = br
d.s = br
}
if d.intern != nil {
d.intern = d.intern[:0]
}
//TODO:
//d.useLoose = false
//d.useJSONTag = false
//d.disallowUnknownFields = false
//d.decodeMapFunc = nil
}
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
func (d *Decoder) UseDecodeInterfaceLoose(on bool) *Decoder {
if on {
d.flags |= looseIfaceFlag
} else {
d.flags &= ^looseIfaceFlag
}
return d
}
// 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
func (d *Decoder) UseJSONTag(on bool) *Decoder {
if on {
d.flags |= decodeUsingJSONFlag
} else {
d.flags &= ^decodeUsingJSONFlag
}
return d
}
func (d *Decoder) Reset(r io.Reader) error {
d.resetReader(r)
return nil
// DisallowUnknownFields causes the Decoder to return an error when the destination
// is a struct and the input contains object keys which do not match any
// non-ignored, exported fields in the destination.
func (d *Decoder) DisallowUnknownFields() {
if true {
d.flags |= disallowUnknownFieldsFlag
} else {
d.flags &= ^disallowUnknownFieldsFlag
}
}
func (d *Decoder) resetReader(r io.Reader) {
reader := newBufReader(r)
d.r = reader
d.s = reader
// Buffered returns a reader of the data remaining in the Decoder's buffer.
// The reader is valid until the next call to Decode.
func (d *Decoder) Buffered() io.Reader {
return d.r
}
//nolint:gocyclo
func (d *Decoder) Decode(v interface{}) error {
var err error
switch v := v.(type) {
......@@ -211,7 +269,7 @@ func (d *Decoder) DecodeMulti(v ...interface{}) error {
}
func (d *Decoder) decodeInterfaceCond() (interface{}, error) {
if d.useLoose {
if d.flags&looseIfaceFlag != 0 {
return d.DecodeInterfaceLoose()
}
return d.DecodeInterface()
......@@ -263,6 +321,14 @@ func (d *Decoder) bool(c codes.Code) (bool, error) {
return false, fmt.Errorf("msgpack: invalid code=%x decoding bool", c)
}
func (d *Decoder) DecodeDuration() (time.Duration, error) {
n, err := d.DecodeInt64()
if err != nil {
return 0, err
}
return time.Duration(n), nil
}
// DecodeInterface decodes value into interface. It returns following types:
// - nil,
// - bool,
......@@ -356,7 +422,7 @@ func (d *Decoder) DecodeInterfaceLoose() (interface{}, error) {
}
if codes.IsFixedNum(c) {
return int64(c), nil
return int64(int8(c)), nil
}
if codes.IsFixedMap(c) {
err = d.s.UnreadByte()
......@@ -412,11 +478,14 @@ func (d *Decoder) Skip() error {
if codes.IsFixedNum(c) {
return nil
} else if codes.IsFixedMap(c) {
}
if codes.IsFixedMap(c) {
return d.skipMap(c)
} else if codes.IsFixedArray(c) {
}
if codes.IsFixedArray(c) {
return d.skipSlice(c)
} else if codes.IsFixedString(c) {
}
if codes.IsFixedString(c) {
return d.skipBytes(c)
}
......@@ -480,21 +549,23 @@ func (d *Decoder) readFull(b []byte) error {
return err
}
if d.rec != nil {
//TODO: read directly into d.rec?
d.rec = append(d.rec, b...)
}
return nil
}
func (d *Decoder) readN(n int) ([]byte, error) {
buf, err := readN(d.r, d.buf, n)
var err error
d.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...)
//TODO: read directly into d.rec?
d.rec = append(d.rec, d.buf...)
}
return buf, nil
return d.buf, nil
}
func readN(r io.Reader, b []byte, n int) ([]byte, error) {
......@@ -502,10 +573,13 @@ func readN(r io.Reader, b []byte, n int) ([]byte, error) {
if n == 0 {
return make([]byte, 0), nil
}
if n <= bytesAllocLimit {
b = make([]byte, n)
} else {
b = make([]byte, bytesAllocLimit)
switch {
case n < 64:
b = make([]byte, 0, 64)
case n <= bytesAllocLimit:
b = make([]byte, 0, n)
default:
b = make([]byte, 0, bytesAllocLimit)
}
}
......@@ -518,15 +592,12 @@ func readN(r io.Reader, b []byte, n int) ([]byte, error) {
var pos int
for {
alloc := n - len(b)
if alloc > bytesAllocLimit {
alloc = bytesAllocLimit
}
alloc := min(n-len(b), bytesAllocLimit)
b = append(b, make([]byte, alloc)...)
_, err := io.ReadFull(r, b[pos:])
if err != nil {
return nil, err
return b, err
}
if len(b) == n {
......@@ -538,7 +609,7 @@ func readN(r io.Reader, b []byte, n int) ([]byte, error) {
return b, nil
}
func min(a, b int) int {
func min(a, b int) int { //nolint:unparam
if a <= b {
return a
}
......
......@@ -5,18 +5,18 @@ import (
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/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 (
mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil))
mapStringStringType = mapStringStringPtrType.Elem()
)
var errInvalidCode = errors.New("invalid code")
var (
mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil))
mapStringInterfaceType = mapStringInterfacePtrType.Elem()
)
func decodeMapValue(d *Decoder, v reflect.Value) error {
size, err := d.DecodeMapLen()
......@@ -106,6 +106,8 @@ func (d *Decoder) _mapLen(c codes.Code) (int, error) {
return 0, errInvalidCode
}
var errInvalidCode = errors.New("invalid code")
func expandInvalidCodeMapLenError(c codes.Code, err error) error {
if err == errInvalidCode {
return fmt.Errorf("msgpack: invalid code=%x decoding map length", c)
......@@ -130,7 +132,7 @@ func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error {
m := *ptr
if m == nil {
*ptr = make(map[string]string, min(size, mapElemsAllocLimit))
*ptr = make(map[string]string, min(size, maxMapSize))
m = *ptr
}
......@@ -166,7 +168,7 @@ func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error
m := *ptr
if m == nil {
*ptr = make(map[string]interface{}, min(n, mapElemsAllocLimit))
*ptr = make(map[string]interface{}, min(n, maxMapSize))
m = *ptr
}
......@@ -185,6 +187,8 @@ func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error
return nil
}
var errUnsupportedMapKey = errors.New("msgpack: unsupported map key")
func (d *Decoder) DecodeMap() (interface{}, error) {
if d.decodeMapFunc != nil {
return d.decodeMapFunc(d)
......@@ -206,7 +210,7 @@ func (d *Decoder) DecodeMap() (interface{}, error) {
return nil, err
}
if codes.IsString(code) {
if codes.IsString(code) || codes.IsBin(code) {
return d.decodeMapStringInterfaceSize(size)
}
......@@ -222,6 +226,11 @@ func (d *Decoder) DecodeMap() (interface{}, error) {
keyType := reflect.TypeOf(key)
valueType := reflect.TypeOf(value)
if !keyType.Comparable() {
return nil, errUnsupportedMapKey
}
mapType := reflect.MapOf(keyType, valueType)
mapValue := reflect.MakeMap(mapType)
......@@ -237,7 +246,7 @@ func (d *Decoder) DecodeMap() (interface{}, error) {
}
func (d *Decoder) decodeMapStringInterfaceSize(size int) (map[string]interface{}, error) {
m := make(map[string]interface{}, min(size, mapElemsAllocLimit))
m := make(map[string]interface{}, min(size, maxMapSize))
for i := 0; i < size; i++ {
mk, err := d.DecodeString()
if err != nil {
......@@ -294,7 +303,7 @@ func decodeStructValue(d *Decoder, v reflect.Value) error {
}
var fields *fields
if d.useJSONTag {
if d.flags&decodeUsingJSONFlag != 0 {
fields = jsonStructs.Fields(v.Type())
} else {
fields = structs.Fields(v.Type())
......@@ -309,12 +318,14 @@ func decodeStructValue(d *Decoder, v reflect.Value) error {
return err
}
}
// Skip extra values.
for i := len(fields.List); i < n; i++ {
if err := d.Skip(); err != nil {
return err
}
}
return nil
}
......@@ -323,14 +334,15 @@ func decodeStructValue(d *Decoder, v reflect.Value) error {
if err != nil {
return err
}
if f := fields.Table[name]; f != nil {
if f := fields.Map[name]; f != nil {
if err := f.DecodeValue(d, v); err != nil {
return err
}
} else {
if err := d.Skip(); err != nil {
return err
}
} else if d.flags&disallowUnknownFieldsFlag != 0 {
return fmt.Errorf("msgpack: unknown field %q", name)
} else if err := d.Skip(); err != nil {
return err
}
}
......
......@@ -5,7 +5,7 @@ import (
"math"
"reflect"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
func (d *Decoder) skipN(n int) error {
......
......@@ -5,7 +5,7 @@ import (
"strconv"
"strings"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
type queryResult struct {
......
......@@ -4,11 +4,9 @@ import (
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
const sliceElemsAllocLimit = 1e4
var sliceStringPtrType = reflect.TypeOf((*[]string)(nil))
// DecodeArrayLen decodes array length. Length is -1 when array is nil.
......@@ -51,7 +49,7 @@ func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
return nil
}
ss := setStringsCap(*ptr, n)
ss := makeStrings(*ptr, n)
for i := 0; i < n; i++ {
s, err := d.DecodeString()
if err != nil {
......@@ -64,9 +62,9 @@ func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
return nil
}
func setStringsCap(s []string, n int) []string {
if n > sliceElemsAllocLimit {
n = sliceElemsAllocLimit
func makeStrings(s []string, n int) []string {
if n > sliceAllocLimit {
n = sliceAllocLimit
}
if s == nil {
......@@ -107,8 +105,8 @@ func decodeSliceValue(d *Decoder, v reflect.Value) error {
if i >= v.Len() {
v.Set(growSliceValue(v, n))
}
sv := v.Index(i)
if err := d.DecodeValue(sv); err != nil {
elem := v.Index(i)
if err := d.DecodeValue(elem); err != nil {
return err
}
}
......@@ -118,8 +116,8 @@ func decodeSliceValue(d *Decoder, v reflect.Value) error {
func growSliceValue(v reflect.Value, n int) reflect.Value {
diff := n - v.Len()
if diff > sliceElemsAllocLimit {
diff = sliceElemsAllocLimit
if diff > sliceAllocLimit {
diff = sliceAllocLimit
}
v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff))
return v
......@@ -134,10 +132,10 @@ func decodeArrayValue(d *Decoder, v reflect.Value) error {
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 {
......@@ -165,7 +163,7 @@ func (d *Decoder) decodeSlice(c codes.Code) ([]interface{}, error) {
return nil, nil
}
s := make([]interface{}, 0, min(n, sliceElemsAllocLimit))
s := make([]interface{}, 0, min(n, sliceAllocLimit))
for i := 0; i < n; i++ {
v, err := d.decodeInterfaceCond()
if err != nil {
......
......@@ -4,15 +4,18 @@ import (
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
func (d *Decoder) bytesLen(c codes.Code) (int, error) {
if c == codes.Nil {
return -1, nil
} else if codes.IsFixedString(c) {
}
if codes.IsFixedString(c) {
return int(c & codes.FixedStrMask), nil
}
switch c {
case codes.Str8, codes.Bin8:
n, err := d.uint8()
......@@ -24,6 +27,7 @@ func (d *Decoder) bytesLen(c codes.Code) (int, error) {
n, err := d.uint32()
return int(n), err
}
return 0, fmt.Errorf("msgpack: invalid code=%x decoding bytes length", c)
}
......@@ -40,7 +44,11 @@ func (d *Decoder) string(c codes.Code) (string, error) {
if err != nil {
return "", err
}
if n == -1 {
return d.stringWithLen(n)
}
func (d *Decoder) stringWithLen(n int) (string, error) {
if n <= 0 {
return "", nil
}
b, err := d.readN(n)
......@@ -48,13 +56,15 @@ func (d *Decoder) string(c codes.Code) (string, error) {
}
func decodeStringValue(d *Decoder, v reflect.Value) error {
s, err := d.DecodeString()
if err != nil {
if err := mustSet(v); err != nil {
return err
}
if err = mustSet(v); err != nil {
s, err := d.DecodeString()
if err != nil {
return err
}
v.SetString(s)
return nil
}
......@@ -128,13 +138,17 @@ func (d *Decoder) skipBytes(c codes.Code) error {
if err != nil {
return err
}
if n == -1 {
if n <= 0 {
return nil
}
return d.skipN(n)
}
func decodeBytesValue(d *Decoder, v reflect.Value) error {
if err := mustSet(v); err != nil {
return err
}
c, err := d.readCode()
if err != nil {
return err
......@@ -145,9 +159,6 @@ func decodeBytesValue(d *Decoder, v reflect.Value) error {
return err
}
if err = mustSet(v); err != nil {
return err
}
v.SetBytes(b)
return nil
......
package msgpack
import (
"encoding"
"errors"
"fmt"
"reflect"
......@@ -11,6 +12,7 @@ var stringType = reflect.TypeOf((*string)(nil)).Elem()
var valueDecoders []decoderFunc
//nolint:gochecknoinits
func init() {
valueDecoders = []decoderFunc{
reflect.Bool: decodeBoolValue,
......@@ -49,12 +51,16 @@ func mustSet(v reflect.Value) error {
}
func getDecoder(typ reflect.Type) decoderFunc {
kind := typ.Kind()
decoder, ok := typDecMap[typ]
if ok {
return decoder
if v, ok := typeDecMap.Load(typ); ok {
return v.(decoderFunc)
}
fn := _getDecoder(typ)
typeDecMap.Store(typ, fn)
return fn
}
func _getDecoder(typ reflect.Type) decoderFunc {
kind := typ.Kind()
if typ.Implements(customDecoderType) {
return decodeCustomValue
......@@ -62,6 +68,9 @@ func getDecoder(typ reflect.Type) decoderFunc {
if typ.Implements(unmarshalerType) {
return unmarshalValue
}
if typ.Implements(binaryUnmarshalerType) {
return unmarshalBinaryValue
}
// Addressable struct field value.
if kind != reflect.Ptr {
......@@ -72,6 +81,9 @@ func getDecoder(typ reflect.Type) decoderFunc {
if ptr.Implements(unmarshalerType) {
return unmarshalValueAddr
}
if ptr.Implements(binaryUnmarshalerType) {
return unmarshalBinaryValueAddr
}
}
switch kind {
......@@ -79,12 +91,10 @@ func getDecoder(typ reflect.Type) decoderFunc {
return ptrDecoderFunc(typ)
case reflect.Slice:
elem := typ.Elem()
switch elem.Kind() {
case reflect.Uint8:
if elem.Kind() == reflect.Uint8 {
return decodeBytesValue
}
switch elem {
case stringType:
if elem == stringType {
return decodeStringSliceValue
}
case reflect.Array:
......@@ -101,6 +111,7 @@ func getDecoder(typ reflect.Type) decoderFunc {
}
}
}
return valueDecoders[kind]
}
......@@ -154,31 +165,35 @@ func unmarshalValueAddr(d *Decoder, v reflect.Value) error {
}
func unmarshalValue(d *Decoder, v reflect.Value) error {
if d.hasNilCode() {
return d.decodeNilValue(v)
if d.extLen == 0 || d.extLen == 1 {
if d.hasNilCode() {
return d.decodeNilValue(v)
}
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
var b []byte
if d.extLen != 0 {
b, err := d.readN(d.extLen)
var err error
b, err = d.readN(d.extLen)
if err != nil {
return err
}
d.rec = b
} else {
d.rec = makeBuffer()
d.rec = make([]byte, 0, 64)
if err := d.Skip(); err != nil {
return err
}
b = d.rec
d.rec = nil
}
unmarshaler := v.Interface().(Unmarshaler)
err := unmarshaler.UnmarshalMsgpack(d.rec)
d.rec = nil
return err
return unmarshaler.UnmarshalMsgpack(b)
}
func decodeBoolValue(d *Decoder, v reflect.Value) error {
......@@ -232,3 +247,30 @@ func (d *Decoder) interfaceValue(v reflect.Value) error {
func decodeUnsupportedValue(d *Decoder, v reflect.Value) error {
return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type())
}
//------------------------------------------------------------------------------
func unmarshalBinaryValueAddr(d *Decoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
}
return unmarshalBinaryValue(d, v.Addr())
}
func unmarshalBinaryValue(d *Decoder, v reflect.Value) error {
if d.hasNilCode() {
return d.decodeNilValue(v)
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
data, err := d.DecodeBytes()
if err != nil {
return err
}
unmarshaler := v.Interface().(encoding.BinaryUnmarshaler)
return unmarshaler.UnmarshalBinary(data)
}
......@@ -4,102 +4,169 @@ import (
"bytes"
"io"
"reflect"
"sync"
"time"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
const (
sortMapKeysFlag uint32 = 1 << iota
structAsArrayFlag
encodeUsingJSONFlag
useCompactIntsFlag
useCompactFloatsFlag
)
type writer interface {
io.Writer
WriteByte(byte) error
WriteString(string) (int, error)
}
type byteWriter struct {
io.Writer
buf []byte
bootstrap [64]byte
buf [1]byte
}
func newByteWriter(w io.Writer) *byteWriter {
bw := &byteWriter{
Writer: w,
}
bw.buf = bw.bootstrap[:]
bw := new(byteWriter)
bw.Reset(w)
return bw
}
func (w *byteWriter) WriteByte(c byte) error {
w.buf = w.buf[:1]
w.buf[0] = c
_, err := w.Write(w.buf)
func (bw *byteWriter) Reset(w io.Writer) {
bw.Writer = w
}
func (bw *byteWriter) WriteByte(c byte) error {
bw.buf[0] = c
_, err := bw.Write(bw.buf[:])
return err
}
func (w *byteWriter) WriteString(s string) (int, error) {
w.buf = append(w.buf[:0], s...)
return w.Write(w.buf)
//------------------------------------------------------------------------------
var encPool = sync.Pool{
New: func() interface{} {
return NewEncoder(nil)
},
}
// Marshal returns the MessagePack encoding of v.
func Marshal(v interface{}) ([]byte, error) {
enc := encPool.Get().(*Encoder)
var buf bytes.Buffer
err := NewEncoder(&buf).Encode(v)
return buf.Bytes(), err
enc.Reset(&buf)
err := enc.Encode(v)
b := buf.Bytes()
encPool.Put(enc)
if err != nil {
return nil, err
}
return b, err
}
type Encoder struct {
w writer
buf []byte
w writer
buf []byte
timeBuf []byte
bootstrap [9 + 12]byte
intern map[string]int
sortMapKeys bool
structAsArray bool
useJSONTag bool
useCompact bool
flags uint32
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
bw, ok := w.(writer)
if !ok {
bw = newByteWriter(w)
e := new(Encoder)
e.buf = e.bootstrap[:9]
e.timeBuf = e.bootstrap[9 : 9+12]
e.Reset(w)
return e
}
func (e *Encoder) Reset(w io.Writer) {
if bw, ok := w.(writer); ok {
e.w = bw
} else if bw, ok := e.w.(*byteWriter); ok {
bw.Reset(w)
} else {
e.w = newByteWriter(w)
}
return &Encoder{
w: bw,
buf: make([]byte, 9),
for k := range e.intern {
delete(e.intern, k)
}
//TODO:
//e.sortMapKeys = false
//e.structAsArray = false
//e.useJSONTag = false
//e.useCompact = false
}
// 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(flag bool) *Encoder {
e.sortMapKeys = flag
func (e *Encoder) SortMapKeys(on bool) *Encoder {
if on {
e.flags |= sortMapKeysFlag
} else {
e.flags &= ^sortMapKeysFlag
}
return e
}
// StructAsArray causes the Encoder to encode Go structs as MessagePack arrays.
func (e *Encoder) StructAsArray(flag bool) *Encoder {
e.structAsArray = flag
// StructAsArray causes the Encoder to encode Go structs as msgpack arrays.
func (e *Encoder) StructAsArray(on bool) *Encoder {
if on {
e.flags |= structAsArrayFlag
} else {
e.flags &= ^structAsArrayFlag
}
return e
}
// UseJSONTag causes the Encoder to use json struct tag as fallback option
// if there is no msgpack tag.
func (e *Encoder) UseJSONTag(flag bool) *Encoder {
e.useJSONTag = flag
func (e *Encoder) UseJSONTag(on bool) *Encoder {
if on {
e.flags |= encodeUsingJSONFlag
} else {
e.flags &= ^encodeUsingJSONFlag
}
return e
}
// UseCompactEncoding causes the Encoder to chose the most compact encoding.
// For example, it allows to encode Go int64 as msgpack int8 saving 7 bytes.
func (e *Encoder) UseCompactEncoding(flag bool) *Encoder {
e.useCompact = flag
// For example, it allows to encode small Go int64 as msgpack int8 saving 7 bytes.
func (e *Encoder) UseCompactEncoding(on bool) *Encoder {
if on {
e.flags |= useCompactIntsFlag
} else {
e.flags &= ^useCompactIntsFlag
}
return e
}
// UseCompactFloats causes the Encoder to chose a compact integer encoding
// for floats that can be represented as integers.
func (e *Encoder) UseCompactFloats(on bool) {
if on {
e.flags |= useCompactFloatsFlag
} else {
e.flags &= ^useCompactFloatsFlag
}
}
func (e *Encoder) Encode(v interface{}) error {
switch v := v.(type) {
case nil:
......@@ -155,6 +222,10 @@ func (e *Encoder) EncodeBool(value bool) error {
return e.writeCode(codes.False)
}
func (e *Encoder) EncodeDuration(d time.Duration) error {
return e.EncodeInt(int64(d))
}
func (e *Encoder) writeCode(c codes.Code) error {
return e.w.WriteByte(byte(c))
}
......@@ -165,6 +236,6 @@ func (e *Encoder) write(b []byte) error {
}
func (e *Encoder) writeString(s string) error {
_, err := e.w.WriteString(s)
_, err := e.w.Write(stringToBytes(s))
return err
}
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