feat: add cache library and enable it in config manager (#13525)

Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
He Weiwei 2020-12-08 17:40:03 +08:00 committed by GitHub
parent 9f8a743da9
commit e92674a42a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 18610 additions and 249 deletions

View File

@ -26,6 +26,7 @@ import (
"github.com/goharbor/harbor/src/common/http/modifier/auth"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/lib/cache"
"github.com/goharbor/harbor/src/lib/log"
)
@ -36,7 +37,14 @@ type CfgManager struct {
// NewDBCfgManager - create DB config manager
func NewDBCfgManager() *CfgManager {
manager := &CfgManager{store: store.NewConfigStore(&driver.Database{})}
cfgDriver := (driver.Driver)(&driver.Database{})
if cache.Default() != nil {
log.Debug("create DB config manager with cache enabled")
cfgDriver = driver.NewCacheDriver(cache.Default(), cfgDriver)
}
manager := &CfgManager{store: store.NewConfigStore(cfgDriver)}
// load default value
manager.loadDefault()
// load system config from env

View File

@ -0,0 +1,68 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package driver
import (
"time"
"github.com/goharbor/harbor/src/lib/cache"
"github.com/goharbor/harbor/src/lib/log"
)
const cacheKey = "cfgs"
// Cache - Used to load/save configuration with cache
type Cache struct {
cache cache.Cache
driver Driver
}
// Load - load config from database, only user setting will be load from database.
func (d *Cache) Load() (map[string]interface{}, error) {
f := func() (interface{}, error) {
return d.driver.Load()
}
result := map[string]interface{}{}
// let the cache expired after one minute
// because the there no way to rollback the config items been saved when invalidate the cache failed
if err := cache.FetchOrSave(d.cache, cacheKey, &result, f, time.Minute); err != nil {
return nil, err
}
return result, nil
}
// Save - Only save user config items in the cfgs map
func (d *Cache) Save(cfgs map[string]interface{}) error {
if err := d.driver.Save(cfgs); err != nil {
return err
}
if err := d.cache.Delete(cacheKey); err != nil {
log.Warningf("failed to invalidate the cache of the configurations immediately, error: %v", err)
}
return nil
}
// NewCacheDriver returns driver with cache
func NewCacheDriver(cache cache.Cache, driver Driver) Driver {
return &Cache{
cache: cache,
driver: driver,
}
}

View File

@ -0,0 +1,70 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package driver
import (
"fmt"
"testing"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/config/metadata"
"github.com/goharbor/harbor/src/lib/cache"
_ "github.com/goharbor/harbor/src/lib/cache/redis" // redis cache
"github.com/stretchr/testify/assert"
)
func TestCacheLoadAndSave(t *testing.T) {
cache, _ := cache.New("redis")
driver := NewCacheDriver(cache, &Database{})
cfgs := map[string]interface{}{
common.AUTHMode: "db_auth",
common.LDAPURL: "ldap://ldap.vmware.com",
}
driver.Save(cfgs)
cf, err := driver.Load()
if err != nil {
fmt.Printf("load failed %v", err)
}
assert.Contains(t, cf, common.AUTHMode)
assert.Contains(t, cf, common.LDAPURL)
}
func BenchmarkCacheLoad(b *testing.B) {
cfgs := map[string]interface{}{}
for _, item := range metadata.Instance().GetAll() {
cfgs[item.Name] = item.DefaultValue
}
driver := Database{}
driver.Save(cfgs)
cache, _ := cache.New("redis")
c := Cache{cache: cache, driver: &driver}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if _, err := c.Load(); err != nil {
fmt.Printf("load failed, %v", err)
}
}
})
if err := cache.Delete(cacheKey); err != nil {
fmt.Printf("Delete cache failed, %v\n", err)
}
}

View File

@ -14,11 +14,14 @@
package driver
import (
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/dao"
"github.com/stretchr/testify/assert"
"fmt"
"os"
"testing"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/config/metadata"
"github.com/goharbor/harbor/src/common/dao"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
@ -62,3 +65,21 @@ func TestDatabase_Save(t *testing.T) {
driver.Save(prevCfg)
}
func BenchmarkDatabaseLoad(b *testing.B) {
cfgs := map[string]interface{}{}
for _, item := range metadata.Instance().GetAll() {
cfgs[item.Name] = item.DefaultValue
}
driver := Database{}
driver.Save(cfgs)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if _, err := driver.Load(); err != nil {
fmt.Printf("load failed %v", err)
}
}
})
}

View File

@ -42,6 +42,9 @@ import (
"github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/core/middlewares"
"github.com/goharbor/harbor/src/core/service/token"
"github.com/goharbor/harbor/src/lib/cache"
_ "github.com/goharbor/harbor/src/lib/cache/memory" // memory cache
_ "github.com/goharbor/harbor/src/lib/cache/redis" // redis cache
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/lib/metric"
"github.com/goharbor/harbor/src/migration"
@ -157,6 +160,11 @@ func main() {
beego.BConfig.WebConfig.Session.SessionProvider = "redis"
beego.BConfig.WebConfig.Session.SessionProviderConfig = strings.Join(ss, ",")
}
log.Info("initializing cache ...")
if err := cache.Initialize(u.Scheme, redisURL); err != nil {
log.Fatalf("failed to initialize cache: %v", err)
}
}
beego.AddTemplateExt("htm")

View File

@ -65,9 +65,10 @@ require (
github.com/robfig/cron v1.0.0
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
github.com/spf13/viper v1.4.0 // indirect
github.com/stretchr/testify v1.5.1
github.com/stretchr/testify v1.6.1
github.com/tencentcloud/tencentcloud-sdk-go v1.0.62
github.com/theupdateframework/notary v0.6.1
github.com/vmihailenco/msgpack/v5 v5.0.0-rc.2
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20200625001655-4c5254603344
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d

View File

@ -764,6 +764,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/tencentcloud/tencentcloud-sdk-go v1.0.62 h1:Vnr3IqaafEuQUciG6D6EaeLJm26Mg8sjAfbI4OoeauM=
@ -780,6 +782,10 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/vmihailenco/msgpack/v5 v5.0.0-rc.2 h1:ognci8XPlosGhIHK1OLYSpSpnlhSFeBklfe18zIEwcU=
github.com/vmihailenco/msgpack/v5 v5.0.0-rc.2/go.mod h1:HVxBVPUK/+fZMonk4bi1islLa8V3cfnBug0+4dykPzo=
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
@ -1101,6 +1107,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=

117
src/lib/cache/cache.go vendored Normal file
View File

@ -0,0 +1,117 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"errors"
"fmt"
"net/url"
"sync"
"time"
"github.com/goharbor/harbor/src/lib"
"github.com/goharbor/harbor/src/lib/log"
)
var (
// ErrNotFound error returns when the key value not found in the cache
ErrNotFound = errors.New("key not found")
)
// Cache cache interface
type Cache interface {
// Contains returns true if key exists
Contains(key string) bool
// Delete delete item from cache by key
Delete(key string) error
// Fetch retrieve the cached key value
Fetch(key string, value interface{}) error
// Ping ping the cache
Ping() error
// Save cache the value by key
Save(key string, value interface{}, expiration ...time.Duration) error
}
var (
factories = map[string]func(opts Options) (Cache, error){}
factoriesMu sync.RWMutex
)
// Register register cache factory for type
func Register(typ string, factory func(opts Options) (Cache, error)) {
factoriesMu.Lock()
defer factoriesMu.Unlock()
factories[typ] = factory
}
// New returns cache from addr
func New(typ string, opt ...Option) (Cache, error) {
opts := newOptions(opt...)
opts.Codec = codec // use the default codec for the cache
factoriesMu.Lock()
defer factoriesMu.Unlock()
factory, ok := factories[typ]
if !ok {
return nil, fmt.Errorf("cache type %s not support", typ)
}
return factory(opts)
}
var (
cache Cache
)
// Initialize initialize the default cache from the addr
func Initialize(typ, addr string) error {
c, err := New(typ, Address(addr), Prefix("cache:"))
if err != nil {
return err
}
redactedAddr := addr
if u, err := url.Parse(addr); err == nil {
redactedAddr = redacted(u)
}
options := []lib.RetryOption{
lib.RetryInitialInterval(time.Millisecond * 500),
lib.RetryMaxInterval(time.Second * 10),
lib.RetryTimeout(time.Minute),
lib.RetryCallback(func(err error, sleep time.Duration) {
log.Errorf("failed to ping %s, retry after %s : %v", redactedAddr, sleep, err)
}),
}
if err := lib.RetryUntil(c.Ping, options...); err != nil {
return err
}
cache = c
return nil
}
// Default returns the default cache
func Default() Cache {
return cache
}

90
src/lib/cache/cache_test.go vendored Normal file
View File

@ -0,0 +1,90 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"fmt"
"testing"
cachetesting "github.com/goharbor/harbor/src/testing/lib/cache"
"github.com/stretchr/testify/suite"
)
type CacheTestSuite struct {
suite.Suite
}
func (suite *CacheTestSuite) SetupSuite() {
Register("mock", func(opts Options) (Cache, error) {
return &cachetesting.Cache{}, nil
})
}
func (suite *CacheTestSuite) TestNew() {
{
c, err := New("")
suite.Nil(c)
suite.Error(err)
}
{
c, err := New("mocks")
suite.Nil(c)
suite.Error(err)
}
{
c, err := New("mock")
suite.NotNil(c)
suite.Nil(err)
}
}
func (suite *CacheTestSuite) TestInitialize() {
{
err := Initialize("cache", "")
suite.Error(err)
}
{
Register("cache", func(opts Options) (Cache, error) {
c := &cachetesting.Cache{}
c.On("Ping").Return(fmt.Errorf("oops"))
return c, nil
})
err := Initialize("cache", "cache://user:pass@localhost")
suite.Error(err)
suite.Nil(Default())
}
{
Register("cache", func(opts Options) (Cache, error) {
c := &cachetesting.Cache{}
c.On("Ping").Return(nil)
return c, nil
})
err := Initialize("cache", "")
suite.Nil(err)
suite.NotNil(Default())
}
}
func TestCacheTestSuite(t *testing.T) {
suite.Run(t, new(CacheTestSuite))
}

43
src/lib/cache/codec.go vendored Normal file
View File

@ -0,0 +1,43 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"github.com/vmihailenco/msgpack/v5"
)
// Codec codec interface for cache
type Codec interface {
// Encode returns the encoded byte array of v.
Encode(v interface{}) ([]byte, error)
// Decode analyzes the encoded data and stores the result into the v.
Decode(data []byte, v interface{}) error
}
var (
// codec the default codec for the cache
codec Codec = &msgpackCodec{}
)
type msgpackCodec struct{}
func (*msgpackCodec) Encode(v interface{}) ([]byte, error) {
return msgpack.Marshal(v)
}
func (*msgpackCodec) Decode(data []byte, v interface{}) error {
return msgpack.Unmarshal(data, v)
}

34
src/lib/cache/codec_test.go vendored Normal file
View File

@ -0,0 +1,34 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"testing"
)
func BenchmarkDefaultCodecEncode(b *testing.B) {
for i := 0; i < b.N; i++ {
codec.Encode("abcdefghigklmopqrztuvwxyz")
}
}
func BenchmarkDefaultCodecDecode(b *testing.B) {
data := []byte("abcdefghigklmopqrztuvwxyz")
for i := 0; i < b.N; i++ {
var str string
codec.Decode(data, &str)
}
}

35
src/lib/cache/context.go vendored Normal file
View File

@ -0,0 +1,35 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"context"
)
type cacheKey struct{}
// FromContext returns cache from context
func FromContext(ctx context.Context) (Cache, bool) {
c, ok := ctx.Value(cacheKey{}).(Cache)
return c, ok
}
// NewContext returns new context with cache
func NewContext(ctx context.Context, c Cache) context.Context {
if ctx == nil {
ctx = context.Background()
}
return context.WithValue(ctx, cacheKey{}, c)
}

77
src/lib/cache/helper.go vendored Normal file
View File

@ -0,0 +1,77 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"errors"
"fmt"
"sync"
"time"
"github.com/goharbor/harbor/src/lib/log"
)
var (
fetchOrSaveMu = keyMutex{m: &sync.Map{}}
)
// FetchOrSave retrieves the value for the key if present in the cache.
// Otherwise, it saves the value from the builder and retrieves the value for the key again.
func FetchOrSave(c Cache, key string, value interface{}, builder func() (interface{}, error), expiration ...time.Duration) error {
err := c.Fetch(key, value)
// value found from the cache
if err == nil {
return nil
}
// internal error
if !errors.Is(err, ErrNotFound) {
return err
}
// lock the key in cache and try to build the value for the key
lockKey := fmt.Sprintf("%p:%s", c, key)
fetchOrSaveMu.Lock(lockKey)
defer fetchOrSaveMu.Unlock(lockKey)
// fetch again to avoid to build the value multi-times
err = c.Fetch(key, value)
if err == nil {
return nil
}
// internal error
if !errors.Is(err, ErrNotFound) {
return err
}
val, err := builder()
if err != nil {
return err
}
if err := c.Save(key, val, expiration...); err != nil {
log.Warningf("failed to save value to cache, error: %v", err)
// save the val to cache failed, copy it to the value using the default codec
data, err := codec.Encode(val)
if err != nil {
return err
}
return codec.Decode(data, value)
}
return c.Fetch(key, value) // after the building, fetch value again
}

120
src/lib/cache/helper_test.go vendored Normal file
View File

@ -0,0 +1,120 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"fmt"
"sync"
"testing"
"time"
cachetesting "github.com/goharbor/harbor/src/testing/lib/cache"
"github.com/goharbor/harbor/src/testing/mock"
"github.com/stretchr/testify/suite"
)
type Foobar struct {
Foo string
Bar int
}
type FetchOrSaveTestSuite struct {
suite.Suite
}
func (suite *FetchOrSaveTestSuite) TestFetchInternalError() {
c := &cachetesting.Cache{}
mock.OnAnything(c, "Fetch").Return(fmt.Errorf("oops"))
var str string
err := FetchOrSave(c, "key", &str, func() (interface{}, error) {
return "str", nil
})
suite.Equal(fmt.Errorf("oops"), err)
}
func (suite *FetchOrSaveTestSuite) TestBuildError() {
c := &cachetesting.Cache{}
mock.OnAnything(c, "Fetch").Return(ErrNotFound)
var str string
err := FetchOrSave(c, "key", &str, func() (interface{}, error) {
return nil, fmt.Errorf("oops")
})
suite.Equal(fmt.Errorf("oops"), err)
}
func (suite *FetchOrSaveTestSuite) TestSaveError() {
c := &cachetesting.Cache{}
mock.OnAnything(c, "Fetch").Return(ErrNotFound)
mock.OnAnything(c, "Save").Return(fmt.Errorf("oops"))
var str string
err := FetchOrSave(c, "key", &str, func() (interface{}, error) {
return "str", nil
})
suite.Nil(err)
suite.Equal("str", str)
}
func (suite *FetchOrSaveTestSuite) TestSaveCalledOnlyOneTime() {
c := &cachetesting.Cache{}
var data sync.Map
mock.OnAnything(c, "Fetch").Return(func(key string, value interface{}) error {
_, ok := data.Load(key)
if ok {
return nil
}
return ErrNotFound
})
mock.OnAnything(c, "Save").Return(func(key string, value interface{}, exp ...time.Duration) error {
data.Store(key, value)
return nil
})
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
var str string
FetchOrSave(c, "key", &str, func() (interface{}, error) {
return "str", nil
})
}()
}
wg.Wait()
c.AssertNumberOfCalls(suite.T(), "Save", 1)
}
func TestFetchOrSaveTestSuite(t *testing.T) {
suite.Run(t, new(FetchOrSaveTestSuite))
}

120
src/lib/cache/memory/memory.go vendored Normal file
View File

@ -0,0 +1,120 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package memory
import (
"fmt"
"math"
"sync"
"time"
"github.com/goharbor/harbor/src/lib/cache"
)
type entry struct {
data []byte
expiratedAt int64
}
func (e *entry) isExpirated() bool {
return e.expiratedAt < time.Now().UnixNano()
}
var _ cache.Cache = (*Cache)(nil)
// Cache memory cache
type Cache struct {
opts *cache.Options
storage sync.Map
}
// Contains returns true if key exists
func (c *Cache) Contains(key string) bool {
e, ok := c.storage.Load(c.opts.Key(key))
if !ok {
return false
}
if e.(*entry).isExpirated() {
c.Delete(c.opts.Key(key))
return false
}
return true
}
// Delete delete item from cache by key
func (c *Cache) Delete(key string) error {
c.storage.Delete(c.opts.Key(key))
return nil
}
// Fetch retrieve the cached key value
func (c *Cache) Fetch(key string, value interface{}) error {
v, ok := c.storage.Load(c.opts.Key(key))
if !ok {
return cache.ErrNotFound
}
e := v.(*entry)
if e.isExpirated() {
c.Delete(c.opts.Key(key))
return cache.ErrNotFound
}
if err := c.opts.Codec.Decode(e.data, value); err != nil {
return fmt.Errorf("failed to decode cached value to dest, key %s, error: %v", key, err)
}
return nil
}
// Ping ping the cache
func (c *Cache) Ping() error {
return nil
}
// Save cache the value by key
func (c *Cache) Save(key string, value interface{}, expiration ...time.Duration) error {
data, err := c.opts.Codec.Encode(value)
if err != nil {
return fmt.Errorf("failed to encode value, key %s, error: %v", key, err)
}
var expiratedAt int64
if len(expiration) > 0 {
expiratedAt = time.Now().Add(expiration[0]).UnixNano()
} else if c.opts.Expiration > 0 {
expiratedAt = time.Now().Add(c.opts.Expiration).UnixNano()
} else {
expiratedAt = math.MaxInt64
}
c.storage.Store(c.opts.Key(key), &entry{
data: data,
expiratedAt: expiratedAt,
})
return nil
}
// New returns memory cache
func New(opts cache.Options) (cache.Cache, error) {
return &Cache{opts: &opts}, nil
}
func init() {
cache.Register("memory", New)
}

134
src/lib/cache/memory/memory_test.go vendored Normal file
View File

@ -0,0 +1,134 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package memory
import (
"testing"
"time"
"github.com/goharbor/harbor/src/lib/cache"
"github.com/stretchr/testify/suite"
)
type CacheTestSuite struct {
suite.Suite
cache cache.Cache
}
func (suite *CacheTestSuite) SetupSuite() {
suite.cache, _ = cache.New("memory", cache.Expiration(time.Second*5))
}
func (suite *CacheTestSuite) TestContains() {
key := "contains"
suite.False(suite.cache.Contains(key))
suite.cache.Save(key, "value")
suite.True(suite.cache.Contains(key))
suite.cache.Delete(key)
suite.False(suite.cache.Contains(key))
suite.cache.Save(key, "value", time.Second*5)
suite.True(suite.cache.Contains(key))
time.Sleep(time.Second * 5)
suite.False(suite.cache.Contains(key))
}
func (suite *CacheTestSuite) TestDelete() {
key := "delete"
suite.cache.Save(key, "value")
suite.True(suite.cache.Contains(key))
suite.cache.Delete(key)
suite.False(suite.cache.Contains(key))
}
func (suite *CacheTestSuite) TestFetch() {
key := "fetch"
suite.cache.Save(key, map[string]interface{}{"name": "harbor", "version": "1.10"})
mp := map[string]interface{}{}
suite.cache.Fetch(key, &mp)
suite.Len(mp, 2)
suite.Equal("harbor", mp["name"])
suite.Equal("1.10", mp["version"])
var str string
suite.Error(suite.cache.Fetch(key, &str))
}
func (suite *CacheTestSuite) TestSave() {
key := "save"
{
suite.cache.Save(key, "hello, save")
var value string
suite.cache.Fetch(key, &value)
suite.Equal("hello, save", value)
time.Sleep(time.Second * 5)
value = ""
suite.Error(suite.cache.Fetch(key, &value))
suite.Equal("", value)
}
{
suite.cache.Save(key, "hello, save", time.Second)
time.Sleep(time.Second * 2)
var value string
suite.Error(suite.cache.Fetch(key, &value))
suite.Equal("", value)
}
}
func (suite *CacheTestSuite) TestPing() {
suite.NoError(suite.cache.Ping())
}
func TestCacheTestSuite(t *testing.T) {
suite.Run(t, new(CacheTestSuite))
}
func BenchmarkCacheFetchParallel(b *testing.B) {
key := "benchmark"
cache, _ := cache.New("memory")
cache.Save(key, "hello, benchmark")
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var value string
cache.Fetch(key, &value)
}
})
}
func BenchmarkCacheSaveParallel(b *testing.B) {
key := "benchmark"
cache, _ := cache.New("memory")
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
cache.Save(key, "hello, benchmark")
}
})
}

66
src/lib/cache/options.go vendored Normal file
View File

@ -0,0 +1,66 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"time"
)
// Option function to set the options of the cache
type Option func(*Options)
// Options options of the cache
type Options struct {
Address string // the address of the cache
Codec Codec // the codec for the cache
Expiration time.Duration // the default expiration for the cache
Prefix string // the prefix for all the keys in the cache
}
// Key returns the real cache key
func (opts *Options) Key(key string) string {
return opts.Prefix + key
}
func newOptions(opt ...Option) Options {
opts := Options{}
for _, o := range opt {
o(&opts)
}
return opts
}
// Address sets the address
func Address(addr string) Option {
return func(o *Options) {
o.Address = addr
}
}
// Expiration sets the default expiration
func Expiration(d time.Duration) Option {
return func(o *Options) {
o.Expiration = d
}
}
// Prefix sets the prefix
func Prefix(prefix string) Option {
return func(o *Options) {
o.Prefix = prefix
}
}

132
src/lib/cache/redis/redis.go vendored Normal file
View File

@ -0,0 +1,132 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package redis
import (
"crypto/md5"
"fmt"
"time"
"github.com/goharbor/harbor/src/lib/cache"
libredis "github.com/goharbor/harbor/src/lib/redis"
"github.com/gomodule/redigo/redis"
)
var _ cache.Cache = (*Cache)(nil)
// Cache redis cache
type Cache struct {
opts *cache.Options
pool *redis.Pool
}
// Contains returns true if key exists
func (c *Cache) Contains(key string) bool {
reply, err := redis.Int(c.do("EXISTS", c.opts.Key(key)))
if err != nil {
return false
}
return reply == 1
}
// Delete delete item from cache by key
func (c *Cache) Delete(key string) error {
_, err := c.do("DEL", c.opts.Key(key))
return err
}
// Fetch retrieve the cached key value
func (c *Cache) Fetch(key string, value interface{}) error {
data, err := redis.Bytes(c.do("GET", c.opts.Key(key)))
if err != nil {
// convert internal or Timeout error to be ErrNotFound
// so that the caller can continue working without breaking
return cache.ErrNotFound
}
if err := c.opts.Codec.Decode(data, value); err != nil {
return fmt.Errorf("failed to decode cached value to dest, key %s, error: %v", key, err)
}
return nil
}
// Ping ping the cache
func (c *Cache) Ping() error {
_, err := c.do("PING")
return err
}
// Save cache the value by key
func (c *Cache) Save(key string, value interface{}, expiration ...time.Duration) error {
data, err := c.opts.Codec.Encode(value)
if err != nil {
return fmt.Errorf("failed to encode value, key %s, error: %v", key, err)
}
args := []interface{}{c.opts.Key(key), data}
var exp time.Duration
if len(expiration) > 0 {
exp = expiration[0]
} else if c.opts.Expiration > 0 {
exp = c.opts.Expiration
}
if exp > 0 {
args = append(args, "EX", int64(exp/time.Second))
}
_, err = c.do("SET", args...)
return err
}
func (c *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
conn := c.pool.Get()
defer conn.Close()
return conn.Do(commandName, args...)
}
// New returns redis cache
func New(opts cache.Options) (cache.Cache, error) {
if opts.Address == "" {
opts.Address = "redis://localhost:6379/0"
}
name := fmt.Sprintf("%x", md5.Sum([]byte(opts.Address)))
param := &libredis.PoolParam{
PoolMaxIdle: 100,
PoolMaxActive: 1000,
PoolIdleTimeout: 10 * time.Minute,
DialConnectionTimeout: time.Second,
DialReadTimeout: time.Second * 2,
DialWriteTimeout: time.Second * 5,
}
pool, err := libredis.GetRedisPool(name, opts.Address, param)
if err != nil {
return nil, err
}
return &Cache{opts: &opts, pool: pool}, nil
}
func init() {
cache.Register("redis", New)
cache.Register("redis+sentinel", New)
}

138
src/lib/cache/redis/redis_test.go vendored Normal file
View File

@ -0,0 +1,138 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package redis
import (
"fmt"
"testing"
"time"
"github.com/goharbor/harbor/src/lib/cache"
"github.com/stretchr/testify/suite"
)
type CacheTestSuite struct {
suite.Suite
cache cache.Cache
}
func (suite *CacheTestSuite) SetupSuite() {
suite.cache, _ = cache.New("redis", cache.Expiration(time.Second*5))
}
func (suite *CacheTestSuite) TestContains() {
key := "contains"
suite.False(suite.cache.Contains(key))
suite.cache.Save(key, "value")
suite.True(suite.cache.Contains(key))
suite.cache.Delete(key)
suite.False(suite.cache.Contains(key))
suite.cache.Save(key, "value", time.Second*5)
suite.True(suite.cache.Contains(key))
time.Sleep(time.Second * 5)
suite.False(suite.cache.Contains(key))
}
func (suite *CacheTestSuite) TestDelete() {
key := "delete"
suite.cache.Save(key, "value")
suite.True(suite.cache.Contains(key))
suite.cache.Delete(key)
suite.False(suite.cache.Contains(key))
}
func (suite *CacheTestSuite) TestFetch() {
key := "fetch"
suite.cache.Save(key, map[string]interface{}{"name": "harbor", "version": "1.10"})
mp := map[string]interface{}{}
suite.cache.Fetch(key, &mp)
suite.Len(mp, 2)
suite.Equal("harbor", mp["name"])
suite.Equal("1.10", mp["version"])
var str string
suite.Error(suite.cache.Fetch(key, &str))
}
func (suite *CacheTestSuite) TestSave() {
key := "save"
{
suite.cache.Save(key, "hello, save")
var value string
suite.cache.Fetch(key, &value)
suite.Equal("hello, save", value)
time.Sleep(time.Second * 5)
value = ""
suite.Error(suite.cache.Fetch(key, &value))
suite.Equal("", value)
}
{
suite.cache.Save(key, "hello, save", time.Second)
time.Sleep(time.Second * 2)
var value string
suite.Error(suite.cache.Fetch(key, &value))
suite.Equal("", value)
}
}
func (suite *CacheTestSuite) TestPing() {
suite.NoError(suite.cache.Ping())
}
func TestCacheTestSuite(t *testing.T) {
suite.Run(t, new(CacheTestSuite))
}
func BenchmarkCacheFetchParallel(b *testing.B) {
key := "benchmark"
cache, _ := cache.New("redis")
cache.Save(key, "hello, benchmark")
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var value string
err := cache.Fetch(key, &value)
if err != nil {
fmt.Printf("failed, error %v\n", err)
}
}
})
}
func BenchmarkCacheSaveParallel(b *testing.B) {
key := "benchmark"
cache, _ := cache.New("redis")
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
cache.Save(key, "hello, benchmark")
}
})
}

59
src/lib/cache/util.go vendored Normal file
View File

@ -0,0 +1,59 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"net/url"
"sync"
)
// TODO: use the URL.Redacted when golang upgrade to 1.15
func redacted(u *url.URL) string {
if u == nil {
return ""
}
ru := *u
if _, has := ru.User.Password(); has {
ru.User = url.UserPassword(ru.User.Username(), "xxxxx")
}
return ru.String()
}
type keyMutex struct {
m *sync.Map
}
func (km keyMutex) Lock(key interface{}) {
m := sync.Mutex{}
act, _ := km.m.LoadOrStore(key, &m)
mm := act.(*sync.Mutex)
mm.Lock()
if mm != &m {
mm.Unlock()
km.Lock(key)
}
}
func (km keyMutex) Unlock(key interface{}) {
act, exist := km.m.Load(key)
if !exist {
panic("unlock of unlocked mutex")
}
m := act.(*sync.Mutex)
km.m.Delete(key)
m.Unlock()
}

43
src/lib/cache/util_test.go vendored Normal file
View File

@ -0,0 +1,43 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
func TestKeyMutex(t *testing.T) {
km := keyMutex{m: &sync.Map{}}
key := "key"
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
km.Lock(key)
km.Unlock(key)
}()
}
wg.Wait()
assert.Panics(t, func() {
km.Unlock(key)
})
}

View File

@ -20,7 +20,6 @@ import (
"sync"
"time"
"github.com/goharbor/harbor/src/core/config"
"github.com/gomodule/redigo/redis"
)
@ -54,7 +53,8 @@ func DefaultPool() *redis.Pool {
idleTimeout = poolIdleTimeout
}
url := config.GetRedisOfRegURL()
// get _REDIS_URL_REG from environment directly here to avoid cyclic dependency
url := os.Getenv("_REDIS_URL_REG")
if url == "" {
url = "redis://localhost:6379/1"
}

133
src/lib/retry.go Normal file
View File

