deps: bump go-cty version (#26079)

go-cty v1.6.1 fixes a panic in the `element` function when called with a negative offset.
This commit is contained in:
Kristin Laemmert 2020-09-03 11:01:15 -04:00 committed by GitHub
parent b4017f693d
commit e6e35f2077
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 1811 additions and 561 deletions

3
go.mod
View File

@ -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

14
go.sum
View File

@ -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=

View File

@ -1,17 +0,0 @@
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

View File

@ -1,170 +0,0 @@
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
useCompact 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(flag bool) *Encoder {
e.sortMapKeys = flag
return e
}
// StructAsArray causes the Encoder to encode Go structs as MessagePack arrays.
func (e *Encoder) StructAsArray(flag bool) *Encoder {
e.structAsArray = flag
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
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
return e
}
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.encodeInt64Cond(int64(v))
case int64:
return e.encodeInt64Cond(v)
case uint:
return e.encodeUint64Cond(uint64(v))
case uint64:
return e.encodeUint64Cond(v)
case bool:
return e.EncodeBool(v)
case float32:
return e.EncodeFloat32(v)
case float64:
return e.EncodeFloat64(v)
case time.Duration:
return e.encodeInt64Cond(int64(v))
case time.Time:
return e.EncodeTime(v)
}
return e.EncodeValue(reflect.ValueOf(v))
}
func (e *Encoder) EncodeMulti(v ...interface{}) error {
for _, vv := range v {
if err := e.Encode(vv); err != nil {
return err
}
}
return nil
}
func (e *Encoder) EncodeValue(v reflect.Value) error {
fn := getEncoder(v.Type())
return fn(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
}

View File

@ -1,42 +0,0 @@
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)
}

12
vendor/github.com/vmihailenco/msgpack/v4/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,12 @@
run:
concurrency: 8
deadline: 5m
tests: false
linters:
enable-all: true
disable:
- gochecknoglobals
- gocognit
- godox
- wsl
- funlen

21
vendor/github.com/vmihailenco/msgpack/v4/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,21 @@
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

View File

@ -1,4 +1,4 @@
## 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.

View File

@ -1,5 +1,6 @@
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

View File

@ -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
go mod init github.com/my/repo
go get github.com/vmihailenco/msgpack/v4
```
## Quickstart
``` 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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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))
mapStringStringType = mapStringStringPtrType.Elem()
)
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")
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,16 +334,17 @@ 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 {
} else if d.flags&disallowUnknownFieldsFlag != 0 {
return fmt.Errorf("msgpack: unknown field %q", name)
} else if err := d.Skip(); err != nil {
return err
}
}
}
return nil
}

View File

@ -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 {

View File

@ -5,7 +5,7 @@ import (
"strconv"
"strings"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
type queryResult struct {

View File

@ -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 {

View File

@ -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 {
if err := mustSet(v); err != nil {
return err
}
s, err := d.DecodeString()
if err != nil {
return err
}
if err = mustSet(v); 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

View File

@ -1,6 +1,7 @@
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.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)
}

241
vendor/github.com/vmihailenco/msgpack/v4/encode.go generated vendored Normal file
View File

@ -0,0 +1,241 @@
package msgpack
import (
"bytes"
"io"
"reflect"
"sync"
"time"
"github.com/vmihailenco/msgpack/v4/codes"
)
const (
sortMapKeysFlag uint32 = 1 << iota
structAsArrayFlag
encodeUsingJSONFlag
useCompactIntsFlag
useCompactFloatsFlag
)
type writer interface {
io.Writer
WriteByte(byte) error
}
type byteWriter struct {
io.Writer
buf [1]byte
}
func newByteWriter(w io.Writer) *byteWriter {
bw := new(byteWriter)
bw.Reset(w)
return bw
}
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
}
//------------------------------------------------------------------------------
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
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
timeBuf []byte
bootstrap [9 + 12]byte
intern map[string]int
flags uint32
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
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)
}
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(on bool) *Encoder {
if on {
e.flags |= sortMapKeysFlag
} else {
e.flags &= ^sortMapKeysFlag
}
return e
}
// 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(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 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:
return e.EncodeNil()
case string:
return e.EncodeString(v)
case []byte:
return e.EncodeBytes(v)
case int:
return e.encodeInt64Cond(int64(v))
case int64:
return e.encodeInt64Cond(v)
case uint:
return e.encodeUint64Cond(uint64(v))
case uint64:
return e.encodeUint64Cond(v)
case bool:
return e.EncodeBool(v)
case float32:
return e.EncodeFloat32(v)
case float64:
return e.EncodeFloat64(v)
case time.Duration:
return e.encodeInt64Cond(int64(v))
case time.Time:
return e.EncodeTime(v)
}
return e.EncodeValue(reflect.ValueOf(v))
}
func (e *Encoder) EncodeMulti(v ...interface{}) error {
for _, vv := range v {
if err := e.Encode(vv); err != nil {
return err
}
}
return nil
}
func (e *Encoder) EncodeValue(v reflect.Value) error {
fn := getEncoder(v.Type())
return fn(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) EncodeDuration(d time.Duration) error {
return e.EncodeInt(int64(d))
}
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.Write(stringToBytes(s))
return err
}

View File