@ -0,0 +1,133 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package lib
import (
"errors"
"math"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
var (
// ErrRetryTimeout timeout error for retrying
ErrRetryTimeout = errors.New("retry timeout")
)
// RetryOptions options for the retry functions
type RetryOptions struct {
InitialInterval time.Duration // the initial interval for retring after failure, default 100 milliseconds
MaxInterval time.Duration // the max interval for retring after failure, default 1 second
Timeout time.Duration // the total time before returning if something is wrong, default 1 minute
Callback func(err error, sleep time.Duration) // the callback function for Retry when the f called failed
}
// RetryOption ...
type RetryOption func(*RetryOptions)
// RetryInitialInterval set initial interval
func RetryInitialInterval(initial time.Duration) RetryOption {
return func(opts *RetryOptions) {
opts.InitialInterval = initial
}
}
// RetryMaxInterval set max interval
func RetryMaxInterval(max time.Duration) RetryOption {
return func(opts *RetryOptions) {
opts.MaxInterval = max
}
}
// RetryTimeout set timeout interval
func RetryTimeout(timeout time.Duration) RetryOption {
return func(opts *RetryOptions) {
opts.Timeout = timeout
}
}
// RetryCallback set callback
func RetryCallback(callback func(err error, sleep time.Duration)) RetryOption {
return func(opts *RetryOptions) {
opts.Callback = callback
}
}
// RetryUntil retry until f run successfully or timeout
//
// NOTE: This function will use exponential backoff and jitter for retrying, see
// https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ for more information
func RetryUntil(f func() error, options ...RetryOption) error {
opts := &RetryOptions{}
for _, o := range options {
o(opts)
}
if opts.InitialInterval <= 0 {
opts.InitialInterval = time.Millisecond * 100
}
if opts.MaxInterval <= 0 {
opts.MaxInterval = time.Second
}
if opts.Timeout <= 0 {
opts.Timeout = time.Minute
}
timeout := time.After(opts.Timeout)
for attempt := 1; ; attempt++ {
select {
case <-timeout:
return ErrRetryTimeout
default:
if err := f(); err != nil {
sleep := getBackoff(attempt, opts.InitialInterval, opts.MaxInterval, true)
if opts.Callback != nil {
opts.Callback(err, sleep)
}
time.Sleep(sleep)
} else {
return nil
}
}
}
}
func getBackoff(attempt int, initialInterval, maxInterval time.Duration, equalJitter bool) time.Duration {
max := float64(maxInterval)
base := float64(initialInterval)
dur := base * math.Pow(2, float64(attempt))
if equalJitter {
dur = dur/2 + float64(rand.Int63n(int64(dur))/2)
}
if dur < base {
dur = base
}
if dur > max {
dur = max
}
return time.Duration(dur)
}

61
src/lib/retry_test.go Normal file
View File

@ -0,0 +1,61 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package lib
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestRetryUntil(t *testing.T) {
assert := assert.New(t)
i := 0
f1 := func() error {
i++
return fmt.Errorf("failed")
}
assert.Error(RetryUntil(f1, RetryInitialInterval(time.Second), RetryMaxInterval(time.Second), RetryTimeout(time.Second*5)))
assert.LessOrEqual(i, 5)
f2 := func() error {
return nil
}
assert.Nil(RetryUntil(f2))
i = 0
f3 := func() error {
defer func() {
i++
}()
if i < 2 {
return fmt.Errorf("failed")
}
return nil
}
assert.Nil(RetryUntil(f3))
RetryUntil(
f1,
RetryTimeout(time.Second*5),
RetryCallback(func(err error, sleep time.Duration) {
fmt.Printf("failed to exec f1 retry after %s : %v\n", sleep, err)
}),
)
}

91
src/testing/lib/cache/cache.go vendored Normal file
View File

@ -0,0 +1,91 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
package cache
import (
time "time"
mock "github.com/stretchr/testify/mock"
)
// Cache is an autogenerated mock type for the Cache type
type Cache struct {
mock.Mock
}
// Contains provides a mock function with given fields: key
func (_m *Cache) Contains(key string) bool {
ret := _m.Called(key)
var r0 bool
if rf, ok := ret.Get(0).(func(string) bool); ok {
r0 = rf(key)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// Delete provides a mock function with given fields: key
func (_m *Cache) Delete(key string) error {
ret := _m.Called(key)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(key)
} else {
r0 = ret.Error(0)
}
return r0
}
// Fetch provides a mock function with given fields: key, value
func (_m *Cache) Fetch(key string, value interface{}) error {
ret := _m.Called(key, value)
var r0 error
if rf, ok := ret.Get(0).(func(string, interface{}) error); ok {
r0 = rf(key, value)
} else {
r0 = ret.Error(0)
}
return r0
}
// Ping provides a mock function with given fields:
func (_m *Cache) Ping() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Save provides a mock function with given fields: key, value, expiration
func (_m *Cache) Save(key string, value interface{}, expiration ...time.Duration) error {
_va := make([]interface{}, len(expiration))
for _i := range expiration {
_va[_i] = expiration[_i]
}
var _ca []interface{}
_ca = append(_ca, key, value)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 error
if rf, ok := ret.Get(0).(func(string, interface{}, ...time.Duration) error); ok {
r0 = rf(key, value, expiration...)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@ -15,3 +15,4 @@
package lib
//go:generate mockery --case snake --dir ../../lib/orm --name Creator --output ./orm --outpkg orm
//go:generate mockery --case snake --dir ../../lib/cache --name Cache --output ./cache --outpkg cache

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell
Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -5,20 +5,28 @@ import (
"reflect"
)
func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
type CompareType int
const (
compareLess CompareType = iota - 1
compareEqual
compareGreater
)
func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) {
switch kind {
case reflect.Int:
{
intobj1 := obj1.(int)
intobj2 := obj2.(int)
if intobj1 > intobj2 {
return -1, true
return compareGreater, true
}
if intobj1 == intobj2 {
return 0, true
return compareEqual, true
}
if intobj1 < intobj2 {
return 1, true
return compareLess, true
}
}
case reflect.Int8:
@ -26,13 +34,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
int8obj1 := obj1.(int8)
int8obj2 := obj2.(int8)
if int8obj1 > int8obj2 {
return -1, true
return compareGreater, true
}
if int8obj1 == int8obj2 {
return 0, true
return compareEqual, true
}
if int8obj1 < int8obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Int16:
@ -40,13 +48,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
int16obj1 := obj1.(int16)
int16obj2 := obj2.(int16)
if int16obj1 > int16obj2 {
return -1, true
return compareGreater, true
}
if int16obj1 == int16obj2 {
return 0, true
return compareEqual, true
}
if int16obj1 < int16obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Int32:
@ -54,13 +62,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
int32obj1 := obj1.(int32)
int32obj2 := obj2.(int32)
if int32obj1 > int32obj2 {
return -1, true
return compareGreater, true
}
if int32obj1 == int32obj2 {
return 0, true
return compareEqual, true
}
if int32obj1 < int32obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Int64:
@ -68,13 +76,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
int64obj1 := obj1.(int64)
int64obj2 := obj2.(int64)
if int64obj1 > int64obj2 {
return -1, true
return compareGreater, true
}
if int64obj1 == int64obj2 {
return 0, true
return compareEqual, true
}
if int64obj1 < int64obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Uint:
@ -82,13 +90,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
uintobj1 := obj1.(uint)
uintobj2 := obj2.(uint)
if uintobj1 > uintobj2 {
return -1, true
return compareGreater, true
}
if uintobj1 == uintobj2 {
return 0, true
return compareEqual, true
}
if uintobj1 < uintobj2 {
return 1, true
return compareLess, true
}
}
case reflect.Uint8:
@ -96,13 +104,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
uint8obj1 := obj1.(uint8)
uint8obj2 := obj2.(uint8)
if uint8obj1 > uint8obj2 {
return -1, true
return compareGreater, true
}
if uint8obj1 == uint8obj2 {
return 0, true
return compareEqual, true
}
if uint8obj1 < uint8obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Uint16:
@ -110,13 +118,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
uint16obj1 := obj1.(uint16)
uint16obj2 := obj2.(uint16)
if uint16obj1 > uint16obj2 {
return -1, true
return compareGreater, true
}
if uint16obj1 == uint16obj2 {
return 0, true
return compareEqual, true
}
if uint16obj1 < uint16obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Uint32:
@ -124,13 +132,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
uint32obj1 := obj1.(uint32)
uint32obj2 := obj2.(uint32)
if uint32obj1 > uint32obj2 {
return -1, true
return compareGreater, true
}
if uint32obj1 == uint32obj2 {
return 0, true
return compareEqual, true
}
if uint32obj1 < uint32obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Uint64:
@ -138,13 +146,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
uint64obj1 := obj1.(uint64)
uint64obj2 := obj2.(uint64)
if uint64obj1 > uint64obj2 {
return -1, true
return compareGreater, true
}
if uint64obj1 == uint64obj2 {
return 0, true
return compareEqual, true
}
if uint64obj1 < uint64obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Float32:
@ -152,13 +160,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
float32obj1 := obj1.(float32)
float32obj2 := obj2.(float32)
if float32obj1 > float32obj2 {
return -1, true
return compareGreater, true
}
if float32obj1 == float32obj2 {
return 0, true
return compareEqual, true
}
if float32obj1 < float32obj2 {
return 1, true
return compareLess, true
}
}
case reflect.Float64:
@ -166,13 +174,13 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
float64obj1 := obj1.(float64)
float64obj2 := obj2.(float64)
if float64obj1 > float64obj2 {
return -1, true
return compareGreater, true
}
if float64obj1 == float64obj2 {
return 0, true
return compareEqual, true
}
if float64obj1 < float64obj2 {
return 1, true
return compareLess, true
}
}
case reflect.String:
@ -180,18 +188,18 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
stringobj1 := obj1.(string)
stringobj2 := obj2.(string)
if stringobj1 > stringobj2 {
return -1, true
return compareGreater, true
}
if stringobj1 == stringobj2 {
return 0, true
return compareEqual, true
}
if stringobj1 < stringobj2 {
return 1, true
return compareLess, true
}
}
}
return 0, false
return compareEqual, false
}
// Greater asserts that the first element is greater than the second
@ -200,26 +208,7 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) {
// assert.Greater(t, float64(2), float64(1))
// assert.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != -1 {
return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...)
}
return true
return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs)
}
// GreaterOrEqual asserts that the first element is greater than or equal to the second
@ -229,26 +218,7 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface
// assert.GreaterOrEqual(t, "b", "a")
// assert.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != -1 && res != 0 {
return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...)
}
return true
return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs)
}
// Less asserts that the first element is less than the second
@ -257,26 +227,7 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in
// assert.Less(t, float64(1), float64(2))
// assert.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != 1 {
return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...)
}
return true
return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs)
}
// LessOrEqual asserts that the first element is less than or equal to the second
@ -286,6 +237,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{})
// assert.LessOrEqual(t, "a", "b")
// assert.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs)
}
func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
@ -296,14 +251,24 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
res, isComparable := compare(e1, e2, e1Kind)
compareResult, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...)
}
if res != 1 && res != 0 {
return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...)
if !containsValue(allowedComparesResults, compareResult) {
return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...)
}
return true
}
func containsValue(values []CompareType, value CompareType) bool {
for _, v := range values {
if v == value {
return true
}
}
return false
}

View File

@ -93,7 +93,7 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args
// EqualValuesf asserts that two objects are equal or convertable to the same types
// and equal.
//
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -127,7 +127,7 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick
// Exactlyf asserts that two objects are equal in value and type.
//
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -173,7 +173,7 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool
// Greaterf asserts that the first element is greater than the second
//
// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
@ -225,7 +225,7 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u
//
// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -237,7 +237,7 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string,
//
// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -245,6 +245,18 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...)
}
// HTTPSuccessf asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
@ -259,7 +271,7 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin
// Implementsf asserts that an object is implemented by the specified interface.
//
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -341,7 +353,7 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
// Lessf asserts that the first element is less than the second
//
// assert.Lessf(t, 1, 2, "error message %s", "formatted")
// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
// assert.Lessf(t, "a", "b", "error message %s", "formatted")
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
@ -454,6 +466,16 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string,
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotNilf asserts that the specified object is not nil.
//
// assert.NotNilf(t, err, "error message %s", "formatted")
@ -476,7 +498,7 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo
// NotRegexpf asserts that a specified regexp does not match a string.
//
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
@ -552,7 +574,7 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str
// Regexpf asserts that a specified regexp matches a string.
//
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {

View File

@ -169,7 +169,7 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
// EqualValuesf asserts that two objects are equal or convertable to the same types
// and equal.
//
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -251,7 +251,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg
// Exactlyf asserts that two objects are equal in value and type.
//
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted")
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -370,7 +370,7 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string,
// Greaterf asserts that the first element is greater than the second
//
// a.Greaterf(2, 1, "error message %s", "formatted")
// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
// a.Greaterf(float64(2), float64(1), "error message %s", "formatted")
// a.Greaterf("b", "a", "error message %s", "formatted")
func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
@ -447,7 +447,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri
//
// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -471,7 +471,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s
//
// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -479,6 +479,30 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url
return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...)
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...)
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
@ -515,7 +539,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{},
// Implementsf asserts that an object is implemented by the specified interface.
//
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -706,7 +730,7 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar
// Lessf asserts that the first element is less than the second
//
// a.Lessf(1, 2, "error message %s", "formatted")
// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
// a.Lessf(float64(1), float64(2), "error message %s", "formatted")
// a.Lessf("a", "b", "error message %s", "formatted")
func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
@ -884,6 +908,26 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr
return NotEqual(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValues(obj1, obj2)
func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqualValues(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted")
func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqualValuesf(a.t, expected, actual, msg, args...)
}
// NotEqualf asserts that the specified values are NOT equal.
//
// a.NotEqualf(obj1, obj2, "error message %s", "formatted")
@ -950,7 +994,7 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in
// NotRegexpf asserts that a specified regexp does not match a string.
//
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
@ -1102,7 +1146,7 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
// Regexpf asserts that a specified regexp matches a string.
//
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {

View File

@ -19,7 +19,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
yaml "gopkg.in/yaml.v2"
yaml "gopkg.in/yaml.v3"
)
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
@ -45,7 +45,7 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
// for table driven tests.
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
// Comparison a custom function that returns true on success and false on failure
// Comparison is a custom function that returns true on success and false on failure
type Comparison func() (success bool)
/*
@ -104,11 +104,11 @@ the problem actually occurred in calling code.*/
// failed.
func CallerInfo() []string {
pc := uintptr(0)
file := ""
line := 0
ok := false
name := ""
var pc uintptr
var ok bool
var file string
var line int
var name string
callers := []string{}
for i := 0; ; i++ {
@ -429,14 +429,27 @@ func samePointers(first, second interface{}) bool {
// to a type conversion in the Go grammar.
func formatUnequalValues(expected, actual interface{}) (e string, a string) {
if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
return fmt.Sprintf("%T(%#v)", expected, expected),
fmt.Sprintf("%T(%#v)", actual, actual)
return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)),
fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual))
}
switch expected.(type) {
case time.Duration:
return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
}
return fmt.Sprintf("%#v", expected), fmt.Sprintf("%#v", actual)
return truncatingFormat(expected), truncatingFormat(actual)
}
// truncatingFormat formats the data and truncates it if it's too long.
//
// This helps keep formatted error messages lines from exceeding the
// bufio.MaxScanTokenSize max line length that the go testing framework imposes.
func truncatingFormat(data interface{}) string {
value := fmt.Sprintf("%#v", data)
max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed.
if len(value) > max {
value = value[0:max] + "<... truncated>"
}
return value
}
// EqualValues asserts that two objects are equal or convertable to the same types
@ -483,12 +496,12 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
//
// assert.NotNil(t, err)
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !isNil(object) {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
}
@ -529,12 +542,12 @@ func isNil(object interface{}) bool {
//
// assert.Nil(t, err)
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if isNil(object) {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
}
@ -571,12 +584,11 @@ func isEmpty(object interface{}) bool {
//
// assert.Empty(t, obj)
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
pass := isEmpty(object)
if !pass {
if h, ok := t.(tHelper); ok {
h.Helper()
}
Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
}
@ -591,12 +603,11 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
// assert.Equal(t, "two", obj[1])
// }
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
pass := !isEmpty(object)
if !pass {
if h, ok := t.(tHelper); ok {
h.Helper()
}
Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
}
@ -639,16 +650,10 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
//
// assert.True(t, myBool)
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if h, ok := t.(interface {
Helper()
}); ok {
h.Helper()
}
if value != true {
if !value {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "Should be true", msgAndArgs...)
}
@ -660,11 +665,10 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
//
// assert.False(t, myBool)
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if value != false {
if value {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "Should be false", msgAndArgs...)
}
@ -695,6 +699,21 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// assert.NotEqualValues(t, obj1, obj2)
func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if ObjectsAreEqualValues(expected, actual) {
return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
}
return true
}
// containsElement try loop over the list check if the list includes the element.
// return (false, false) if impossible.
// return (true, false) if element was not found.
@ -747,10 +766,10 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
ok, found := includeElement(s, contains)
if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...)
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
}
if !found {
return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...)
return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...)
}
return true
@ -881,27 +900,39 @@ func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface
return true
}
aKind := reflect.TypeOf(listA).Kind()
bKind := reflect.TypeOf(listB).Kind()
if aKind != reflect.Array && aKind != reflect.Slice {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listA, aKind), msgAndArgs...)
if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) {
return false
}
if bKind != reflect.Array && bKind != reflect.Slice {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listB, bKind), msgAndArgs...)
extraA, extraB := diffLists(listA, listB)
if len(extraA) == 0 && len(extraB) == 0 {
return true
}
return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...)
}
// isList checks that the provided value is array or slice.
func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) {
kind := reflect.TypeOf(list).Kind()
if kind != reflect.Array && kind != reflect.Slice {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind),
msgAndArgs...)
}
return true
}
// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B.
// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and
// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored.
func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) {
aValue := reflect.ValueOf(listA)
bValue := reflect.ValueOf(listB)
aLen := aValue.Len()
bLen := bValue.Len()
if aLen != bLen {
return Fail(t, fmt.Sprintf("lengths don't match: %d != %d", aLen, bLen), msgAndArgs...)
}
// Mark indexes in bValue that we already used
visited := make([]bool, bLen)
for i := 0; i < aLen; i++ {
@ -918,11 +949,38 @@ func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface
}
}
if !found {
return Fail(t, fmt.Sprintf("element %s appears more times in %s than in %s", element, aValue, bValue), msgAndArgs...)
extraA = append(extraA, element)
}
}
return true
for j := 0; j < bLen; j++ {
if visited[j] {
continue
}
extraB = append(extraB, bValue.Index(j).Interface())
}
return
}
func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string {
var msg bytes.Buffer
msg.WriteString("elements differ")
if len(extraA) > 0 {
msg.WriteString("\n\nextra elements in list A:\n")
msg.WriteString(spewConfig.Sdump(extraA))
}
if len(extraB) > 0 {
msg.WriteString("\n\nextra elements in list B:\n")
msg.WriteString(spewConfig.Sdump(extraB))
}
msg.WriteString("\n\nlistA:\n")
msg.WriteString(spewConfig.Sdump(listA))
msg.WriteString("\n\nlistB:\n")
msg.WriteString(spewConfig.Sdump(listB))
return msg.String()
}
// Condition uses a Comparison to assert a complex condition.
@ -1058,6 +1116,8 @@ func toFloat(x interface{}) (float64, bool) {
xok := true
switch xn := x.(type) {
case uint:
xf = float64(xn)
case uint8:
xf = float64(xn)
case uint16:
@ -1079,7 +1139,7 @@ func toFloat(x interface{}) (float64, bool) {
case float32:
xf = float64(xn)
case float64:
xf = float64(xn)
xf = xn
case time.Duration:
xf = float64(xn)
default:
@ -1193,6 +1253,9 @@ func calcRelativeError(expected, actual interface{}) (float64, error) {
if !aok {
return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
}
if math.IsNaN(af) {
return 0, errors.New("expected value must not be NaN")
}
if af == 0 {
return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
}
@ -1200,6 +1263,9 @@ func calcRelativeError(expected, actual interface{}) (float64, error) {
if !bok {
return 0, fmt.Errorf("actual value %q cannot be converted to float", actual)
}
if math.IsNaN(bf) {
return 0, errors.New("actual value must not be NaN")
}
return math.Abs(af-bf) / math.Abs(af), nil
}
@ -1209,6 +1275,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
if h, ok := t.(tHelper); ok {
h.Helper()
}
if math.IsNaN(epsilon) {
return Fail(t, "epsilon must not be NaN")
}
actualEpsilon, err := calcRelativeError(expected, actual)
if err != nil {
return Fail(t, err.Error(), msgAndArgs...)
@ -1256,10 +1325,10 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
// assert.Equal(t, expectedObj, actualObj)
// }
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err != nil {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
}
@ -1273,11 +1342,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
// assert.Equal(t, expectedError, err)
// }
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err == nil {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "An error is expected but got nil.", msgAndArgs...)
}
@ -1553,6 +1621,7 @@ var spewConfig = spew.ConfigState{
DisablePointerAddresses: true,
DisableCapacities: true,
SortKeys: true,
DisableMethods: true,
}
type tHelper interface {

View File

@ -33,7 +33,6 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
return false
}
isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
@ -56,7 +55,6 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
return false
}
isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
@ -79,7 +77,6 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
return false
}
isErrorCode := code >= http.StatusBadRequest
@ -90,6 +87,28 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values
return isErrorCode
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
}
successful := code == statuscode
if !successful {
Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code))
}
return successful
}
// HTTPBody is a helper that returns HTTP body of the response. It returns
// empty string if building a new request fails.
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {

View File

@ -65,6 +65,11 @@ type Call struct {
// reference. It's useful when mocking methods such as unmarshalers or
// decoders.
RunFn func(Arguments)
// PanicMsg holds msg to be used to mock panic on the function call
// if the PanicMsg is set to a non nil string the function call will panic
// irrespective of other settings
PanicMsg *string
}
func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call {
@ -77,6 +82,7 @@ func newCall(parent *Mock, methodName string, callerInfo []string, methodArgumen
Repeatability: 0,
WaitFor: nil,
RunFn: nil,
PanicMsg: nil,
}
}
@ -100,6 +106,18 @@ func (c *Call) Return(returnArguments ...interface{}) *Call {
return c
}
// Panic specifies if the functon call should fail and the panic message
//
// Mock.On("DoSomething").Panic("test panic")
func (c *Call) Panic(msg string) *Call {
c.lock()
defer c.unlock()
c.PanicMsg = &msg
return c
}
// Once indicates that that the mock should only return the value once.
//
// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once()
@ -150,7 +168,7 @@ func (c *Call) After(d time.Duration) *Call {
// mocking a method (such as an unmarshaler) that takes a pointer to a struct and
// sets properties in such struct
//
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}").Return().Run(func(args Arguments) {
// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) {
// arg := args.Get(0).(*map[string]interface{})
// arg["foo"] = "bar"
// })
@ -392,6 +410,13 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
time.Sleep(call.waitTime)
}
m.mutex.Lock()
panicMsg := call.PanicMsg
m.mutex.Unlock()
if panicMsg != nil {
panic(*panicMsg)
}
m.mutex.Lock()
runFn := call.RunFn
m.mutex.Unlock()
@ -527,6 +552,45 @@ func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...inter
return true
}
// IsMethodCallable checking that the method can be called
// If the method was called more than `Repeatability` return false
func (m *Mock) IsMethodCallable(t TestingT, methodName string, arguments ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
m.mutex.Lock()
defer m.mutex.Unlock()
for _, v := range m.ExpectedCalls {
if v.Method != methodName {
continue
}
if len(arguments) != len(v.Arguments) {
continue
}
if v.Repeatability < v.totalCalls {
continue
}
if isArgsEqual(v.Arguments, arguments) {
return true
}
}
return false
}
// isArgsEqual compares arguments
func isArgsEqual(expected Arguments, args []interface{}) bool {
if len(expected) != len(args) {
return false
}
for i, v := range args {
if !reflect.DeepEqual(expected[i], v) {
return false
}
}
return true
}
func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool {
for _, call := range m.calls() {
if call.Method == methodName {
@ -791,7 +855,7 @@ func (args Arguments) String(indexOrNil ...int) string {
// normal String() method - return a string representation of the args
var argsStr []string
for _, arg := range args {
argsStr = append(argsStr, fmt.Sprintf("%s", reflect.TypeOf(arg)))
argsStr = append(argsStr, fmt.Sprintf("%T", arg)) // handles nil nicely
}
return strings.Join(argsStr, ",")
} else if len(indexOrNil) == 1 {

View File

@ -212,7 +212,7 @@ func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArg
// EqualValuesf asserts that two objects are equal or convertable to the same types
// and equal.
//
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -315,7 +315,7 @@ func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ..
// Exactlyf asserts that two objects are equal in value and type.
//
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -470,7 +470,7 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg
// Greaterf asserts that the first element is greater than the second
//
// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1))
// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
@ -565,7 +565,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string,
//
// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -595,7 +595,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url strin
//
// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -606,6 +606,36 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri
t.FailNow()
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) {
return
}
t.FailNow()
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) {
return
}
t.FailNow()
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
@ -651,7 +681,7 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg
// Implementsf asserts that an object is implemented by the specified interface.
//
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
@ -902,7 +932,7 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args .
// Lessf asserts that the first element is less than the second
//
// assert.Lessf(t, 1, 2, "error message %s", "formatted")
// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2))
// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
// assert.Lessf(t, "a", "b", "error message %s", "formatted")
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
@ -1128,6 +1158,32 @@ func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs .
t.FailNow()
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// assert.NotEqualValues(t, obj1, obj2)
func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEqualValues(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEqualValuesf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// NotEqualf asserts that the specified values are NOT equal.
//
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
@ -1212,7 +1268,7 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
// NotRegexpf asserts that a specified regexp does not match a string.
//
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
@ -1406,7 +1462,7 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface
// Regexpf asserts that a specified regexp matches a string.
//
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {

View File

@ -170,7 +170,7 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
// EqualValuesf asserts that two objects are equal or convertable to the same types
// and equal.
//
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -252,7 +252,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg
// Exactlyf asserts that two objects are equal in value and type.
//
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted")
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -371,7 +371,7 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string,
// Greaterf asserts that the first element is greater than the second
//
// a.Greaterf(2, 1, "error message %s", "formatted")
// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1))
// a.Greaterf(float64(2), float64(1), "error message %s", "formatted")
// a.Greaterf("b", "a", "error message %s", "formatted")
func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
@ -448,7 +448,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri
//
// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -472,7 +472,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s
//
// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -480,6 +480,30 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url
HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...)
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...)
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
@ -516,7 +540,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{},
// Implementsf asserts that an object is implemented by the specified interface.
//
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
@ -707,7 +731,7 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar
// Lessf asserts that the first element is less than the second
//
// a.Lessf(1, 2, "error message %s", "formatted")
// a.Lessf(float64(1, "error message %s", "formatted"), float64(2))
// a.Lessf(float64(1), float64(2), "error message %s", "formatted")
// a.Lessf("a", "b", "error message %s", "formatted")
func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
@ -885,6 +909,26 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr
NotEqual(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValues(obj1, obj2)
func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqualValues(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted")
func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqualValuesf(a.t, expected, actual, msg, args...)
}
// NotEqualf asserts that the specified values are NOT equal.
//
// a.NotEqualf(obj1, obj2, "error message %s", "formatted")
@ -951,7 +995,7 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in
// NotRegexpf asserts that a specified regexp does not match a string.
//
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
@ -1103,7 +1147,7 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
// Regexpf asserts that a specified regexp matches a string.
//
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {

View File

@ -44,3 +44,10 @@ type BeforeTest interface {
type AfterTest interface {
AfterTest(suiteName, testName string)
}
// WithStats implements HandleStats, a function that will be executed
// when a test suite is finished. The stats contain information about
// the execution of that suite and its tests.
type WithStats interface {
HandleStats(suiteName string, stats *SuiteInformation)
}

46
src/vendor/github.com/stretchr/testify/suite/stats.go generated vendored Normal file
View File

@ -0,0 +1,46 @@
package suite
import "time"
// SuiteInformation stats stores stats for the whole suite execution.
type SuiteInformation struct {
Start, End time.Time
TestStats map[string]*TestInformation
}
// TestInformation stores information about the execution of each test.
type TestInformation struct {
TestName string
Start, End time.Time
Passed bool
}
func newSuiteInformation() *SuiteInformation {
testStats := make(map[string]*TestInformation)
return &SuiteInformation{
TestStats: testStats,
}
}
func (s SuiteInformation) start(testName string) {
s.TestStats[testName] = &TestInformation{
TestName: testName,
Start: time.Now(),
}
}
func (s SuiteInformation) end(testName string, passed bool) {
s.TestStats[testName].End = time.Now()
s.TestStats[testName].Passed = passed
}
func (s SuiteInformation) Passed() bool {
for _, stats := range s.TestStats {
if !stats.Passed {
return false
}
}
return true
}

View File

@ -7,8 +7,8 @@ import (
"reflect"
"regexp"
"runtime/debug"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -81,43 +81,68 @@ func (suite *Suite) Run(name string, subtest func()) bool {
// Run takes a testing suite and runs all of the tests attached
// to it.
func Run(t *testing.T, suite TestingSuite) {
testsSync := &sync.WaitGroup{}
suite.SetT(t)
defer failOnPanic(t)
suiteSetupDone := false
suite.SetT(t)
var suiteSetupDone bool
var stats *SuiteInformation
if _, ok := suite.(WithStats); ok {
stats = newSuiteInformation()
}
methodFinder := reflect.TypeOf(suite)
tests := []testing.InternalTest{}
for index := 0; index < methodFinder.NumMethod(); index++ {
method := methodFinder.Method(index)
methodFinder := reflect.TypeOf(suite)
suiteName := methodFinder.Elem().Name()
for i := 0; i < methodFinder.NumMethod(); i++ {
method := methodFinder.Method(i)
ok, err := methodFilter(method.Name)
if err != nil {
fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err)
os.Exit(1)
}
if !ok {
continue
}
if !suiteSetupDone {
if stats != nil {
stats.Start = time.Now()
}
if setupAllSuite, ok := suite.(SetupAllSuite); ok {
setupAllSuite.SetupSuite()
}
defer func() {
if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
testsSync.Wait()
tearDownAllSuite.TearDownSuite()
}
}()
suiteSetupDone = true
}
test := testing.InternalTest{
Name: method.Name,
F: func(t *testing.T) {
defer testsSync.Done()
parentT := suite.T()
suite.SetT(t)
defer failOnPanic(t)
defer func() {
if stats != nil {
passed := !t.Failed()
stats.end(method.Name, passed)
}
if afterTestSuite, ok := suite.(AfterTest); ok {
afterTestSuite.AfterTest(suiteName, method.Name)
}
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
tearDownTestSuite.TearDownTest()
}
suite.SetT(parentT)
}()
if setupTestSuite, ok := suite.(SetupTestSuite); ok {
setupTestSuite.SetupTest()
@ -125,25 +150,47 @@ func Run(t *testing.T, suite TestingSuite) {
if beforeTestSuite, ok := suite.(BeforeTest); ok {
beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name)
}
defer func() {
if afterTestSuite, ok := suite.(AfterTest); ok {
afterTestSuite.AfterTest(methodFinder.Elem().Name(), method.Name)
}
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
tearDownTestSuite.TearDownTest()
}
suite.SetT(parentT)
}()
if stats != nil {
stats.start(method.Name)
}
method.Func.Call([]reflect.Value{reflect.ValueOf(suite)})
},
}
tests = append(tests, test)
testsSync.Add(1)
}
if suiteSetupDone {
defer func() {
if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
tearDownAllSuite.TearDownSuite()
}
if suiteWithStats, measureStats := suite.(WithStats); measureStats {
stats.End = time.Now()
suiteWithStats.HandleStats(suiteName, stats)
}
}()
}
runTests(t, tests)
}
// Filtering method according to set regular expression
// specified command-line argument -m
func methodFilter(name string) (bool, error) {
if ok, _ := regexp.MatchString("^Test", name); !ok {
return false, nil
}
return regexp.MatchString(*matchMethod, name)
}
func runTests(t testing.TB, tests []testing.InternalTest) {
if len(tests) == 0 {
t.Log("warning: no tests to run")
return
}
r, ok := t.(runner)
if !ok { // backwards compatibility with Go 1.6 and below
if !testing.RunTests(allTestsFilter, tests) {
@ -157,15 +204,6 @@ func runTests(t testing.TB, tests []testing.InternalTest) {
}
}
// Filtering method according to set regular expression
// specified command-line argument -m
func methodFilter(name string) (bool, error) {
if ok, _ := regexp.MatchString("^Test", name); !ok {
return false, nil
}
return regexp.MatchString(*matchMethod, name)
}
type runner interface {
Run(name string, f func(t *testing.T)) bool
}

View File

@ -0,0 +1,18 @@
run:
concurrency: 8
deadline: 5m
tests: false
linters:
enable-all: true
disable:
- gochecknoglobals
- gocognit
- godox
- wsl
- funlen
- gochecknoinits
- gomnd
- nlreturn
- goerr113
- exhaustive
- nestif

View File

@ -0,0 +1,4 @@
semi: false
singleQuote: true
proseWrap: always
printWidth: 100

View File

@ -0,0 +1,20 @@
sudo: false
language: go
go:
- 1.14.x
- 1.15.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.31.0

View File

@ -0,0 +1,3 @@
# Changelog
See https://msgpack.uptrace.dev/changelog/

25
src/vendor/github.com/vmihailenco/msgpack/v5/LICENSE generated vendored Normal file
View File

@ -0,0 +1,25 @@
Copyright (c) 2013 The github.com/vmihailenco/msgpack Authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,7 @@
all:
go test ./...
go test ./... -short -race
go test ./... -run=NONE -bench=. -benchmem
env GOOS=linux GOARCH=386 go test ./...
go vet
golangci-lint run

81
src/vendor/github.com/vmihailenco/msgpack/v5/README.md generated vendored Normal file
View File

@ -0,0 +1,81 @@
# MessagePack encoding for Golang
[![Build Status](https://travis-ci.org/vmihailenco/msgpack.svg)](https://travis-ci.org/vmihailenco/msgpack)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/vmihailenco/msgpack/v5)](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5)
[![Documentation](https://img.shields.io/badge/msgpack-documentation-informational)](https://msgpack.uptrace.dev/)
[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj)
> :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev)
- Join [Discord](https://discord.gg/rWtp5Aj) to ask questions.
- [Documentation](https://msgpack.uptrace.dev)
- [Reference](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5)
- [Examples](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#pkg-examples)
## Features
- Primitives, arrays, maps, structs, time.Time and interface{}.
- Appengine \*datastore.Key and datastore.Cursor.
- [CustomEncoder](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-CustomEncoder)/CustomDecoder
interfaces for custom encoding.
- [Extensions](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-RegisterExt) to encode
type information.
- 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://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal--OmitEmpty).
- [Map keys sorting](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.SortMapKeys).
- Encoding/decoding all
[structs as arrays](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.UseArrayForStructs)
or
[individual structs](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal--AsArray).
- [Encoder.UseJSONTag](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.UseJSONTag) with
[Decoder.UseJSONTag](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Decoder.UseJSONTag) can
turn msgpack into drop-in replacement for JSON.
- Simple but very fast and efficient
[queries](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Decoder-Query).
## Installation
msgpack supports 2 last Go versions and requires support for
[Go modules](https://github.com/golang/go/wiki/Modules). So make sure to initialize a Go module:
```shell
go mod init github.com/my/repo
```
And then install msgpack/v5 (note _v5_ in the import; omitting it is a popular mistake):
```shell
go get github.com/vmihailenco/msgpack/v5
```
## Quickstart
```go
import "github.com/vmihailenco/msgpack/v5"
func ExampleMarshal() {
type Item struct {
Foo string
}
b, err := msgpack.Marshal(&Item{Foo: "bar"})
if err != nil {
panic(err)
}
var item Item
err = msgpack.Unmarshal(b, &item)
if err != nil {
panic(err)
}
fmt.Println(item.Foo)
// Output: bar
}
```
## See also
- [Fast and flexible HTTP router](https://github.com/vmihailenco/treemux)
- [Golang PostgreSQL ORM](https://github.com/go-pg/pg)
- [Golang message task queue](https://github.com/vmihailenco/taskq)

657
src/vendor/github.com/vmihailenco/msgpack/v5/decode.go generated vendored Normal file
View File

@ -0,0 +1,657 @@
package msgpack
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"reflect"
"sync"
"time"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
const (
looseInterfaceDecodingFlag uint32 = 1 << iota
disallowUnknownFieldsFlag
)
const (
bytesAllocLimit = 1e6 // 1mb
sliceAllocLimit = 1e4
maxMapSize = 1e6
)
type bufReader interface {
io.Reader
io.ByteScanner
}
//------------------------------------------------------------------------------
var decPool = sync.Pool{
New: func() interface{} {
return NewDecoder(nil)
},
}
func GetDecoder() *Decoder {
return decPool.Get().(*Decoder)
}
func PutDecoder(dec *Decoder) {
dec.r = nil
dec.s = nil
decPool.Put(dec)
}
//------------------------------------------------------------------------------
// Unmarshal decodes the MessagePack-encoded data and stores the result
// in the value pointed to by v.
func Unmarshal(data []byte, v interface{}) error {
dec := GetDecoder()
dec.Reset(bytes.NewReader(data))
err := dec.Decode(v)
PutDecoder(dec)
return err
}
// A Decoder reads and decodes MessagePack values from an input stream.
type Decoder struct {
r io.Reader
s io.ByteScanner
buf []byte
rec []byte // accumulates read data if not nil
dict []string
flags uint32
structTag string
decodeMapFunc func(*Decoder) (interface{}, error)
}
// NewDecoder returns a new decoder that reads from r.
//
// The decoder introduces its own buffering and may read data from r
// beyond the requested msgpack values. Buffering can be disabled
// by passing a reader that implements io.ByteScanner interface.
func NewDecoder(r io.Reader) *Decoder {
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) {
d.ResetDict(r, nil)
}
// ResetDict is like Reset, but also resets the dict.
func (d *Decoder) ResetDict(r io.Reader, dict []string) {
d.resetReader(r)
d.flags = 0
d.structTag = ""
d.decodeMapFunc = nil
if len(dict) > 0 {
d.dict = dict
} else {
d.dict = d.dict[:0]
}
}
func (d *Decoder) resetReader(r io.Reader) {
if br, ok := r.(bufReader); ok {
d.r = br
d.s = br
} else {
br := bufio.NewReader(r)
d.r = br
d.s = br
}
}
func (d *Decoder) SetMapDecoder(fn func(*Decoder) (interface{}, error)) {
d.decodeMapFunc = fn
}
// UseLooseInterfaceDecoding causes decoder to use DecodeInterfaceLoose
// to decode msgpack value into Go interface{}.
func (d *Decoder) UseLooseInterfaceDecoding(on bool) {
if on {
d.flags |= looseInterfaceDecodingFlag
} else {
d.flags &= ^looseInterfaceDecodingFlag
}
}
// SetCustomStructTag causes the decoder to use the supplied tag as a fallback option
// if there is no msgpack tag.
func (d *Decoder) SetCustomStructTag(tag string) {
d.structTag = tag
}
// 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(on bool) {
if on {
d.flags |= disallowUnknownFieldsFlag
} else {
d.flags &= ^disallowUnknownFieldsFlag
}
}
// UseInternedStrings enables support for decoding interned strings.
func (d *Decoder) UseInternedStrings(on bool) {
if on {
d.flags |= useInternedStringsFlag
} else {
d.flags &= ^useInternedStringsFlag
}
}
// 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) {
case *string:
if v != nil {
*v, err = d.DecodeString()
return err
}
case *[]byte:
if v != nil {
return d.decodeBytesPtr(v)
}
case *int:
if v != nil {
*v, err = d.DecodeInt()
return err
}
case *int8:
if v != nil {
*v, err = d.DecodeInt8()
return err
}
case *int16:
if v != nil {
*v, err = d.DecodeInt16()
return err
}
case *int32:
if v != nil {
*v, err = d.DecodeInt32()
return err
}
case *int64:
if v != nil {
*v, err = d.DecodeInt64()
return err
}
case *uint:
if v != nil {
*v, err = d.DecodeUint()
return err
}
case *uint8:
if v != nil {
*v, err = d.DecodeUint8()
return err
}
case *uint16:
if v != nil {
*v, err = d.DecodeUint16()
return err
}
case *uint32:
if v != nil {
*v, err = d.DecodeUint32()
return err
}
case *uint64:
if v != nil {
*v, err = d.DecodeUint64()
return err
}
case *bool:
if v != nil {
*v, err = d.DecodeBool()
return err
}
case *float32:
if v != nil {
*v, err = d.DecodeFloat32()
return err
}
case *float64:
if v != nil {
*v, err = d.DecodeFloat64()
return err
}
case *[]string:
return d.decodeStringSlicePtr(v)
case *map[string]string:
return d.decodeMapStringStringPtr(v)
case *map[string]interface{}:
return d.decodeMapStringInterfacePtr(v)
case *time.Duration:
if v != nil {
vv, err := d.DecodeInt64()
*v = time.Duration(vv)
return err
}
case *time.Time:
if v != nil {
*v, err = d.DecodeTime()
return err
}
}
vv := reflect.ValueOf(v)
if !vv.IsValid() {
return errors.New("msgpack: Decode(nil)")
}
if vv.Kind() != reflect.Ptr {
return fmt.Errorf("msgpack: Decode(non-pointer %T)", v)
}
if vv.IsNil() {
return fmt.Errorf("msgpack: Decode(non-settable %T)", v)
}
vv = vv.Elem()
if vv.Kind() == reflect.Interface {
if !vv.IsNil() {
vv = vv.Elem()
if vv.Kind() != reflect.Ptr {
return fmt.Errorf("msgpack: Decode(non-pointer %s)", vv.Type().String())
}
}
}
return d.DecodeValue(vv)
}
func (d *Decoder) DecodeMulti(v ...interface{}) error {
for _, vv := range v {
if err := d.Decode(vv); err != nil {
return err
}
}
return nil
}
func (d *Decoder) decodeInterfaceCond() (interface{}, error) {
if d.flags&looseInterfaceDecodingFlag != 0 {
return d.DecodeInterfaceLoose()
}
return d.DecodeInterface()
}
func (d *Decoder) DecodeValue(v reflect.Value) error {
decode := getDecoder(v.Type())
return decode(d, v)
}
func (d *Decoder) DecodeNil() error {
c, err := d.readCode()
if err != nil {
return err
}
if c != msgpcode.Nil {
return fmt.Errorf("msgpack: invalid code=%x decoding nil", c)
}
return nil
}
func (d *Decoder) decodeNilValue(v reflect.Value) error {
err := d.DecodeNil()
if v.IsNil() {
return err
}
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
v.Set(reflect.Zero(v.Type()))
return err
}
func (d *Decoder) DecodeBool() (bool, error) {
c, err := d.readCode()
if err != nil {
return false, err
}
return d.bool(c)
}
func (d *Decoder) bool(c byte) (bool, error) {
if c == msgpcode.False {
return false, nil
}
if c == msgpcode.True {
return true, nil
}
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,
// - int8, int16, int32, int64,
// - uint8, uint16, uint32, uint64,
// - float32 and float64,
// - string,
// - []byte,
// - slices of any of the above,
// - maps of any of the above.
//
// DecodeInterface should be used only when you don't know the type of value
// you are decoding. For example, if you are decoding number it is better to use
// DecodeInt64 for negative numbers and DecodeUint64 for positive numbers.
func (d *Decoder) DecodeInterface() (interface{}, error) {
c, err := d.readCode()
if err != nil {
return nil, err
}
if msgpcode.IsFixedNum(c) {
return int8(c), nil
}
if msgpcode.IsFixedMap(c) {
err = d.s.UnreadByte()
if err != nil {
return nil, err
}
return d.decodeMapDefault()
}
if msgpcode.IsFixedArray(c) {
return d.decodeSlice(c)
}
if msgpcode.IsFixedString(c) {
return d.string(c)
}
switch c {
case msgpcode.Nil:
return nil, nil
case msgpcode.False, msgpcode.True:
return d.bool(c)
case msgpcode.Float:
return d.float32(c)
case msgpcode.Double:
return d.float64(c)
case msgpcode.Uint8:
return d.uint8()
case msgpcode.Uint16:
return d.uint16()
case msgpcode.Uint32:
return d.uint32()
case msgpcode.Uint64:
return d.uint64()
case msgpcode.Int8:
return d.int8()
case msgpcode.Int16:
return d.int16()
case msgpcode.Int32:
return d.int32()
case msgpcode.Int64:
return d.int64()
case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32:
return d.bytes(c, nil)
case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32:
return d.string(c)
case msgpcode.Array16, msgpcode.Array32:
return d.decodeSlice(c)
case msgpcode.Map16, msgpcode.Map32:
err = d.s.UnreadByte()
if err != nil {
return nil, err
}
return d.decodeMapDefault()
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16,
msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32:
return d.decodeInterfaceExt(c)
}
return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c)
}
// DecodeInterfaceLoose is like DecodeInterface except that:
// - int8, int16, and int32 are converted to int64,
// - uint8, uint16, and uint32 are converted to uint64,
// - float32 is converted to float64.
func (d *Decoder) DecodeInterfaceLoose() (interface{}, error) {
c, err := d.readCode()
if err != nil {
return nil, err
}
if msgpcode.IsFixedNum(c) {
return int64(int8(c)), nil
}
if msgpcode.IsFixedMap(c) {
err = d.s.UnreadByte()
if err != nil {
return nil, err
}
return d.decodeMapDefault()
}
if msgpcode.IsFixedArray(c) {
return d.decodeSlice(c)
}
if msgpcode.IsFixedString(c) {
return d.string(c)
}
switch c {
case msgpcode.Nil:
return nil, nil
case msgpcode.False, msgpcode.True:
return d.bool(c)
case msgpcode.Float, msgpcode.Double:
return d.float64(c)
case msgpcode.Uint8, msgpcode.Uint16, msgpcode.Uint32, msgpcode.Uint64:
return d.uint(c)
case msgpcode.Int8, msgpcode.Int16, msgpcode.Int32, msgpcode.Int64:
return d.int(c)
case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32:
return d.bytes(c, nil)
case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32:
return d.string(c)
case msgpcode.Array16, msgpcode.Array32:
return d.decodeSlice(c)
case msgpcode.Map16, msgpcode.Map32:
err = d.s.UnreadByte()
if err != nil {
return nil, err
}
return d.decodeMapDefault()
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16,
msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32:
return d.decodeInterfaceExt(c)
}
return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c)
}
// Skip skips next value.
func (d *Decoder) Skip() error {
c, err := d.readCode()
if err != nil {
return err
}
if msgpcode.IsFixedNum(c) {
return nil
}
if msgpcode.IsFixedMap(c) {
return d.skipMap(c)
}
if msgpcode.IsFixedArray(c) {
return d.skipSlice(c)
}
if msgpcode.IsFixedString(c) {
return d.skipBytes(c)
}
switch c {
case msgpcode.Nil, msgpcode.False, msgpcode.True:
return nil
case msgpcode.Uint8, msgpcode.Int8:
return d.skipN(1)
case msgpcode.Uint16, msgpcode.Int16:
return d.skipN(2)
case msgpcode.Uint32, msgpcode.Int32, msgpcode.Float:
return d.skipN(4)
case msgpcode.Uint64, msgpcode.Int64, msgpcode.Double:
return d.skipN(8)
case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32:
return d.skipBytes(c)
case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32:
return d.skipBytes(c)
case msgpcode.Array16, msgpcode.Array32:
return d.skipSlice(c)
case msgpcode.Map16, msgpcode.Map32:
return d.skipMap(c)
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16,
msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32:
return d.skipExt(c)
}
return fmt.Errorf("msgpack: unknown code %x", c)
}
func (d *Decoder) DecodeRaw() (RawMessage, error) {
d.rec = make([]byte, 0)
if err := d.Skip(); err != nil {
return nil, err
}
msg := RawMessage(d.rec)
d.rec = nil
return msg, nil
}
// PeekCode returns the next MessagePack code without advancing the reader.
// Subpackage msgpack/codes defines the list of available msgpcode.
func (d *Decoder) PeekCode() (byte, error) {
c, err := d.s.ReadByte()
if err != nil {
return 0, err
}
return c, d.s.UnreadByte()
}
// ReadFull reads exactly len(buf) bytes into the buf.
func (d *Decoder) ReadFull(buf []byte) error {
_, err := readN(d.r, buf, len(buf))
return err
}
func (d *Decoder) hasNilCode() bool {
code, err := d.PeekCode()
return err == nil && code == msgpcode.Nil
}
func (d *Decoder) readCode() (byte, error) {
c, err := d.s.ReadByte()
if err != nil {
return 0, err
}
if d.rec != nil {
d.rec = append(d.rec, c)
}
return c, nil
}
func (d *Decoder) readFull(b []byte) error {
_, err := io.ReadFull(d.r, b)
if err != nil {
return err
}
if d.rec != nil {
d.rec = append(d.rec, b...)
}
return nil
}
func (d *Decoder) readN(n int) ([]byte, error) {
var err error
d.buf, err = readN(d.r, d.buf, n)
if err != nil {
return nil, err
}
if d.rec != nil {
// TODO: read directly into d.rec?
d.rec = append(d.rec, d.buf...)
}
return d.buf, nil
}
func readN(r io.Reader, b []byte, n int) ([]byte, error) {
if b == nil {
if n == 0 {
return make([]byte, 0), nil
}
switch {
case n < 64:
b = make([]byte, 0, 64)
case n <= bytesAllocLimit:
b = make([]byte, 0, n)
default:
b = make([]byte, 0, bytesAllocLimit)
}
}
if n <= cap(b) {
b = b[:n]
_, err := io.ReadFull(r, b)
return b, err
}
b = b[:cap(b)]
var pos int
for {
alloc := min(n-len(b), bytesAllocLimit)
b = append(b, make([]byte, alloc)...)
_, err := io.ReadFull(r, b[pos:])
if err != nil {
return b, err
}
if len(b) == n {
break
}
pos = len(b)
}
return b, nil
}
func min(a, b int) int { //nolint:unparam
if a <= b {
return a
}
return b
}

View File

@ -0,0 +1,349 @@
package msgpack
import (
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
var (
mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil))
mapStringStringType = mapStringStringPtrType.Elem()
)
var (
mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil))
mapStringInterfaceType = mapStringInterfacePtrType.Elem()
)
func decodeMapValue(d *Decoder, v reflect.Value) error {
n, err := d.DecodeMapLen()
if err != nil {
return err
}
typ := v.Type()
if n == -1 {
v.Set(reflect.Zero(typ))
return nil
}
if v.IsNil() {
v.Set(reflect.MakeMap(typ))
}
if n == 0 {
return nil
}
return d.decodeTypedMapValue(v, n)
}
func (d *Decoder) decodeMapDefault() (interface{}, error) {
if d.decodeMapFunc != nil {
return d.decodeMapFunc(d)
}
n, err := d.DecodeMapLen()
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
code, err := d.PeekCode()
if err != nil {
return nil, err
}
if msgpcode.IsString(code) || msgpcode.IsBin(code) || msgpcode.IsExt(code) {
return d.decodeMap(n)
}
return d.decodeUntypedMap(n)
}
// DecodeMapLen decodes map length. Length is -1 when map is nil.
func (d *Decoder) DecodeMapLen() (int, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
if msgpcode.IsExt(c) {
if err = d.skipExtHeader(c); err != nil {
return 0, err
}
c, err = d.readCode()
if err != nil {
return 0, err
}
}
return d.mapLen(c)
}
func (d *Decoder) mapLen(c byte) (int, error) {
if c == msgpcode.Nil {
return -1, nil
}
if c >= msgpcode.FixedMapLow && c <= msgpcode.FixedMapHigh {
return int(c & msgpcode.FixedMapMask), nil
}
if c == msgpcode.Map16 {
size, err := d.uint16()
return int(size), err
}
if c == msgpcode.Map32 {
size, err := d.uint32()
return int(size), err
}
return 0, unexpectedCodeError{code: c, hint: "map length"}
}
func decodeMapStringStringValue(d *Decoder, v reflect.Value) error {
mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string)
return d.decodeMapStringStringPtr(mptr)
}
func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error {
size, err := d.DecodeMapLen()
if err != nil {
return err
}
if size == -1 {
*ptr = nil
return nil
}
m := *ptr
if m == nil {
*ptr = make(map[string]string, min(size, maxMapSize))
m = *ptr
}
for i := 0; i < size; i++ {
mk, err := d.DecodeString()
if err != nil {
return err
}
mv, err := d.DecodeString()
if err != nil {
return err
}
m[mk] = mv
}
return nil
}
func decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error {
ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{})
return d.decodeMapStringInterfacePtr(ptr)
}
func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error {
m, err := d.DecodeMap()
if err != nil {
return err
}
*ptr = m
return nil
}
func (d *Decoder) DecodeMap() (map[string]interface{}, error) {
n, err := d.DecodeMapLen()
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
return d.decodeMap(n)
}
func (d *Decoder) decodeMap(n int) (map[string]interface{}, error) {
m := make(map[string]interface{}, min(n, maxMapSize))
for i := 0; i < n; i++ {
mk, err := d.DecodeString()
if err != nil {
return nil, err
}
mv, err := d.decodeInterfaceCond()
if err != nil {
return nil, err
}
m[mk] = mv
}
return m, nil
}
func (d *Decoder) DecodeUntypedMap() (interface{}, error) {
n, err := d.DecodeMapLen()
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
return d.decodeUntypedMap(n)
}
func (d *Decoder) decodeUntypedMap(n int) (interface{}, error) {
m := make(map[interface{}]interface{}, min(n, maxMapSize))
for i := 0; i < n; i++ {
mk, err := d.decodeInterfaceCond()
if err != nil {
return nil, err
}
mv, err := d.decodeInterfaceCond()
if err != nil {
return nil, err
}
m[mk] = mv
}
return m, nil
}
func (d *Decoder) DecodeTypedMap() (interface{}, error) {
n, err := d.DecodeMapLen()
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
key, err := d.decodeInterfaceCond()
if err != nil {
return nil, err
}
value, err := d.decodeInterfaceCond()
if err != nil {
return nil, err
}
keyType := reflect.TypeOf(key)
valueType := reflect.TypeOf(value)
if !keyType.Comparable() {
return nil, fmt.Errorf("msgpack: unsupported map key: %s", keyType.String())
}
mapType := reflect.MapOf(keyType, valueType)
mapValue := reflect.MakeMap(mapType)
mapValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value))
n--
if err := d.decodeTypedMapValue(mapValue, n); err != nil {
return nil, err
}
return mapValue.Interface(), nil
}
func (d *Decoder) decodeTypedMapValue(v reflect.Value, n int) error {
typ := v.Type()
keyType := typ.Key()
valueType := typ.Elem()
for i := 0; i < n; i++ {
mk := reflect.New(keyType).Elem()
if err := d.DecodeValue(mk); err != nil {
return err
}
mv := reflect.New(valueType).Elem()
if err := d.DecodeValue(mv); err != nil {
return err
}
v.SetMapIndex(mk, mv)
}
return nil
}
func (d *Decoder) skipMap(c byte) error {
n, err := d.mapLen(c)
if err != nil {
return err
}
for i := 0; i < n; i++ {
if err := d.Skip(); err != nil {
return err
}
if err := d.Skip(); err != nil {
return err
}
}
return nil
}
func decodeStructValue(d *Decoder, v reflect.Value) error {
c, err := d.readCode()
if err != nil {
return err
}
var isArray bool
n, err := d.mapLen(c)
if err != nil {
var err2 error
n, err2 = d.arrayLen(c)
if err2 != nil {
return err
}
isArray = true
}
if n == -1 {
v.Set(reflect.Zero(v.Type()))
return nil
}
fields := structs.Fields(v.Type(), d.structTag)
if isArray {
for i, f := range fields.List {
if i >= n {
break
}
if err := f.DecodeValue(d, v); err != nil {
return err
}
}
// Skip extra values.
for i := len(fields.List); i < n; i++ {
if err := d.Skip(); err != nil {
return err
}
}
return nil
}
for i := 0; i < n; i++ {
name, err := d.bytesTemp()
if err != nil {
return err
}
if f := fields.Map[string(name)]; f != nil {
if err := f.DecodeValue(d, v); err != nil {
return err
}
} else if d.flags&disallowUnknownFieldsFlag != 0 {
return fmt.Errorf("msgpack: unknown field %q", name)
} else if err := d.Skip(); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,295 @@
package msgpack
import (
"fmt"
"math"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
func (d *Decoder) skipN(n int) error {
_, err := d.readN(n)
return err
}
func (d *Decoder) uint8() (uint8, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return c, nil
}
func (d *Decoder) int8() (int8, error) {
n, err := d.uint8()
return int8(n), err
}
func (d *Decoder) uint16() (uint16, error) {
b, err := d.readN(2)
if err != nil {
return 0, err
}
return (uint16(b[0]) << 8) | uint16(b[1]), nil
}
func (d *Decoder) int16() (int16, error) {
n, err := d.uint16()
return int16(n), err
}
func (d *Decoder) uint32() (uint32, error) {
b, err := d.readN(4)
if err != nil {
return 0, err
}
n := (uint32(b[0]) << 24) |
(uint32(b[1]) << 16) |
(uint32(b[2]) << 8) |
uint32(b[3])
return n, nil
}
func (d *Decoder) int32() (int32, error) {
n, err := d.uint32()
return int32(n), err
}
func (d *Decoder) uint64() (uint64, error) {
b, err := d.readN(8)
if err != nil {
return 0, err
}
n := (uint64(b[0]) << 56) |
(uint64(b[1]) << 48) |
(uint64(b[2]) << 40) |
(uint64(b[3]) << 32) |
(uint64(b[4]) << 24) |
(uint64(b[5]) << 16) |
(uint64(b[6]) << 8) |
uint64(b[7])
return n, nil
}
func (d *Decoder) int64() (int64, error) {
n, err := d.uint64()
return int64(n), err
}
// DecodeUint64 decodes msgpack int8/16/32/64 and uint8/16/32/64
// into Go uint64.
func (d *Decoder) DecodeUint64() (uint64, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return d.uint(c)
}
func (d *Decoder) uint(c byte) (uint64, error) {
if c == msgpcode.Nil {
return 0, nil
}
if msgpcode.IsFixedNum(c) {
return uint64(int8(c)), nil
}
switch c {
case msgpcode.Uint8:
n, err := d.uint8()
return uint64(n), err
case msgpcode.Int8:
n, err := d.int8()
return uint64(n), err
case msgpcode.Uint16:
n, err := d.uint16()
return uint64(n), err
case msgpcode.Int16:
n, err := d.int16()
return uint64(n), err
case msgpcode.Uint32:
n, err := d.uint32()
return uint64(n), err
case msgpcode.Int32:
n, err := d.int32()
return uint64(n), err
case msgpcode.Uint64, msgpcode.Int64:
return d.uint64()
}
return 0, fmt.Errorf("msgpack: invalid code=%x decoding uint64", c)
}
// DecodeInt64 decodes msgpack int8/16/32/64 and uint8/16/32/64
// into Go int64.
func (d *Decoder) DecodeInt64() (int64, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return d.int(c)
}
func (d *Decoder) int(c byte) (int64, error) {
if c == msgpcode.Nil {
return 0, nil
}
if msgpcode.IsFixedNum(c) {
return int64(int8(c)), nil
}
switch c {
case msgpcode.Uint8:
n, err := d.uint8()
return int64(n), err
case msgpcode.Int8:
n, err := d.uint8()
return int64(int8(n)), err
case msgpcode.Uint16:
n, err := d.uint16()
return int64(n), err
case msgpcode.Int16:
n, err := d.uint16()
return int64(int16(n)), err
case msgpcode.Uint32:
n, err := d.uint32()
return int64(n), err
case msgpcode.Int32:
n, err := d.uint32()
return int64(int32(n)), err
case msgpcode.Uint64, msgpcode.Int64:
n, err := d.uint64()
return int64(n), err
}
return 0, fmt.Errorf("msgpack: invalid code=%x decoding int64", c)
}
func (d *Decoder) DecodeFloat32() (float32, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return d.float32(c)
}
func (d *Decoder) float32(c byte) (float32, error) {
if c == msgpcode.Float {
n, err := d.uint32()
if err != nil {
return 0, err
}
return math.Float32frombits(n), nil
}
n, err := d.int(c)
if err != nil {
return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c)
}
return float32(n), nil
}
// DecodeFloat64 decodes msgpack float32/64 into Go float64.
func (d *Decoder) DecodeFloat64() (float64, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return d.float64(c)
}
func (d *Decoder) float64(c byte) (float64, error) {
switch c {
case msgpcode.Float:
n, err := d.float32(c)
if err != nil {
return 0, err
}
return float64(n), nil
case msgpcode.Double:
n, err := d.uint64()
if err != nil {
return 0, err
}
return math.Float64frombits(n), nil
}
n, err := d.int(c)
if err != nil {
return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c)
}
return float64(n), nil
}
func (d *Decoder) DecodeUint() (uint, error) {
n, err := d.DecodeUint64()
return uint(n), err
}
func (d *Decoder) DecodeUint8() (uint8, error) {
n, err := d.DecodeUint64()
return uint8(n), err
}
func (d *Decoder) DecodeUint16() (uint16, error) {
n, err := d.DecodeUint64()
return uint16(n), err
}
func (d *Decoder) DecodeUint32() (uint32, error) {
n, err := d.DecodeUint64()
return uint32(n), err
}
func (d *Decoder) DecodeInt() (int, error) {
n, err := d.DecodeInt64()
return int(n), err
}
func (d *Decoder) DecodeInt8() (int8, error) {
n, err := d.DecodeInt64()
return int8(n), err
}
func (d *Decoder) DecodeInt16() (int16, error) {
n, err := d.DecodeInt64()
return int16(n), err
}
func (d *Decoder) DecodeInt32() (int32, error) {
n, err := d.DecodeInt64()
return int32(n), err
}
func decodeFloat32Value(d *Decoder, v reflect.Value) error {
f, err := d.DecodeFloat32()
if err != nil {
return err
}
v.SetFloat(float64(f))
return nil
}
func decodeFloat64Value(d *Decoder, v reflect.Value) error {
f, err := d.DecodeFloat64()
if err != nil {
return err
}
v.SetFloat(f)
return nil
}
func decodeInt64Value(d *Decoder, v reflect.Value) error {
n, err := d.DecodeInt64()
if err != nil {
return err
}
v.SetInt(n)
return nil
}
func decodeUint64Value(d *Decoder, v reflect.Value) error {
n, err := d.DecodeUint64()
if err != nil {
return err
}
v.SetUint(n)
return nil
}

View File

@ -0,0 +1,158 @@
package msgpack
import (
"fmt"
"strconv"
"strings"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
type queryResult struct {
query string
key string
hasAsterisk bool
values []interface{}
}
func (q *queryResult) nextKey() {
ind := strings.IndexByte(q.query, '.')
if ind == -1 {
q.key = q.query
q.query = ""
return
}
q.key = q.query[:ind]
q.query = q.query[ind+1:]
}
// Query extracts data specified by the query from the msgpack stream skipping
// any other data. Query consists of map keys and array indexes separated with dot,
// e.g. key1.0.key2.
func (d *Decoder) Query(query string) ([]interface{}, error) {
res := queryResult{
query: query,
}
if err := d.query(&res); err != nil {
return nil, err
}
return res.values, nil
}
func (d *Decoder) query(q *queryResult) error {
q.nextKey()
if q.key == "" {
v, err := d.decodeInterfaceCond()
if err != nil {
return err
}
q.values = append(q.values, v)
return nil
}
code, err := d.PeekCode()
if err != nil {
return err
}
switch {
case code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code):
err = d.queryMapKey(q)
case code == msgpcode.Array16 || code == msgpcode.Array32 || msgpcode.IsFixedArray(code):
err = d.queryArrayIndex(q)
default:
err = fmt.Errorf("msgpack: unsupported code=%x decoding key=%q", code, q.key)
}
return err
}
func (d *Decoder) queryMapKey(q *queryResult) error {
n, err := d.DecodeMapLen()
if err != nil {
return err
}
if n == -1 {
return nil
}
for i := 0; i < n; i++ {
key, err := d.bytesTemp()
if err != nil {
return err
}
if string(key) == q.key {
if err := d.query(q); err != nil {
return err
}
if q.hasAsterisk {
return d.skipNext((n - i - 1) * 2)
}
return nil
}
if err := d.Skip(); err != nil {
return err
}
}
return nil
}
func (d *Decoder) queryArrayIndex(q *queryResult) error {
n, err := d.DecodeArrayLen()
if err != nil {
return err
}
if n == -1 {
return nil
}
if q.key == "*" {
q.hasAsterisk = true
query := q.query
for i := 0; i < n; i++ {
q.query = query
if err := d.query(q); err != nil {
return err
}
}
q.hasAsterisk = false
return nil
}
ind, err := strconv.Atoi(q.key)
if err != nil {
return err
}
for i := 0; i < n; i++ {
if i == ind {
if err := d.query(q); err != nil {
return err
}
if q.hasAsterisk {
return d.skipNext(n - i - 1)
}
return nil
}
if err := d.Skip(); err != nil {
return err
}
}
return nil
}
func (d *Decoder) skipNext(n int) error {
for i := 0; i < n; i++ {
if err := d.Skip(); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,191 @@
package msgpack
import (
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
var sliceStringPtrType = reflect.TypeOf((*[]string)(nil))
// DecodeArrayLen decodes array length. Length is -1 when array is nil.
func (d *Decoder) DecodeArrayLen() (int, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return d.arrayLen(c)
}
func (d *Decoder) arrayLen(c byte) (int, error) {
if c == msgpcode.Nil {
return -1, nil
} else if c >= msgpcode.FixedArrayLow && c <= msgpcode.FixedArrayHigh {
return int(c & msgpcode.FixedArrayMask), nil
}
switch c {
case msgpcode.Array16:
n, err := d.uint16()
return int(n), err
case msgpcode.Array32:
n, err := d.uint32()
return int(n), err
}
return 0, fmt.Errorf("msgpack: invalid code=%x decoding array length", c)
}
func decodeStringSliceValue(d *Decoder, v reflect.Value) error {
ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string)
return d.decodeStringSlicePtr(ptr)
}
func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
n, err := d.DecodeArrayLen()
if err != nil {
return err
}
if n == -1 {
return nil
}
ss := makeStrings(*ptr, n)
for i := 0; i < n; i++ {
s, err := d.DecodeString()
if err != nil {
return err
}
ss = append(ss, s)
}
*ptr = ss
return nil
}
func makeStrings(s []string, n int) []string {
if n > sliceAllocLimit {
n = sliceAllocLimit
}
if s == nil {
return make([]string, 0, n)
}
if cap(s) >= n {
return s[:0]
}
s = s[:cap(s)]
s = append(s, make([]string, n-len(s))...)
return s[:0]
}
func decodeSliceValue(d *Decoder, v reflect.Value) error {
n, err := d.DecodeArrayLen()
if err != nil {
return err
}
if n == -1 {
v.Set(reflect.Zero(v.Type()))
return nil
}
if n == 0 && v.IsNil() {
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
return nil
}
if v.Cap() >= n {
v.Set(v.Slice(0, n))
} else if v.Len() < v.Cap() {
v.Set(v.Slice(0, v.Cap()))
}
for i := 0; i < n; i++ {
if i >= v.Len() {
v.Set(growSliceValue(v, n))
}
elem := v.Index(i)
if err := d.DecodeValue(elem); err != nil {
return err
}
}
return nil
}
func growSliceValue(v reflect.Value, n int) reflect.Value {
diff := n - v.Len()
if diff > sliceAllocLimit {
diff = sliceAllocLimit
}
v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff))
return v
}
func decodeArrayValue(d *Decoder, v reflect.Value) error {
n, err := d.DecodeArrayLen()
if err != nil {
return err
}
if n == -1 {
return nil
}
if n > v.Len() {
return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n)
}
for i := 0; i < n; i++ {
sv := v.Index(i)
if err := d.DecodeValue(sv); err != nil {
return err
}
}
return nil
}
func (d *Decoder) DecodeSlice() ([]interface{}, error) {
c, err := d.readCode()
if err != nil {
return nil, err
}
return d.decodeSlice(c)
}
func (d *Decoder) decodeSlice(c byte) ([]interface{}, error) {
n, err := d.arrayLen(c)
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
s := make([]interface{}, 0, min(n, sliceAllocLimit))
for i := 0; i < n; i++ {
v, err := d.decodeInterfaceCond()
if err != nil {
return nil, err
}
s = append(s, v)
}
return s, nil
}
func (d *Decoder) skipSlice(c byte) error {
n, err := d.arrayLen(c)
if err != nil {
return err
}
for i := 0; i < n; i++ {
if err := d.Skip(); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,181 @@
package msgpack
import (
"fmt"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
func (d *Decoder) bytesLen(c byte) (int, error) {
if c == msgpcode.Nil {
return -1, nil
}
if msgpcode.IsFixedString(c) {
return int(c & msgpcode.FixedStrMask), nil
}
switch c {
case msgpcode.Str8, msgpcode.Bin8:
n, err := d.uint8()
return int(n), err
case msgpcode.Str16, msgpcode.Bin16:
n, err := d.uint16()
return int(n), err
case msgpcode.Str32, msgpcode.Bin32:
n, err := d.uint32()
return int(n), err
}
return 0, fmt.Errorf("msgpack: invalid code=%x decoding string/bytes length", c)
}
func (d *Decoder) DecodeString() (string, error) {
if intern := d.flags&useInternedStringsFlag != 0; intern || len(d.dict) > 0 {
return d.decodeInternedString(intern)
}
c, err := d.readCode()
if err != nil {
return "", err
}
return d.string(c)
}
func (d *Decoder) string(c byte) (string, error) {
n, err := d.bytesLen(c)
if err != nil {
return "", err
}
return d.stringWithLen(n)
}
func (d *Decoder) stringWithLen(n int) (string, error) {
if n <= 0 {
return "", nil
}
b, err := d.readN(n)
return string(b), err
}
func decodeStringValue(d *Decoder, v reflect.Value) error {
s, err := d.DecodeString()
if err != nil {
return err
}
v.SetString(s)
return nil
}
func (d *Decoder) DecodeBytesLen() (int, error) {
c, err := d.readCode()
if err != nil {
return 0, err
}
return d.bytesLen(c)
}
func (d *Decoder) DecodeBytes() ([]byte, error) {
c, err := d.readCode()
if err != nil {
return nil, err
}
return d.bytes(c, nil)
}
func (d *Decoder) bytes(c byte, b []byte) ([]byte, error) {
n, err := d.bytesLen(c)
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
return readN(d.r, b, n)
}
func (d *Decoder) bytesTemp() ([]byte, error) {
c, err := d.readCode()
if err != nil {
return nil, err
}
n, err := d.bytesLen(c)
if err != nil {
return nil, err
}
if n == -1 {
return nil, nil
}
return d.readN(n)
}
func (d *Decoder) decodeBytesPtr(ptr *[]byte) error {
c, err := d.readCode()
if err != nil {
return err
}
return d.bytesPtr(c, ptr)
}
func (d *Decoder) bytesPtr(c byte, ptr *[]byte) error {
n, err := d.bytesLen(c)
if err != nil {
return err
}
if n == -1 {
*ptr = nil
return nil
}
*ptr, err = readN(d.r, *ptr, n)
return err
}
func (d *Decoder) skipBytes(c byte) error {
n, err := d.bytesLen(c)
if err != nil {
return err
}
if n <= 0 {
return nil
}
return d.skipN(n)
}
func decodeBytesValue(d *Decoder, v reflect.Value) error {
c, err := d.readCode()
if err != nil {
return err
}
b, err := d.bytes(c, v.Bytes())
if err != nil {
return err
}
v.SetBytes(b)
return nil
}
func decodeByteArrayValue(d *Decoder, v reflect.Value) error {
c, err := d.readCode()
if err != nil {
return err
}
n, err := d.bytesLen(c)
if err != nil {
return err
}
if n == -1 {
return nil
}
if n > v.Len() {
return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n)
}
b := v.Slice(0, n).Bytes()
return d.readFull(b)
}

View File

@ -0,0 +1,282 @@
package msgpack
import (
"encoding"
"errors"
"fmt"
"reflect"
)
var (
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
stringType = reflect.TypeOf((*string)(nil)).Elem()
)
var valueDecoders []decoderFunc
//nolint:gochecknoinits
func init() {
valueDecoders = []decoderFunc{
reflect.Bool: decodeBoolValue,
reflect.Int: decodeInt64Value,
reflect.Int8: decodeInt64Value,
reflect.Int16: decodeInt64Value,
reflect.Int32: decodeInt64Value,
reflect.Int64: decodeInt64Value,
reflect.Uint: decodeUint64Value,
reflect.Uint8: decodeUint64Value,
reflect.Uint16: decodeUint64Value,
reflect.Uint32: decodeUint64Value,
reflect.Uint64: decodeUint64Value,
reflect.Float32: decodeFloat32Value,
reflect.Float64: decodeFloat64Value,
reflect.Complex64: decodeUnsupportedValue,
reflect.Complex128: decodeUnsupportedValue,
reflect.Array: decodeArrayValue,
reflect.Chan: decodeUnsupportedValue,
reflect.Func: decodeUnsupportedValue,
reflect.Interface: decodeInterfaceValue,
reflect.Map: decodeMapValue,
reflect.Ptr: decodeUnsupportedValue,
reflect.Slice: decodeSliceValue,
reflect.String: decodeStringValue,
reflect.Struct: decodeStructValue,
reflect.UnsafePointer: decodeUnsupportedValue,
}
}
func getDecoder(typ reflect.Type) decoderFunc {
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 kind == reflect.Ptr {
if _, ok := typeDecMap.Load(typ.Elem()); ok {
return ptrDecoderFunc(typ)
}
}
if typ.Implements(customDecoderType) {
return decodeCustomValue
}
if typ.Implements(unmarshalerType) {
return unmarshalValue
}
if typ.Implements(binaryUnmarshalerType) {
return unmarshalBinaryValue
}
if typ.Implements(textUnmarshalerType) {
return unmarshalTextValue
}
// Addressable struct field value.
if kind != reflect.Ptr {
ptr := reflect.PtrTo(typ)
if ptr.Implements(customDecoderType) {
return decodeCustomValueAddr
}
if ptr.Implements(unmarshalerType) {
return unmarshalValueAddr
}
if ptr.Implements(binaryUnmarshalerType) {
return unmarshalBinaryValueAddr
}
if ptr.Implements(textUnmarshalerType) {
return unmarshalTextValueAddr
}
}
switch kind {
case reflect.Ptr:
return ptrDecoderFunc(typ)
case reflect.Slice:
elem := typ.Elem()
if elem.Kind() == reflect.Uint8 {
return decodeBytesValue
}
if elem == stringType {
return decodeStringSliceValue
}
case reflect.Array:
if typ.Elem().Kind() == reflect.Uint8 {
return decodeByteArrayValue
}
case reflect.Map:
if typ.Key() == stringType {
switch typ.Elem() {
case stringType:
return decodeMapStringStringValue
case interfaceType:
return decodeMapStringInterfaceValue
}
}
}
return valueDecoders[kind]
}
func ptrDecoderFunc(typ reflect.Type) decoderFunc {
decoder := getDecoder(typ.Elem())
return func(d *Decoder, v reflect.Value) error {
if d.hasNilCode() {
if !v.IsNil() {
v.Set(reflect.Zero(v.Type()))
}
return d.DecodeNil()
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
return decoder(d, v.Elem())
}
}
func decodeCustomValueAddr(d *Decoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
}
return decodeCustomValue(d, v.Addr())
}
func decodeCustomValue(d *Decoder, v reflect.Value) error {
if d.hasNilCode() {
return d.decodeNilValue(v)
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
decoder := v.Interface().(CustomDecoder)
return decoder.DecodeMsgpack(d)
}
func unmarshalValueAddr(d *Decoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
}
return unmarshalValue(d, v.Addr())
}
func unmarshalValue(d *Decoder, v reflect.Value) error {
if d.hasNilCode() {
return d.decodeNilValue(v)
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
var b []byte
d.rec = make([]byte, 0, 64)
if err := d.Skip(); err != nil {
return err
}
b = d.rec
d.rec = nil
unmarshaler := v.Interface().(Unmarshaler)
return unmarshaler.UnmarshalMsgpack(b)
}
func decodeBoolValue(d *Decoder, v reflect.Value) error {
flag, err := d.DecodeBool()
if err != nil {
return err
}
v.SetBool(flag)
return nil
}
func decodeInterfaceValue(d *Decoder, v reflect.Value) error {
if v.IsNil() {
return d.interfaceValue(v)
}
return d.DecodeValue(v.Elem())
}
func (d *Decoder) interfaceValue(v reflect.Value) error {
vv, err := d.decodeInterfaceCond()
if err != nil {
return err
}
if vv != nil {
if v.Type() == errorType {
if vv, ok := vv.(string); ok {
v.Set(reflect.ValueOf(errors.New(vv)))
return nil
}
}
v.Set(reflect.ValueOf(vv))
}
return nil
}
func decodeUnsupportedValue(d *Decoder, v reflect.Value) error {
return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type())
}
//------------------------------------------------------------------------------
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)
}
//------------------------------------------------------------------------------
func unmarshalTextValueAddr(d *Decoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
}
return unmarshalTextValue(d, v.Addr())
}
func unmarshalTextValue(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.TextUnmarshaler)
return unmarshaler.UnmarshalText(data)
}

258
src/vendor/github.com/vmihailenco/msgpack/v5/encode.go generated vendored Normal file
View File

@ -0,0 +1,258 @@
package msgpack
import (
"bytes"
"io"
"reflect"
"sync"
"time"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
const (
sortMapKeysFlag uint32 = 1 << iota
arrayEncodedStructsFlag
useCompactIntsFlag
useCompactFloatsFlag
useInternedStringsFlag
)
type writer interface {
io.Writer
WriteByte(byte) error
}
type byteWriter struct {
io.Writer
}
func newByteWriter(w io.Writer) byteWriter {
return byteWriter{
Writer: w,
}
}
func (bw byteWriter) WriteByte(c byte) error {
_, err := bw.Write([]byte{c})
return err
}
//------------------------------------------------------------------------------
var encPool = sync.Pool{
New: func() interface{} {
return NewEncoder(nil)
},
}
func GetEncoder() *Encoder {
return encPool.Get().(*Encoder)
}
func PutEncoder(enc *Encoder) {
enc.w = nil
encPool.Put(enc)
}
// Marshal returns the MessagePack encoding of v.
func Marshal(v interface{}) ([]byte, error) {
enc := GetEncoder()
var buf bytes.Buffer
enc.Reset(&buf)
err := enc.Encode(v)
b := buf.Bytes()
PutEncoder(enc)
if err != nil {
return nil, err
}
return b, err
}
type Encoder struct {
w writer
buf []byte
timeBuf []byte
dict map[string]int
flags uint32
structTag string
}
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
e := &Encoder{
buf: make([]byte, 9),
}
e.Reset(w)
return e
}
// Writer returns the Encoder's writer.
func (e *Encoder) Writer() io.Writer {
return e.w
}
// Reset discards any buffered data, resets all state, and switches the writer to write to w.
func (e *Encoder) Reset(w io.Writer) {
e.ResetDict(w, nil)
}
// ResetDict is like Reset, but also resets the dict.
func (e *Encoder) ResetDict(w io.Writer, dict map[string]int) {
e.resetWriter(w)
e.flags = 0
e.structTag = ""
if len(dict) > 0 {
e.dict = dict
} else {
for k := range e.dict {
delete(e.dict, k)
}
}
}
func (e *Encoder) resetWriter(w io.Writer) {
if bw, ok := w.(writer); ok {
e.w = bw
} else {
e.w = newByteWriter(w)
}
}
// SetSortMapKeys causes the Encoder to encode map keys in increasing order.
// Supported map types are:
// - map[string]string
// - map[string]interface{}
func (e *Encoder) SetSortMapKeys(on bool) *Encoder {
if on {
e.flags |= sortMapKeysFlag
} else {
e.flags &= ^sortMapKeysFlag
}
return e
}
// SetCustomStructTag causes the Encoder to use a custom struct tag as
// fallback option if there is no msgpack tag.
func (e *Encoder) SetCustomStructTag(tag string) {
e.structTag = tag
}
// UseArrayEncodedStructs causes the Encoder to encode Go structs as msgpack arrays.
func (e *Encoder) UseArrayEncodedStructs(on bool) {
if on {
e.flags |= arrayEncodedStructsFlag
} else {
e.flags &= ^arrayEncodedStructsFlag
}
}
// 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) UseCompactInts(on bool) {
if on {
e.flags |= useCompactIntsFlag
} else {
e.flags &= ^useCompactIntsFlag
}
}
// 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
}
}
// UseInternedStrings causes the Encoder to intern strings.
func (e *Encoder) UseInternedStrings(on bool) {
if on {
e.flags |= useInternedStringsFlag
} else {
e.flags &= ^useInternedStringsFlag
}
}
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(msgpcode.Nil)
}
func (e *Encoder) EncodeBool(value bool) error {
if value {
return e.writeCode(msgpcode.True)
}
return e.writeCode(msgpcode.False)
}
func (e *Encoder) EncodeDuration(d time.Duration) error {
return e.EncodeInt(int64(d))
}
func (e *Encoder) writeCode(c byte) error {
return e.w.WriteByte(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

@ -0,0 +1,178 @@
package msgpack
import (
"math"
"reflect"
"sort"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
func encodeMapValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
if err := e.EncodeMapLen(v.Len()); err != nil {
return err
}
for _, key := range v.MapKeys() {
if err := e.EncodeValue(key); err != nil {
return err
}
if err := e.EncodeValue(v.MapIndex(key)); err != nil {
return err
}
}
return nil
}
func encodeMapStringStringValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
if err := e.EncodeMapLen(v.Len()); err != nil {
return err
}
m := v.Convert(mapStringStringType).Interface().(map[string]string)
if e.flags&sortMapKeysFlag != 0 {
return e.encodeSortedMapStringString(m)
}
for mk, mv := range m {
if err := e.EncodeString(mk); err != nil {
return err
}
if err := e.EncodeString(mv); err != nil {
return err
}
}
return nil
}
func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{})
if e.flags&sortMapKeysFlag != 0 {
return e.EncodeMapSorted(m)
}
return e.EncodeMap(m)
}
func (e *Encoder) EncodeMap(m map[string]interface{}) error {
if m == nil {
return e.EncodeNil()
}
if err := e.EncodeMapLen(len(m)); err != nil {
return err
}
for mk, mv := range m {
if err := e.EncodeString(mk); err != nil {
return err
}
if err := e.Encode(mv); err != nil {
return err
}
}
return nil
}
func (e *Encoder) EncodeMapSorted(m map[string]interface{}) error {
if m == nil {
return e.EncodeNil()
}
if err := e.EncodeMapLen(len(m)); err != nil {
return err
}
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
if err := e.EncodeString(k); err != nil {
return err
}
if err := e.Encode(m[k]); err != nil {
return err
}
}
return nil
}
func (e *Encoder) encodeSortedMapStringString(m map[string]string) error {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
err := e.EncodeString(k)
if err != nil {
return err
}
if err = e.EncodeString(m[k]); err != nil {
return err
}
}
return nil
}
func (e *Encoder) EncodeMapLen(l int) error {
if l < 16 {
return e.writeCode(msgpcode.FixedMapLow | byte(l))
}
if l <= math.MaxUint16 {
return e.write2(msgpcode.Map16, uint16(l))
}
return e.write4(msgpcode.Map32, uint32(l))
}
func encodeStructValue(e *Encoder, strct reflect.Value) error {
structFields := structs.Fields(strct.Type(), e.structTag)
if e.flags&arrayEncodedStructsFlag != 0 || structFields.AsArray {
return encodeStructValueAsArray(e, strct, structFields.List)
}
fields := structFields.OmitEmpty(strct)
if err := e.EncodeMapLen(len(fields)); err != nil {
return err
}
for _, f := range fields {
if err := e.EncodeString(f.name); err != nil {
return err
}
if err := f.EncodeValue(e, strct); err != nil {
return err
}
}
return nil
}
func encodeStructValueAsArray(e *Encoder, strct reflect.Value, fields []*field) error {
if err := e.EncodeArrayLen(len(fields)); err != nil {
return err
}
for _, f := range fields {
if err := f.EncodeValue(e, strct); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,244 @@
package msgpack
import (
"math"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
// EncodeUint8 encodes an uint8 in 2 bytes preserving type of the number.
func (e *Encoder) EncodeUint8(n uint8) error {
return e.write1(msgpcode.Uint8, n)
}
func (e *Encoder) encodeUint8Cond(n uint8) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(uint64(n))
}
return e.EncodeUint8(n)
}
// EncodeUint16 encodes an uint16 in 3 bytes preserving type of the number.
func (e *Encoder) EncodeUint16(n uint16) error {
return e.write2(msgpcode.Uint16, n)
}
func (e *Encoder) encodeUint16Cond(n uint16) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(uint64(n))
}
return e.EncodeUint16(n)
}
// EncodeUint32 encodes an uint16 in 5 bytes preserving type of the number.
func (e *Encoder) EncodeUint32(n uint32) error {
return e.write4(msgpcode.Uint32, n)
}
func (e *Encoder) encodeUint32Cond(n uint32) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(uint64(n))
}
return e.EncodeUint32(n)
}
// EncodeUint64 encodes an uint16 in 9 bytes preserving type of the number.
func (e *Encoder) EncodeUint64(n uint64) error {
return e.write8(msgpcode.Uint64, n)
}
func (e *Encoder) encodeUint64Cond(n uint64) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeUint(n)
}
return e.EncodeUint64(n)
}
// EncodeInt8 encodes an int8 in 2 bytes preserving type of the number.
func (e *Encoder) EncodeInt8(n int8) error {
return e.write1(msgpcode.Int8, uint8(n))
}
func (e *Encoder) encodeInt8Cond(n int8) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(int64(n))
}
return e.EncodeInt8(n)
}
// EncodeInt16 encodes an int16 in 3 bytes preserving type of the number.
func (e *Encoder) EncodeInt16(n int16) error {
return e.write2(msgpcode.Int16, uint16(n))
}
func (e *Encoder) encodeInt16Cond(n int16) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(int64(n))
}
return e.EncodeInt16(n)
}
// EncodeInt32 encodes an int32 in 5 bytes preserving type of the number.
func (e *Encoder) EncodeInt32(n int32) error {
return e.write4(msgpcode.Int32, uint32(n))
}
func (e *Encoder) encodeInt32Cond(n int32) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(int64(n))
}
return e.EncodeInt32(n)
}
// EncodeInt64 encodes an int64 in 9 bytes preserving type of the number.
func (e *Encoder) EncodeInt64(n int64) error {
return e.write8(msgpcode.Int64, uint64(n))
}
func (e *Encoder) encodeInt64Cond(n int64) error {
if e.flags&useCompactIntsFlag != 0 {
return e.EncodeInt(n)
}
return e.EncodeInt64(n)
}
// EncodeUnsignedNumber encodes an uint64 in 1, 2, 3, 5, or 9 bytes.
// Type of the number is lost during encoding.
func (e *Encoder) EncodeUint(n uint64) error {
if n <= math.MaxInt8 {
return e.w.WriteByte(byte(n))
}
if n <= math.MaxUint8 {
return e.EncodeUint8(uint8(n))
}
if n <= math.MaxUint16 {
return e.EncodeUint16(uint16(n))
}
if n <= math.MaxUint32 {
return e.EncodeUint32(uint32(n))
}
return e.EncodeUint64(n)
}
// EncodeNumber encodes an int64 in 1, 2, 3, 5, or 9 bytes.
// Type of the number is lost during encoding.
func (e *Encoder) EncodeInt(n int64) error {
if n >= 0 {
return e.EncodeUint(uint64(n))
}
if n >= int64(int8(msgpcode.NegFixedNumLow)) {
return e.w.WriteByte(byte(n))
}
if n >= math.MinInt8 {
return e.EncodeInt8(int8(n))
}
if n >= math.MinInt16 {
return e.EncodeInt16(int16(n))
}
if n >= math.MinInt32 {
return e.EncodeInt32(int32(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(msgpcode.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(msgpcode.Double, math.Float64bits(n))
}
func (e *Encoder) write1(code byte, n uint8) error {
e.buf = e.buf[:2]
e.buf[0] = code
e.buf[1] = n
return e.write(e.buf)
}
func (e *Encoder) write2(code byte, n uint16) error {
e.buf = e.buf[:3]
e.buf[0] = code
e.buf[1] = byte(n >> 8)
e.buf[2] = byte(n)
return e.write(e.buf)
}
func (e *Encoder) write4(code byte, n uint32) error {
e.buf = e.buf[:5]
e.buf[0] = code
e.buf[1] = byte(n >> 24)
e.buf[2] = byte(n >> 16)
e.buf[3] = byte(n >> 8)
e.buf[4] = byte(n)
return e.write(e.buf)
}
func (e *Encoder) write8(code byte, n uint64) error {
e.buf = e.buf[:9]
e.buf[0] = code
e.buf[1] = byte(n >> 56)
e.buf[2] = byte(n >> 48)
e.buf[3] = byte(n >> 40)
e.buf[4] = byte(n >> 32)
e.buf[5] = byte(n >> 24)
e.buf[6] = byte(n >> 16)
e.buf[7] = byte(n >> 8)
e.buf[8] = byte(n)
return e.write(e.buf)
}
func encodeUint8CondValue(e *Encoder, v reflect.Value) error {
return e.encodeUint8Cond(uint8(v.Uint()))
}
func encodeUint16CondValue(e *Encoder, v reflect.Value) error {
return e.encodeUint16Cond(uint16(v.Uint()))
}
func encodeUint32CondValue(e *Encoder, v reflect.Value) error {
return e.encodeUint32Cond(uint32(v.Uint()))
}
func encodeUint64CondValue(e *Encoder, v reflect.Value) error {
return e.encodeUint64Cond(v.Uint())
}
func encodeInt8CondValue(e *Encoder, v reflect.Value) error {
return e.encodeInt8Cond(int8(v.Int()))
}
func encodeInt16CondValue(e *Encoder, v reflect.Value) error {
return e.encodeInt16Cond(int16(v.Int()))
}
func encodeInt32CondValue(e *Encoder, v reflect.Value) error {
return e.encodeInt32Cond(int32(v.Int()))
}
func encodeInt64CondValue(e *Encoder, v reflect.Value) error {
return e.encodeInt64Cond(v.Int())
}
func encodeFloat32Value(e *Encoder, v reflect.Value) error {
return e.EncodeFloat32(float32(v.Float()))
}
func encodeFloat64Value(e *Encoder, v reflect.Value) error {
return e.EncodeFloat64(v.Float())
}

View File

@ -0,0 +1,139 @@
package msgpack
import (
"math"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
var stringSliceType = reflect.TypeOf(([]string)(nil))
func encodeStringValue(e *Encoder, v reflect.Value) error {
return e.EncodeString(v.String())
}
func encodeByteSliceValue(e *Encoder, v reflect.Value) error {
return e.EncodeBytes(v.Bytes())
}
func encodeByteArrayValue(e *Encoder, v reflect.Value) error {
if err := e.EncodeBytesLen(v.Len()); err != nil {
return err
}
if v.CanAddr() {
b := v.Slice(0, v.Len()).Bytes()
return e.write(b)
}
e.buf = grow(e.buf, v.Len())
reflect.Copy(reflect.ValueOf(e.buf), v)
return e.write(e.buf)
}
func grow(b []byte, n int) []byte {
if cap(b) >= n {
return b[:n]
}
b = b[:cap(b)]
b = append(b, make([]byte, n-len(b))...)
return b
}
func (e *Encoder) EncodeBytesLen(l int) error {
if l < 256 {
return e.write1(msgpcode.Bin8, uint8(l))
}
if l <= math.MaxUint16 {
return e.write2(msgpcode.Bin16, uint16(l))
}
return e.write4(msgpcode.Bin32, uint32(l))
}
func (e *Encoder) encodeStringLen(l int) error {
if l < 32 {
return e.writeCode(msgpcode.FixedStrLow | byte(l))
}
if l < 256 {
return e.write1(msgpcode.Str8, uint8(l))
}
if l <= math.MaxUint16 {
return e.write2(msgpcode.Str16, uint16(l))
}
return e.write4(msgpcode.Str32, uint32(l))
}
func (e *Encoder) EncodeString(v string) error {
if intern := e.flags&useInternedStringsFlag != 0; intern || len(e.dict) > 0 {
return e.encodeInternedString(v, intern)
}
return e.encodeNormalString(v)
}
func (e *Encoder) encodeNormalString(v string) error {
if err := e.encodeStringLen(len(v)); err != nil {
return err
}
return e.writeString(v)
}
func (e *Encoder) EncodeBytes(v []byte) error {
if v == nil {
return e.EncodeNil()
}
if err := e.EncodeBytesLen(len(v)); err != nil {
return err
}
return e.write(v)
}
func (e *Encoder) EncodeArrayLen(l int) error {
if l < 16 {
return e.writeCode(msgpcode.FixedArrayLow | byte(l))
}
if l <= math.MaxUint16 {
return e.write2(msgpcode.Array16, uint16(l))
}
return e.write4(msgpcode.Array32, uint32(l))
}
func encodeStringSliceValue(e *Encoder, v reflect.Value) error {
ss := v.Convert(stringSliceType).Interface().([]string)
return e.encodeStringSlice(ss)
}
func (e *Encoder) encodeStringSlice(s []string) error {
if s == nil {
return e.EncodeNil()
}
if err := e.EncodeArrayLen(len(s)); err != nil {
return err
}
for _, v := range s {
if err := e.EncodeString(v); err != nil {
return err
}
}
return nil
}
func encodeSliceValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
return encodeArrayValue(e, v)
}
func encodeArrayValue(e *Encoder, v reflect.Value) error {
l := v.Len()
if err := e.EncodeArrayLen(l); err != nil {
return err
}
for i := 0; i < l; i++ {
if err := e.EncodeValue(v.Index(i)); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,245 @@
package msgpack
import (
"encoding"
"fmt"
"reflect"
)
var valueEncoders []encoderFunc
//nolint:gochecknoinits
func init() {
valueEncoders = []encoderFunc{
reflect.Bool: encodeBoolValue,
reflect.Int: encodeInt64CondValue,
reflect.Int8: encodeInt8CondValue,
reflect.Int16: encodeInt16CondValue,
reflect.Int32: encodeInt32CondValue,
reflect.Int64: encodeInt64CondValue,
reflect.Uint: encodeUint64CondValue,
reflect.Uint8: encodeUint8CondValue,
reflect.Uint16: encodeUint16CondValue,
reflect.Uint32: encodeUint32CondValue,
reflect.Uint64: encodeUint64CondValue,
reflect.Float32: encodeFloat32Value,
reflect.Float64: encodeFloat64Value,
reflect.Complex64: encodeUnsupportedValue,
reflect.Complex128: encodeUnsupportedValue,
reflect.Array: encodeArrayValue,
reflect.Chan: encodeUnsupportedValue,
reflect.Func: encodeUnsupportedValue,
reflect.Interface: encodeInterfaceValue,
reflect.Map: encodeMapValue,
reflect.Ptr: encodeUnsupportedValue,
reflect.Slice: encodeSliceValue,
reflect.String: encodeStringValue,
reflect.Struct: encodeStructValue,
reflect.UnsafePointer: encodeUnsupportedValue,
}
}
func getEncoder(typ reflect.Type) encoderFunc {
if 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) {
return encodeCustomValue
}
if typ.Implements(marshalerType) {
return marshalValue
}
if typ.Implements(binaryMarshalerType) {
return marshalBinaryValue
}
if typ.Implements(textMarshalerType) {
return marshalTextValue
}
// Addressable struct field value.
if kind != reflect.Ptr {
ptr := reflect.PtrTo(typ)
if ptr.Implements(customEncoderType) {
return encodeCustomValuePtr
}
if ptr.Implements(marshalerType) {
return marshalValuePtr
}
if ptr.Implements(binaryMarshalerType) {
return marshalBinaryValueAddr
}
if ptr.Implements(textMarshalerType) {
return marshalTextValueAddr
}
}
if typ == errorType {
return encodeErrorValue
}
switch kind {
case reflect.Ptr:
return ptrEncoderFunc(typ)
case reflect.Slice:
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
}
case reflect.Map:
if typ.Key() == stringType {
switch typ.Elem() {
case stringType:
return encodeMapStringStringValue
case interfaceType:
return encodeMapStringInterfaceValue
}
}
}
return valueEncoders[kind]
}
func ptrEncoderFunc(typ reflect.Type) encoderFunc {
encoder := getEncoder(typ.Elem())
return func(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
return encoder(e, v.Elem())
}
}
func encodeCustomValuePtr(e *Encoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
}
encoder := v.Addr().Interface().(CustomEncoder)
return encoder.EncodeMsgpack(e)
}
func encodeCustomValue(e *Encoder, v reflect.Value) error {
if nilable(v) && v.IsNil() {
return e.EncodeNil()
}
encoder := v.Interface().(CustomEncoder)
return encoder.EncodeMsgpack(e)
}
func marshalValuePtr(e *Encoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
}
return marshalValue(e, v.Addr())
}
func marshalValue(e *Encoder, v reflect.Value) error {
if nilable(v) && v.IsNil() {
return e.EncodeNil()
}
marshaler := v.Interface().(Marshaler)
b, err := marshaler.MarshalMsgpack()
if err != nil {
return err
}
_, err = e.w.Write(b)
return err
}
func encodeBoolValue(e *Encoder, v reflect.Value) error {
return e.EncodeBool(v.Bool())
}
func encodeInterfaceValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
return e.EncodeValue(v.Elem())
}
func encodeErrorValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
return e.EncodeString(v.Interface().(error).Error())
}
func encodeUnsupportedValue(e *Encoder, v reflect.Value) error {
return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type())
}
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 marshalBinaryValueAddr(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)
}
//------------------------------------------------------------------------------
func marshalTextValueAddr(e *Encoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface())
}
return marshalTextValue(e, v.Addr())
}
func marshalTextValue(e *Encoder, v reflect.Value) error {
if nilable(v) && v.IsNil() {
return e.EncodeNil()
}
marshaler := v.Interface().(encoding.TextMarshaler)
data, err := marshaler.MarshalText()
if err != nil {
return err
}
return e.EncodeBytes(data)
}