@ -4,7 +4,7 @@ import (
"reflect"
"sort"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
func encodeMapValue(e *Encoder, v reflect.Value) error {
@ -38,7 +38,7 @@ func encodeMapStringStringValue(e *Encoder, v reflect.Value) error {
}
m := v.Convert(mapStringStringType).Interface().(map[string]string)
if e.sortMapKeys {
if e.flags&sortMapKeysFlag != 0 {
return e.encodeSortedMapStringString(m)
}
@ -64,7 +64,7 @@ func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error {
}
m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{})
if e.sortMapKeys {
if e.flags&sortMapKeysFlag != 0 {
return e.encodeSortedMapStringInterface(m)
}
@ -82,7 +82,7 @@ func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error {
func (e *Encoder) encodeSortedMapStringString(m map[string]string) error {
keys := make([]string, 0, len(m))
for k, _ := range m {
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
@ -102,7 +102,7 @@ func (e *Encoder) encodeSortedMapStringString(m map[string]string) error {
func (e *Encoder) encodeSortedMapStringInterface(m map[string]interface{}) error {
keys := make([]string, 0, len(m))
for k, _ := range m {
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
@ -132,13 +132,13 @@ func (e *Encoder) EncodeMapLen(l int) error {
func encodeStructValue(e *Encoder, strct reflect.Value) error {
var structFields *fields
if e.useJSONTag {
if e.flags&encodeUsingJSONFlag != 0 {
structFields = jsonStructs.Fields(strct.Type())
} else {
structFields = structs.Fields(strct.Type())
}
if e.structAsArray || structFields.AsArray {
if e.flags&structAsArrayFlag != 0 || structFields.AsArray {
return encodeStructValueAsArray(e, strct, structFields.List)
}
fields := structFields.OmitEmpty(strct)

View File

@ -4,7 +4,7 @@ import (
"math"
"reflect"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
// EncodeUint8 encodes an uint8 in 2 bytes preserving type of the number.
@ -13,7 +13,7 @@ func (e *Encoder) EncodeUint8(n uint8) error {
}
func (e *Encoder) encodeUint8Cond(n uint8) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(uint64(n))
}
return e.EncodeUint8(n)
@ -25,7 +25,7 @@ func (e *Encoder) EncodeUint16(n uint16) error {
}
func (e *Encoder) encodeUint16Cond(n uint16) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(uint64(n))
}
return e.EncodeUint16(n)
@ -37,7 +37,7 @@ func (e *Encoder) EncodeUint32(n uint32) error {
}
func (e *Encoder) encodeUint32Cond(n uint32) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(uint64(n))
}
return e.EncodeUint32(n)
@ -49,7 +49,7 @@ func (e *Encoder) EncodeUint64(n uint64) error {
}
func (e *Encoder) encodeUint64Cond(n uint64) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(n)
}
return e.EncodeUint64(n)
@ -61,7 +61,7 @@ func (e *Encoder) EncodeInt8(n int8) error {
}
func (e *Encoder) encodeInt8Cond(n int8) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(int64(n))
}
return e.EncodeInt8(n)
@ -73,7 +73,7 @@ func (e *Encoder) EncodeInt16(n int16) error {
}
func (e *Encoder) encodeInt16Cond(n int16) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(int64(n))
}
return e.EncodeInt16(n)
@ -85,7 +85,7 @@ func (e *Encoder) EncodeInt32(n int32) error {
}
func (e *Encoder) encodeInt32Cond(n int32) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(int64(n))
}
return e.EncodeInt32(n)
@ -97,7 +97,7 @@ func (e *Encoder) EncodeInt64(n int64) error {
}
func (e *Encoder) encodeInt64Cond(n int64) error {
if e.useCompact {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(n)
}
return e.EncodeInt64(n)
@ -118,11 +118,11 @@ func (e *Encoder) EncodeUint(n uint64) error {
if n <= math.MaxUint32 {
return e.EncodeUint32(uint32(n))
}
return e.EncodeUint64(uint64(n))
return e.EncodeUint64(n)
}
// EncodeNumber encodes an int64 in 1, 2, 3, 5, or 9 bytes.
// Type of number is lost during encoding.
// Type of the number is lost during encoding.
func (e *Encoder) EncodeInt(n int64) error {
if n >= 0 {
return e.EncodeUint(uint64(n))
@ -139,21 +139,35 @@ func (e *Encoder) EncodeInt(n int64) error {
if n >= math.MinInt32 {
return e.EncodeInt32(int32(n))
}
return e.EncodeInt64(int64(n))
return e.EncodeInt64(n)
}
func (e *Encoder) EncodeFloat32(n float32) error {
if e.flags&useCompactFloatsFlag != 0 {
if float32(int64(n)) == n {
return e.EncodeInt(int64(n))
}
}
return e.write4(codes.Float, math.Float32bits(n))
}
func (e *Encoder) EncodeFloat64(n float64) error {
if e.flags&useCompactFloatsFlag != 0 {
// Both NaN and Inf convert to int64(-0x8000000000000000)
// If n is NaN then it never compares true with any other value
// If n is Inf then it doesn't convert from int64 back to +/-Inf
// In both cases the comparison works.
if float64(int64(n)) == n {
return e.EncodeInt(int64(n))
}
}
return e.write8(codes.Double, math.Float64bits(n))
}
func (e *Encoder) write1(code codes.Code, n uint8) error {
e.buf = e.buf[:2]
e.buf[0] = byte(code)
e.buf[1] = byte(n)
e.buf[1] = n
return e.write(e.buf)
}

View File

@ -3,9 +3,11 @@ package msgpack
import (
"reflect"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
var sliceStringType = reflect.TypeOf(([]string)(nil))
func encodeStringValue(e *Encoder, v reflect.Value) error {
return e.EncodeString(v.String())
}
@ -88,6 +90,11 @@ func (e *Encoder) EncodeArrayLen(l int) error {
return e.write4(codes.Array32, uint32(l))
}
func encodeStringSliceValue(e *Encoder, v reflect.Value) error {
ss := v.Convert(sliceStringType).Interface().([]string)
return e.encodeStringSlice(ss)
}
func (e *Encoder) encodeStringSlice(s []string) error {
if s == nil {
return e.EncodeNil()

View File

@ -1,12 +1,14 @@
package msgpack
import (
"encoding"
"fmt"
"reflect"
)
var valueEncoders []encoderFunc
//nolint:gochecknoinits
func init() {
valueEncoders = []encoderFunc{
reflect.Bool: encodeBoolValue,
@ -38,8 +40,21 @@ func init() {
}
func getEncoder(typ reflect.Type) encoderFunc {
if encoder, ok := typEncMap[typ]; ok {
return encoder
if v, ok := typeEncMap.Load(typ); ok {
return v.(encoderFunc)
}
fn := _getEncoder(typ)
typeEncMap.Store(typ, fn)
return fn
}
func _getEncoder(typ reflect.Type) encoderFunc {
kind := typ.Kind()
if kind == reflect.Ptr {
if _, ok := typeEncMap.Load(typ.Elem()); ok {
return ptrEncoderFunc(typ)
}
}
if typ.Implements(customEncoderType) {
@ -48,8 +63,9 @@ func getEncoder(typ reflect.Type) encoderFunc {
if typ.Implements(marshalerType) {
return marshalValue
}
kind := typ.Kind()
if typ.Implements(binaryMarshalerType) {
return marshalBinaryValue
}
// Addressable struct field value.
if kind != reflect.Ptr {
@ -60,6 +76,9 @@ func getEncoder(typ reflect.Type) encoderFunc {
if ptr.Implements(marshalerType) {
return marshalValuePtr
}
if ptr.Implements(binaryMarshalerType) {
return marshalBinaryValuePtr
}
}
if typ == errorType {
@ -70,9 +89,13 @@ func getEncoder(typ reflect.Type) encoderFunc {
case reflect.Ptr:
return ptrEncoderFunc(typ)
case reflect.Slice:
if typ.Elem().Kind() == reflect.Uint8 {
elem := typ.Elem()
if elem.Kind() == reflect.Uint8 {
return encodeByteSliceValue
}
if elem == stringType {
return encodeStringSliceValue
}
case reflect.Array:
if typ.Elem().Kind() == reflect.Uint8 {
return encodeByteArrayValue
@ -87,6 +110,7 @@ func getEncoder(typ reflect.Type) encoderFunc {
}
}
}
return valueEncoders[kind]
}
@ -109,12 +133,9 @@ func encodeCustomValuePtr(e *Encoder, v reflect.Value) error {
}
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() {
if nilable(v) && v.IsNil() {
return e.EncodeNil()
}
}
encoder := v.Interface().(CustomEncoder)
return encoder.EncodeMsgpack(e)
@ -128,12 +149,9 @@ func marshalValuePtr(e *Encoder, v reflect.Value) error {
}
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() {
if nilable(v) && v.IsNil() {
return e.EncodeNil()
}
}
marshaler := v.Interface().(Marshaler)
b, err := marshaler.MarshalMsgpack()
@ -165,3 +183,34 @@ func encodeErrorValue(e *Encoder, v reflect.Value) error {
func encodeUnsupportedValue(e *Encoder, v reflect.Value) error {
return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type())
}
func nilable(v reflect.Value) bool {
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return true
}
return false
}
//------------------------------------------------------------------------------
func marshalBinaryValuePtr(e *Encoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
}
return marshalBinaryValue(e, v.Addr())
}
func marshalBinaryValue(e *Encoder, v reflect.Value) error {
if nilable(v) && v.IsNil() {
return e.EncodeNil()
}
marshaler := v.Interface().(encoding.BinaryMarshaler)
data, err := marshaler.MarshalBinary()
if err != nil {
return err
}
return e.EncodeBytes(data)
}

View File

@ -6,10 +6,15 @@ import (
"reflect"
"sync"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
var extTypes = make(map[int8]reflect.Type)
type extInfo struct {
Type reflect.Type
Decoder decoderFunc
}
var extTypes = make(map[int8]*extInfo)
var bufferPool = &sync.Pool{
New: func() interface{} {
@ -39,28 +44,29 @@ func RegisterExt(id int8, value interface{}) {
}
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)
typeEncMap.Store(typ, makeExtEncoder(id, enc))
}
if dec != nil {
typDecMap[typ] = makeExtDecoder(id, dec)
extTypes[id] = &extInfo{
Type: typ,
Decoder: dec,
}
typeDecMap.Store(typ, makeExtDecoder(id, dec))
}
}
func (e *Encoder) EncodeExtHeader(typeId int8, length int) error {
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 {
if err := e.w.WriteByte(byte(typeID)); err != nil {
return err
}
return nil
}
func makeExtEncoder(typeId int8, enc encoderFunc) encoderFunc {
func makeExtEncoder(typeID int8, enc encoderFunc) encoderFunc {
return func(e *Encoder, v reflect.Value) error {
buf := bufferPool.Get().(*bytes.Buffer)
defer bufferPool.Put(buf)
@ -75,7 +81,7 @@ func makeExtEncoder(typeId int8, enc encoderFunc) encoderFunc {
return err
}
err = e.EncodeExtHeader(typeId, buf.Len())
err = e.EncodeExtHeader(typeID, buf.Len())
if err != nil {
return err
}
@ -83,7 +89,7 @@ func makeExtEncoder(typeId int8, enc encoderFunc) encoderFunc {
}
}
func makeExtDecoder(typeId int8, dec decoderFunc) decoderFunc {
func makeExtDecoder(typeID int8, dec decoderFunc) decoderFunc {
return func(d *Decoder, v reflect.Value) error {
c, err := d.PeekCode()
if err != nil {
@ -99,8 +105,8 @@ func makeExtDecoder(typeId int8, dec decoderFunc) decoderFunc {
return err
}
if id != typeId {
return fmt.Errorf("msgpack: got ext type=%d, wanted %d", int8(c), typeId)
if id != typeID {
return fmt.Errorf("msgpack: got ext type=%d, wanted %d", id, typeID)
}
d.extLen = extLen
@ -156,43 +162,43 @@ func (d *Decoder) parseExtLen(c codes.Code) (int, error) {
}
}
func (d *Decoder) decodeExtHeader(c codes.Code) (int8, int, error) {
func (d *Decoder) extHeader(c codes.Code) (int8, int, error) {
length, err := d.parseExtLen(c)
if err != nil {
return 0, 0, err
}
typeId, err := d.readCode()
typeID, err := d.readCode()
if err != nil {
return 0, 0, err
}
return int8(typeId), length, nil
return int8(typeID), length, nil
}
func (d *Decoder) DecodeExtHeader() (typeId int8, length int, err error) {
func (d *Decoder) DecodeExtHeader() (typeID int8, length int, err error) {
c, err := d.readCode()
if err != nil {
return
}
return d.decodeExtHeader(c)
return d.extHeader(c)
}
func (d *Decoder) extInterface(c codes.Code) (interface{}, error) {
extId, extLen, err := d.decodeExtHeader(c)
extID, extLen, err := d.extHeader(c)
if err != nil {
return nil, err
}
typ, ok := extTypes[extId]
info, ok := extTypes[extID]
if !ok {
return nil, fmt.Errorf("msgpack: unregistered ext id=%d", extId)
return nil, fmt.Errorf("msgpack: unknown ext id=%d", extID)
}
v := reflect.New(typ)
v := reflect.New(info.Type)
d.extLen = extLen
err = d.DecodeValue(v.Elem())
err = info.Decoder(d, v.Elem())
d.extLen = 0
if err != nil {
return nil, err

13
vendor/github.com/vmihailenco/msgpack/v4/go.mod generated vendored Normal file
View File

@ -0,0 +1,13 @@
module github.com/vmihailenco/msgpack/v4
require (
github.com/davecgh/go-spew v1.1.1
github.com/golang/protobuf v1.3.4 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/vmihailenco/tagparser v0.1.1
golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
google.golang.org/appengine v1.6.5
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
)
go 1.11

24
vendor/github.com/vmihailenco/msgpack/v4/go.sum generated vendored Normal file
View File

@ -0,0 +1,24 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

236
vendor/github.com/vmihailenco/msgpack/v4/intern.go generated vendored Normal file
View File

@ -0,0 +1,236 @@
package msgpack
import (
"encoding/binary"
"errors"
"fmt"
"math"
"reflect"
"github.com/vmihailenco/msgpack/v4/codes"
)
var internStringExtID int8 = -128
var errUnexpectedCode = errors.New("msgpack: unexpected code")
func encodeInternInterfaceValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
v = v.Elem()
if v.Kind() == reflect.String {
return encodeInternStringValue(e, v)
}
return e.EncodeValue(v)
}
func encodeInternStringValue(e *Encoder, v reflect.Value) error {
s := v.String()
if s != "" {
if idx, ok := e.intern[s]; ok {
return e.internStringIndex(idx)
}
if e.intern == nil {
e.intern = make(map[string]int)
}
idx := len(e.intern)
e.intern[s] = idx
}
return e.EncodeString(s)
}
func (e *Encoder) internStringIndex(idx int) error {
if idx < math.MaxUint8 {
if err := e.writeCode(codes.FixExt1); err != nil {
return err
}
if err := e.w.WriteByte(byte(internStringExtID)); err != nil {
return err
}
return e.w.WriteByte(byte(idx))
}
if idx < math.MaxUint16 {
if err := e.writeCode(codes.FixExt2); err != nil {
return err
}
if err := e.w.WriteByte(byte(internStringExtID)); err != nil {
return err
}
if err := e.w.WriteByte(byte(idx >> 8)); err != nil {
return err
}
return e.w.WriteByte(byte(idx))
}
if int64(idx) < math.MaxUint32 {
if err := e.writeCode(codes.FixExt4); err != nil {
return err
}
if err := e.w.WriteByte(byte(internStringExtID)); err != nil {
return err
}
if err := e.w.WriteByte(byte(idx >> 24)); err != nil {
return err
}
if err := e.w.WriteByte(byte(idx >> 16)); err != nil {
return err
}
if err := e.w.WriteByte(byte(idx >> 8)); err != nil {
return err
}
return e.w.WriteByte(byte(idx))
}
return fmt.Errorf("msgpack: intern string index=%d is too large", idx)
}
//------------------------------------------------------------------------------
func decodeInternInterfaceValue(d *Decoder, v reflect.Value) error {
c, err := d.readCode()
if err != nil {
return err
}
s, err := d.internString(c)
if err == nil {
v.Set(reflect.ValueOf(s))
return nil
}
if err != nil && err != errUnexpectedCode {
return err
}
if err := d.s.UnreadByte(); err != nil {
return err
}
return decodeInterfaceValue(d, v)
}
func decodeInternStringValue(d *Decoder, v reflect.Value) error {
if err := mustSet(v); err != nil {
return err
}
c, err := d.readCode()
if err != nil {
return err
}
s, err := d.internString(c)
if err != nil {
if err == errUnexpectedCode {
return fmt.Errorf("msgpack: invalid code=%x decoding intern string", c)
}
return err
}
v.SetString(s)
return nil
}
func (d *Decoder) internString(c codes.Code) (string, error) {
if codes.IsFixedString(c) {
n := int(c & codes.FixedStrMask)
return d.internStringWithLen(n)
}
switch c {
case codes.FixExt1, codes.FixExt2, codes.FixExt4:
typeID, length, err := d.extHeader(c)
if err != nil {
return "", err
}
if typeID != internStringExtID {
err := fmt.Errorf("msgpack: got ext type=%d, wanted %d",
typeID, internStringExtID)
return "", err
}
idx, err := d.internStringIndex(length)
if err != nil {
return "", err
}
return d.internStringAtIndex(idx)
case codes.Str8, codes.Bin8:
n, err := d.uint8()
if err != nil {
return "", err
}
return d.internStringWithLen(int(n))
case codes.Str16, codes.Bin16:
n, err := d.uint16()
if err != nil {
return "", err
}
return d.internStringWithLen(int(n))
case codes.Str32, codes.Bin32:
n, err := d.uint32()
if err != nil {
return "", err
}
return d.internStringWithLen(int(n))
}
return "", errUnexpectedCode
}
func (d *Decoder) internStringIndex(length int) (int, error) {
switch length {
case 1:
c, err := d.s.ReadByte()
if err != nil {
return 0, err
}
return int(c), nil
case 2:
b, err := d.readN(2)
if err != nil {
return 0, err
}
n := binary.BigEndian.Uint16(b)
return int(n), nil
case 4:
b, err := d.readN(4)
if err != nil {
return 0, err
}
n := binary.BigEndian.Uint32(b)
return int(n), nil
}
err := fmt.Errorf("msgpack: unsupported intern string index length=%d", length)
return 0, err
}
func (d *Decoder) internStringAtIndex(idx int) (string, error) {
if idx >= len(d.intern) {
err := fmt.Errorf("msgpack: intern string with index=%d does not exist", idx)
return "", err
}
return d.intern[idx], nil
}
func (d *Decoder) internStringWithLen(n int) (string, error) {
if n <= 0 {
return "", nil
}
s, err := d.stringWithLen(n)
if err != nil {
return "", err
}
d.intern = append(d.intern, s)
return s, nil
}

13
vendor/github.com/vmihailenco/msgpack/v4/safe.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// +build appengine
package msgpack
// bytesToString converts byte slice to string.
func bytesToString(b []byte) string {
return string(b)
}
// stringToBytes converts string to byte slice.
func stringToBytes(s string) []byte {
return []byte(s)
}

View File

@ -6,14 +6,16 @@ import (
"reflect"
"time"
"github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4/codes"
)
var timeExtId int8 = -1
var timeExtID int8 = -1
var timePtrType = reflect.TypeOf((*time.Time)(nil))
//nolint:gochecknoinits
func init() {
timeType := reflect.TypeOf((*time.Time)(nil)).Elem()
registerExt(timeExtId, timeType, encodeTimeValue, decodeTimeValue)
registerExt(timeExtID, timePtrType.Elem(), encodeTimeValue, decodeTimeValue)
}
func (e *Encoder) EncodeTime(tm time.Time) error {
@ -21,7 +23,7 @@ func (e *Encoder) EncodeTime(tm time.Time) error {
if err := e.encodeExtLen(len(b)); err != nil {
return err
}
if err := e.w.WriteByte(byte(timeExtId)); err != nil {
if err := e.w.WriteByte(byte(timeExtID)); err != nil {
return err
}
return e.write(b)
@ -32,19 +34,18 @@ func (e *Encoder) encodeTime(tm time.Time) []byte {
if secs>>34 == 0 {
data := uint64(tm.Nanosecond())<<34 | secs
if data&0xffffffff00000000 == 0 {
b := make([]byte, 4)
b := e.timeBuf[:4]
binary.BigEndian.PutUint32(b, uint32(data))
return b
} else {
b := make([]byte, 8)
}
b := e.timeBuf[:8]
binary.BigEndian.PutUint64(b, data)
return b
}
}
b := make([]byte, 12)
b := e.timeBuf[:12]
binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond()))
binary.BigEndian.PutUint64(b[4:], uint64(secs))
binary.BigEndian.PutUint64(b[4:], secs)
return b
}
@ -140,6 +141,9 @@ func decodeTimeValue(d *Decoder, v reflect.Value) error {
if err != nil {
return err
}
v.Set(reflect.ValueOf(tm))
ptr := v.Addr().Interface().(*time.Time)
*ptr = tm
return nil
}

View File

@ -1,23 +1,41 @@
package msgpack
import (
"encoding"
"fmt"
"log"
"reflect"
"sync"
"github.com/vmihailenco/tagparser"
)
var errorType = reflect.TypeOf((*error)(nil)).Elem()
var customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem()
var customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem()
var (
customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem()
customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem()
)
var marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
var (
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
)
type encoderFunc func(*Encoder, reflect.Value) error
type decoderFunc func(*Decoder, reflect.Value) error
var (
binaryMarshalerType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
binaryUnmarshalerType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
)
var typEncMap = make(map[reflect.Type]encoderFunc)
var typDecMap = make(map[reflect.Type]decoderFunc)
type (
encoderFunc func(*Encoder, reflect.Value) error
decoderFunc func(*Decoder, reflect.Value) error
)
var (
typeEncMap sync.Map
typeDecMap sync.Map
)
// Register registers encoder and decoder functions for a value.
// This is low level API and in most cases you should prefer implementing
@ -25,49 +43,39 @@ var typDecMap = make(map[reflect.Type]decoderFunc)
func Register(value interface{}, enc encoderFunc, dec decoderFunc) {
typ := reflect.TypeOf(value)
if enc != nil {
typEncMap[typ] = enc
typeEncMap.Store(typ, enc)
}
if dec != nil {
typDecMap[typ] = dec
typeDecMap.Store(typ, dec)
}
}
//------------------------------------------------------------------------------
var structs = newStructCache(false)
var jsonStructs = newStructCache(true)
var (
structs = newStructCache(false)
jsonStructs = newStructCache(true)
)
type structCache struct {
mu sync.RWMutex
m map[reflect.Type]*fields
m sync.Map
useJSONTag bool
}
func newStructCache(useJSONTag bool) *structCache {
return &structCache{
m: make(map[reflect.Type]*fields),
useJSONTag: useJSONTag,
}
}
func (m *structCache) Fields(typ reflect.Type) *fields {
m.mu.RLock()
fs, ok := m.m[typ]
m.mu.RUnlock()
if ok {
return fs
if v, ok := m.m.Load(typ); ok {
return v.(*fields)
}
m.mu.Lock()
fs, ok = m.m[typ]
if !ok {
fs = getFields(typ, m.useJSONTag)
m.m[typ] = fs
}
m.mu.Unlock()
fs := getFields(typ, m.useJSONTag)
m.m.Store(typ, fs)
return fs
}
@ -81,84 +89,99 @@ type field struct {
decoder decoderFunc
}
func (f *field) value(v reflect.Value) reflect.Value {
return fieldByIndex(v, f.index)
}
func (f *field) Omit(strct reflect.Value) bool {
return f.omitEmpty && isEmptyValue(f.value(strct))
v, isNil := fieldByIndex(strct, f.index)
if isNil {
return true
}
return f.omitEmpty && isEmptyValue(v)
}
func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error {
return f.encoder(e, f.value(strct))
v, isNil := fieldByIndex(strct, f.index)
if isNil {
return e.EncodeNil()
}
return f.encoder(e, v)
}
func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error {
return f.decoder(d, f.value(strct))
v := fieldByIndexAlloc(strct, f.index)
return f.decoder(d, v)
}
//------------------------------------------------------------------------------
type fields struct {
Table map[string]*field
Type reflect.Type
Map map[string]*field
List []*field
AsArray bool
hasOmitEmpty bool
}
func newFields(numField int) *fields {
func newFields(typ reflect.Type) *fields {
return &fields{
Table: make(map[string]*field, numField),
List: make([]*field, 0, numField),
Type: typ,
Map: make(map[string]*field, typ.NumField()),
List: make([]*field, 0, typ.NumField()),
}
}
func (fs *fields) Add(field *field) {
fs.Table[field.name] = field
fs.warnIfFieldExists(field.name)
fs.Map[field.name] = field
fs.List = append(fs.List, field)
if field.omitEmpty {
fs.hasOmitEmpty = true
}
}
func (fs *fields) warnIfFieldExists(name string) {
if _, ok := fs.Map[name]; ok {
log.Printf("msgpack: %s already has field=%s", fs.Type, name)
}
}
func (fs *fields) OmitEmpty(strct reflect.Value) []*field {
if !fs.hasOmitEmpty {
return fs.List
}
fields := make([]*field, 0, len(fs.List))
for _, f := range fs.List {
if !f.Omit(strct) {
fields = append(fields, f)
}
}
return fields
}
func getFields(typ reflect.Type, useJSONTag bool) *fields {
numField := typ.NumField()
fs := newFields(numField)
fs := newFields(typ)
var omitEmpty bool
for i := 0; i < numField; i++ {
for i := 0; i < typ.NumField(); i++ {
f := typ.Field(i)
tag := f.Tag.Get("msgpack")
if useJSONTag && tag == "" {
tag = f.Tag.Get("json")
tagStr := f.Tag.Get("msgpack")
if useJSONTag && tagStr == "" {
tagStr = f.Tag.Get("json")
}
name, opt := parseTag(tag)
if name == "-" {
tag := tagparser.Parse(tagStr)
if tag.Name == "-" {
continue
}
if f.Name == "_msgpack" {
if opt.Contains("asArray") {
if tag.HasOption("asArray") {
fs.AsArray = true
}
if opt.Contains("omitempty") {
if tag.HasOption("omitempty") {
omitEmpty = true
}
}
@ -168,38 +191,65 @@ func getFields(typ reflect.Type, useJSONTag bool) *fields {
}
field := &field{
name: name,
name: tag.Name,
index: f.Index,
omitEmpty: omitEmpty || opt.Contains("omitempty"),
encoder: getEncoder(f.Type),
decoder: getDecoder(f.Type),
omitEmpty: omitEmpty || tag.HasOption("omitempty"),
}
if tag.HasOption("intern") {
switch f.Type.Kind() {
case reflect.Interface:
field.encoder = encodeInternInterfaceValue
field.decoder = decodeInternInterfaceValue
case reflect.String:
field.encoder = encodeInternStringValue
field.decoder = decodeInternStringValue
default:
err := fmt.Errorf("msgpack: intern strings are not supported on %s", f.Type)
panic(err)
}
} else {
field.encoder = getEncoder(f.Type)
field.decoder = getDecoder(f.Type)
}
if field.name == "" {
field.name = f.Name
}
if f.Anonymous && !opt.Contains("noinline") {
inline := opt.Contains("inline")
if f.Anonymous && !tag.HasOption("noinline") {
inline := tag.HasOption("inline")
if inline {
inlineFields(fs, f.Type, field, useJSONTag)
} else {
inline = autoinlineFields(fs, f.Type, field, useJSONTag)
inline = shouldInline(fs, f.Type, field, useJSONTag)
}
if inline {
fs.Table[field.name] = field
if _, ok := fs.Map[field.name]; ok {
log.Printf("msgpack: %s already has field=%s", fs.Type, field.name)
}
fs.Map[field.name] = field
continue
}
}
fs.Add(field)
if alias, ok := tag.Options["alias"]; ok {
fs.warnIfFieldExists(alias)
fs.Map[alias] = field
}
}
return fs
}
var encodeStructValuePtr uintptr
var decodeStructValuePtr uintptr
var (
encodeStructValuePtr uintptr
decodeStructValuePtr uintptr
)
//nolint:gochecknoinits
func init() {
encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer()
decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer()
@ -208,7 +258,7 @@ func init() {
func inlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) {
inlinedFields := getFields(typ, useJSONTag).List
for _, field := range inlinedFields {
if _, ok := fs.Table[field.name]; ok {
if _, ok := fs.Map[field.name]; ok {
// Don't inline shadowed fields.
continue
}
@ -217,7 +267,7 @@ func inlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) {
}
}
func autoinlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) bool {
func shouldInline(fs *fields, typ reflect.Type, f *field, useJSONTag bool) bool {
var encoder encoderFunc
var decoder decoderFunc
@ -244,7 +294,7 @@ func autoinlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) b
inlinedFields := getFields(typ, useJSONTag).List
for _, field := range inlinedFields {
if _, ok := fs.Table[field.name]; ok {
if _, ok := fs.Map[field.name]; ok {
// Don't auto inline if there are shadowed fields.
return false
}
@ -275,11 +325,32 @@ func isEmptyValue(v reflect.Value) bool {
return false
}
func fieldByIndex(v reflect.Value, index []int) reflect.Value {
func fieldByIndex(v reflect.Value, index []int) (_ reflect.Value, isNil bool) {
if len(index) == 1 {
return v.Field(index[0]), false
}
for i, idx := range index {
if i > 0 {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return v, true
}
v = v.Elem()
}
}
v = v.Field(idx)
}
return v, false
}
func fieldByIndexAlloc(v reflect.Value, index []int) reflect.Value {
if len(index) == 1 {
return v.Field(index[0])
}
for i, x := range index {
for i, idx := range index {
if i > 0 {
var ok bool
v, ok = indirectNew(v)
@ -287,8 +358,9 @@ func fieldByIndex(v reflect.Value, index []int) reflect.Value {
return v
}
}
v = v.Field(x)
v = v.Field(idx)
}
return v
}

22
vendor/github.com/vmihailenco/msgpack/v4/unsafe.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
// +build !appengine
package msgpack
import (
"unsafe"
)
// bytesToString converts byte slice to string.
func bytesToString(b []byte) string { //nolint:deadcode,unused
return *(*string)(unsafe.Pointer(&b))
}
// stringToBytes converts string to byte slice.
func stringToBytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(
&struct {
string
Cap int
}{s, len(s)},
))
}

24
vendor/github.com/vmihailenco/tagparser/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,24 @@
dist: xenial
sudo: false
language: go
go:
- 1.11.x
- 1.12.x
- tip
matrix:
allow_failures:
- go: tip
env:
- GO111MODULE=on
go_import_path: github.com/vmihailenco/tagparser
before_install:
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.17.1
script:
- make
- golangci-lint run

25
vendor/github.com/vmihailenco/tagparser/LICENSE generated vendored Normal file
View File

@ -0,0 +1,25 @@
Copyright (c) 2019 The github.com/vmihailenco/tagparser 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.

8
vendor/github.com/vmihailenco/tagparser/Makefile generated vendored Normal file
View File

@ -0,0 +1,8 @@
all:
go test ./...
go test ./... -short -race
go test ./... -run=NONE -bench=. -benchmem
env GOOS=linux GOARCH=386 go test ./...
go vet ./...
go get github.com/gordonklaus/ineffassign
ineffassign .

24
vendor/github.com/vmihailenco/tagparser/README.md generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Opinionated Golang tag parser
[![Build Status](https://travis-ci.org/vmihailenco/tagparser.png?branch=master)](https://travis-ci.org/vmihailenco/tagparser)
[![GoDoc](https://godoc.org/github.com/vmihailenco/tagparser?status.svg)](https://godoc.org/github.com/vmihailenco/tagparser)
## Installation
Install:
```shell
go get -u github.com/vmihailenco/tagparser
```
## Quickstart
```go
func ExampleParse() {
tag := tagparser.Parse("some_name,key:value,key2:'complex value'")
fmt.Println(tag.Name)
fmt.Println(tag.Options)
// Output: some_name
// map[key:value key2:'complex value']
}
```

3
vendor/github.com/vmihailenco/tagparser/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/vmihailenco/tagparser
go 1.13

View File

@ -0,0 +1,82 @@
package parser
import (
"bytes"
"github.com/vmihailenco/tagparser/internal"
)
type Parser struct {
b []byte
i int
}
func New(b []byte) *Parser {
return &Parser{
b: b,
}
}
func NewString(s string) *Parser {
return New(internal.StringToBytes(s))
}
func (p *Parser) Bytes() []byte {
return p.b[p.i:]
}
func (p *Parser) Valid() bool {
return p.i < len(p.b)
}
func (p *Parser) Read() byte {
if p.Valid() {
c := p.b[p.i]
p.Advance()
return c
}
return 0
}
func (p *Parser) Peek() byte {
if p.Valid() {
return p.b[p.i]
}
return 0
}
func (p *Parser) Advance() {
p.i++
}
func (p *Parser) Skip(skip byte) bool {
if p.Peek() == skip {
p.Advance()
return true
}
return false
}
func (p *Parser) SkipBytes(skip []byte) bool {
if len(skip) > len(p.b[p.i:]) {
return false
}
if !bytes.Equal(p.b[p.i:p.i+len(skip)], skip) {
return false
}
p.i += len(skip)
return true
}
func (p *Parser) ReadSep(sep byte) ([]byte, bool) {
ind := bytes.IndexByte(p.b[p.i:], sep)
if ind == -1 {
b := p.b[p.i:]
p.i = len(p.b)
return b, false
}
b := p.b[p.i : p.i+ind]
p.i += ind + 1
return b, true
}

View File

@ -0,0 +1,11 @@
// +build appengine
package internal
func BytesToString(b []byte) string {
return string(b)
}
func StringToBytes(s string) []byte {
return []byte(s)
}

View File

@ -0,0 +1,22 @@
// +build !appengine
package internal
import (
"unsafe"
)
// BytesToString converts byte slice to string.
func BytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// StringToBytes converts string to byte slice.
func StringToBytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(
&struct {
string
Cap int
}{s, len(s)},
))
}

176
vendor/github.com/vmihailenco/tagparser/tagparser.go generated vendored Normal file
View File

@ -0,0 +1,176 @@
package tagparser
import (
"github.com/vmihailenco/tagparser/internal/parser"
)
type Tag struct {
Name string
Options map[string]string
}
func (t *Tag) HasOption(name string) bool {
_, ok := t.Options[name]
return ok
}
func Parse(s string) *Tag {
p := &tagParser{
Parser: parser.NewString(s),
}
p.parseKey()
return &p.Tag
}
type tagParser struct {
*parser.Parser
Tag Tag
hasName bool
key string
}
func (p *tagParser) setTagOption(key, value string) {
if !p.hasName {
p.hasName = true
if key == "" {
p.Tag.Name = value
return
}
}
if p.Tag.Options == nil {
p.Tag.Options = make(map[string]string)
}
if key == "" {
p.Tag.Options[value] = ""
} else {
p.Tag.Options[key] = value
}
}
func (p *tagParser) parseKey() {
p.key = ""
var b []byte
for p.Valid() {
c := p.Read()
switch c {
case ',':
p.Skip(' ')
p.setTagOption("", string(b))
p.parseKey()
return
case ':':
p.key = string(b)
p.parseValue()
return
case '\'':
p.parseQuotedValue()
return
default:
b = append(b, c)
}
}
if len(b) > 0 {
p.setTagOption("", string(b))
}
}
func (p *tagParser) parseValue() {
const quote = '\''
c := p.Peek()
if c == quote {
p.Skip(quote)
p.parseQuotedValue()
return
}
var b []byte
for p.Valid() {
c = p.Read()
switch c {
case '\\':
b = append(b, p.Read())
case '(':
b = append(b, c)
b = p.readBrackets(b)
case ',':
p.Skip(' ')
p.setTagOption(p.key, string(b))
p.parseKey()
return
default:
b = append(b, c)
}
}
p.setTagOption(p.key, string(b))
}
func (p *tagParser) readBrackets(b []byte) []byte {
var lvl int
loop:
for p.Valid() {
c := p.Read()
switch c {
case '\\':
b = append(b, p.Read())
case '(':
b = append(b, c)
lvl++
case ')':
b = append(b, c)
lvl--
if lvl < 0 {
break loop
}
default:
b = append(b, c)
}
}
return b
}
func (p *tagParser) parseQuotedValue() {
const quote = '\''
var b []byte
b = append(b, quote)
for p.Valid() {
bb, ok := p.ReadSep(quote)
if !ok {
b = append(b, bb...)
break
}
if len(bb) > 0 && bb[len(bb)-1] == '\\' {
b = append(b, bb[:len(bb)-1]...)
b = append(b, quote)
continue
}
b = append(b, bb...)
b = append(b, quote)
break
}
p.setTagOption(p.key, string(b))
if p.Skip(',') {
p.Skip(' ')
}
p.parseKey()
}
func Unquote(s string) (string, bool) {
const quote = '\''
if len(s) < 2 {
return s, false
}
if s[0] == quote && s[len(s)-1] == quote {
return s[1 : len(s)-1], true
}
return s, false
}

View File

@ -13,6 +13,14 @@ import (
// if we're converting from a set into a list of the same element type.)
func conversionCollectionToList(ety cty.Type, conv conversion) conversion {
return func(val cty.Value, path cty.Path) (cty.Value, error) {
if !val.Length().IsKnown() {
// If the input collection has an unknown length (which is true
// for a set containing unknown values) then our result must be
// an unknown list, because we can't predict how many elements
// the resulting list should have.
return cty.UnknownVal(cty.List(val.Type().ElementType())), nil
}
elems := make([]cty.Value, 0, val.LengthInt())
i := int64(0)
elemPath := append(path.Copy(), nil)
@ -458,6 +466,16 @@ func conversionMapToObject(mapType cty.Type, objType cty.Type, unsafe bool) conv
elems[name.AsString()] = val
}
for name, aty := range objectAtys {
if _, exists := elems[name]; !exists {
if optional := objType.AttributeOptional(name); optional {
elems[name] = cty.NullVal(aty)
} else {
return cty.NilVal, path.NewErrorf("map has no element for required attribute %q", name)
}
}
}
return cty.ObjectVal(elems), nil
}
}

View File

@ -11,17 +11,29 @@ import (
// type, meaning that each attribute of the output type has a corresponding
// attribute in the input type where a recursive conversion is available.
//
// If the "out" type has any optional attributes, those attributes may be
// absent in the "in" type, in which case null values will be used in their
// place in the result.
//
// Shallow object conversions work the same for both safe and unsafe modes,
// but the safety flag is passed on to recursive conversions and may thus
// limit the above definition of "subset".
func conversionObjectToObject(in, out cty.Type, unsafe bool) conversion {
inAtys := in.AttributeTypes()
outAtys := out.AttributeTypes()
outOptionals := out.OptionalAttributes()
attrConvs := make(map[string]conversion)
for name, outAty := range outAtys {
inAty, exists := inAtys[name]
if !exists {
if _, optional := outOptionals[name]; optional {
// If it's optional then we'll skip inserting an
// attribute conversion and then deal with inserting
// the default value in our overall conversion logic
// later.
continue
}
// No conversion is available, then.
return nil
}
@ -71,6 +83,13 @@ func conversionObjectToObject(in, out cty.Type, unsafe bool) conversion {
attrVals[name] = val
}
for name := range outOptionals {
if _, exists := attrVals[name]; !exists {
wantTy := outAtys[name]
attrVals[name] = cty.NullVal(wantTy)
}
}
return cty.ObjectVal(attrVals), nil
}
}

View File

@ -78,7 +78,9 @@ func mismatchMessageObjects(got, want cty.Type) string {
for name, wantAty := range wantAtys {
gotAty, exists := gotAtys[name]
if !exists {
if !want.AttributeOptional(name) {
missingAttrs = append(missingAttrs, name)
}
continue
}

View File

@ -138,6 +138,13 @@ var ElementFunc = function.New(&function.Spec{
},
Type: func(args []cty.Value) (cty.Type, error) {
list := args[0]
index := args[1]
if index.IsKnown() {
if index.LessThan(cty.NumberIntVal(0)).True() {
return cty.DynamicPseudoType, fmt.Errorf("cannot use element function with a negative index")
}
}
listTy := list.Type()
switch {
case listTy.IsListType():
@ -173,6 +180,10 @@ var ElementFunc = function.New(&function.Spec{
return cty.DynamicVal, fmt.Errorf("invalid index: %s", err)
}
if args[1].LessThan(cty.NumberIntVal(0)).True() {
return cty.DynamicVal, fmt.Errorf("cannot use element function with a negative index")
}
if !args[0].IsKnown() {
return cty.UnknownVal(retType), nil
}
@ -492,6 +503,11 @@ var FlattenFunc = function.New(&function.Spec{
// We can flatten lists with unknown values, as long as they are not
// lists themselves.
func flattener(flattenList cty.Value) ([]cty.Value, bool) {
if !flattenList.Length().IsKnown() {
// If we don't know the length of what we're flattening then we can't
// predict the length of our result yet either.
return nil, false
}
out := make([]cty.Value, 0)
for it := flattenList.ElementIterator(); it.Next(); {
_, val := it.Element()
@ -872,6 +888,10 @@ var SetProductFunc = function.New(&function.Spec{
total := 1
for _, arg := range args {
if !arg.Length().IsKnown() {
return cty.UnknownVal(retType), nil
}
// Because of our type checking function, we are guaranteed that
// all of the arguments are known, non-null values of types that
// support LengthInt.
@ -1019,7 +1039,8 @@ func sliceIndexes(args []cty.Value) (int, int, bool, error) {
var startIndex, endIndex, length int
var startKnown, endKnown, lengthKnown bool
if args[0].Type().IsTupleType() || args[0].IsKnown() { // if it's a tuple then we always know the length by the type, but lists must be known
// If it's a tuple then we always know the length by the type, but collections might be unknown or have unknown length
if args[0].Type().IsTupleType() || args[0].Length().IsKnown() {
length = args[0].LengthInt()
lengthKnown = true
}

View File

@ -85,7 +85,7 @@ var FormatListFunc = function.New(&function.Spec{
argTy := arg.Type()
switch {
case (argTy.IsListType() || argTy.IsSetType() || argTy.IsTupleType()) && !arg.IsNull():
if !argTy.IsTupleType() && !arg.IsKnown() {
if !argTy.IsTupleType() && !(arg.IsKnown() && arg.Length().IsKnown()) {
// We can't iterate this one at all yet then, so we can't
// yet produce a result.
unknowns[i] = true

View File

@ -44,7 +44,7 @@ var SetUnionFunc = function.New(&function.Spec{
Type: setOperationReturnType,
Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet {
return s1.Union(s2)
}),
}, true),
})
var SetIntersectionFunc = function.New(&function.Spec{
@ -63,7 +63,7 @@ var SetIntersectionFunc = function.New(&function.Spec{
Type: setOperationReturnType,
Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet {
return s1.Intersection(s2)
}),
}, false),
})
var SetSubtractFunc = function.New(&function.Spec{
@ -82,7 +82,7 @@ var SetSubtractFunc = function.New(&function.Spec{
Type: setOperationReturnType,
Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet {
return s1.Subtract(s2)
}),
}, false),
})
var SetSymmetricDifferenceFunc = function.New(&function.Spec{
@ -100,8 +100,8 @@ var SetSymmetricDifferenceFunc = function.New(&function.Spec{
},
Type: setOperationReturnType,
Impl: setOperationImpl(func(s1, s2 cty.ValueSet) cty.ValueSet {
return s1.Subtract(s2)
}),
return s1.SymmetricDifference(s2)
}, false),
})
// SetHasElement determines whether the given set contains the given value as an
@ -187,13 +187,21 @@ func setOperationReturnType(args []cty.Value) (ret cty.Type, err error) {
return cty.Set(newEty), nil
}
func setOperationImpl(f func(s1, s2 cty.ValueSet) cty.ValueSet) function.ImplFunc {
func setOperationImpl(f func(s1, s2 cty.ValueSet) cty.ValueSet, allowUnknowns bool) function.ImplFunc {
return func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
first := args[0]
first, err = convert.Convert(first, retType)
if err != nil {
return cty.NilVal, function.NewArgError(0, err)
}
if !allowUnknowns && !first.IsWhollyKnown() {
// This set function can produce a correct result only when all
// elements are known, because eventually knowing the unknown
// values may cause the result to have fewer known elements, or
// might cause a result with no unknown elements at all to become
// one with a different length.
return cty.UnknownVal(retType), nil
}
set := first.AsValueSet()
for i, arg := range args[1:] {
@ -201,6 +209,10 @@ func setOperationImpl(f func(s1, s2 cty.ValueSet) cty.ValueSet) function.ImplFun
if err != nil {
return cty.NilVal, function.NewArgError(i+1, err)
}
if !allowUnknowns && !arg.IsWhollyKnown() {
// (For the same reason as we did this check for "first" above.)
return cty.UnknownVal(retType), nil
}
argSet := arg.AsValueSet()
set = f(set, argSet)

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"sort"
)
// MarshalJSON is an implementation of json.Marshaler that allows Type
@ -52,6 +53,19 @@ func (t Type) MarshalJSON() ([]byte, error) {
}
buf.WriteString(`["object",`)
buf.Write(atysJSON)
if optionals := t.OptionalAttributes(); len(optionals) > 0 {
buf.WriteByte(',')
optionalNames := make([]string, 0, len(optionals))
for k := range optionals {
optionalNames = append(optionalNames, k)
}
sort.Strings(optionalNames)
optionalsJSON, err := json.Marshal(optionalNames)
if err != nil {
return nil, err
}
buf.Write(optionalsJSON)
}
buf.WriteRune(']')
return buf.Bytes(), nil
case typeTuple:
@ -148,7 +162,16 @@ func (t *Type) UnmarshalJSON(buf []byte) error {
if err != nil {
return err
}
if dec.More() {
var optionals []string
err = dec.Decode(&optionals)
if err != nil {
return err
}
*t = ObjectWithOptionalAttrs(atys, optionals)
} else {
*t = Object(atys)
}
case "tuple":
var etys []Type
err = dec.Decode(&etys)

View File

@ -3,7 +3,7 @@ package msgpack
import (
"bytes"
"github.com/vmihailenco/msgpack"
"github.com/vmihailenco/msgpack/v4"
"github.com/zclconf/go-cty/cty"
)

View File

@ -5,7 +5,7 @@ import (
"math/big"
"sort"
"github.com/vmihailenco/msgpack"
"github.com/vmihailenco/msgpack/v4"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
)
@ -31,6 +31,7 @@ func Marshal(val cty.Value, ty cty.Type) ([]byte, error) {
var path cty.Path
var buf bytes.Buffer
enc := msgpack.NewEncoder(&buf)
enc.UseCompactEncoding(true)
err := marshal(val, ty, path, enc)
if err != nil {

View File

@ -5,8 +5,8 @@ import (
"fmt"
"io"
"github.com/vmihailenco/msgpack"
msgpackcodes "github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4"
msgpackcodes "github.com/vmihailenco/msgpack/v4/codes"
"github.com/zclconf/go-cty/cty"
)

View File

@ -3,8 +3,8 @@ package msgpack
import (
"bytes"
"github.com/vmihailenco/msgpack"
msgpackCodes "github.com/vmihailenco/msgpack/codes"
"github.com/vmihailenco/msgpack/v4"
msgpackCodes "github.com/vmihailenco/msgpack/v4/codes"
"github.com/zclconf/go-cty/cty"
)

View File

@ -2,11 +2,13 @@ package cty
import (
"fmt"
"sort"
)
type typeObject struct {
typeImplSigil
AttrTypes map[string]Type
AttrOptional map[string]struct{}
}
// Object creates an object type with the given attribute types.
@ -14,14 +16,52 @@ type typeObject struct {
// After a map is passed to this function the caller must no longer access it,
// since ownership is transferred to this library.
func Object(attrTypes map[string]Type) Type {
return ObjectWithOptionalAttrs(attrTypes, nil)
}
// ObjectWithOptionalAttrs creates an object type where some of its attributes
// are optional.
//
// This function is EXPERIMENTAL. The behavior of the function or of any other
// functions working either directly or indirectly with a type created by
// this function is not currently considered as a compatibility constraint, and
// is subject to change even in minor-version releases of this module. Other
// modules that work with cty types and values may or may not support object
// types with optional attributes; if they do not, their behavior when
// receiving one may be non-ideal.
//
// Optional attributes are significant only when an object type is being used
// as a target type for conversion in the "convert" package. A value of an
// object type always has a value for each of the attributes in the attribute
// types table, with optional values replaced with null during conversion.
//
// All keys in the optional slice must also exist in the attrTypes map. If not,
// this function will panic.
//
// After a map or array is passed to this function the caller must no longer
// access it, since ownership is transferred to this library.
func ObjectWithOptionalAttrs(attrTypes map[string]Type, optional []string) Type {
attrTypesNorm := make(map[string]Type, len(attrTypes))
for k, v := range attrTypes {
attrTypesNorm[NormalizeString(k)] = v
}
var optionalSet map[string]struct{}
if len(optional) > 0 {
optionalSet = make(map[string]struct{}, len(optional))
for _, k := range optional {
k = NormalizeString(k)
if _, exists := attrTypesNorm[k]; !exists {
panic(fmt.Sprintf("optional contains undeclared attribute %q", k))
}
optionalSet[k] = struct{}{}
}
}
return Type{
typeObject{
AttrTypes: attrTypesNorm,
AttrOptional: optionalSet,
},
}
}
@ -44,6 +84,11 @@ func (t typeObject) Equals(other Type) bool {
if !oty.Equals(ty) {
return false
}
_, opt := t.AttrOptional[attr]
_, oopt := ot.AttrOptional[attr]
if opt != oopt {
return false
}
}
return true
@ -66,6 +111,14 @@ func (t typeObject) GoString() string {
if len(t.AttrTypes) == 0 {
return "cty.EmptyObject"
}
if len(t.AttrOptional) > 0 {
opt := make([]string, len(t.AttrOptional))
for k := range t.AttrOptional {
opt = append(opt, k)
}
sort.Strings(opt)
return fmt.Sprintf("cty.ObjectWithOptionalAttrs(%#v, %#v)", t.AttrTypes, opt)
}
return fmt.Sprintf("cty.Object(%#v)", t.AttrTypes)
}
@ -133,3 +186,35 @@ func (t Type) AttributeTypes() map[string]Type {
}
panic("AttributeTypes on non-object Type")
}
// OptionalAttributes returns a map representing the set of attributes
// that are optional. Will panic if the receiver is not an object type
// (use IsObjectType to confirm).
//
// The returned map is part of the internal state of the type, and is provided
// for read access only. It is forbidden for any caller to modify the returned
// map.
func (t Type) OptionalAttributes() map[string]struct{} {
if ot, ok := t.typeImpl.(typeObject); ok {
return ot.AttrOptional
}
panic("OptionalAttributes on non-object Type")
}
// AttributeOptional returns true if the attribute of the given name is
// optional.
//
// Will panic if the receiver is not an object type (use IsObjectType to
// confirm) or if the object type has no such attribute (use HasAttribute to
// confirm).
func (t Type) AttributeOptional(name string) bool {
name = NormalizeString(name)
if ot, ok := t.typeImpl.(typeObject); ok {
if _, hasAttr := ot.AttrTypes[name]; !hasAttr {
panic("no such attribute")
}
_, exists := ot.AttrOptional[name]
return exists
}
panic("AttributeDefaultValue on non-object Type")
}

View File

@ -5,7 +5,8 @@ package cty
type unknownType struct {
}
// Unknown is a special value that can be
// unknown is a special value that can be used as the internal value of a
// Value to create a placeholder for a value that isn't yet known.
var unknown interface{} = &unknownType{}
// UnknownVal returns an Value that represents an unknown value of the given

View File

@ -3,7 +3,6 @@ package cty
import (
"fmt"
"math/big"
"reflect"
"github.com/zclconf/go-cty/cty/set"
)
@ -270,24 +269,26 @@ func (val Value) Equals(other Value) Value {
s2 := other.v.(set.Set)
equal := true
// Note that by our definition of sets it's never possible for two
// sets that contain unknown values (directly or indicrectly) to
// ever be equal, even if they are otherwise identical.
// FIXME: iterating both lists and checking each item is not the
// ideal implementation here, but it works with the primitives we
// have in the set implementation. Perhaps the set implementation
// can provide its own equality test later.
s1.EachValue(func(v interface{}) {
if !s2.Has(v) {
// Two sets are equal if all of their values are known and all values
// in one are also in the other.
for it := s1.Iterator(); it.Next(); {
rv := it.Value()
if rv == unknown { // "unknown" is the internal representation of unknown-ness
return UnknownVal(Bool)
}
if !s2.Has(rv) {
equal = false
}
})
s2.EachValue(func(v interface{}) {
if !s1.Has(v) {
}
for it := s2.Iterator(); it.Next(); {
rv := it.Value()
if rv == unknown { // "unknown" is the internal representation of unknown-ness
return UnknownVal(Bool)
}
if !s1.Has(rv) {
equal = false
}
})
}
result = equal
case ty.IsMapType():
@ -462,17 +463,32 @@ func (val Value) RawEquals(other Value) bool {
return true
}
return false
case ty.IsSetType():
s1 := val.v.(set.Set)
s2 := other.v.(set.Set)
// Since we're intentionally ignoring our rule that two unknowns
// are never equal, we can cheat here.
// (This isn't 100% right since e.g. it will fail if the set contains
// numbers that are infinite, which DeepEqual can't compare properly.
// We're accepting that limitation for simplicity here, since this
// function is here primarily for testing.)
return reflect.DeepEqual(s1, s2)
case ty.IsSetType():
// Convert the set values into a slice so that we can compare each
// value. This is safe because the underlying sets are ordered (see
// setRules in set_internals.go), and so the results are guaranteed to
// be in a consistent order for two equal sets
setList1 := val.AsValueSlice()
setList2 := other.AsValueSlice()
// If both physical sets have the same length and they have all of their
// _known_ values in common, we know that both sets also have the same
// number of unknown values.
if len(setList1) != len(setList2) {
return false
}
for i := range setList1 {
eq := setList1[i].RawEquals(setList2[i])
if !eq {
return false
}
}
// If we got here without returning false already then our sets are
// equal enough for RawEquals purposes.
return true
case ty.IsMapType():
ety := ty.typeImpl.(typeMap).ElementTypeT
@ -955,8 +971,7 @@ func (val Value) HasElement(elem Value) Value {
// If the receiver is null then this function will panic.
//
// Note that Length is not supported for strings. To determine the length
// of a string, call AsString and take the length of the native Go string
// that is returned.
// of a string, use the Length function in funcs/stdlib.
func (val Value) Length() Value {
if val.IsMarked() {
val, valMarks := val.Unmark()
@ -971,6 +986,25 @@ func (val Value) Length() Value {
if !val.IsKnown() {
return UnknownVal(Number)
}
if val.Type().IsSetType() {
// The Length rules are a little different for sets because if any
// unknown values are present then the values they are standing in for
// may or may not be equal to other elements in the set, and thus they
// may or may not coalesce with other elements and produce fewer
// items in the resulting set.
storeLength := int64(val.v.(set.Set).Length())
if storeLength == 1 || val.IsWhollyKnown() {
// If our set is wholly known then we know its length.
//
// We also know the length if the physical store has only one
// element, even if that element is unknown, because there's
// nothing else in the set for it to coalesce with and a single
// unknown value cannot represent more than one known value.
return NumberIntVal(storeLength)
}
// Otherwise, we cannot predict the length.
return UnknownVal(Number)
}
return NumberIntVal(int64(val.LengthInt()))
}
@ -980,6 +1014,13 @@ func (val Value) Length() Value {
//
// This is an integration method provided for the convenience of code bridging
// into Go's type system.
//
// For backward compatibility with an earlier implementation error, LengthInt's
// result can disagree with Length's result for any set containing unknown
// values. Length can potentially indicate the set's length is unknown in that
// case, whereas LengthInt will return the maximum possible length as if the
// unknown values were each a placeholder for a value not equal to any other
// value in the set.
func (val Value) LengthInt() int {
val.assertUnmarked()
if val.Type().IsTupleType() {
@ -1003,6 +1044,15 @@ func (val Value) LengthInt() int {
return len(val.v.([]interface{}))
case val.ty.IsSetType():
// NOTE: This is technically not correct in cases where the set
// contains unknown values, because in that case we can't know how
// many known values those unknown values are standing in for -- they
// might coalesce with other values once known.
//
// However, this incorrect behavior is preserved for backward
// compatibility with callers that were relying on LengthInt rather
// than calling Length. Instead of panicking when a set contains an
// unknown value, LengthInt returns the largest possible length.
return val.v.(set.Set).Length()
case val.ty.IsMapType():

View File

@ -1,10 +1,9 @@
module google.golang.org/appengine
go 1.11
require (
github.com/golang/protobuf v1.3.1
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 // indirect
golang.org/x/net v0.0.0-20190603091049-60506f45cf65
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c // indirect
golang.org/x/text v0.3.2
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b // indirect
)

View File

@ -1,22 +1,11 @@
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225 h1:kNX+jCowfMYzvlSvJu5pQWEmyWFrBXJ3PBy10xKMXK8=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=

View File

@ -32,7 +32,7 @@ func limitDial(network, addr string) (net.Conn, error) {
// Dial with a timeout in case the API host is MIA.
// The connection should normally be very fast.
conn, err := net.DialTimeout(network, addr, 500*time.Millisecond)
conn, err := net.DialTimeout(network, addr, 10*time.Second)
if err != nil {
limitRelease()
return nil, err

15
vendor/modules.txt vendored
View File

@ -590,10 +590,13 @@ github.com/ulikunitz/xz
github.com/ulikunitz/xz/internal/hash
github.com/ulikunitz/xz/internal/xlog
github.com/ulikunitz/xz/lzma
# github.com/vmihailenco/msgpack v4.0.1+incompatible
## explicit
github.com/vmihailenco/msgpack
github.com/vmihailenco/msgpack/codes
# github.com/vmihailenco/msgpack/v4 v4.3.12
github.com/vmihailenco/msgpack/v4
github.com/vmihailenco/msgpack/v4/codes
# github.com/vmihailenco/tagparser v0.1.1
github.com/vmihailenco/tagparser
github.com/vmihailenco/tagparser/internal
github.com/vmihailenco/tagparser/internal/parser
# github.com/xanzy/ssh-agent v0.2.1
## explicit
github.com/xanzy/ssh-agent
@ -602,7 +605,7 @@ github.com/xanzy/ssh-agent
# github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
## explicit
github.com/xlab/treeprint
# github.com/zclconf/go-cty v1.5.1
# github.com/zclconf/go-cty v1.6.1
## explicit
github.com/zclconf/go-cty/cty
github.com/zclconf/go-cty/cty/convert
@ -739,7 +742,7 @@ google.golang.org/api/option
google.golang.org/api/storage/v1
google.golang.org/api/transport/http
google.golang.org/api/transport/http/internal/propagation
# google.golang.org/appengine v1.6.1
# google.golang.org/appengine v1.6.5
google.golang.org/appengine
google.golang.org/appengine/datastore
google.golang.org/appengine/datastore/internal/cloudkey