277
src/vendor/github.com/vmihailenco/msgpack/v5/ext.go generated vendored Normal file
View File

@ -0,0 +1,277 @@
package msgpack
import (
"fmt"
"math"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
type extInfo struct {
Type reflect.Type
Decoder func(d *Decoder, v reflect.Value, extLen int) error
}
var extTypes = make(map[int8]*extInfo)
type MarshalerUnmarshaler interface {
Marshaler
Unmarshaler
}
func RegisterExt(extID int8, value MarshalerUnmarshaler) {
RegisterExtEncoder(extID, value, func(e *Encoder, v reflect.Value) ([]byte, error) {
marshaler := v.Interface().(Marshaler)
return marshaler.MarshalMsgpack()
})
RegisterExtDecoder(extID, value, func(d *Decoder, v reflect.Value, extLen int) error {
b, err := d.readN(extLen)
if err != nil {
return err
}
return v.Interface().(Unmarshaler).UnmarshalMsgpack(b)
})
}
func RegisterExtEncoder(
extID int8,
value interface{},
encoder func(enc *Encoder, v reflect.Value) ([]byte, error),
) {
typ := reflect.TypeOf(value)
extEncoder := makeExtEncoder(extID, typ, encoder)
typeEncMap.Store(typ, extEncoder)
if typ.Kind() == reflect.Ptr {
typeEncMap.Store(typ.Elem(), makeExtEncoderAddr(extEncoder))
}
}
func makeExtEncoder(
extID int8,
typ reflect.Type,
encoder func(enc *Encoder, v reflect.Value) ([]byte, error),
) encoderFunc {
nilable := typ.Kind() == reflect.Ptr
return func(e *Encoder, v reflect.Value) error {
if nilable && v.IsNil() {
return e.EncodeNil()
}
b, err := encoder(e, v)
if err != nil {
return err
}
if err := e.EncodeExtHeader(extID, len(b)); err != nil {
return err
}
return e.write(b)
}
}
func makeExtEncoderAddr(extEncoder encoderFunc) encoderFunc {
return func(e *Encoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
}
return extEncoder(e, v.Addr())
}
}
func RegisterExtDecoder(
extID int8,
value interface{},
decoder func(dec *Decoder, v reflect.Value, extLen int) error,
) {
typ := reflect.TypeOf(value)
extDecoder := makeExtDecoder(extID, typ, decoder)
extTypes[extID] = &extInfo{
Type: typ,
Decoder: decoder,
}
typeDecMap.Store(typ, extDecoder)
if typ.Kind() == reflect.Ptr {
typeDecMap.Store(typ.Elem(), makeExtDecoderAddr(extDecoder))
}
}
func makeExtDecoder(
wantedExtID int8,
typ reflect.Type,
decoder func(d *Decoder, v reflect.Value, extLen int) error,
) decoderFunc {
nilable := typ.Kind() == reflect.Ptr
return func(d *Decoder, v reflect.Value) error {
if d.hasNilCode() {
v.Set(reflect.Zero(typ))
return d.DecodeNil()
}
if nilable && v.IsNil() {
v.Set(reflect.New(typ.Elem()))
}
extID, extLen, err := d.DecodeExtHeader()
if err != nil {
return err
}
if extID != wantedExtID {
return fmt.Errorf("msgpack: got ext type=%d, wanted %d", extID, wantedExtID)
}
return decoder(d, v, extLen)
}
}
func makeExtDecoderAddr(extDecoder decoderFunc) decoderFunc {
return func(d *Decoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
}
return extDecoder(d, v.Addr())
}
}
func (e *Encoder) EncodeExtHeader(extID int8, extLen int) error {
if err := e.encodeExtLen(extLen); err != nil {
return err
}
if err := e.w.WriteByte(byte(extID)); err != nil {
return err
}
return nil
}
func (e *Encoder) encodeExtLen(l int) error {
switch l {
case 1:
return e.writeCode(msgpcode.FixExt1)
case 2:
return e.writeCode(msgpcode.FixExt2)
case 4:
return e.writeCode(msgpcode.FixExt4)
case 8:
return e.writeCode(msgpcode.FixExt8)
case 16:
return e.writeCode(msgpcode.FixExt16)
}
if l <= math.MaxUint8 {
return e.write1(msgpcode.Ext8, uint8(l))
}
if l <= math.MaxUint16 {
return e.write2(msgpcode.Ext16, uint16(l))
}
return e.write4(msgpcode.Ext32, uint32(l))
}
func (d *Decoder) DecodeExtHeader() (extID int8, extLen int, err error) {
c, err := d.readCode()
if err != nil {
return
}
return d.extHeader(c)
}
func (d *Decoder) extHeader(c byte) (int8, int, error) {
extLen, err := d.parseExtLen(c)
if err != nil {
return 0, 0, err
}
extID, err := d.readCode()
if err != nil {
return 0, 0, err
}
return int8(extID), extLen, nil
}
func (d *Decoder) parseExtLen(c byte) (int, error) {
switch c {
case msgpcode.FixExt1:
return 1, nil
case msgpcode.FixExt2:
return 2, nil
case msgpcode.FixExt4:
return 4, nil
case msgpcode.FixExt8:
return 8, nil
case msgpcode.FixExt16:
return 16, nil
case msgpcode.Ext8:
n, err := d.uint8()
return int(n), err
case msgpcode.Ext16:
n, err := d.uint16()
return int(n), err
case msgpcode.Ext32:
n, err := d.uint32()
return int(n), err
default:
return 0, fmt.Errorf("msgpack: invalid code=%x decoding ext len", c)
}
}
func (d *Decoder) decodeInterfaceExt(c byte) (interface{}, error) {
extID, extLen, err := d.extHeader(c)
if err != nil {
return nil, err
}
info, ok := extTypes[extID]
if !ok {
return nil, fmt.Errorf("msgpack: unknown ext id=%d", extID)
}
v := reflect.New(info.Type).Elem()
if nilable(v) && v.IsNil() {
v.Set(reflect.New(info.Type.Elem()))
}
if err := info.Decoder(d, v, extLen); err != nil {
return nil, err
}
return v.Interface(), nil
}
func (d *Decoder) skipExt(c byte) error {
n, err := d.parseExtLen(c)
if err != nil {
return err
}
return d.skipN(n + 1)
}
func (d *Decoder) skipExtHeader(c byte) error {
// Read ext type.
_, err := d.readCode()
if err != nil {
return err
}
// Read ext body len.
for i := 0; i < extHeaderLen(c); i++ {
_, err := d.readCode()
if err != nil {
return err
}
}
return nil
}
func extHeaderLen(c byte) int {
switch c {
case msgpcode.Ext8:
return 1
case msgpcode.Ext16:
return 2
case msgpcode.Ext32:
return 4
}
return 0
}

11
src/vendor/github.com/vmihailenco/msgpack/v5/go.mod generated vendored Normal file
View File

@ -0,0 +1,11 @@
module github.com/vmihailenco/msgpack/v5
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/stretchr/testify v1.6.1
github.com/vmihailenco/tagparser v0.1.2
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
)
go 1.11

20
src/vendor/github.com/vmihailenco/msgpack/v5/go.sum generated vendored Normal file
View File

@ -0,0 +1,20 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
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=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

238
src/vendor/github.com/vmihailenco/msgpack/v5/intern.go generated vendored Normal file
View File

@ -0,0 +1,238 @@
package msgpack
import (
"fmt"
"math"
"reflect"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
const (
minInternedStringLen = 3
maxDictLen = math.MaxUint16
)
var internedStringExtID = int8(math.MinInt8)
func init() {
extTypes[internedStringExtID] = &extInfo{
Type: stringType,
Decoder: decodeInternedStringExt,
}
}
func decodeInternedStringExt(d *Decoder, v reflect.Value, extLen int) error {
idx, err := d.decodeInternedStringIndex(extLen)
if err != nil {
return err
}
s, err := d.internedStringAtIndex(idx)
if err != nil {
return err
}
v.SetString(s)
return nil
}
//------------------------------------------------------------------------------
func encodeInternedInterfaceValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
v = v.Elem()
if v.Kind() == reflect.String {
return e.encodeInternedString(v.String(), true)
}
return e.EncodeValue(v)
}
func encodeInternedStringValue(e *Encoder, v reflect.Value) error {
return e.encodeInternedString(v.String(), true)
}
func (e *Encoder) encodeInternedString(s string, intern bool) error {
// Interned string takes at least 3 bytes. Plain string 1 byte + string len.
if len(s) >= minInternedStringLen {
if idx, ok := e.dict[s]; ok {
return e.encodeInternedStringIndex(idx)
}
if intern && len(e.dict) < maxDictLen {
if e.dict == nil {
e.dict = make(map[string]int)
}
idx := len(e.dict)
e.dict[s] = idx
}
}
return e.encodeNormalString(s)
}
func (e *Encoder) encodeInternedStringIndex(idx int) error {
if idx <= math.MaxUint8 {
if err := e.writeCode(msgpcode.FixExt1); err != nil {
return err
}
return e.write1(byte(internedStringExtID), uint8(idx))
}
if idx <= math.MaxUint16 {
if err := e.writeCode(msgpcode.FixExt2); err != nil {
return err
}
return e.write2(byte(internedStringExtID), uint16(idx))
}
if uint64(idx) <= math.MaxUint32 {
if err := e.writeCode(msgpcode.FixExt4); err != nil {
return err
}
return e.write4(byte(internedStringExtID), uint32(idx))
}
return fmt.Errorf("msgpack: interned string index=%d is too large", idx)
}
//------------------------------------------------------------------------------
func decodeInternedInterfaceValue(d *Decoder, v reflect.Value) error {
s, err := d.decodeInternedString(true)
if err == nil {
v.Set(reflect.ValueOf(s))
return nil
}
if err != nil {
if _, ok := err.(unexpectedCodeError); !ok {
return err
}
}
if err := d.s.UnreadByte(); err != nil {
return err
}
return decodeInterfaceValue(d, v)
}
func decodeInternedStringValue(d *Decoder, v reflect.Value) error {
s, err := d.decodeInternedString(true)
if err != nil {
return err
}
v.SetString(s)
return nil
}
func (d *Decoder) decodeInternedString(intern bool) (string, error) {
c, err := d.readCode()
if err != nil {
return "", err
}
if msgpcode.IsFixedString(c) {
n := int(c & msgpcode.FixedStrMask)
return d.decodeInternedStringWithLen(n, intern)
}
switch c {
case msgpcode.Nil:
return "", nil
case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4:
typeID, extLen, err := d.extHeader(c)
if err != nil {
return "", err
}
if typeID != internedStringExtID {
err := fmt.Errorf("msgpack: got ext type=%d, wanted %d",
typeID, internedStringExtID)
return "", err
}
idx, err := d.decodeInternedStringIndex(extLen)
if err != nil {
return "", err
}
return d.internedStringAtIndex(idx)
case msgpcode.Str8, msgpcode.Bin8:
n, err := d.uint8()
if err != nil {
return "", err
}
return d.decodeInternedStringWithLen(int(n), intern)
case msgpcode.Str16, msgpcode.Bin16:
n, err := d.uint16()
if err != nil {
return "", err
}
return d.decodeInternedStringWithLen(int(n), intern)
case msgpcode.Str32, msgpcode.Bin32:
n, err := d.uint32()
if err != nil {
return "", err
}
return d.decodeInternedStringWithLen(int(n), intern)
}
return "", unexpectedCodeError{
code: c,
hint: "interned string",
}
}
func (d *Decoder) decodeInternedStringIndex(extLen int) (int, error) {
switch extLen {
case 1:
n, err := d.uint8()
if err != nil {
return 0, err
}
return int(n), nil
case 2:
n, err := d.uint16()
if err != nil {
return 0, err
}
return int(n), nil
case 4:
n, err := d.uint32()
if err != nil {
return 0, err
}
return int(n), nil
}
err := fmt.Errorf("msgpack: unsupported ext len=%d decoding interned string", extLen)
return 0, err
}
func (d *Decoder) internedStringAtIndex(idx int) (string, error) {
if idx >= len(d.dict) {
err := fmt.Errorf("msgpack: interned string at index=%d does not exist", idx)
return "", err
}
return d.dict[idx], nil
}
func (d *Decoder) decodeInternedStringWithLen(n int, intern bool) (string, error) {
if n <= 0 {
return "", nil
}
s, err := d.stringWithLen(n)
if err != nil {
return "", err
}
if intern && len(s) >= minInternedStringLen && len(d.dict) < maxDictLen {
d.dict = append(d.dict, s)
}
return s, nil
}

View File

@ -0,0 +1,52 @@
package msgpack
import "fmt"
type Marshaler interface {
MarshalMsgpack() ([]byte, error)
}
type Unmarshaler interface {
UnmarshalMsgpack([]byte) error
}
type CustomEncoder interface {
EncodeMsgpack(*Encoder) error
}
type CustomDecoder interface {
DecodeMsgpack(*Decoder) error
}
//------------------------------------------------------------------------------
type RawMessage []byte
var (
_ CustomEncoder = (RawMessage)(nil)
_ CustomDecoder = (*RawMessage)(nil)
)
func (m RawMessage) EncodeMsgpack(enc *Encoder) error {
return enc.write(m)
}
func (m *RawMessage) DecodeMsgpack(dec *Decoder) error {
msg, err := dec.DecodeRaw()
if err != nil {
return err
}
*m = msg
return nil
}
//------------------------------------------------------------------------------
type unexpectedCodeError struct {
code byte
hint string
}
func (err unexpectedCodeError) Error() string {
return fmt.Sprintf("msgpack: unexpected code=%x decoding %s", err.code, err.hint)
}

View File

@ -0,0 +1,88 @@
package msgpcode
var (
PosFixedNumHigh byte = 0x7f
NegFixedNumLow byte = 0xe0
Nil byte = 0xc0
False byte = 0xc2
True byte = 0xc3
Float byte = 0xca
Double byte = 0xcb
Uint8 byte = 0xcc
Uint16 byte = 0xcd
Uint32 byte = 0xce
Uint64 byte = 0xcf
Int8 byte = 0xd0
Int16 byte = 0xd1
Int32 byte = 0xd2
Int64 byte = 0xd3
FixedStrLow byte = 0xa0
FixedStrHigh byte = 0xbf
FixedStrMask byte = 0x1f
Str8 byte = 0xd9
Str16 byte = 0xda
Str32 byte = 0xdb
Bin8 byte = 0xc4
Bin16 byte = 0xc5
Bin32 byte = 0xc6
FixedArrayLow byte = 0x90
FixedArrayHigh byte = 0x9f
FixedArrayMask byte = 0xf
Array16 byte = 0xdc
Array32 byte = 0xdd
FixedMapLow byte = 0x80
FixedMapHigh byte = 0x8f
FixedMapMask byte = 0xf
Map16 byte = 0xde
Map32 byte = 0xdf
FixExt1 byte = 0xd4
FixExt2 byte = 0xd5
FixExt4 byte = 0xd6
FixExt8 byte = 0xd7
FixExt16 byte = 0xd8
Ext8 byte = 0xc7
Ext16 byte = 0xc8
Ext32 byte = 0xc9
)
func IsFixedNum(c byte) bool {
return c <= PosFixedNumHigh || c >= NegFixedNumLow
}
func IsFixedMap(c byte) bool {
return c >= FixedMapLow && c <= FixedMapHigh
}
func IsFixedArray(c byte) bool {
return c >= FixedArrayLow && c <= FixedArrayHigh
}
func IsFixedString(c byte) bool {
return c >= FixedStrLow && c <= FixedStrHigh
}
func IsString(c byte) bool {
return IsFixedString(c) || c == Str8 || c == Str16 || c == Str32
}
func IsBin(c byte) bool {
return c == Bin8 || c == Bin16 || c == Bin32
}
func IsFixedExt(c byte) bool {
return c >= FixExt1 && c <= FixExt16
}
func IsExt(c byte) bool {
return IsFixedExt(c) || c == Ext8 || c == Ext16 || c == Ext32
}

View File

@ -0,0 +1,5 @@
{
"extends": [
"config:base"
]
}

13
src/vendor/github.com/vmihailenco/msgpack/v5/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)
}

145
src/vendor/github.com/vmihailenco/msgpack/v5/time.go generated vendored Normal file
View File

@ -0,0 +1,145 @@
package msgpack
import (
"encoding/binary"
"fmt"
"reflect"
"time"
"github.com/vmihailenco/msgpack/v5/msgpcode"
)
var timeExtID int8 = -1
func init() {
RegisterExtEncoder(timeExtID, time.Time{}, timeEncoder)
RegisterExtDecoder(timeExtID, time.Time{}, timeDecoder)
}
func timeEncoder(e *Encoder, v reflect.Value) ([]byte, error) {
return e.encodeTime(v.Interface().(time.Time)), nil
}
func timeDecoder(d *Decoder, v reflect.Value, extLen int) error {
tm, err := d.decodeTime(extLen)
if err != nil {
return err
}
ptr := v.Addr().Interface().(*time.Time)
*ptr = tm
return nil
}
func (e *Encoder) EncodeTime(tm time.Time) error {
b := e.encodeTime(tm)
if err := e.encodeExtLen(len(b)); err != nil {
return err
}
if err := e.w.WriteByte(byte(timeExtID)); err != nil {
return err
}
return e.write(b)
}
func (e *Encoder) encodeTime(tm time.Time) []byte {
if e.timeBuf == nil {
e.timeBuf = make([]byte, 12)
}
secs := uint64(tm.Unix())
if secs>>34 == 0 {
data := uint64(tm.Nanosecond())<<34 | secs
if data&0xffffffff00000000 == 0 {
b := e.timeBuf[:4]
binary.BigEndian.PutUint32(b, uint32(data))
return b
}
b := e.timeBuf[:8]
binary.BigEndian.PutUint64(b, data)
return b
}
b := e.timeBuf[:12]
binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond()))
binary.BigEndian.PutUint64(b[4:], secs)
return b
}
func (d *Decoder) DecodeTime() (time.Time, error) {
c, err := d.readCode()
if err != nil {
return time.Time{}, err
}
// Legacy format.
if c == msgpcode.FixedArrayLow|2 {
sec, err := d.DecodeInt64()
if err != nil {
return time.Time{}, err
}
nsec, err := d.DecodeInt64()
if err != nil {
return time.Time{}, err
}
return time.Unix(sec, nsec), nil
}
if msgpcode.IsString(c) {
s, err := d.string(c)
if err != nil {
return time.Time{}, err
}
return time.Parse(time.RFC3339Nano, s)
}
extID, extLen, err := d.extHeader(c)
if err != nil {
return time.Time{}, err
}
if extID != timeExtID {
return time.Time{}, fmt.Errorf("msgpack: invalid time ext id=%d", extID)
}
tm, err := d.decodeTime(extLen)
if err != nil {
return tm, err
}
if tm.IsZero() {
// Zero time does not have timezone information.
return tm.UTC(), nil
}
return tm, nil
}
func (d *Decoder) decodeTime(extLen int) (time.Time, error) {
b, err := d.readN(extLen)
if err != nil {
return time.Time{}, err
}
switch len(b) {
case 4:
sec := binary.BigEndian.Uint32(b)
return time.Unix(int64(sec), 0), nil
case 8:
sec := binary.BigEndian.Uint64(b)
nsec := int64(sec >> 34)
sec &= 0x00000003ffffffff
return time.Unix(int64(sec), nsec), nil
case 12:
nsec := binary.BigEndian.Uint32(b)
sec := binary.BigEndian.Uint64(b[4:])
return time.Unix(int64(sec), int64(nsec)), nil
default:
err = fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen)
return time.Time{}, err
}
}

388
src/vendor/github.com/vmihailenco/msgpack/v5/types.go generated vendored Normal file
View File

@ -0,0 +1,388 @@
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()
customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem()
)
var (
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
)
var (
binaryMarshalerType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
binaryUnmarshalerType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
)
var (
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
)
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
// CustomEncoder/CustomDecoder or Marshaler/Unmarshaler interfaces.
func Register(value interface{}, enc encoderFunc, dec decoderFunc) {
typ := reflect.TypeOf(value)
if enc != nil {
typeEncMap.Store(typ, enc)
}
if dec != nil {
typeDecMap.Store(typ, dec)
}
}
//------------------------------------------------------------------------------
const defaultStructTag = "msgpack"
var structs = newStructCache()
type structCache struct {
m sync.Map
}
type structCacheKey struct {
tag string
typ reflect.Type
}
func newStructCache() *structCache {
return new(structCache)
}
func (m *structCache) Fields(typ reflect.Type, tag string) *fields {
key := structCacheKey{tag: tag, typ: typ}
if v, ok := m.m.Load(key); ok {
return v.(*fields)
}
fs := getFields(typ, tag)
m.m.Store(key, fs)
return fs
}
//------------------------------------------------------------------------------
type field struct {
name string
index []int
omitEmpty bool
encoder encoderFunc
decoder decoderFunc
}
func (f *field) Omit(strct reflect.Value) bool {
v, ok := fieldByIndex(strct, f.index)
if !ok {
return true
}
return f.omitEmpty && isEmptyValue(v)
}
func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error {
v, ok := fieldByIndex(strct, f.index)
if !ok {
return e.EncodeNil()
}
return f.encoder(e, v)
}
func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error {
v := fieldByIndexAlloc(strct, f.index)
return f.decoder(d, v)
}
//------------------------------------------------------------------------------
type fields struct {
Type reflect.Type
Map map[string]*field
List []*field
AsArray bool
hasOmitEmpty bool
}
func newFields(typ reflect.Type) *fields {
return &fields{
Type: typ,
Map: make(map[string]*field, typ.NumField()),
List: make([]*field, 0, typ.NumField()),
}
}
func (fs *fields) Add(field *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, fallbackTag string) *fields {
fs := newFields(typ)
var omitEmpty bool
for i := 0; i < typ.NumField(); i++ {
f := typ.Field(i)
tagStr := f.Tag.Get(defaultStructTag)
if tagStr == "" && fallbackTag != "" {
tagStr = f.Tag.Get(fallbackTag)
}
tag := tagparser.Parse(tagStr)
if tag.Name == "-" {
continue
}
if f.Name == "_msgpack" {
fs.AsArray = tag.HasOption("as_array") || tag.HasOption("asArray")
if tag.HasOption("omitempty") {
omitEmpty = true
}
}
if f.PkgPath != "" && !f.Anonymous {
continue
}
field := &field{
name: tag.Name,
index: f.Index,
omitEmpty: omitEmpty || tag.HasOption("omitempty"),
}
if tag.HasOption("intern") {
switch f.Type.Kind() {
case reflect.Interface:
field.encoder = encodeInternedInterfaceValue
field.decoder = decodeInternedInterfaceValue
case reflect.String:
field.encoder = encodeInternedStringValue
field.decoder = decodeInternedStringValue
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 && !tag.HasOption("noinline") {
inline := tag.HasOption("inline")
if inline {
inlineFields(fs, f.Type, field, fallbackTag)
} else {
inline = shouldInline(fs, f.Type, field, fallbackTag)
}
if inline {
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
decodeStructValuePtr uintptr
)
//nolint:gochecknoinits
func init() {
encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer()
decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer()
}
func inlineFields(fs *fields, typ reflect.Type, f *field, tag string) {
inlinedFields := getFields(typ, tag).List
for _, field := range inlinedFields {
if _, ok := fs.Map[field.name]; ok {
// Don't inline shadowed fields.
continue
}
field.index = append(f.index, field.index...)
fs.Add(field)
}
}
func shouldInline(fs *fields, typ reflect.Type, f *field, tag string) bool {
var encoder encoderFunc
var decoder decoderFunc
if typ.Kind() == reflect.Struct {
encoder = f.encoder
decoder = f.decoder
} else {
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
encoder = getEncoder(typ)
decoder = getDecoder(typ)
}
if typ.Kind() != reflect.Struct {
return false
}
}
if reflect.ValueOf(encoder).Pointer() != encodeStructValuePtr {
return false
}
if reflect.ValueOf(decoder).Pointer() != decodeStructValuePtr {
return false
}
inlinedFields := getFields(typ, tag).List
for _, field := range inlinedFields {
if _, ok := fs.Map[field.name]; ok {
// Don't auto inline if there are shadowed fields.
return false
}
}
for _, field := range inlinedFields {
field.index = append(f.index, field.index...)
fs.Add(field)
}
return true
}
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
func fieldByIndex(v reflect.Value, index []int) (_ reflect.Value, ok bool) {
if len(index) == 1 {
return v.Field(index[0]), true
}
for i, idx := range index {
if i > 0 {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return v, false
}
v = v.Elem()
}
}
v = v.Field(idx)
}
return v, true
}
func fieldByIndexAlloc(v reflect.Value, index []int) reflect.Value {
if len(index) == 1 {
return v.Field(index[0])
}
for i, idx := range index {
if i > 0 {
var ok bool
v, ok = indirectNil(v)
if !ok {
return v
}
}
v = v.Field(idx)
}
return v
}
func indirectNil(v reflect.Value) (reflect.Value, bool) {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
if !v.CanSet() {
return v, false
}
elemType := v.Type().Elem()
if elemType.Kind() != reflect.Struct {
return v, false
}
v.Set(reflect.New(elemType))
}
v = v.Elem()
}
return v, true
}

22
src/vendor/github.com/vmihailenco/msgpack/v5/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)},
))
}

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
src/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
src/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
src/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
src/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)},
))
}

View File

@ -0,0 +1,181 @@
package tagparser
import (
"strings"
"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) {
key = strings.TrimSpace(key)
value = strings.TrimSpace(value)
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
}

16
src/vendor/gopkg.in/yaml.v3/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,16 @@
language: go
go:
- "1.4.x"
- "1.5.x"
- "1.6.x"
- "1.7.x"
- "1.8.x"
- "1.9.x"
- "1.10.x"
- "1.11.x"
- "1.12.x"
- "1.13.x"
- "tip"
go_import_path: gopkg.in/yaml.v3

50
src/vendor/gopkg.in/yaml.v3/LICENSE generated vendored Normal file
View File

@ -0,0 +1,50 @@
This project is covered by two different licenses: MIT and Apache.
#### MIT License ####
The following files were ported to Go from C files of libyaml, and thus
are still covered by their original MIT license, with the additional
copyright staring in 2011 when the project was ported over:
apic.go emitterc.go parserc.go readerc.go scannerc.go
writerc.go yamlh.go yamlprivateh.go
Copyright (c) 2006-2010 Kirill Simonov
Copyright (c) 2006-2011 Kirill Simonov
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
### Apache License ###
All the remaining project files are covered by the Apache license:
Copyright (c) 2011-2019 Canonical Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

13
src/vendor/gopkg.in/yaml.v3/NOTICE generated vendored Normal file
View File

@ -0,0 +1,13 @@
Copyright 2011-2016 Canonical Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

150
src/vendor/gopkg.in/yaml.v3/README.md generated vendored Normal file
View File

@ -0,0 +1,150 @@
# YAML support for the Go language
Introduction
------------
The yaml package enables Go programs to comfortably encode and decode YAML
values. It was developed within [Canonical](https://www.canonical.com) as
part of the [juju](https://juju.ubuntu.com) project, and is based on a
pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
C library to parse and generate YAML data quickly and reliably.
Compatibility
-------------
The yaml package supports most of YAML 1.2, but preserves some behavior
from 1.1 for backwards compatibility.
Specifically, as of v3 of the yaml package:
- YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being
decoded into a typed bool value. Otherwise they behave as a string. Booleans
in YAML 1.2 are _true/false_ only.
- Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_
as specified in YAML 1.2, because most parsers still use the old format.
Octals in the _0o777_ format are supported though, so new files work.
- Does not support base-60 floats. These are gone from YAML 1.2, and were
actually never supported by this package as it's clearly a poor choice.
and offers backwards
compatibility with YAML 1.1 in some cases.
1.2, including support for
anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
implemented, and base-60 floats from YAML 1.1 are purposefully not
supported since they're a poor design and are gone in YAML 1.2.
Installation and usage
----------------------
The import path for the package is *gopkg.in/yaml.v3*.
To install it, run:
go get gopkg.in/yaml.v3
API documentation
-----------------
If opened in a browser, the import path itself leads to the API documentation:
- [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3)
API stability
-------------
The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in).
License
-------
The yaml package is licensed under the MIT and Apache License 2.0 licenses.
Please see the LICENSE file for details.
Example
-------
```Go
package main
import (
"fmt"
"log"
"gopkg.in/yaml.v3"
)
var data = `
a: Easy!
b:
c: 2
d: [3, 4]
`
// Note: struct fields must be public in order for unmarshal to
// correctly populate the data.
type T struct {
A string
B struct {
RenamedC int `yaml:"c"`
D []int `yaml:",flow"`
}
}
func main() {
t := T{}
err := yaml.Unmarshal([]byte(data), &t)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- t:\n%v\n\n", t)
d, err := yaml.Marshal(&t)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- t dump:\n%s\n\n", string(d))
m := make(map[interface{}]interface{})
err = yaml.Unmarshal([]byte(data), &m)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- m:\n%v\n\n", m)
d, err = yaml.Marshal(&m)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- m dump:\n%s\n\n", string(d))
}
```
This example will generate the following output:
```
--- t:
{Easy! {2 [3 4]}}
--- t dump:
a: Easy!
b:
c: 2
d: [3, 4]
--- m:
map[a:Easy! b:map[c:2 d:[3 4]]]
--- m dump:
a: Easy!
b:
c: 2
d:
- 3
- 4
```

746
src/vendor/gopkg.in/yaml.v3/apic.go generated vendored Normal file
View File

@ -0,0 +1,746 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package yaml
import (
"io"
)
func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
//fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
// Check if we can move the queue at the beginning of the buffer.
if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
if parser.tokens_head != len(parser.tokens) {
copy(parser.tokens, parser.tokens[parser.tokens_head:])
}
parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
parser.tokens_head = 0
}
parser.tokens = append(parser.tokens, *token)
if pos < 0 {
return
}
copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
parser.tokens[parser.tokens_head+pos] = *token
}
// Create a new parser object.
func yaml_parser_initialize(parser *yaml_parser_t) bool {
*parser = yaml_parser_t{
raw_buffer: make([]byte, 0, input_raw_buffer_size),
buffer: make([]byte, 0, input_buffer_size),
}
return true
}
// Destroy a parser object.
func yaml_parser_delete(parser *yaml_parser_t) {
*parser = yaml_parser_t{}
}
// String read handler.
func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
if parser.input_pos == len(parser.input) {
return 0, io.EOF
}
n = copy(buffer, parser.input[parser.input_pos:])
parser.input_pos += n
return n, nil
}
// Reader read handler.
func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
return parser.input_reader.Read(buffer)
}
// Set a string input.
func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
if parser.read_handler != nil {
panic("must set the input source only once")
}
parser.read_handler = yaml_string_read_handler
parser.input = input
parser.input_pos = 0
}
// Set a file input.
func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
if parser.read_handler != nil {
panic("must set the input source only once")
}
parser.read_handler = yaml_reader_read_handler
parser.input_reader = r
}
// Set the source encoding.
func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
if parser.encoding != yaml_ANY_ENCODING {
panic("must set the encoding only once")
}
parser.encoding = encoding
}
// Create a new emitter object.
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
*emitter = yaml_emitter_t{
buffer: make([]byte, output_buffer_size),
raw_buffer: make([]byte, 0, output_raw_buffer_size),
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
events: make([]yaml_event_t, 0, initial_queue_size),
}
}
// Destroy an emitter object.
func yaml_emitter_delete(emitter *yaml_emitter_t) {
*emitter = yaml_emitter_t{}
}
// String write handler.
func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
return nil
}
// yaml_writer_write_handler uses emitter.output_writer to write the
// emitted text.
func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
_, err := emitter.output_writer.Write(buffer)
return err
}
// Set a string output.
func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
if emitter.write_handler != nil {
panic("must set the output target only once")
}
emitter.write_handler = yaml_string_write_handler
emitter.output_buffer = output_buffer
}
// Set a file output.
func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
if emitter.write_handler != nil {
panic("must set the output target only once")
}
emitter.write_handler = yaml_writer_write_handler
emitter.output_writer = w
}
// Set the output encoding.
func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
if emitter.encoding != yaml_ANY_ENCODING {
panic("must set the output encoding only once")
}
emitter.encoding = encoding
}
// Set the canonical output style.
func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
emitter.canonical = canonical
}
// Set the indentation increment.
func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
if indent < 2 || indent > 9 {
indent = 2
}
emitter.best_indent = indent
}
// Set the preferred line width.
func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
if width < 0 {
width = -1
}
emitter.best_width = width
}
// Set if unescaped non-ASCII characters are allowed.
func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
emitter.unicode = unicode
}
// Set the preferred line break character.
func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
emitter.line_break = line_break
}
///*
// * Destroy a token object.
// */
//
//YAML_DECLARE(void)
//yaml_token_delete(yaml_token_t *token)
//{
// assert(token); // Non-NULL token object expected.
//
// switch (token.type)
// {
// case YAML_TAG_DIRECTIVE_TOKEN:
// yaml_free(token.data.tag_directive.handle);
// yaml_free(token.data.tag_directive.prefix);
// break;
//
// case YAML_ALIAS_TOKEN:
// yaml_free(token.data.alias.value);
// break;
//
// case YAML_ANCHOR_TOKEN:
// yaml_free(token.data.anchor.value);
// break;
//
// case YAML_TAG_TOKEN:
// yaml_free(token.data.tag.handle);
// yaml_free(token.data.tag.suffix);
// break;
//
// case YAML_SCALAR_TOKEN:
// yaml_free(token.data.scalar.value);
// break;
//
// default:
// break;
// }
//
// memset(token, 0, sizeof(yaml_token_t));
//}
//
///*
// * Check if a string is a valid UTF-8 sequence.
// *
// * Check 'reader.c' for more details on UTF-8 encoding.
// */
//
//static int
//yaml_check_utf8(yaml_char_t *start, size_t length)
//{
// yaml_char_t *end = start+length;
// yaml_char_t *pointer = start;
//
// while (pointer < end) {
// unsigned char octet;
// unsigned int width;
// unsigned int value;
// size_t k;
//
// octet = pointer[0];
// width = (octet & 0x80) == 0x00 ? 1 :
// (octet & 0xE0) == 0xC0 ? 2 :
// (octet & 0xF0) == 0xE0 ? 3 :
// (octet & 0xF8) == 0xF0 ? 4 : 0;
// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
// if (!width) return 0;
// if (pointer+width > end) return 0;
// for (k = 1; k < width; k ++) {
// octet = pointer[k];
// if ((octet & 0xC0) != 0x80) return 0;
// value = (value << 6) + (octet & 0x3F);
// }
// if (!((width == 1) ||
// (width == 2 && value >= 0x80) ||
// (width == 3 && value >= 0x800) ||
// (width == 4 && value >= 0x10000))) return 0;
//
// pointer += width;
// }
//
// return 1;
//}
//
// Create STREAM-START.
func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
*event = yaml_event_t{
typ: yaml_STREAM_START_EVENT,
encoding: encoding,
}
}
// Create STREAM-END.
func yaml_stream_end_event_initialize(event *yaml_event_t) {
*event = yaml_event_t{
typ: yaml_STREAM_END_EVENT,
}
}
// Create DOCUMENT-START.
func yaml_document_start_event_initialize(
event *yaml_event_t,
version_directive *yaml_version_directive_t,
tag_directives []yaml_tag_directive_t,
implicit bool,
) {
*event = yaml_event_t{
typ: yaml_DOCUMENT_START_EVENT,
version_directive: version_directive,
tag_directives: tag_directives,
implicit: implicit,
}
}
// Create DOCUMENT-END.
func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
*event = yaml_event_t{
typ: yaml_DOCUMENT_END_EVENT,
implicit: implicit,
}
}
// Create ALIAS.
func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool {
*event = yaml_event_t{
typ: yaml_ALIAS_EVENT,
anchor: anchor,
}
return true
}
// Create SCALAR.
func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
*event = yaml_event_t{
typ: yaml_SCALAR_EVENT,
anchor: anchor,
tag: tag,
value: value,
implicit: plain_implicit,
quoted_implicit: quoted_implicit,
style: yaml_style_t(style),
}
return true
}
// Create SEQUENCE-START.
func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
*event = yaml_event_t{
typ: yaml_SEQUENCE_START_EVENT,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(style),
}
return true
}
// Create SEQUENCE-END.
func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
*event = yaml_event_t{
typ: yaml_SEQUENCE_END_EVENT,
}
return true
}
// Create MAPPING-START.
func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
*event = yaml_event_t{
typ: yaml_MAPPING_START_EVENT,
anchor: anchor,
tag: tag,
implicit: implicit,
style: yaml_style_t(style),
}
}
// Create MAPPING-END.
func yaml_mapping_end_event_initialize(event *yaml_event_t) {
*event = yaml_event_t{
typ: yaml_MAPPING_END_EVENT,
}
}
// Destroy an event object.
func yaml_event_delete(event *yaml_event_t) {
*event = yaml_event_t{}
}
///*
// * Create a document object.
// */
//
//YAML_DECLARE(int)
//yaml_document_initialize(document *yaml_document_t,
// version_directive *yaml_version_directive_t,
// tag_directives_start *yaml_tag_directive_t,
// tag_directives_end *yaml_tag_directive_t,
// start_implicit int, end_implicit int)
//{
// struct {
// error yaml_error_type_t
// } context
// struct {
// start *yaml_node_t
// end *yaml_node_t
// top *yaml_node_t
// } nodes = { NULL, NULL, NULL }
// version_directive_copy *yaml_version_directive_t = NULL
// struct {
// start *yaml_tag_directive_t
// end *yaml_tag_directive_t
// top *yaml_tag_directive_t
// } tag_directives_copy = { NULL, NULL, NULL }
// value yaml_tag_directive_t = { NULL, NULL }
// mark yaml_mark_t = { 0, 0, 0 }
//
// assert(document) // Non-NULL document object is expected.
// assert((tag_directives_start && tag_directives_end) ||
// (tag_directives_start == tag_directives_end))
// // Valid tag directives are expected.
//
// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
//
// if (version_directive) {
// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
// if (!version_directive_copy) goto error
// version_directive_copy.major = version_directive.major
// version_directive_copy.minor = version_directive.minor
// }
//
// if (tag_directives_start != tag_directives_end) {
// tag_directive *yaml_tag_directive_t
// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
// goto error
// for (tag_directive = tag_directives_start
// tag_directive != tag_directives_end; tag_directive ++) {
// assert(tag_directive.handle)
// assert(tag_directive.prefix)
// if (!yaml_check_utf8(tag_directive.handle,
// strlen((char *)tag_directive.handle)))
// goto error
// if (!yaml_check_utf8(tag_directive.prefix,
// strlen((char *)tag_directive.prefix)))
// goto error
// value.handle = yaml_strdup(tag_directive.handle)
// value.prefix = yaml_strdup(tag_directive.prefix)
// if (!value.handle || !value.prefix) goto error
// if (!PUSH(&context, tag_directives_copy, value))
// goto error
// value.handle = NULL
// value.prefix = NULL
// }
// }
//
// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
// tag_directives_copy.start, tag_directives_copy.top,
// start_implicit, end_implicit, mark, mark)
//
// return 1
//
//error:
// STACK_DEL(&context, nodes)
// yaml_free(version_directive_copy)
// while (!STACK_EMPTY(&context, tag_directives_copy)) {
// value yaml_tag_directive_t = POP(&context, tag_directives_copy)
// yaml_free(value.handle)
// yaml_free(value.prefix)
// }
// STACK_DEL(&context, tag_directives_copy)
// yaml_free(value.handle)
// yaml_free(value.prefix)
//
// return 0
//}
//
///*
// * Destroy a document object.
// */
//
//YAML_DECLARE(void)
//yaml_document_delete(document *yaml_document_t)
//{
// struct {
// error yaml_error_type_t
// } context
// tag_directive *yaml_tag_directive_t
//
// context.error = YAML_NO_ERROR // Eliminate a compiler warning.
//
// assert(document) // Non-NULL document object is expected.
//
// while (!STACK_EMPTY(&context, document.nodes)) {
// node yaml_node_t = POP(&context, document.nodes)
// yaml_free(node.tag)
// switch (node.type) {
// case YAML_SCALAR_NODE:
// yaml_free(node.data.scalar.value)
// break
// case YAML_SEQUENCE_NODE:
// STACK_DEL(&context, node.data.sequence.items)
// break
// case YAML_MAPPING_NODE:
// STACK_DEL(&context, node.data.mapping.pairs)
// break
// default:
// assert(0) // Should not happen.
// }
// }
// STACK_DEL(&context, document.nodes)
//
// yaml_free(document.version_directive)
// for (tag_directive = document.tag_directives.start
// tag_directive != document.tag_directives.end
// tag_directive++) {
// yaml_free(tag_directive.handle)
// yaml_free(tag_directive.prefix)
// }
// yaml_free(document.tag_directives.start)
//
// memset(document, 0, sizeof(yaml_document_t))
//}
//
///**
// * Get a document node.
// */
//
//YAML_DECLARE(yaml_node_t *)
//yaml_document_get_node(document *yaml_document_t, index int)
//{
// assert(document) // Non-NULL document object is expected.
//
// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
// return document.nodes.start + index - 1
// }
// return NULL
//}
//
///**
// * Get the root object.
// */
//
//YAML_DECLARE(yaml_node_t *)
//yaml_document_get_root_node(document *yaml_document_t)
//{
// assert(document) // Non-NULL document object is expected.
//
// if (document.nodes.top != document.nodes.start) {
// return document.nodes.start
// }
// return NULL
//}
//
///*
// * Add a scalar node to a document.
// */
//
//YAML_DECLARE(int)
//yaml_document_add_scalar(document *yaml_document_t,
// tag *yaml_char_t, value *yaml_char_t, length int,
// style yaml_scalar_style_t)
//{
// struct {
// error yaml_error_type_t
// } context
// mark yaml_mark_t = { 0, 0, 0 }
// tag_copy *yaml_char_t = NULL
// value_copy *yaml_char_t = NULL
// node yaml_node_t
//
// assert(document) // Non-NULL document object is expected.
// assert(value) // Non-NULL value is expected.
//
// if (!tag) {
// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
// }
//
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
// tag_copy = yaml_strdup(tag)
// if (!tag_copy) goto error
//
// if (length < 0) {
// length = strlen((char *)value)
// }
//
// if (!yaml_check_utf8(value, length)) goto error
// value_copy = yaml_malloc(length+1)
// if (!value_copy) goto error
// memcpy(value_copy, value, length)
// value_copy[length] = '\0'
//
// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
// if (!PUSH(&context, document.nodes, node)) goto error
//
// return document.nodes.top - document.nodes.start
//
//error:
// yaml_free(tag_copy)
// yaml_free(value_copy)
//
// return 0
//}
//
///*
// * Add a sequence node to a document.
// */
//
//YAML_DECLARE(int)
//yaml_document_add_sequence(document *yaml_document_t,
// tag *yaml_char_t, style yaml_sequence_style_t)
//{
// struct {
// error yaml_error_type_t
// } context
// mark yaml_mark_t = { 0, 0, 0 }
// tag_copy *yaml_char_t = NULL
// struct {
// start *yaml_node_item_t
// end *yaml_node_item_t
// top *yaml_node_item_t
// } items = { NULL, NULL, NULL }
// node yaml_node_t
//
// assert(document) // Non-NULL document object is expected.
//
// if (!tag) {
// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
// }
//
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
// tag_copy = yaml_strdup(tag)
// if (!tag_copy) goto error
//
// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
//
// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
// style, mark, mark)
// if (!PUSH(&context, document.nodes, node)) goto error
//
// return document.nodes.top - document.nodes.start
//
//error:
// STACK_DEL(&context, items)
// yaml_free(tag_copy)
//
// return 0
//}
//
///*
// * Add a mapping node to a document.
// */
//
//YAML_DECLARE(int)
//yaml_document_add_mapping(document *yaml_document_t,
// tag *yaml_char_t, style yaml_mapping_style_t)
//{
// struct {
// error yaml_error_type_t
// } context
// mark yaml_mark_t = { 0, 0, 0 }
// tag_copy *yaml_char_t = NULL
// struct {
// start *yaml_node_pair_t
// end *yaml_node_pair_t
// top *yaml_node_pair_t
// } pairs = { NULL, NULL, NULL }
// node yaml_node_t
//
// assert(document) // Non-NULL document object is expected.
//
// if (!tag) {
// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
// }
//
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
// tag_copy = yaml_strdup(tag)
// if (!tag_copy) goto error
//
// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
//
// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
// style, mark, mark)
// if (!PUSH(&context, document.nodes, node)) goto error
//
// return document.nodes.top - document.nodes.start
//
//error:
// STACK_DEL(&context, pairs)
// yaml_free(tag_copy)
//
// return 0
//}
//
///*
// * Append an item to a sequence node.
// */
//
//YAML_DECLARE(int)
//yaml_document_append_sequence_item(document *yaml_document_t,
// sequence int, item int)
//{
// struct {
// error yaml_error_type_t
// } context
//
// assert(document) // Non-NULL document is required.
// assert(sequence > 0
// && document.nodes.start + sequence <= document.nodes.top)
// // Valid sequence id is required.
// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
// // A sequence node is required.
// assert(item > 0 && document.nodes.start + item <= document.nodes.top)
// // Valid item id is required.
//
// if (!PUSH(&context,
// document.nodes.start[sequence-1].data.sequence.items, item))
// return 0
//
// return 1
//}
//
///*
// * Append a pair of a key and a value to a mapping node.
// */
//
//YAML_DECLARE(int)
//yaml_document_append_mapping_pair(document *yaml_document_t,
// mapping int, key int, value int)
//{
// struct {
// error yaml_error_type_t
// } context
//
// pair yaml_node_pair_t
//
// assert(document) // Non-NULL document is required.
// assert(mapping > 0
// && document.nodes.start + mapping <= document.nodes.top)
// // Valid mapping id is required.
// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
// // A mapping node is required.
// assert(key > 0 && document.nodes.start + key <= document.nodes.top)
// // Valid key id is required.
// assert(value > 0 && document.nodes.start + value <= document.nodes.top)
// // Valid value id is required.
//
// pair.key = key
// pair.value = value
//
// if (!PUSH(&context,
// document.nodes.start[mapping-1].data.mapping.pairs, pair))
// return 0
//
// return 1
//}
//
//

931
src/vendor/gopkg.in/yaml.v3/decode.go generated vendored Normal file
View File

@ -0,0 +1,931 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package yaml
import (
"encoding"
"encoding/base64"
"fmt"
"io"
"math"
"reflect"
"strconv"
"time"
)
// ----------------------------------------------------------------------------
// Parser, produces a node tree out of a libyaml event stream.
type parser struct {
parser yaml_parser_t
event yaml_event_t
doc *Node
anchors map[string]*Node
doneInit bool
}
func newParser(b []byte) *parser {
p := parser{}
if !yaml_parser_initialize(&p.parser) {
panic("failed to initialize YAML emitter")
}
if len(b) == 0 {
b = []byte{'\n'}
}
yaml_parser_set_input_string(&p.parser, b)
return &p
}
func newParserFromReader(r io.Reader) *parser {
p := parser{}
if !yaml_parser_initialize(&p.parser) {
panic("failed to initialize YAML emitter")
}
yaml_parser_set_input_reader(&p.parser, r)
return &p
}
func (p *parser) init() {
if p.doneInit {
return
}
p.anchors = make(map[string]*Node)
p.expect(yaml_STREAM_START_EVENT)
p.doneInit = true
}
func (p *parser) destroy() {
if p.event.typ != yaml_NO_EVENT {
yaml_event_delete(&p.event)
}
yaml_parser_delete(&p.parser)
}
// expect consumes an event from the event stream and
// checks that it's of the expected type.
func (p *parser) expect(e yaml_event_type_t) {
if p.event.typ == yaml_NO_EVENT {
if !yaml_parser_parse(&p.parser, &p.event) {
p.fail()
}
}
if p.event.typ == yaml_STREAM_END_EVENT {
failf("attempted to go past the end of stream; corrupted value?")
}
if p.event.typ != e {
p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
p.fail()
}
yaml_event_delete(&p.event)
p.event.typ = yaml_NO_EVENT
}
// peek peeks at the next event in the event stream,
// puts the results into p.event and returns the event type.
func (p *parser) peek() yaml_event_type_t {
if p.event.typ != yaml_NO_EVENT {
return p.event.typ
}
if !yaml_parser_parse(&p.parser, &p.event) {
p.fail()
}
return p.event.typ
}
func (p *parser) fail() {
var where string
var line int
if p.parser.problem_mark.line != 0 {
line = p.parser.problem_mark.line
// Scanner errors don't iterate line before returning error
if p.parser.error == yaml_SCANNER_ERROR {
line++
}
} else if p.parser.context_mark.line != 0 {
line = p.parser.context_mark.line
}
if line != 0 {
where = "line " + strconv.Itoa(line) + ": "
}
var msg string
if len(p.parser.problem) > 0 {
msg = p.parser.problem
} else {
msg = "unknown problem parsing YAML content"
}
failf("%s%s", where, msg)
}
func (p *parser) anchor(n *Node, anchor []byte) {
if anchor != nil {
n.Anchor = string(anchor)
p.anchors[n.Anchor] = n
}
}
func (p *parser) parse() *Node {
p.init()
switch p.peek() {
case yaml_SCALAR_EVENT:
return p.scalar()
case yaml_ALIAS_EVENT:
return p.alias()
case yaml_MAPPING_START_EVENT:
return p.mapping()
case yaml_SEQUENCE_START_EVENT:
return p.sequence()
case yaml_DOCUMENT_START_EVENT:
return p.document()
case yaml_STREAM_END_EVENT:
// Happens when attempting to decode an empty buffer.
return nil
case yaml_TAIL_COMMENT_EVENT:
panic("internal error: unexpected tail comment event (please report)")
default:
panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
}
}
func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
var style Style
if tag != "" && tag != "!" {
tag = shortTag(tag)
style = TaggedStyle
} else if defaultTag != "" {
tag = defaultTag
} else if kind == ScalarNode {
tag, _ = resolve("", value)
}
return &Node{
Kind: kind,
Tag: tag,
Value: value,
Style: style,
Line: p.event.start_mark.line + 1,
Column: p.event.start_mark.column + 1,
HeadComment: string(p.event.head_comment),
LineComment: string(p.event.line_comment),
FootComment: string(p.event.foot_comment),
}
}
func (p *parser) parseChild(parent *Node) *Node {
child := p.parse()
parent.Content = append(parent.Content, child)
return child
}
func (p *parser) document() *Node {
n := p.node(DocumentNode, "", "", "")
p.doc = n
p.expect(yaml_DOCUMENT_START_EVENT)
p.parseChild(n)
if p.peek() == yaml_DOCUMENT_END_EVENT {
n.FootComment = string(p.event.foot_comment)
}
p.expect(yaml_DOCUMENT_END_EVENT)
return n
}
func (p *parser) alias() *Node {
n := p.node(AliasNode, "", "", string(p.event.anchor))
n.Alias = p.anchors[n.Value]
if n.Alias == nil {
failf("unknown anchor '%s' referenced", n.Value)
}
p.expect(yaml_ALIAS_EVENT)
return n
}
func (p *parser) scalar() *Node {
var parsedStyle = p.event.scalar_style()
var nodeStyle Style
switch {
case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
nodeStyle = DoubleQuotedStyle
case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
nodeStyle = SingleQuotedStyle
case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
nodeStyle = LiteralStyle
case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
nodeStyle = FoldedStyle
}
var nodeValue = string(p.event.value)
var nodeTag = string(p.event.tag)
var defaultTag string
if nodeStyle == 0 {
if nodeValue == "<<" {
defaultTag = mergeTag
}
} else {
defaultTag = strTag
}
n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
n.Style |= nodeStyle
p.anchor(n, p.event.anchor)
p.expect(yaml_SCALAR_EVENT)
return n
}
func (p *parser) sequence() *Node {
n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
n.Style |= FlowStyle
}
p.anchor(n, p.event.anchor)
p.expect(yaml_SEQUENCE_START_EVENT)
for p.peek() != yaml_SEQUENCE_END_EVENT {
p.parseChild(n)
}
n.LineComment = string(p.event.line_comment)
n.FootComment = string(p.event.foot_comment)
p.expect(yaml_SEQUENCE_END_EVENT)
return n
}
func (p *parser) mapping() *Node {
n := p.node(MappingNode, mapTag, string(p.event.tag), "")
block := true
if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
block = false
n.Style |= FlowStyle
}
p.anchor(n, p.event.anchor)
p.expect(yaml_MAPPING_START_EVENT)
for p.peek() != yaml_MAPPING_END_EVENT {
k := p.parseChild(n)
if block && k.FootComment != "" {
// Must be a foot comment for the prior value when being dedented.
if len(n.Content) > 2 {
n.Content[len(n.Content)-3].FootComment = k.FootComment
k.FootComment = ""
}
}
v := p.parseChild(n)
if k.FootComment == "" && v.FootComment != "" {
k.FootComment = v.FootComment
v.FootComment = ""
}
if p.peek() == yaml_TAIL_COMMENT_EVENT {
if k.FootComment == "" {
k.FootComment = string(p.event.foot_comment)
}
p.expect(yaml_TAIL_COMMENT_EVENT)
}
}
n.LineComment = string(p.event.line_comment)
n.FootComment = string(p.event.foot_comment)
if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
n.Content[len(n.Content)-2].FootComment = n.FootComment
n.FootComment = ""
}
p.expect(yaml_MAPPING_END_EVENT)
return n
}
// ----------------------------------------------------------------------------
// Decoder, unmarshals a node into a provided value.
type decoder struct {
doc *Node
aliases map[*Node]bool
terrors []string
stringMapType reflect.Type
generalMapType reflect.Type
knownFields bool
uniqueKeys bool
decodeCount int
aliasCount int
aliasDepth int
}
var (
nodeType = reflect.TypeOf(Node{})
durationType = reflect.TypeOf(time.Duration(0))
stringMapType = reflect.TypeOf(map[string]interface{}{})
generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
ifaceType = generalMapType.Elem()
timeType = reflect.TypeOf(time.Time{})
ptrTimeType = reflect.TypeOf(&time.Time{})
)
func newDecoder() *decoder {
d := &decoder{
stringMapType: stringMapType,
generalMapType: generalMapType,
uniqueKeys: true,
}
d.aliases = make(map[*Node]bool)
return d
}
func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
if n.Tag != "" {
tag = n.Tag
}
value := n.Value
if tag != seqTag && tag != mapTag {
if len(value) > 10 {
value = " `" + value[:7] + "...`"
} else {
value = " `" + value + "`"
}
}
d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
}
func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
err := u.UnmarshalYAML(n)
if e, ok := err.(*TypeError); ok {
d.terrors = append(d.terrors, e.Errors...)
return false
}
if err != nil {
fail(err)
}
return true
}
func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
terrlen := len(d.terrors)
err := u.UnmarshalYAML(func(v interface{}) (err error) {
defer handleErr(&err)
d.unmarshal(n, reflect.ValueOf(v))
if len(d.terrors) > terrlen {
issues := d.terrors[terrlen:]
d.terrors = d.terrors[:terrlen]
return &TypeError{issues}
}
return nil
})
if e, ok := err.(*TypeError); ok {
d.terrors = append(d.terrors, e.Errors...)
return false
}
if err != nil {
fail(err)
}
return true
}
// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
// if a value is found to implement it.
// It returns the initialized and dereferenced out value, whether
// unmarshalling was already done by UnmarshalYAML, and if so whether
// its types unmarshalled appropriately.
//
// If n holds a null value, prepare returns before doing anything.
func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
if n.ShortTag() == nullTag {
return out, false, false
}
again := true
for again {
again = false
if out.Kind() == reflect.Ptr {
if out.IsNil() {
out.Set(reflect.New(out.Type().Elem()))
}
out = out.Elem()
again = true
}
if out.CanAddr() {
outi := out.Addr().Interface()
if u, ok := outi.(Unmarshaler); ok {
good = d.callUnmarshaler(n, u)
return out, true, good
}
if u, ok := outi.(obsoleteUnmarshaler); ok {
good = d.callObsoleteUnmarshaler(n, u)
return out, true, good
}
}
}
return out, false, false
}
func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
if n.ShortTag() == nullTag {
return reflect.Value{}
}
for _, num := range index {
for {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
continue
}
break
}
v = v.Field(num)
}
return v
}
const (
// 400,000 decode operations is ~500kb of dense object declarations, or
// ~5kb of dense object declarations with 10000% alias expansion
alias_ratio_range_low = 400000
// 4,000,000 decode operations is ~5MB of dense object declarations, or
// ~4.5MB of dense object declarations with 10% alias expansion
alias_ratio_range_high = 4000000
// alias_ratio_range is the range over which we scale allowed alias ratios
alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
)
func allowedAliasRatio(decodeCount int) float64 {
switch {
case decodeCount <= alias_ratio_range_low:
// allow 99% to come from alias expansion for small-to-medium documents
return 0.99
case decodeCount >= alias_ratio_range_high:
// allow 10% to come from alias expansion for very large documents
return 0.10
default:
// scale smoothly from 99% down to 10% over the range.
// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
}
}
func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
d.decodeCount++
if d.aliasDepth > 0 {
d.aliasCount++
}
if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
failf("document contains excessive aliasing")
}
if out.Type() == nodeType {
out.Set(reflect.ValueOf(n).Elem())
return true
}
switch n.Kind {
case DocumentNode:
return d.document(n, out)
case AliasNode:
return d.alias(n, out)
}
out, unmarshaled, good := d.prepare(n, out)
if unmarshaled {
return good
}
switch n.Kind {
case ScalarNode:
good = d.scalar(n, out)
case MappingNode:
good = d.mapping(n, out)
case SequenceNode:
good = d.sequence(n, out)
default:
panic("internal error: unknown node kind: " + strconv.Itoa(int(n.Kind)))
}
return good
}
func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
if len(n.Content) == 1 {
d.doc = n
d.unmarshal(n.Content[0], out)
return true
}
return false
}
func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
if d.aliases[n] {
// TODO this could actually be allowed in some circumstances.
failf("anchor '%s' value contains itself", n.Value)
}
d.aliases[n] = true
d.aliasDepth++
good = d.unmarshal(n.Alias, out)
d.aliasDepth--
delete(d.aliases, n)
return good
}
var zeroValue reflect.Value
func resetMap(out reflect.Value) {
for _, k := range out.MapKeys() {
out.SetMapIndex(k, zeroValue)
}
}
func (d *decoder) scalar(n *Node, out reflect.Value) bool {
var tag string
var resolved interface{}
if n.indicatedString() {
tag = strTag
resolved = n.Value
} else {
tag, resolved = resolve(n.Tag, n.Value)
if tag == binaryTag {
data, err := base64.StdEncoding.DecodeString(resolved.(string))
if err != nil {
failf("!!binary value contains invalid base64 data")
}
resolved = string(data)
}
}
if resolved == nil {
if out.CanAddr() {
switch out.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
out.Set(reflect.Zero(out.Type()))
return true
}
}
return false
}
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
// We've resolved to exactly the type we want, so use that.
out.Set(resolvedv)
return true
}
// Perhaps we can use the value as a TextUnmarshaler to
// set its value.
if out.CanAddr() {
u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
if ok {
var text []byte
if tag == binaryTag {
text = []byte(resolved.(string))
} else {
// We let any value be unmarshaled into TextUnmarshaler.
// That might be more lax than we'd like, but the
// TextUnmarshaler itself should bowl out any dubious values.
text = []byte(n.Value)
}
err := u.UnmarshalText(text)
if err != nil {
fail(err)
}
return true
}
}
switch out.Kind() {
case reflect.String:
if tag == binaryTag {
out.SetString(resolved.(string))
return true
}
out.SetString(n.Value)
return true
case reflect.Interface:
out.Set(reflect.ValueOf(resolved))
return true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
// This used to work in v2, but it's very unfriendly.
isDuration := out.Type() == durationType
switch resolved := resolved.(type) {
case int:
if !isDuration && !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
return true
}
case int64:
if !isDuration && !out.OverflowInt(resolved) {
out.SetInt(resolved)
return true
}
case uint64:
if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
return true
}
case float64:
if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
return true
}
case string:
if out.Type() == durationType {
d, err := time.ParseDuration(resolved)
if err == nil {
out.SetInt(int64(d))
return true
}
}
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
switch resolved := resolved.(type) {
case int:
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
return true
}
case int64:
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
return true
}
case uint64:
if !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
return true
}
case float64:
if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
return true
}
}
case reflect.Bool:
switch resolved := resolved.(type) {
case bool:
out.SetBool(resolved)
return true
case string:
// This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
// It only works if explicitly attempting to unmarshal into a typed bool value.
switch resolved {
case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
out.SetBool(true)
return true
case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
out.SetBool(false)
return true
}
}
case reflect.Float32, reflect.Float64:
switch resolved := resolved.(type) {
case int:
out.SetFloat(float64(resolved))
return true
case int64:
out.SetFloat(float64(resolved))
return true
case uint64:
out.SetFloat(float64(resolved))
return true
case float64:
out.SetFloat(resolved)
return true
}
case reflect.Struct:
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
out.Set(resolvedv)
return true
}
case reflect.Ptr:
panic("yaml internal error: please report the issue")
}
d.terror(n, tag, out)
return false
}
func settableValueOf(i interface{}) reflect.Value {
v := reflect.ValueOf(i)
sv := reflect.New(v.Type()).Elem()
sv.Set(v)
return sv
}
func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
l := len(n.Content)
var iface reflect.Value
switch out.Kind() {
case reflect.Slice:
out.Set(reflect.MakeSlice(out.Type(), l, l))
case reflect.Array:
if l != out.Len() {
failf("invalid array: want %d elements but got %d", out.Len(), l)
}
case reflect.Interface:
// No type hints. Will have to use a generic sequence.
iface = out
out = settableValueOf(make([]interface{}, l))
default:
d.terror(n, seqTag, out)
return false
}
et := out.Type().Elem()
j := 0
for i := 0; i < l; i++ {
e := reflect.New(et).Elem()
if ok := d.unmarshal(n.Content[i], e); ok {
out.Index(j).Set(e)
j++
}
}
if out.Kind() != reflect.Array {
out.Set(out.Slice(0, j))
}
if iface.IsValid() {
iface.Set(out)
}
return true
}
func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
l := len(n.Content)
if d.uniqueKeys {
nerrs := len(d.terrors)
for i := 0; i < l; i += 2 {
ni := n.Content[i]
for j := i + 2; j < l; j += 2 {
nj := n.Content[j]
if ni.Kind == nj.Kind && ni.Value == nj.Value {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
}
}
}
if len(d.terrors) > nerrs {
return false
}
}
switch out.Kind() {
case reflect.Struct:
return d.mappingStruct(n, out)
case reflect.Map:
// okay
case reflect.Interface:
iface := out
if isStringMap(n) {
out = reflect.MakeMap(d.stringMapType)
} else {
out = reflect.MakeMap(d.generalMapType)
}
iface.Set(out)
default:
d.terror(n, mapTag, out)
return false
}
outt := out.Type()
kt := outt.Key()
et := outt.Elem()
stringMapType := d.stringMapType
generalMapType := d.generalMapType
if outt.Elem() == ifaceType {
if outt.Key().Kind() == reflect.String {
d.stringMapType = outt
} else if outt.Key() == ifaceType {
d.generalMapType = outt
}
}
if out.IsNil() {
out.Set(reflect.MakeMap(outt))
}
for i := 0; i < l; i += 2 {
if isMerge(n.Content[i]) {
d.merge(n.Content[i+1], out)
continue
}
k := reflect.New(kt).Elem()
if d.unmarshal(n.Content[i], k) {
kkind := k.Kind()
if kkind == reflect.Interface {
kkind = k.Elem().Kind()
}
if kkind == reflect.Map || kkind == reflect.Slice {
failf("invalid map key: %#v", k.Interface())
}
e := reflect.New(et).Elem()
if d.unmarshal(n.Content[i+1], e) {
out.SetMapIndex(k, e)
}
}
}
d.stringMapType = stringMapType
d.generalMapType = generalMapType
return true
}
func isStringMap(n *Node) bool {
if n.Kind != MappingNode {
return false
}
l := len(n.Content)
for i := 0; i < l; i += 2 {
if n.Content[i].ShortTag() != strTag {
return false
}
}
return true
}
func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
sinfo, err := getStructInfo(out.Type())
if err != nil {
panic(err)
}
var inlineMap reflect.Value
var elemType reflect.Type
if sinfo.InlineMap != -1 {
inlineMap = out.Field(sinfo.InlineMap)
inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
elemType = inlineMap.Type().Elem()
}
for _, index := range sinfo.InlineUnmarshalers {
field := d.fieldByIndex(n, out, index)
d.prepare(n, field)
}
var doneFields []bool
if d.uniqueKeys {
doneFields = make([]bool, len(sinfo.FieldsList))
}
name := settableValueOf("")
l := len(n.Content)
for i := 0; i < l; i += 2 {
ni := n.Content[i]
if isMerge(ni) {
d.merge(n.Content[i+1], out)
continue
}
if !d.unmarshal(ni, name) {
continue
}
if info, ok := sinfo.FieldsMap[name.String()]; ok {
if d.uniqueKeys {
if doneFields[info.Id] {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
continue
}
doneFields[info.Id] = true
}
var field reflect.Value
if info.Inline == nil {
field = out.Field(info.Num)
} else {
field = d.fieldByIndex(n, out, info.Inline)
}
d.unmarshal(n.Content[i+1], field)
} else if sinfo.InlineMap != -1 {
if inlineMap.IsNil() {
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
}
value := reflect.New(elemType).Elem()
d.unmarshal(n.Content[i+1], value)
inlineMap.SetMapIndex(name, value)
} else if d.knownFields {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
}
}
return true
}
func failWantMap() {
failf("map merge requires map or sequence of maps as the value")
}
func (d *decoder) merge(n *Node, out reflect.Value) {
switch n.Kind {
case MappingNode:
d.unmarshal(n, out)
case AliasNode:
if n.Alias != nil && n.Alias.Kind != MappingNode {
failWantMap()
}
d.unmarshal(n, out)
case SequenceNode:
// Step backwards as earlier nodes take precedence.
for i := len(n.Content) - 1; i >= 0; i-- {
ni := n.Content[i]
if ni.Kind == AliasNode {
if ni.Alias != nil && ni.Alias.Kind != MappingNode {
failWantMap()
}
} else if ni.Kind != MappingNode {
failWantMap()
}
d.unmarshal(ni, out)
}
default:
failWantMap()
}
}
func isMerge(n *Node) bool {
return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
}

1992
src/vendor/gopkg.in/yaml.v3/emitterc.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

561
src/vendor/gopkg.in/yaml.v3/encode.go generated vendored Normal file
View File

@ -0,0 +1,561 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package yaml
import (
"encoding"
"fmt"
"io"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"time"
"unicode/utf8"
)
type encoder struct {
emitter yaml_emitter_t
event yaml_event_t
out []byte
flow bool
indent int
doneInit bool
}
func newEncoder() *encoder {
e := &encoder{}
yaml_emitter_initialize(&e.emitter)
yaml_emitter_set_output_string(&e.emitter, &e.out)
yaml_emitter_set_unicode(&e.emitter, true)
return e
}
func newEncoderWithWriter(w io.Writer) *encoder {
e := &encoder{}
yaml_emitter_initialize(&e.emitter)
yaml_emitter_set_output_writer(&e.emitter, w)
yaml_emitter_set_unicode(&e.emitter, true)
return e
}
func (e *encoder) init() {
if e.doneInit {
return
}
if e.indent == 0 {
e.indent = 4
}
e.emitter.best_indent = e.indent
yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
e.emit()
e.doneInit = true
}
func (e *encoder) finish() {
e.emitter.open_ended = false
yaml_stream_end_event_initialize(&e.event)
e.emit()
}
func (e *encoder) destroy() {
yaml_emitter_delete(&e.emitter)
}
func (e *encoder) emit() {
// This will internally delete the e.event value.
e.must(yaml_emitter_emit(&e.emitter, &e.event))
}
func (e *encoder) must(ok bool) {
if !ok {
msg := e.emitter.problem
if msg == "" {
msg = "unknown problem generating YAML content"
}
failf("%s", msg)
}
}
func (e *encoder) marshalDoc(tag string, in reflect.Value) {
e.init()
var node *Node
if in.IsValid() {
node, _ = in.Interface().(*Node)
}
if node != nil && node.Kind == DocumentNode {
e.nodev(in)
} else {
yaml_document_start_event_initialize(&e.event, nil, nil, true)
e.emit()
e.marshal(tag, in)
yaml_document_end_event_initialize(&e.event, true)
e.emit()
}
}
func (e *encoder) marshal(tag string, in reflect.Value) {
tag = shortTag(tag)
if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
e.nilv()
return
}
iface := in.Interface()
switch value := iface.(type) {
case *Node:
e.nodev(in)
return
case time.Time:
e.timev(tag, in)
return
case *time.Time:
e.timev(tag, in.Elem())
return
case time.Duration:
e.stringv(tag, reflect.ValueOf(value.String()))
return
case Marshaler:
v, err := value.MarshalYAML()
if err != nil {
fail(err)
}
if v == nil {
e.nilv()
return
}
e.marshal(tag, reflect.ValueOf(v))
return
case encoding.TextMarshaler:
text, err := value.MarshalText()
if err != nil {
fail(err)
}
in = reflect.ValueOf(string(text))
case nil:
e.nilv()
return
}
switch in.Kind() {
case reflect.Interface:
e.marshal(tag, in.Elem())
case reflect.Map:
e.mapv(tag, in)
case reflect.Ptr:
e.marshal(tag, in.Elem())
case reflect.Struct:
e.structv(tag, in)
case reflect.Slice, reflect.Array:
e.slicev(tag, in)
case reflect.String:
e.stringv(tag, in)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
e.intv(tag, in)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
e.uintv(tag, in)
case reflect.Float32, reflect.Float64:
e.floatv(tag, in)
case reflect.Bool:
e.boolv(tag, in)
default:
panic("cannot marshal type: " + in.Type().String())
}
}
func (e *encoder) mapv(tag string, in reflect.Value) {
e.mappingv(tag, func() {
keys := keyList(in.MapKeys())
sort.Sort(keys)
for _, k := range keys {
e.marshal("", k)
e.marshal("", in.MapIndex(k))
}
})
}
func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) {
for _, num := range index {
for {
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return reflect.Value{}
}
v = v.Elem()
continue
}
break
}
v = v.Field(num)
}
return v
}
func (e *encoder) structv(tag string, in reflect.Value) {
sinfo, err := getStructInfo(in.Type())
if err != nil {
panic(err)
}
e.mappingv(tag, func() {
for _, info := range sinfo.FieldsList {
var value reflect.Value
if info.Inline == nil {
value = in.Field(info.Num)
} else {
value = e.fieldByIndex(in, info.Inline)
if !value.IsValid() {
continue
}
}
if info.OmitEmpty && isZero(value) {
continue
}
e.marshal("", reflect.ValueOf(info.Key))
e.flow = info.Flow
e.marshal("", value)
}
if sinfo.InlineMap >= 0 {
m := in.Field(sinfo.InlineMap)
if m.Len() > 0 {
e.flow = false
keys := keyList(m.MapKeys())
sort.Sort(keys)
for _, k := range keys {
if _, found := sinfo.FieldsMap[k.String()]; found {
panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String()))
}
e.marshal("", k)
e.flow = false
e.marshal("", m.MapIndex(k))
}
}
}
})
}
func (e *encoder) mappingv(tag string, f func()) {
implicit := tag == ""
style := yaml_BLOCK_MAPPING_STYLE
if e.flow {
e.flow = false
style = yaml_FLOW_MAPPING_STYLE
}
yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
e.emit()
f()
yaml_mapping_end_event_initialize(&e.event)
e.emit()
}
func (e *encoder) slicev(tag string, in reflect.Value) {
implicit := tag == ""
style := yaml_BLOCK_SEQUENCE_STYLE
if e.flow {
e.flow = false
style = yaml_FLOW_SEQUENCE_STYLE
}
e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
e.emit()
n := in.Len()
for i := 0; i < n; i++ {
e.marshal("", in.Index(i))
}
e.must(yaml_sequence_end_event_initialize(&e.event))
e.emit()
}
// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
//
// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
// in YAML 1.2 and by this package, but these should be marshalled quoted for
// the time being for compatibility with other parsers.
func isBase60Float(s string) (result bool) {
// Fast path.
if s == "" {
return false
}
c := s[0]
if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
return false
}
// Do the full match.
return base60float.MatchString(s)
}
// From http://yaml.org/type/float.html, except the regular expression there
// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
// isOldBool returns whether s is bool notation as defined in YAML 1.1.
//
// We continue to force strings that YAML 1.1 would interpret as booleans to be
// rendered as quotes strings so that the marshalled output valid for YAML 1.1
// parsing.
func isOldBool(s string) (result bool) {
switch s {
case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON",
"n", "N", "no", "No", "NO", "off", "Off", "OFF":
return true
default:
return false
}
}
func (e *encoder) stringv(tag string, in reflect.Value) {
var style yaml_scalar_style_t
s := in.String()
canUsePlain := true
switch {
case !utf8.ValidString(s):
if tag == binaryTag {
failf("explicitly tagged !!binary data must be base64-encoded")
}
if tag != "" {
failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
}
// It can't be encoded directly as YAML so use a binary tag
// and encode it as base64.
tag = binaryTag
s = encodeBase64(s)
case tag == "":
// Check to see if it would resolve to a specific
// tag when encoded unquoted. If it doesn't,
// there's no need to quote it.
rtag, _ := resolve("", s)
canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s))
}
// Note: it's possible for user code to emit invalid YAML
// if they explicitly specify a tag and a string containing
// text that's incompatible with that tag.
switch {
case strings.Contains(s, "\n"):
if e.flow {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
} else {
style = yaml_LITERAL_SCALAR_STYLE
}
case canUsePlain:
style = yaml_PLAIN_SCALAR_STYLE
default:
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
e.emitScalar(s, "", tag, style, nil, nil, nil, nil)
}
func (e *encoder) boolv(tag string, in reflect.Value) {
var s string
if in.Bool() {
s = "true"
} else {
s = "false"
}
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}
func (e *encoder) intv(tag string, in reflect.Value) {
s := strconv.FormatInt(in.Int(), 10)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}
func (e *encoder) uintv(tag string, in reflect.Value) {
s := strconv.FormatUint(in.Uint(), 10)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}
func (e *encoder) timev(tag string, in reflect.Value) {
t := in.Interface().(time.Time)
s := t.Format(time.RFC3339Nano)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}
func (e *encoder) floatv(tag string, in reflect.Value) {
// Issue #352: When formatting, use the precision of the underlying value
precision := 64
if in.Kind() == reflect.Float32 {
precision = 32
}
s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
switch s {
case "+Inf":
s = ".inf"
case "-Inf":
s = "-.inf"
case "NaN":
s = ".nan"
}
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}
func (e *encoder) nilv() {
e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}
func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) {
// TODO Kill this function. Replace all initialize calls by their underlining Go literals.
implicit := tag == ""
if !implicit {
tag = longTag(tag)
}
e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
e.event.head_comment = head
e.event.line_comment = line
e.event.foot_comment = foot
e.event.tail_comment = tail
e.emit()
}
func (e *encoder) nodev(in reflect.Value) {
e.node(in.Interface().(*Node), "")
}
func (e *encoder) node(node *Node, tail string) {
// If the tag was not explicitly requested, and dropping it won't change the
// implicit tag of the value, don't include it in the presentation.
var tag = node.Tag
var stag = shortTag(tag)
var rtag string
var forceQuoting bool
if tag != "" && node.Style&TaggedStyle == 0 {
if node.Kind == ScalarNode {
if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 {
tag = ""
} else {
rtag, _ = resolve("", node.Value)
if rtag == stag {
tag = ""
} else if stag == strTag {
tag = ""
forceQuoting = true
}
}
} else {
switch node.Kind {
case MappingNode:
rtag = mapTag
case SequenceNode:
rtag = seqTag
}
if rtag == stag {
tag = ""
}
}
}
switch node.Kind {
case DocumentNode:
yaml_document_start_event_initialize(&e.event, nil, nil, true)
e.event.head_comment = []byte(node.HeadComment)
e.emit()
for _, node := range node.Content {
e.node(node, "")
}
yaml_document_end_event_initialize(&e.event, true)
e.event.foot_comment = []byte(node.FootComment)
e.emit()
case SequenceNode:
style := yaml_BLOCK_SEQUENCE_STYLE
if node.Style&FlowStyle != 0 {
style = yaml_FLOW_SEQUENCE_STYLE
}
e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style))
e.event.head_comment = []byte(node.HeadComment)
e.emit()
for _, node := range node.Content {
e.node(node, "")
}
e.must(yaml_sequence_end_event_initialize(&e.event))
e.event.line_comment = []byte(node.LineComment)
e.event.foot_comment = []byte(node.FootComment)
e.emit()
case MappingNode:
style := yaml_BLOCK_MAPPING_STYLE
if node.Style&FlowStyle != 0 {
style = yaml_FLOW_MAPPING_STYLE
}
yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style)
e.event.tail_comment = []byte(tail)
e.event.head_comment = []byte(node.HeadComment)
e.emit()
// The tail logic below moves the foot comment of prior keys to the following key,
// since the value for each key may be a nested structure and the foot needs to be
// processed only the entirety of the value is streamed. The last tail is processed
// with the mapping end event.
var tail string
for i := 0; i+1 < len(node.Content); i += 2 {
k := node.Content[i]
foot := k.FootComment
if foot != "" {
kopy := *k
kopy.FootComment = ""
k = &kopy
}
e.node(k, tail)
tail = foot
v := node.Content[i+1]
e.node(v, "")
}
yaml_mapping_end_event_initialize(&e.event)
e.event.tail_comment = []byte(tail)
e.event.line_comment = []byte(node.LineComment)
e.event.foot_comment = []byte(node.FootComment)
e.emit()
case AliasNode:
yaml_alias_event_initialize(&e.event, []byte(node.Value))
e.event.head_comment = []byte(node.HeadComment)
e.event.line_comment = []byte(node.LineComment)
e.event.foot_comment = []byte(node.FootComment)
e.emit()
case ScalarNode:
value := node.Value
if !utf8.ValidString(value) {
if tag == binaryTag {
failf("explicitly tagged !!binary data must be base64-encoded")
}
if tag != "" {
failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
}
// It can't be encoded directly as YAML so use a binary tag
// and encode it as base64.
tag = binaryTag
value = encodeBase64(value)
}
style := yaml_PLAIN_SCALAR_STYLE
switch {
case node.Style&DoubleQuotedStyle != 0:
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
case node.Style&SingleQuotedStyle != 0:
style = yaml_SINGLE_QUOTED_SCALAR_STYLE
case node.Style&LiteralStyle != 0:
style = yaml_LITERAL_SCALAR_STYLE
case node.Style&FoldedStyle != 0:
style = yaml_FOLDED_SCALAR_STYLE
case strings.Contains(value, "\n"):
style = yaml_LITERAL_SCALAR_STYLE
case forceQuoting:
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail))
}
}

5
src/vendor/gopkg.in/yaml.v3/go.mod generated vendored Normal file
View File

@ -0,0 +1,5 @@
module "gopkg.in/yaml.v3"
require (
"gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
)

1229
src/vendor/gopkg.in/yaml.v3/parserc.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

434
src/vendor/gopkg.in/yaml.v3/readerc.go generated vendored Normal file
View File

@ -0,0 +1,434 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package yaml
import (
"io"
)
// Set the reader error and return 0.
func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
parser.error = yaml_READER_ERROR
parser.problem = problem
parser.problem_offset = offset
parser.problem_value = value
return false
}
// Byte order marks.
const (
bom_UTF8 = "\xef\xbb\xbf"
bom_UTF16LE = "\xff\xfe"
bom_UTF16BE = "\xfe\xff"
)
// Determine the input stream encoding by checking the BOM symbol. If no BOM is
// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
// Ensure that we had enough bytes in the raw buffer.
for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
if !yaml_parser_update_raw_buffer(parser) {
return false
}
}
// Determine the encoding.
buf := parser.raw_buffer
pos := parser.raw_buffer_pos
avail := len(buf) - pos
if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
parser.encoding = yaml_UTF16LE_ENCODING
parser.raw_buffer_pos += 2
parser.offset += 2
} else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
parser.encoding = yaml_UTF16BE_ENCODING
parser.raw_buffer_pos += 2
parser.offset += 2
} else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
parser.encoding = yaml_UTF8_ENCODING
parser.raw_buffer_pos += 3
parser.offset += 3
} else {
parser.encoding = yaml_UTF8_ENCODING
}
return true
}
// Update the raw buffer.
func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
size_read := 0
// Return if the raw buffer is full.
if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
return true
}
// Return on EOF.
if parser.eof {
return true
}
// Move the remaining bytes in the raw buffer to the beginning.
if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
}
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
parser.raw_buffer_pos = 0
// Call the read handler to fill the buffer.
size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
if err == io.EOF {
parser.eof = true
} else if err != nil {
return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
}
return true
}
// Ensure that the buffer contains at least `length` characters.
// Return true on success, false on failure.
//
// The length is supposed to be significantly less that the buffer size.
func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
if parser.read_handler == nil {
panic("read handler must be set")
}
// [Go] This function was changed to guarantee the requested length size at EOF.
// The fact we need to do this is pretty awful, but the description above implies
// for that to be the case, and there are tests
// If the EOF flag is set and the raw buffer is empty, do nothing.
if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
// [Go] ACTUALLY! Read the documentation of this function above.
// This is just broken. To return true, we need to have the
// given length in the buffer. Not doing that means every single
// check that calls this function to make sure the buffer has a
// given length is Go) panicking; or C) accessing invalid memory.
//return true
}
// Return if the buffer contains enough characters.
if parser.unread >= length {
return true
}
// Determine the input encoding if it is not known yet.
if parser.encoding == yaml_ANY_ENCODING {
if !yaml_parser_determine_encoding(parser) {
return false
}
}
// Move the unread characters to the beginning of the buffer.
buffer_len := len(parser.buffer)
if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
copy(parser.buffer, parser.buffer[parser.buffer_pos:])
buffer_len -= parser.buffer_pos
parser.buffer_pos = 0
} else if parser.buffer_pos == buffer_len {
buffer_len = 0
parser.buffer_pos = 0
}
// Open the whole buffer for writing, and cut it before returning.
parser.buffer = parser.buffer[:cap(parser.buffer)]
// Fill the buffer until it has enough characters.
first := true
for parser.unread < length {
// Fill the raw buffer if necessary.
if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
if !yaml_parser_update_raw_buffer(parser) {
parser.buffer = parser.buffer[:buffer_len]
return false
}
}
first = false
// Decode the raw buffer.
inner:
for parser.raw_buffer_pos != len(parser.raw_buffer) {
var value rune
var width int
raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
// Decode the next character.
switch parser.encoding {
case yaml_UTF8_ENCODING:
// Decode a UTF-8 character. Check RFC 3629
// (http://www.ietf.org/rfc/rfc3629.txt) for more details.
//
// The following table (taken from the RFC) is used for
// decoding.
//
// Char. number range | UTF-8 octet sequence
// (hexadecimal) | (binary)
// --------------------+------------------------------------
// 0000 0000-0000 007F | 0xxxxxxx
// 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
// 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
// 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
//
// Additionally, the characters in the range 0xD800-0xDFFF
// are prohibited as they are reserved for use with UTF-16
// surrogate pairs.
// Determine the length of the UTF-8 sequence.
octet := parser.raw_buffer[parser.raw_buffer_pos]
switch {
case octet&0x80 == 0x00:
width = 1
case octet&0xE0 == 0xC0:
width = 2
case octet&0xF0 == 0xE0:
width = 3
case octet&0xF8 == 0xF0:
width = 4
default:
// The leading octet is invalid.
return yaml_parser_set_reader_error(parser,
"invalid leading UTF-8 octet",
parser.offset, int(octet))
}
// Check if the raw buffer contains an incomplete character.
if width > raw_unread {
if parser.eof {
return yaml_parser_set_reader_error(parser,
"incomplete UTF-8 octet sequence",
parser.offset, -1)
}
break inner
}
// Decode the leading octet.
switch {
case octet&0x80 == 0x00:
value = rune(octet & 0x7F)
case octet&0xE0 == 0xC0:
value = rune(octet & 0x1F)
case octet&0xF0 == 0xE0:
value = rune(octet & 0x0F)
case octet&0xF8 == 0xF0:
value = rune(octet & 0x07)
default:
value = 0
}
// Check and decode the trailing octets.
for k := 1; k < width; k++ {
octet = parser.raw_buffer[parser.raw_buffer_pos+k]
// Check if the octet is valid.
if (octet & 0xC0) != 0x80 {
return yaml_parser_set_reader_error(parser,
"invalid trailing UTF-8 octet",
parser.offset+k, int(octet))
}
// Decode the octet.
value = (value << 6) + rune(octet&0x3F)
}
// Check the length of the sequence against the value.
switch {
case width == 1:
case width == 2 && value >= 0x80:
case width == 3 && value >= 0x800:
case width == 4 && value >= 0x10000:
default:
return yaml_parser_set_reader_error(parser,
"invalid length of a UTF-8 sequence",
parser.offset, -1)
}
// Check the range of the value.
if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
return yaml_parser_set_reader_error(parser,
"invalid Unicode character",
parser.offset, int(value))
}
case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
var low, high int
if parser.encoding == yaml_UTF16LE_ENCODING {
low, high = 0, 1
} else {
low, high = 1, 0
}
// The UTF-16 encoding is not as simple as one might
// naively think. Check RFC 2781
// (http://www.ietf.org/rfc/rfc2781.txt).
//
// Normally, two subsequent bytes describe a Unicode
// character. However a special technique (called a
// surrogate pair) is used for specifying character
// values larger than 0xFFFF.
//
// A surrogate pair consists of two pseudo-characters:
// high surrogate area (0xD800-0xDBFF)
// low surrogate area (0xDC00-0xDFFF)
//
// The following formulas are used for decoding
// and encoding characters using surrogate pairs:
//
// U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
// U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
// W1 = 110110yyyyyyyyyy
// W2 = 110111xxxxxxxxxx
//
// where U is the character value, W1 is the high surrogate
// area, W2 is the low surrogate area.
// Check for incomplete UTF-16 character.
if raw_unread < 2 {
if parser.eof {
return yaml_parser_set_reader_error(parser,
"incomplete UTF-16 character",
parser.offset, -1)
}
break inner
}
// Get the character.
value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
(rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
// Check for unexpected low surrogate area.
if value&0xFC00 == 0xDC00 {
return yaml_parser_set_reader_error(parser,
"unexpected low surrogate area",
parser.offset, int(value))
}
// Check for a high surrogate area.
if value&0xFC00 == 0xD800 {
width = 4
// Check for incomplete surrogate pair.
if raw_unread < 4 {
if parser.eof {
return yaml_parser_set_reader_error(parser,
"incomplete UTF-16 surrogate pair",
parser.offset, -1)
}
break inner
}
// Get the next character.
value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
(rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
// Check for a low surrogate area.
if value2&0xFC00 != 0xDC00 {
return yaml_parser_set_reader_error(parser,
"expected low surrogate area",
parser.offset+2, int(value2))
}
// Generate the value of the surrogate pair.
value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
} else {
width = 2
}
default:
panic("impossible")
}
// Check if the character is in the allowed range:
// #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
// | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
// | [#x10000-#x10FFFF] (32 bit)
switch {
case value == 0x09:
case value == 0x0A:
case value == 0x0D:
case value >= 0x20 && value <= 0x7E:
case value == 0x85:
case value >= 0xA0 && value <= 0xD7FF:
case value >= 0xE000 && value <= 0xFFFD:
case value >= 0x10000 && value <= 0x10FFFF:
default:
return yaml_parser_set_reader_error(parser,
"control characters are not allowed",
parser.offset, int(value))
}
// Move the raw pointers.
parser.raw_buffer_pos += width
parser.offset += width
// Finally put the character into the buffer.
if value <= 0x7F {
// 0000 0000-0000 007F . 0xxxxxxx
parser.buffer[buffer_len+0] = byte(value)
buffer_len += 1
} else if value <= 0x7FF {
// 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
buffer_len += 2
} else if value <= 0xFFFF {
// 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
buffer_len += 3
} else {
// 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
buffer_len += 4
}
parser.unread++
}
// On EOF, put NUL into the buffer and return.
if parser.eof {
parser.buffer[buffer_len] = 0
buffer_len++
parser.unread++
break
}
}
// [Go] Read the documentation of this function above. To return true,
// we need to have the given length in the buffer. Not doing that means
// every single check that calls this function to make sure the buffer
// has a given length is Go) panicking; or C) accessing invalid memory.
// This happens here due to the EOF above breaking early.
for buffer_len < length {
parser.buffer[buffer_len] = 0
buffer_len++
}
parser.buffer = parser.buffer[:buffer_len]
return true
}

326
src/vendor/gopkg.in/yaml.v3/resolve.go generated vendored Normal file
View File

@ -0,0 +1,326 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package yaml
import (
"encoding/base64"
"math"
"regexp"
"strconv"
"strings"
"time"
)
type resolveMapItem struct {
value interface{}
tag string
}
var resolveTable = make([]byte, 256)
var resolveMap = make(map[string]resolveMapItem)
func init() {
t := resolveTable
t[int('+')] = 'S' // Sign
t[int('-')] = 'S'
for _, c := range "0123456789" {
t[int(c)] = 'D' // Digit
}
for _, c := range "yYnNtTfFoO~" {
t[int(c)] = 'M' // In map
}
t[int('.')] = '.' // Float (potentially in map)
var resolveMapList = []struct {
v interface{}
tag string
l []string
}{
{true, boolTag, []string{"true", "True", "TRUE"}},
{false, boolTag, []string{"false", "False", "FALSE"}},
{nil, nullTag, []string{"", "~", "null", "Null", "NULL"}},
{math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}},
{math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}},
{math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}},
{math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}},
{"<<", mergeTag, []string{"<<"}},
}
m := resolveMap
for _, item := range resolveMapList {
for _, s := range item.l {
m[s] = resolveMapItem{item.v, item.tag}
}
}
}
const (
nullTag = "!!null"
boolTag = "!!bool"
strTag = "!!str"
intTag = "!!int"
floatTag = "!!float"
timestampTag = "!!timestamp"
seqTag = "!!seq"
mapTag = "!!map"
binaryTag = "!!binary"
mergeTag = "!!merge"
)
var longTags = make(map[string]string)
var shortTags = make(map[string]string)
func init() {
for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} {
ltag := longTag(stag)
longTags[stag] = ltag
shortTags[ltag] = stag
}
}
const longTagPrefix = "tag:yaml.org,2002:"
func shortTag(tag string) string {
if strings.HasPrefix(tag, longTagPrefix) {
if stag, ok := shortTags[tag]; ok {
return stag
}
return "!!" + tag[len(longTagPrefix):]
}
return tag
}
func longTag(tag string) string {
if strings.HasPrefix(tag, "!!") {
if ltag, ok := longTags[tag]; ok {
return ltag
}
return longTagPrefix + tag[2:]
}
return tag
}
func resolvableTag(tag string) bool {
switch tag {
case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag:
return true
}
return false
}
var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
func resolve(tag string, in string) (rtag string, out interface{}) {
tag = shortTag(tag)
if !resolvableTag(tag) {
return tag, in
}
defer func() {
switch tag {
case "", rtag, strTag, binaryTag:
return
case floatTag:
if rtag == intTag {
switch v := out.(type) {
case int64:
rtag = floatTag
out = float64(v)
return
case int:
rtag = floatTag
out = float64(v)
return
}
}
}
failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
}()
// Any data is accepted as a !!str or !!binary.
// Otherwise, the prefix is enough of a hint about what it might be.
hint := byte('N')
if in != "" {
hint = resolveTable[in[0]]
}
if hint != 0 && tag != strTag && tag != binaryTag {
// Handle things we can lookup in a map.
if item, ok := resolveMap[in]; ok {
return item.tag, item.value
}
// Base 60 floats are a bad idea, were dropped in YAML 1.2, and
// are purposefully unsupported here. They're still quoted on
// the way out for compatibility with other parser, though.
switch hint {
case 'M':
// We've already checked the map above.
case '.':
// Not in the map, so maybe a normal float.
floatv, err := strconv.ParseFloat(in, 64)
if err == nil {
return floatTag, floatv
}
case 'D', 'S':
// Int, float, or timestamp.
// Only try values as a timestamp if the value is unquoted or there's an explicit
// !!timestamp tag.
if tag == "" || tag == timestampTag {
t, ok := parseTimestamp(in)
if ok {
return timestampTag, t
}
}
plain := strings.Replace(in, "_", "", -1)
intv, err := strconv.ParseInt(plain, 0, 64)
if err == nil {
if intv == int64(int(intv)) {
return intTag, int(intv)
} else {
return intTag, intv
}
}
uintv, err := strconv.ParseUint(plain, 0, 64)
if err == nil {
return intTag, uintv
}
if yamlStyleFloat.MatchString(plain) {
floatv, err := strconv.ParseFloat(plain, 64)
if err == nil {
return floatTag, floatv
}
}
if strings.HasPrefix(plain, "0b") {
intv, err := strconv.ParseInt(plain[2:], 2, 64)
if err == nil {
if intv == int64(int(intv)) {
return intTag, int(intv)
} else {
return intTag, intv
}
}
uintv, err := strconv.ParseUint(plain[2:], 2, 64)
if err == nil {
return intTag, uintv
}
} else if strings.HasPrefix(plain, "-0b") {
intv, err := strconv.ParseInt("-"+plain[3:], 2, 64)
if err == nil {
if true || intv == int64(int(intv)) {
return intTag, int(intv)
} else {
return intTag, intv
}
}
}
// Octals as introduced in version 1.2 of the spec.
// Octals from the 1.1 spec, spelled as 0777, are still
// decoded by default in v3 as well for compatibility.
// May be dropped in v4 depending on how usage evolves.
if strings.HasPrefix(plain, "0o") {
intv, err := strconv.ParseInt(plain[2:], 8, 64)
if err == nil {
if intv == int64(int(intv)) {
return intTag, int(intv)
} else {
return intTag, intv
}
}
uintv, err := strconv.ParseUint(plain[2:], 8, 64)
if err == nil {
return intTag, uintv
}
} else if strings.HasPrefix(plain, "-0o") {
intv, err := strconv.ParseInt("-"+plain[3:], 8, 64)
if err == nil {
if true || intv == int64(int(intv)) {
return intTag, int(intv)
} else {
return intTag, intv
}
}
}
default:
panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")")
}
}
return strTag, in
}
// encodeBase64 encodes s as base64 that is broken up into multiple lines
// as appropriate for the resulting length.
func encodeBase64(s string) string {
const lineLen = 70
encLen := base64.StdEncoding.EncodedLen(len(s))
lines := encLen/lineLen + 1
buf := make([]byte, encLen*2+lines)
in := buf[0:encLen]
out := buf[encLen:]
base64.StdEncoding.Encode(in, []byte(s))
k := 0
for i := 0; i < len(in); i += lineLen {
j := i + lineLen
if j > len(in) {
j = len(in)
}
k += copy(out[k:], in[i:j])
if lines > 1 {
out[k] = '\n'
k++
}
}
return string(out[:k])
}
// This is a subset of the formats allowed by the regular expression
// defined at http://yaml.org/type/timestamp.html.
var allowedTimestampFormats = []string{
"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
"2006-1-2 15:4:5.999999999", // space separated with no time zone
"2006-1-2", // date only
// Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
// from the set of examples.
}
// parseTimestamp parses s as a timestamp string and
// returns the timestamp and reports whether it succeeded.
// Timestamp formats are defined at http://yaml.org/type/timestamp.html
func parseTimestamp(s string) (time.Time, bool) {
// TODO write code to check all the formats supported by
// http://yaml.org/type/timestamp.html instead of using time.Parse.
// Quick check: all date formats start with YYYY-.
i := 0
for ; i < len(s); i++ {
if c := s[i]; c < '0' || c > '9' {
break
}
}
if i != 4 || i == len(s) || s[i] != '-' {
return time.Time{}, false
}
for _, format := range allowedTimestampFormats {
if t, err := time.Parse(format, s); err == nil {
return t, true
}
}
return time.Time{}, false
}

3025
src/vendor/gopkg.in/yaml.v3/scannerc.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

134
src/vendor/gopkg.in/yaml.v3/sorter.go generated vendored Normal file
View File

@ -0,0 +1,134 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package yaml
import (
"reflect"
"unicode"
)
type keyList []reflect.Value
func (l keyList) Len() int { return len(l) }
func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l keyList) Less(i, j int) bool {
a := l[i]
b := l[j]
ak := a.Kind()
bk := b.Kind()
for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
a = a.Elem()
ak = a.Kind()
}
for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
b = b.Elem()
bk = b.Kind()
}
af, aok := keyFloat(a)
bf, bok := keyFloat(b)
if aok && bok {
if af != bf {
return af < bf
}
if ak != bk {
return ak < bk
}
return numLess(a, b)
}
if ak != reflect.String || bk != reflect.String {
return ak < bk
}
ar, br := []rune(a.String()), []rune(b.String())
digits := false
for i := 0; i < len(ar) && i < len(br); i++ {
if ar[i] == br[i] {
digits = unicode.IsDigit(ar[i])
continue
}
al := unicode.IsLetter(ar[i])
bl := unicode.IsLetter(br[i])
if al && bl {
return ar[i] < br[i]
}
if al || bl {
if digits {
return al
} else {
return bl
}
}
var ai, bi int
var an, bn int64
if ar[i] == '0' || br[i] == '0' {
for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
if ar[j] != '0' {
an = 1
bn = 1
break
}
}
}
for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
an = an*10 + int64(ar[ai]-'0')
}
for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
bn = bn*10 + int64(br[bi]-'0')
}
if an != bn {
return an < bn
}
if ai != bi {
return ai < bi
}
return ar[i] < br[i]
}
return len(ar) < len(br)
}
// keyFloat returns a float value for v if it is a number/bool
// and whether it is a number/bool or not.
func keyFloat(v reflect.Value) (f float64, ok bool) {
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return float64(v.Int()), true
case reflect.Float32, reflect.Float64:
return v.Float(), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return float64(v.Uint()), true
case reflect.Bool:
if v.Bool() {
return 1, true
}
return 0, true
}
return 0, false
}
// numLess returns whether a < b.
// a and b must necessarily have the same kind.
func numLess(a, b reflect.Value) bool {
switch a.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return a.Int() < b.Int()
case reflect.Float32, reflect.Float64:
return a.Float() < b.Float()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return a.Uint() < b.Uint()
case reflect.Bool:
return !a.Bool() && b.Bool()
}
panic("not a number")
}

48
src/vendor/gopkg.in/yaml.v3/writerc.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package yaml
// Set the writer error and return false.
func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
emitter.error = yaml_WRITER_ERROR
emitter.problem = problem
return false
}
// Flush the output buffer.
func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
if emitter.write_handler == nil {
panic("write handler not set")
}
// Check if the buffer is empty.
if emitter.buffer_pos == 0 {
return true
}
if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
}
emitter.buffer_pos = 0
return true
}

662
src/vendor/gopkg.in/yaml.v3/yaml.go generated vendored Normal file
View File

@ -0,0 +1,662 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package yaml implements YAML support for the Go language.
//
// Source code and other details for the project are available at GitHub:
//
// https://github.com/go-yaml/yaml
//
package yaml
import (
"errors"
"fmt"
"io"
"reflect"
"strings"
"sync"
"unicode/utf8"
)
// The Unmarshaler interface may be implemented by types to customize their
// behavior when being unmarshaled from a YAML document.
type Unmarshaler interface {
UnmarshalYAML(value *Node) error
}
type obsoleteUnmarshaler interface {
UnmarshalYAML(unmarshal func(interface{}) error) error
}
// The Marshaler interface may be implemented by types to customize their
// behavior when being marshaled into a YAML document. The returned value
// is marshaled in place of the original value implementing Marshaler.
//
// If an error is returned by MarshalYAML, the marshaling procedure stops
// and returns with the provided error.
type Marshaler interface {
MarshalYAML() (interface{}, error)
}
// Unmarshal decodes the first document found within the in byte slice
// and assigns decoded values into the out value.
//
// Maps and pointers (to a struct, string, int, etc) are accepted as out
// values. If an internal pointer within a struct is not initialized,
// the yaml package will initialize it if necessary for unmarshalling
// the provided data. The out parameter must not be nil.
//
// The type of the decoded values should be compatible with the respective
// values in out. If one or more values cannot be decoded due to a type
// mismatches, decoding continues partially until the end of the YAML
// content, and a *yaml.TypeError is returned with details for all
// missed values.
//
// Struct fields are only unmarshalled if they are exported (have an
// upper case first letter), and are unmarshalled using the field name
// lowercased as the default key. Custom keys may be defined via the
// "yaml" name in the field tag: the content preceding the first comma
// is used as the key, and the following comma-separated options are
// used to tweak the marshalling process (see Marshal).
// Conflicting names result in a runtime error.
//
// For example:
//
// type T struct {
// F int `yaml:"a,omitempty"`
// B int
// }
// var t T
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
//
// See the documentation of Marshal for the format of tags and a list of
// supported tag options.
//
func Unmarshal(in []byte, out interface{}) (err error) {
return unmarshal(in, out, false)
}
// A Decorder reads and decodes YAML values from an input stream.
type Decoder struct {
parser *parser
knownFields bool
}
// NewDecoder returns a new decoder that reads from r.
//
// The decoder introduces its own buffering and may read
// data from r beyond the YAML values requested.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
parser: newParserFromReader(r),
}
}
// KnownFields ensures that the keys in decoded mappings to
// exist as fields in the struct being decoded into.
func (dec *Decoder) KnownFields(enable bool) {
dec.knownFields = enable
}
// Decode reads the next YAML-encoded value from its input
// and stores it in the value pointed to by v.
//
// See the documentation for Unmarshal for details about the
// conversion of YAML into a Go value.
func (dec *Decoder) Decode(v interface{}) (err error) {
d := newDecoder()
d.knownFields = dec.knownFields
defer handleErr(&err)
node := dec.parser.parse()
if node == nil {
return io.EOF
}
out := reflect.ValueOf(v)
if out.Kind() == reflect.Ptr && !out.IsNil() {
out = out.Elem()
}
d.unmarshal(node, out)
if len(d.terrors) > 0 {
return &TypeError{d.terrors}
}
return nil
}
// Decode decodes the node and stores its data into the value pointed to by v.
//
// See the documentation for Unmarshal for details about the
// conversion of YAML into a Go value.
func (n *Node) Decode(v interface{}) (err error) {
d := newDecoder()
defer handleErr(&err)
out := reflect.ValueOf(v)
if out.Kind() == reflect.Ptr && !out.IsNil() {
out = out.Elem()
}
d.unmarshal(n, out)
if len(d.terrors) > 0 {
return &TypeError{d.terrors}
}
return nil
}
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
defer handleErr(&err)
d := newDecoder()
p := newParser(in)
defer p.destroy()
node := p.parse()
if node != nil {
v := reflect.ValueOf(out)
if v.Kind() == reflect.Ptr && !v.IsNil() {
v = v.Elem()
}
d.unmarshal(node, v)
}
if len(d.terrors) > 0 {
return &TypeError{d.terrors}
}
return nil
}
// Marshal serializes the value provided into a YAML document. The structure
// of the generated document will reflect the structure of the value itself.
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
//
// Struct fields are only marshalled if they are exported (have an upper case
// first letter), and are marshalled using the field name lowercased as the
// default key. Custom keys may be defined via the "yaml" name in the field
// tag: the content preceding the first comma is used as the key, and the
// following comma-separated options are used to tweak the marshalling process.
// Conflicting names result in a runtime error.
//
// The field tag format accepted is:
//
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
//
// The following flags are currently supported:
//
// omitempty Only include the field if it's not set to the zero
// value for the type or to empty slices or maps.
// Zero valued structs will be omitted if all their public
// fields are zero, unless they implement an IsZero
// method (see the IsZeroer interface type), in which
// case the field will be included if that method returns true.
//
// flow Marshal using a flow style (useful for structs,
// sequences and maps).
//
// inline Inline the field, which must be a struct or a map,
// causing all of its fields or keys to be processed as if
// they were part of the outer struct. For maps, keys must
// not conflict with the yaml keys of other struct fields.
//
// In addition, if the key is "-", the field is ignored.
//
// For example:
//
// type T struct {
// F int `yaml:"a,omitempty"`
// B int
// }
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
//
func Marshal(in interface{}) (out []byte, err error) {
defer handleErr(&err)
e := newEncoder()
defer e.destroy()
e.marshalDoc("", reflect.ValueOf(in))
e.finish()
out = e.out
return
}
// An Encoder writes YAML values to an output stream.
type Encoder struct {
encoder *encoder
}
// NewEncoder returns a new encoder that writes to w.
// The Encoder should be closed after use to flush all data
// to w.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
encoder: newEncoderWithWriter(w),
}
}
// Encode writes the YAML encoding of v to the stream.
// If multiple items are encoded to the stream, the
// second and subsequent document will be preceded
// with a "---" document separator, but the first will not.
//
// See the documentation for Marshal for details about the conversion of Go
// values to YAML.
func (e *Encoder) Encode(v interface{}) (err error) {
defer handleErr(&err)
e.encoder.marshalDoc("", reflect.ValueOf(v))
return nil
}
// SetIndent changes the used indentation used when encoding.
func (e *Encoder) SetIndent(spaces int) {
if spaces < 0 {
panic("yaml: cannot indent to a negative number of spaces")
}
e.encoder.indent = spaces
}
// Close closes the encoder by writing any remaining data.
// It does not write a stream terminating string "...".
func (e *Encoder) Close() (err error) {
defer handleErr(&err)
e.encoder.finish()
return nil
}
func handleErr(err *error) {
if v := recover(); v != nil {
if e, ok := v.(yamlError); ok {
*err = e.err
} else {
panic(v)
}
}
}
type yamlError struct {
err error
}
func fail(err error) {
panic(yamlError{err})
}
func failf(format string, args ...interface{}) {
panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
}
// A TypeError is returned by Unmarshal when one or more fields in
// the YAML document cannot be properly decoded into the requested
// types. When this error is returned, the value is still
// unmarshaled partially.
type TypeError struct {
Errors []string
}
func (e *TypeError) Error() string {
return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
}
type Kind uint32
const (
DocumentNode Kind = 1 << iota
SequenceNode
MappingNode
ScalarNode
AliasNode
)
type Style uint32
const (
TaggedStyle Style = 1 << iota
DoubleQuotedStyle
SingleQuotedStyle
LiteralStyle
FoldedStyle
FlowStyle
)
// Node represents an element in the YAML document hierarchy. While documents
// are typically encoded and decoded into higher level types, such as structs
// and maps, Node is an intermediate representation that allows detailed
// control over the content being decoded or encoded.
//
// Values that make use of the Node type interact with the yaml package in the
// same way any other type would do, by encoding and decoding yaml data
// directly or indirectly into them.
//
// For example:
//
// var person struct {
// Name string
// Address yaml.Node
// }
// err := yaml.Unmarshal(data, &person)
//
// Or by itself:
//
// var person Node
// err := yaml.Unmarshal(data, &person)
//
type Node struct {
// Kind defines whether the node is a document, a mapping, a sequence,
// a scalar value, or an alias to another node. The specific data type of
// scalar nodes may be obtained via the ShortTag and LongTag methods.
Kind Kind
// Style allows customizing the apperance of the node in the tree.
Style Style
// Tag holds the YAML tag defining the data type for the value.
// When decoding, this field will always be set to the resolved tag,
// even when it wasn't explicitly provided in the YAML content.
// When encoding, if this field is unset the value type will be
// implied from the node properties, and if it is set, it will only
// be serialized into the representation if TaggedStyle is used or
// the implicit tag diverges from the provided one.
Tag string
// Value holds the unescaped and unquoted represenation of the value.
Value string
// Anchor holds the anchor name for this node, which allows aliases to point to it.
Anchor string
// Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
Alias *Node
// Content holds contained nodes for documents, mappings, and sequences.
Content []*Node
// HeadComment holds any comments in the lines preceding the node and
// not separated by an empty line.
HeadComment string
// LineComment holds any comments at the end of the line where the node is in.
LineComment string
// FootComment holds any comments following the node and before empty lines.
FootComment string
// Line and Column hold the node position in the decoded YAML text.
// These fields are not respected when encoding the node.
Line int
Column int
}
// LongTag returns the long form of the tag that indicates the data type for
// the node. If the Tag field isn't explicitly defined, one will be computed
// based on the node properties.
func (n *Node) LongTag() string {
return longTag(n.ShortTag())
}
// ShortTag returns the short form of the YAML tag that indicates data type for
// the node. If the Tag field isn't explicitly defined, one will be computed
// based on the node properties.
func (n *Node) ShortTag() string {
if n.indicatedString() {
return strTag
}
if n.Tag == "" || n.Tag == "!" {
switch n.Kind {
case MappingNode:
return mapTag
case SequenceNode:
return seqTag
case AliasNode:
if n.Alias != nil {
return n.Alias.ShortTag()
}
case ScalarNode:
tag, _ := resolve("", n.Value)
return tag
}
return ""
}
return shortTag(n.Tag)
}
func (n *Node) indicatedString() bool {
return n.Kind == ScalarNode &&
(shortTag(n.Tag) == strTag ||
(n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
}
// SetString is a convenience function that sets the node to a string value
// and defines its style in a pleasant way depending on its content.
func (n *Node) SetString(s string) {
n.Kind = ScalarNode
if utf8.ValidString(s) {
n.Value = s
n.Tag = strTag
} else {
n.Value = encodeBase64(s)
n.Tag = binaryTag
}
if strings.Contains(n.Value, "\n") {
n.Style = LiteralStyle
}
}
// --------------------------------------------------------------------------
// Maintain a mapping of keys to structure field indexes
// The code in this section was copied from mgo/bson.
// structInfo holds details for the serialization of fields of
// a given struct.
type structInfo struct {
FieldsMap map[string]fieldInfo
FieldsList []fieldInfo
// InlineMap is the number of the field in the struct that
// contains an ,inline map, or -1 if there's none.
InlineMap int
// InlineUnmarshalers holds indexes to inlined fields that
// contain unmarshaler values.
InlineUnmarshalers [][]int
}
type fieldInfo struct {
Key string
Num int
OmitEmpty bool
Flow bool
// Id holds the unique field identifier, so we can cheaply
// check for field duplicates without maintaining an extra map.
Id int
// Inline holds the field index if the field is part of an inlined struct.
Inline []int
}
var structMap = make(map[reflect.Type]*structInfo)
var fieldMapMutex sync.RWMutex
var unmarshalerType reflect.Type
func init() {
var v Unmarshaler
unmarshalerType = reflect.ValueOf(&v).Elem().Type()
}
func getStructInfo(st reflect.Type) (*structInfo, error) {
fieldMapMutex.RLock()
sinfo, found := structMap[st]
fieldMapMutex.RUnlock()
if found {
return sinfo, nil
}
n := st.NumField()
fieldsMap := make(map[string]fieldInfo)
fieldsList := make([]fieldInfo, 0, n)
inlineMap := -1
inlineUnmarshalers := [][]int(nil)
for i := 0; i != n; i++ {
field := st.Field(i)
if field.PkgPath != "" && !field.Anonymous {
continue // Private field
}
info := fieldInfo{Num: i}
tag := field.Tag.Get("yaml")
if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
tag = string(field.Tag)
}
if tag == "-" {
continue
}
inline := false
fields := strings.Split(tag, ",")
if len(fields) > 1 {
for _, flag := range fields[1:] {
switch flag {
case "omitempty":
info.OmitEmpty = true
case "flow":
info.Flow = true
case "inline":
inline = true
default:
return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
}
}
tag = fields[0]
}
if inline {
switch field.Type.Kind() {
case reflect.Map:
if inlineMap >= 0 {
return nil, errors.New("multiple ,inline maps in struct " + st.String())
}
if field.Type.Key() != reflect.TypeOf("") {
return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
}
inlineMap = info.Num
case reflect.Struct, reflect.Ptr:
ftype := field.Type
for ftype.Kind() == reflect.Ptr {
ftype = ftype.Elem()
}
if ftype.Kind() != reflect.Struct {
return nil, errors.New("option ,inline may only be used on a struct or map field")
}
if reflect.PtrTo(ftype).Implements(unmarshalerType) {
inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
} else {
sinfo, err := getStructInfo(ftype)
if err != nil {
return nil, err
}
for _, index := range sinfo.InlineUnmarshalers {
inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
}
for _, finfo := range sinfo.FieldsList {
if _, found := fieldsMap[finfo.Key]; found {
msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
return nil, errors.New(msg)
}
if finfo.Inline == nil {
finfo.Inline = []int{i, finfo.Num}
} else {
finfo.Inline = append([]int{i}, finfo.Inline...)
}
finfo.Id = len(fieldsList)
fieldsMap[finfo.Key] = finfo
fieldsList = append(fieldsList, finfo)
}
}
default:
return nil, errors.New("option ,inline may only be used on a struct or map field")
}
continue
}
if tag != "" {
info.Key = tag
} else {
info.Key = strings.ToLower(field.Name)
}
if _, found = fieldsMap[info.Key]; found {
msg := "duplicated key '" + info.Key + "' in struct " + st.String()
return nil, errors.New(msg)
}
info.Id = len(fieldsList)
fieldsList = append(fieldsList, info)
fieldsMap[info.Key] = info
}
sinfo = &structInfo{
FieldsMap: fieldsMap,
FieldsList: fieldsList,
InlineMap: inlineMap,
InlineUnmarshalers: inlineUnmarshalers,
}
fieldMapMutex.Lock()
structMap[st] = sinfo
fieldMapMutex.Unlock()
return sinfo, nil
}
// IsZeroer is used to check whether an object is zero to
// determine whether it should be omitted when marshaling
// with the omitempty flag. One notable implementation
// is time.Time.
type IsZeroer interface {
IsZero() bool
}
func isZero(v reflect.Value) bool {
kind := v.Kind()
if z, ok := v.Interface().(IsZeroer); ok {
if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
return true
}
return z.IsZero()
}
switch kind {
case reflect.String:
return len(v.String()) == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
case reflect.Slice:
return v.Len() == 0
case reflect.Map:
return v.Len() == 0
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Struct:
vt := v.Type()
for i := v.NumField() - 1; i >= 0; i-- {
if vt.Field(i).PkgPath != "" {
continue // Private field
}
if !isZero(v.Field(i)) {
return false
}
}
return true
}
return false
}

805
src/vendor/gopkg.in/yaml.v3/yamlh.go generated vendored Normal file
View File

@ -0,0 +1,805 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package yaml
import (
"fmt"
"io"
)
// The version directive data.
type yaml_version_directive_t struct {
major int8 // The major version number.
minor int8 // The minor version number.
}
// The tag directive data.
type yaml_tag_directive_t struct {
handle []byte // The tag handle.
prefix []byte // The tag prefix.
}
type yaml_encoding_t int
// The stream encoding.
const (
// Let the parser choose the encoding.
yaml_ANY_ENCODING yaml_encoding_t = iota
yaml_UTF8_ENCODING // The default UTF-8 encoding.
yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
)
type yaml_break_t int
// Line break types.
const (
// Let the parser choose the break type.
yaml_ANY_BREAK yaml_break_t = iota
yaml_CR_BREAK // Use CR for line breaks (Mac style).
yaml_LN_BREAK // Use LN for line breaks (Unix style).
yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
)
type yaml_error_type_t int
// Many bad things could happen with the parser and emitter.
const (
// No error is produced.
yaml_NO_ERROR yaml_error_type_t = iota
yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory.
yaml_READER_ERROR // Cannot read or decode the input stream.
yaml_SCANNER_ERROR // Cannot scan the input stream.
yaml_PARSER_ERROR // Cannot parse the input stream.
yaml_COMPOSER_ERROR // Cannot compose a YAML document.
yaml_WRITER_ERROR // Cannot write to the output stream.
yaml_EMITTER_ERROR // Cannot emit a YAML stream.
)
// The pointer position.
type yaml_mark_t struct {
index int // The position index.
line int // The position line.
column int // The position column.
}
// Node Styles
type yaml_style_t int8
type yaml_scalar_style_t yaml_style_t
// Scalar styles.
const (
// Let the emitter choose the style.
yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0
yaml_PLAIN_SCALAR_STYLE yaml_scalar_style_t = 1 << iota // The plain scalar style.
yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
yaml_LITERAL_SCALAR_STYLE // The literal scalar style.
yaml_FOLDED_SCALAR_STYLE // The folded scalar style.
)
type yaml_sequence_style_t yaml_style_t
// Sequence styles.
const (
// Let the emitter choose the style.
yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
yaml_FLOW_SEQUENCE_STYLE // The flow sequence style.
)
type yaml_mapping_style_t yaml_style_t
// Mapping styles.
const (
// Let the emitter choose the style.
yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
yaml_BLOCK_MAPPING_STYLE // The block mapping style.
yaml_FLOW_MAPPING_STYLE // The flow mapping style.
)
// Tokens
type yaml_token_type_t int
// Token types.
const (
// An empty token.
yaml_NO_TOKEN yaml_token_type_t = iota
yaml_STREAM_START_TOKEN // A STREAM-START token.
yaml_STREAM_END_TOKEN // A STREAM-END token.
yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token.
yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token.
yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token.
yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token.
yaml_BLOCK_END_TOKEN // A BLOCK-END token.
yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token.
yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token.
yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token.
yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token.
yaml_KEY_TOKEN // A KEY token.
yaml_VALUE_TOKEN // A VALUE token.
yaml_ALIAS_TOKEN // An ALIAS token.
yaml_ANCHOR_TOKEN // An ANCHOR token.
yaml_TAG_TOKEN // A TAG token.
yaml_SCALAR_TOKEN // A SCALAR token.
)
func (tt yaml_token_type_t) String() string {
switch tt {
case yaml_NO_TOKEN:
return "yaml_NO_TOKEN"
case yaml_STREAM_START_TOKEN:
return "yaml_STREAM_START_TOKEN"
case yaml_STREAM_END_TOKEN:
return "yaml_STREAM_END_TOKEN"
case yaml_VERSION_DIRECTIVE_TOKEN:
return "yaml_VERSION_DIRECTIVE_TOKEN"
case yaml_TAG_DIRECTIVE_TOKEN:
return "yaml_TAG_DIRECTIVE_TOKEN"
case yaml_DOCUMENT_START_TOKEN:
return "yaml_DOCUMENT_START_TOKEN"
case yaml_DOCUMENT_END_TOKEN:
return "yaml_DOCUMENT_END_TOKEN"
case yaml_BLOCK_SEQUENCE_START_TOKEN:
return "yaml_BLOCK_SEQUENCE_START_TOKEN"
case yaml_BLOCK_MAPPING_START_TOKEN:
return "yaml_BLOCK_MAPPING_START_TOKEN"
case yaml_BLOCK_END_TOKEN:
return "yaml_BLOCK_END_TOKEN"
case yaml_FLOW_SEQUENCE_START_TOKEN:
return "yaml_FLOW_SEQUENCE_START_TOKEN"
case yaml_FLOW_SEQUENCE_END_TOKEN:
return "yaml_FLOW_SEQUENCE_END_TOKEN"
case yaml_FLOW_MAPPING_START_TOKEN:
return "yaml_FLOW_MAPPING_START_TOKEN"
case yaml_FLOW_MAPPING_END_TOKEN:
return "yaml_FLOW_MAPPING_END_TOKEN"
case yaml_BLOCK_ENTRY_TOKEN:
return "yaml_BLOCK_ENTRY_TOKEN"
case yaml_FLOW_ENTRY_TOKEN:
return "yaml_FLOW_ENTRY_TOKEN"
case yaml_KEY_TOKEN:
return "yaml_KEY_TOKEN"
case yaml_VALUE_TOKEN:
return "yaml_VALUE_TOKEN"
case yaml_ALIAS_TOKEN:
return "yaml_ALIAS_TOKEN"
case yaml_ANCHOR_TOKEN:
return "yaml_ANCHOR_TOKEN"
case yaml_TAG_TOKEN:
return "yaml_TAG_TOKEN"
case yaml_SCALAR_TOKEN:
return "yaml_SCALAR_TOKEN"
}
return "<unknown token>"
}
// The token structure.
type yaml_token_t struct {
// The token type.
typ yaml_token_type_t
// The start/end of the token.
start_mark, end_mark yaml_mark_t
// The stream encoding (for yaml_STREAM_START_TOKEN).
encoding yaml_encoding_t
// The alias/anchor/scalar value or tag/tag directive handle
// (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
value []byte
// The tag suffix (for yaml_TAG_TOKEN).
suffix []byte
// The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
prefix []byte
// The scalar style (for yaml_SCALAR_TOKEN).
style yaml_scalar_style_t
// The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
major, minor int8
}
// Events
type yaml_event_type_t int8
// Event types.
const (
// An empty event.
yaml_NO_EVENT yaml_event_type_t = iota
yaml_STREAM_START_EVENT // A STREAM-START event.
yaml_STREAM_END_EVENT // A STREAM-END event.
yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event.
yaml_ALIAS_EVENT // An ALIAS event.
yaml_SCALAR_EVENT // A SCALAR event.
yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event.
yaml_MAPPING_START_EVENT // A MAPPING-START event.
yaml_MAPPING_END_EVENT // A MAPPING-END event.
yaml_TAIL_COMMENT_EVENT
)
var eventStrings = []string{
yaml_NO_EVENT: "none",
yaml_STREAM_START_EVENT: "stream start",
yaml_STREAM_END_EVENT: "stream end",
yaml_DOCUMENT_START_EVENT: "document start",
yaml_DOCUMENT_END_EVENT: "document end",
yaml_ALIAS_EVENT: "alias",
yaml_SCALAR_EVENT: "scalar",
yaml_SEQUENCE_START_EVENT: "sequence start",
yaml_SEQUENCE_END_EVENT: "sequence end",
yaml_MAPPING_START_EVENT: "mapping start",
yaml_MAPPING_END_EVENT: "mapping end",
yaml_TAIL_COMMENT_EVENT: "tail comment",
}
func (e yaml_event_type_t) String() string {
if e < 0 || int(e) >= len(eventStrings) {
return fmt.Sprintf("unknown event %d", e)
}
return eventStrings[e]
}
// The event structure.
type yaml_event_t struct {
// The event type.
typ yaml_event_type_t
// The start and end of the event.
start_mark, end_mark yaml_mark_t
// The document encoding (for yaml_STREAM_START_EVENT).
encoding yaml_encoding_t
// The version directive (for yaml_DOCUMENT_START_EVENT).
version_directive *yaml_version_directive_t
// The list of tag directives (for yaml_DOCUMENT_START_EVENT).
tag_directives []yaml_tag_directive_t
// The comments
head_comment []byte
line_comment []byte
foot_comment []byte
tail_comment []byte
// The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
anchor []byte
// The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
tag []byte
// The scalar value (for yaml_SCALAR_EVENT).
value []byte
// Is the document start/end indicator implicit, or the tag optional?
// (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
implicit bool
// Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
quoted_implicit bool
// The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
style yaml_style_t
}
func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) }
func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) }
// Nodes
const (
yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null.
yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false.
yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values.
yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values.
yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values.
yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
// Not in original libyaml.
yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
yaml_MERGE_TAG = "tag:yaml.org,2002:merge"
yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str.
yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map.
)
type yaml_node_type_t int
// Node types.
const (
// An empty node.
yaml_NO_NODE yaml_node_type_t = iota
yaml_SCALAR_NODE // A scalar node.
yaml_SEQUENCE_NODE // A sequence node.
yaml_MAPPING_NODE // A mapping node.
)
// An element of a sequence node.
type yaml_node_item_t int
// An element of a mapping node.
type yaml_node_pair_t struct {
key int // The key of the element.
value int // The value of the element.
}
// The node structure.
type yaml_node_t struct {
typ yaml_node_type_t // The node type.
tag []byte // The node tag.
// The node data.
// The scalar parameters (for yaml_SCALAR_NODE).
scalar struct {
value []byte // The scalar value.
length int // The length of the scalar value.
style yaml_scalar_style_t // The scalar style.
}
// The sequence parameters (for YAML_SEQUENCE_NODE).
sequence struct {
items_data []yaml_node_item_t // The stack of sequence items.
style yaml_sequence_style_t // The sequence style.
}
// The mapping parameters (for yaml_MAPPING_NODE).
mapping struct {
pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value).
pairs_start *yaml_node_pair_t // The beginning of the stack.
pairs_end *yaml_node_pair_t // The end of the stack.
pairs_top *yaml_node_pair_t // The top of the stack.
style yaml_mapping_style_t // The mapping style.
}
start_mark yaml_mark_t // The beginning of the node.
end_mark yaml_mark_t // The end of the node.
}
// The document structure.
type yaml_document_t struct {
// The document nodes.
nodes []yaml_node_t
// The version directive.
version_directive *yaml_version_directive_t
// The list of tag directives.
tag_directives_data []yaml_tag_directive_t
tag_directives_start int // The beginning of the tag directives list.
tag_directives_end int // The end of the tag directives list.
start_implicit int // Is the document start indicator implicit?
end_implicit int // Is the document end indicator implicit?
// The start/end of the document.
start_mark, end_mark yaml_mark_t
}
// The prototype of a read handler.
//
// The read handler is called when the parser needs to read more bytes from the
// source. The handler should write not more than size bytes to the buffer.
// The number of written bytes should be set to the size_read variable.
//
// [in,out] data A pointer to an application data specified by
// yaml_parser_set_input().
// [out] buffer The buffer to write the data from the source.
// [in] size The size of the buffer.
// [out] size_read The actual number of bytes read from the source.
//
// On success, the handler should return 1. If the handler failed,
// the returned value should be 0. On EOF, the handler should set the
// size_read to 0 and return 1.
type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
// This structure holds information about a potential simple key.
type yaml_simple_key_t struct {
possible bool // Is a simple key possible?
required bool // Is a simple key required?
token_number int // The number of the token.
mark yaml_mark_t // The position mark.
}
// The states of the parser.
type yaml_parser_state_t int
const (
yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document.
yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START.
yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document.
yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END.
yaml_PARSE_BLOCK_NODE_STATE // Expect a block node.
yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
yaml_PARSE_FLOW_NODE_STATE // Expect a flow node.
yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence.
yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence.
yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence.
yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key.
yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value.
yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence.
yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence.
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping.
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry.
yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping.
yaml_PARSE_END_STATE // Expect nothing.
)
func (ps yaml_parser_state_t) String() string {
switch ps {
case yaml_PARSE_STREAM_START_STATE:
return "yaml_PARSE_STREAM_START_STATE"
case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
case yaml_PARSE_DOCUMENT_START_STATE:
return "yaml_PARSE_DOCUMENT_START_STATE"
case yaml_PARSE_DOCUMENT_CONTENT_STATE:
return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
case yaml_PARSE_DOCUMENT_END_STATE:
return "yaml_PARSE_DOCUMENT_END_STATE"
case yaml_PARSE_BLOCK_NODE_STATE:
return "yaml_PARSE_BLOCK_NODE_STATE"
case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
case yaml_PARSE_FLOW_NODE_STATE:
return "yaml_PARSE_FLOW_NODE_STATE"
case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
case yaml_PARSE_END_STATE:
return "yaml_PARSE_END_STATE"
}
return "<unknown parser state>"
}
// This structure holds aliases data.
type yaml_alias_data_t struct {
anchor []byte // The anchor.
index int // The node id.
mark yaml_mark_t // The anchor mark.
}
// The parser structure.
//
// All members are internal. Manage the structure using the
// yaml_parser_ family of functions.
type yaml_parser_t struct {
// Error handling
error yaml_error_type_t // Error type.
problem string // Error description.
// The byte about which the problem occurred.
problem_offset int
problem_value int
problem_mark yaml_mark_t
// The error context.
context string
context_mark yaml_mark_t
// Reader stuff
read_handler yaml_read_handler_t // Read handler.
input_reader io.Reader // File input data.
input []byte // String input data.
input_pos int
eof bool // EOF flag
buffer []byte // The working buffer.
buffer_pos int // The current position of the buffer.
unread int // The number of unread characters in the buffer.
newlines int // The number of line breaks since last non-break/non-blank character
raw_buffer []byte // The raw buffer.
raw_buffer_pos int // The current position of the buffer.
encoding yaml_encoding_t // The input encoding.
offset int // The offset of the current position (in bytes).
mark yaml_mark_t // The mark of the current position.
// Comments
head_comment []byte // The current head comments
line_comment []byte // The current line comments
foot_comment []byte // The current foot comments
tail_comment []byte // Foot comment that happens at the end of a block.
stem_comment []byte // Comment in item preceding a nested structure (list inside list item, etc)
comments []yaml_comment_t // The folded comments for all parsed tokens
comments_head int
// Scanner stuff
stream_start_produced bool // Have we started to scan the input stream?
stream_end_produced bool // Have we reached the end of the input stream?
flow_level int // The number of unclosed '[' and '{' indicators.
tokens []yaml_token_t // The tokens queue.
tokens_head int // The head of the tokens queue.
tokens_parsed int // The number of tokens fetched from the queue.
token_available bool // Does the tokens queue contain a token ready for dequeueing.
indent int // The current indentation level.
indents []int // The indentation levels stack.
simple_key_allowed bool // May a simple key occur at the current position?
simple_keys []yaml_simple_key_t // The stack of simple keys.
simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
// Parser stuff
state yaml_parser_state_t // The current parser state.
states []yaml_parser_state_t // The parser states stack.
marks []yaml_mark_t // The stack of marks.
tag_directives []yaml_tag_directive_t // The list of TAG directives.
// Dumper stuff
aliases []yaml_alias_data_t // The alias data.
document *yaml_document_t // The currently parsed document.
}
type yaml_comment_t struct {
scan_mark yaml_mark_t // Position where scanning for comments started
token_mark yaml_mark_t // Position after which tokens will be associated with this comment
start_mark yaml_mark_t // Position of '#' comment mark
end_mark yaml_mark_t // Position where comment terminated
head []byte
line []byte
foot []byte
}
// Emitter Definitions
// The prototype of a write handler.
//
// The write handler is called when the emitter needs to flush the accumulated
// characters to the output. The handler should write @a size bytes of the
// @a buffer to the output.
//
// @param[in,out] data A pointer to an application data specified by
// yaml_emitter_set_output().
// @param[in] buffer The buffer with bytes to be written.
// @param[in] size The size of the buffer.
//
// @returns On success, the handler should return @c 1. If the handler failed,
// the returned value should be @c 0.
//
type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
type yaml_emitter_state_t int
// The emitter states.
const (
// Expect STREAM-START.
yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END.
yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END.
yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document.
yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END.
yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence.
yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE // Expect the next item of a flow sequence, with the comma already written out
yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence.
yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE // Expect the next key of a flow mapping, with the comma already written out
yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping.
yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence.
yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence.
yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping.
yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping.
yaml_EMIT_END_STATE // Expect nothing.
)
// The emitter structure.
//
// All members are internal. Manage the structure using the @c yaml_emitter_
// family of functions.
type yaml_emitter_t struct {
// Error handling
error yaml_error_type_t // Error type.
problem string // Error description.
// Writer stuff
write_handler yaml_write_handler_t // Write handler.
output_buffer *[]byte // String output data.
output_writer io.Writer // File output data.
buffer []byte // The working buffer.
buffer_pos int // The current position of the buffer.
raw_buffer []byte // The raw buffer.
raw_buffer_pos int // The current position of the buffer.
encoding yaml_encoding_t // The stream encoding.
// Emitter stuff
canonical bool // If the output is in the canonical style?
best_indent int // The number of indentation spaces.
best_width int // The preferred width of the output lines.
unicode bool // Allow unescaped non-ASCII characters?
line_break yaml_break_t // The preferred line break.
state yaml_emitter_state_t // The current emitter state.
states []yaml_emitter_state_t // The stack of states.
events []yaml_event_t // The event queue.
events_head int // The head of the event queue.
indents []int // The stack of indentation levels.
tag_directives []yaml_tag_directive_t // The list of tag directives.
indent int // The current indentation level.
flow_level int // The current flow level.
root_context bool // Is it the document root context?
sequence_context bool // Is it a sequence context?
mapping_context bool // Is it a mapping context?
simple_key_context bool // Is it a simple mapping key context?
line int // The current line.
column int // The current column.
whitespace bool // If the last character was a whitespace?
indention bool // If the last character was an indentation character (' ', '-', '?', ':')?
open_ended bool // If an explicit document end is required?
space_above bool // Is there's an empty line above?
foot_indent int // The indent used to write the foot comment above, or -1 if none.
// Anchor analysis.
anchor_data struct {
anchor []byte // The anchor value.
alias bool // Is it an alias?
}
// Tag analysis.
tag_data struct {
handle []byte // The tag handle.
suffix []byte // The tag suffix.
}
// Scalar analysis.
scalar_data struct {
value []byte // The scalar value.
multiline bool // Does the scalar contain line breaks?
flow_plain_allowed bool // Can the scalar be expessed in the flow plain style?
block_plain_allowed bool // Can the scalar be expressed in the block plain style?
single_quoted_allowed bool // Can the scalar be expressed in the single quoted style?
block_allowed bool // Can the scalar be expressed in the literal or folded styles?
style yaml_scalar_style_t // The output style.
}
// Comments
head_comment []byte
line_comment []byte
foot_comment []byte
tail_comment []byte
// Dumper stuff
opened bool // If the stream was already opened?
closed bool // If the stream was already closed?
// The information associated with the document nodes.
anchors *struct {
references int // The number of references.
anchor int // The anchor id.
serialized bool // If the node has been emitted?
}
last_anchor_id int // The last assigned anchor id.
document *yaml_document_t // The currently emitted document.
}

198
src/vendor/gopkg.in/yaml.v3/yamlprivateh.go generated vendored Normal file
View File

@ -0,0 +1,198 @@
//
// Copyright (c) 2011-2019 Canonical Ltd
// Copyright (c) 2006-2010 Kirill Simonov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package yaml
const (
// The size of the input raw buffer.
input_raw_buffer_size = 512
// The size of the input buffer.
// It should be possible to decode the whole raw buffer.
input_buffer_size = input_raw_buffer_size * 3
// The size of the output buffer.
output_buffer_size = 128
// The size of the output raw buffer.
// It should be possible to encode the whole output buffer.
output_raw_buffer_size = (output_buffer_size*2 + 2)
// The size of other stacks and queues.
initial_stack_size = 16
initial_queue_size = 16
initial_string_size = 16
)
// Check if the character at the specified position is an alphabetical
// character, a digit, '_', or '-'.
func is_alpha(b []byte, i int) bool {
return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
}
// Check if the character at the specified position is a digit.
func is_digit(b []byte, i int) bool {
return b[i] >= '0' && b[i] <= '9'
}
// Get the value of a digit.
func as_digit(b []byte, i int) int {
return int(b[i]) - '0'
}
// Check if the character at the specified position is a hex-digit.
func is_hex(b []byte, i int) bool {
return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
}
// Get the value of a hex-digit.
func as_hex(b []byte, i int) int {
bi := b[i]
if bi >= 'A' && bi <= 'F' {
return int(bi) - 'A' + 10
}
if bi >= 'a' && bi <= 'f' {
return int(bi) - 'a' + 10
}
return int(bi) - '0'
}
// Check if the character is ASCII.
func is_ascii(b []byte, i int) bool {
return b[i] <= 0x7F
}
// Check if the character at the start of the buffer can be printed unescaped.
func is_printable(b []byte, i int) bool {
return ((b[i] == 0x0A) || // . == #x0A
(b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
(b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
(b[i] > 0xC2 && b[i] < 0xED) ||
(b[i] == 0xED && b[i+1] < 0xA0) ||
(b[i] == 0xEE) ||
(b[i] == 0xEF && // #xE000 <= . <= #xFFFD
!(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
!(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
}
// Check if the character at the specified position is NUL.
func is_z(b []byte, i int) bool {
return b[i] == 0x00
}
// Check if the beginning of the buffer is a BOM.
func is_bom(b []byte, i int) bool {
return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
}
// Check if the character at the specified position is space.
func is_space(b []byte, i int) bool {
return b[i] == ' '
}
// Check if the character at the specified position is tab.
func is_tab(b []byte, i int) bool {
return b[i] == '\t'
}
// Check if the character at the specified position is blank (space or tab).
func is_blank(b []byte, i int) bool {
//return is_space(b, i) || is_tab(b, i)
return b[i] == ' ' || b[i] == '\t'
}
// Check if the character at the specified position is a line break.
func is_break(b []byte, i int) bool {
return (b[i] == '\r' || // CR (#xD)
b[i] == '\n' || // LF (#xA)
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
}
func is_crlf(b []byte, i int) bool {
return b[i] == '\r' && b[i+1] == '\n'
}
// Check if the character is a line break or NUL.
func is_breakz(b []byte, i int) bool {
//return is_break(b, i) || is_z(b, i)
return (
// is_break:
b[i] == '\r' || // CR (#xD)
b[i] == '\n' || // LF (#xA)
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
// is_z:
b[i] == 0)
}
// Check if the character is a line break, space, or NUL.
func is_spacez(b []byte, i int) bool {
//return is_space(b, i) || is_breakz(b, i)
return (
// is_space:
b[i] == ' ' ||
// is_breakz:
b[i] == '\r' || // CR (#xD)
b[i] == '\n' || // LF (#xA)
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
b[i] == 0)
}
// Check if the character is a line break, space, tab, or NUL.
func is_blankz(b []byte, i int) bool {
//return is_blank(b, i) || is_breakz(b, i)
return (
// is_blank:
b[i] == ' ' || b[i] == '\t' ||
// is_breakz:
b[i] == '\r' || // CR (#xD)
b[i] == '\n' || // LF (#xA)
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
b[i] == 0)
}
// Determine the width of the character.
func width(b byte) int {
// Don't replace these by a switch without first
// confirming that it is being inlined.
if b&0x80 == 0x00 {
return 1
}
if b&0xE0 == 0xC0 {
return 2
}
if b&0xF0 == 0xE0 {
return 3
}
if b&0xF8 == 0xF0 {
return 4
}
return 0
}

View File

@ -471,7 +471,7 @@ github.com/spf13/pflag
## explicit
# github.com/stretchr/objx v0.2.0
github.com/stretchr/objx
# github.com/stretchr/testify v1.5.1
# github.com/stretchr/testify v1.6.1
## explicit
github.com/stretchr/testify/assert
github.com/stretchr/testify/mock
@ -500,6 +500,14 @@ github.com/theupdateframework/notary/tuf/data
github.com/theupdateframework/notary/tuf/signed
github.com/theupdateframework/notary/tuf/utils
github.com/theupdateframework/notary/tuf/validation
# github.com/vmihailenco/msgpack/v5 v5.0.0-rc.2
## explicit
github.com/vmihailenco/msgpack/v5
github.com/vmihailenco/msgpack/v5/msgpcode
# github.com/vmihailenco/tagparser v0.1.2
github.com/vmihailenco/tagparser
github.com/vmihailenco/tagparser/internal
github.com/vmihailenco/tagparser/internal/parser
# github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f
github.com/xeipuuv/gojsonpointer
# github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415
@ -675,6 +683,8 @@ gopkg.in/square/go-jose.v2/json
# gopkg.in/yaml.v2 v2.3.0
## explicit
gopkg.in/yaml.v2
# gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
gopkg.in/yaml.v3
# helm.sh/helm/v3 v3.1.1
## explicit
helm.sh/helm/v3/cmd/helm/search