From 91a76b2df9d2379f84ff9de8676729ca18652cf7 Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Thu, 13 Aug 2020 13:05:57 +0530 Subject: [PATCH] MM-27456: Use reflect-free serialization for hot structs (#15171) Automatic Merge --- Makefile | 9 +- go.mod | 3 +- go.sum | 2 + go.tools.mod | 3 + go.tools.sum | 6 + model/serialized_gen.go | 1622 +++++++++++++++++ model/session.go | 5 + model/user.go | 5 + services/cache/lru.go | 48 +- services/cache/lru_test.go | 112 +- store/localcachelayer/user_layer_test.go | 4 + vendor/github.com/tinylib/msgp/.gitignore | 10 + vendor/github.com/tinylib/msgp/.travis.yml | 11 + vendor/github.com/tinylib/msgp/Makefile | 52 + vendor/github.com/tinylib/msgp/README.md | 102 ++ vendor/github.com/tinylib/msgp/gen/decode.go | 231 +++ vendor/github.com/tinylib/msgp/gen/elem.go | 739 ++++++++ vendor/github.com/tinylib/msgp/gen/encode.go | 270 +++ vendor/github.com/tinylib/msgp/gen/marshal.go | 283 +++ vendor/github.com/tinylib/msgp/gen/size.go | 292 +++ vendor/github.com/tinylib/msgp/gen/spec.go | 519 ++++++ vendor/github.com/tinylib/msgp/gen/testgen.go | 182 ++ .../github.com/tinylib/msgp/gen/unmarshal.go | 214 +++ vendor/github.com/tinylib/msgp/main.go | 119 ++ .../tinylib/msgp/parse/directives.go | 130 ++ .../github.com/tinylib/msgp/parse/getast.go | 617 +++++++ .../github.com/tinylib/msgp/parse/inline.go | 169 ++ .../github.com/tinylib/msgp/printer/print.go | 132 ++ vendor/github.com/ttacon/chalk/.gitignore | 23 + vendor/github.com/ttacon/chalk/LICENSE | 21 + vendor/github.com/ttacon/chalk/README.md | 67 + vendor/github.com/ttacon/chalk/chalk.go | 162 ++ vendor/github.com/ttacon/chalk/doc.go | 59 + vendor/modules.txt | 7 + 34 files changed, 6224 insertions(+), 6 deletions(-) create mode 100644 model/serialized_gen.go create mode 100644 vendor/github.com/tinylib/msgp/.gitignore create mode 100644 vendor/github.com/tinylib/msgp/.travis.yml create mode 100644 vendor/github.com/tinylib/msgp/Makefile create mode 100644 vendor/github.com/tinylib/msgp/README.md create mode 100644 vendor/github.com/tinylib/msgp/gen/decode.go create mode 100644 vendor/github.com/tinylib/msgp/gen/elem.go create mode 100644 vendor/github.com/tinylib/msgp/gen/encode.go create mode 100644 vendor/github.com/tinylib/msgp/gen/marshal.go create mode 100644 vendor/github.com/tinylib/msgp/gen/size.go create mode 100644 vendor/github.com/tinylib/msgp/gen/spec.go create mode 100644 vendor/github.com/tinylib/msgp/gen/testgen.go create mode 100644 vendor/github.com/tinylib/msgp/gen/unmarshal.go create mode 100644 vendor/github.com/tinylib/msgp/main.go create mode 100644 vendor/github.com/tinylib/msgp/parse/directives.go create mode 100644 vendor/github.com/tinylib/msgp/parse/getast.go create mode 100644 vendor/github.com/tinylib/msgp/parse/inline.go create mode 100644 vendor/github.com/tinylib/msgp/printer/print.go create mode 100644 vendor/github.com/ttacon/chalk/.gitignore create mode 100644 vendor/github.com/ttacon/chalk/LICENSE create mode 100644 vendor/github.com/ttacon/chalk/README.md create mode 100644 vendor/github.com/ttacon/chalk/chalk.go create mode 100644 vendor/github.com/ttacon/chalk/doc.go diff --git a/Makefile b/Makefile index 94d3284ac0..42f4d9013d 100644 --- a/Makefile +++ b/Makefile @@ -554,7 +554,7 @@ vet: ## Run mattermost go vet specific checks echo "mattermost-govet is not installed. Please install it executing \"GO111MODULE=off GOBIN=$(PWD)/bin go get -u github.com/mattermost/mattermost-govet\""; \ exit 1; \ fi; - @VET_CMD="-license -structuredLogging -inconsistentReceiverName -tFatal"; \ + @VET_CMD="-license -structuredLogging -inconsistentReceiverName -inconsistentReceiverName.ignore=serialized_gen.go -tFatal"; \ if ! [ -z "${MM_VET_OPENSPEC_PATH}" ] && [ -f "${MM_VET_OPENSPEC_PATH}" ]; then \ VET_CMD="$$VET_CMD -openApiSync -openApiSync.spec=$$MM_VET_OPENSPEC_PATH"; \ else \ @@ -567,6 +567,13 @@ ifneq ($(MM_NO_ENTERPRISE_LINT),true) endif endif +gen-serialized: ## Generates serialization methods for hot structs + # This tool only works at a file level, not at a package level. + # So you would need to move the structs that need to be serialized temporarily + # to session.go and run the tool. + $(GO) get -modfile=go.tools.mod github.com/tinylib/msgp + $(GOBIN)/msgp -file=./model/session.go -tests=false -o=./model/serialized_gen.go + todo: ## Display TODO and FIXME items in the source code. @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime TODO @! ag --ignore Makefile --ignore-dir vendor --ignore-dir runtime XXX diff --git a/go.mod b/go.mod index 1cb713571a..5b63ad31fa 100644 --- a/go.mod +++ b/go.mod @@ -103,7 +103,8 @@ require ( github.com/stretchr/testify v1.6.1 github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/throttled/throttled v2.2.4+incompatible - github.com/tinylib/msgp v1.1.2 // indirect + github.com/tinylib/msgp v1.1.2 + github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 // indirect github.com/tylerb/graceful v1.2.15 github.com/uber/jaeger-client-go v2.24.0+incompatible github.com/uber/jaeger-lib v2.2.0+incompatible diff --git a/go.sum b/go.sum index 4346809274..56b05899fb 100644 --- a/go.sum +++ b/go.sum @@ -719,6 +719,8 @@ github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tylerb/graceful v1.2.15 h1:B0x01Y8fsJpogzZTkDg6BDi6eMf03s01lEKGdrv83oA= github.com/tylerb/graceful v1.2.15/go.mod h1:LPYTbOYmUTdabwRt0TGhLllQ0MUNbs0Y5q1WXJOI9II= diff --git a/go.tools.mod b/go.tools.mod index 94fd2edc36..ed1a0c2910 100644 --- a/go.tools.mod +++ b/go.tools.mod @@ -5,6 +5,9 @@ go 1.14 require ( github.com/jstemmer/go-junit-report v0.9.1 // indirect github.com/mattermost/mattermost-utilities/mmgotool v0.0.0-20200730135456-e2334fe87160 // indirect + github.com/philhofer/fwd v1.0.0 // indirect github.com/reflog/struct2interface v0.6.1 // indirect + github.com/tinylib/msgp v1.1.2 // indirect + github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 // indirect github.com/vektra/mockery v1.1.2 // indirect ) diff --git a/go.tools.sum b/go.tools.sum index 5319c67df1..895eb1d65f 100644 --- a/go.tools.sum +++ b/go.tools.sum @@ -64,6 +64,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -100,7 +102,11 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= +github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/vektra/mockery v1.1.2 h1:uc0Yn67rJpjt8U/mAZimdCKn9AeA97BOkjpmtBSlfP4= diff --git a/model/serialized_gen.go b/model/serialized_gen.go new file mode 100644 index 0000000000..c64d88de2e --- /dev/null +++ b/model/serialized_gen.go @@ -0,0 +1,1622 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "github.com/tinylib/msgp/msgp" +) + +// DecodeMsg implements msgp.Decodable +func (z *Session) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0001 uint32 + zb0001, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 13 { + err = msgp.ArrayError{Wanted: 13, Got: zb0001} + return + } + z.Id, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.Token, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Token") + return + } + z.CreateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.ExpiresAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "ExpiresAt") + return + } + z.LastActivityAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.UserId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + z.DeviceId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "DeviceId") + return + } + z.Roles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.IsOAuth, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "IsOAuth") + return + } + z.ExpiredNotify, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "ExpiredNotify") + return + } + var zb0002 uint32 + zb0002, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + if z.Props == nil { + z.Props = make(StringMap, zb0002) + } else if len(z.Props) > 0 { + for key := range z.Props { + delete(z.Props, key) + } + } + for zb0002 > 0 { + zb0002-- + var za0001 string + var za0002 string + za0001, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + za0002, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + z.Props[za0001] = za0002 + } + var zb0003 uint32 + zb0003, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err, "TeamMembers") + return + } + if cap(z.TeamMembers) >= int(zb0003) { + z.TeamMembers = (z.TeamMembers)[:zb0003] + } else { + z.TeamMembers = make([]*TeamMember, zb0003) + } + for za0003 := range z.TeamMembers { + if dc.IsNil() { + err = dc.ReadNil() + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + z.TeamMembers[za0003] = nil + } else { + if z.TeamMembers[za0003] == nil { + z.TeamMembers[za0003] = new(TeamMember) + } + err = z.TeamMembers[za0003].DecodeMsg(dc) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + z.Local, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "Local") + return + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *Session) EncodeMsg(en *msgp.Writer) (err error) { + // array header, size 13 + err = en.Append(0x9d) + if err != nil { + return + } + err = en.WriteString(z.Id) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + err = en.WriteString(z.Token) + if err != nil { + err = msgp.WrapError(err, "Token") + return + } + err = en.WriteInt64(z.CreateAt) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + err = en.WriteInt64(z.ExpiresAt) + if err != nil { + err = msgp.WrapError(err, "ExpiresAt") + return + } + err = en.WriteInt64(z.LastActivityAt) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + err = en.WriteString(z.UserId) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + err = en.WriteString(z.DeviceId) + if err != nil { + err = msgp.WrapError(err, "DeviceId") + return + } + err = en.WriteString(z.Roles) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + err = en.WriteBool(z.IsOAuth) + if err != nil { + err = msgp.WrapError(err, "IsOAuth") + return + } + err = en.WriteBool(z.ExpiredNotify) + if err != nil { + err = msgp.WrapError(err, "ExpiredNotify") + return + } + err = en.WriteMapHeader(uint32(len(z.Props))) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + for za0001, za0002 := range z.Props { + err = en.WriteString(za0001) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + err = en.WriteString(za0002) + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + } + err = en.WriteArrayHeader(uint32(len(z.TeamMembers))) + if err != nil { + err = msgp.WrapError(err, "TeamMembers") + return + } + for za0003 := range z.TeamMembers { + if z.TeamMembers[za0003] == nil { + err = en.WriteNil() + if err != nil { + return + } + } else { + err = z.TeamMembers[za0003].EncodeMsg(en) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + err = en.WriteBool(z.Local) + if err != nil { + err = msgp.WrapError(err, "Local") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *Session) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // array header, size 13 + o = append(o, 0x9d) + o = msgp.AppendString(o, z.Id) + o = msgp.AppendString(o, z.Token) + o = msgp.AppendInt64(o, z.CreateAt) + o = msgp.AppendInt64(o, z.ExpiresAt) + o = msgp.AppendInt64(o, z.LastActivityAt) + o = msgp.AppendString(o, z.UserId) + o = msgp.AppendString(o, z.DeviceId) + o = msgp.AppendString(o, z.Roles) + o = msgp.AppendBool(o, z.IsOAuth) + o = msgp.AppendBool(o, z.ExpiredNotify) + o = msgp.AppendMapHeader(o, uint32(len(z.Props))) + for za0001, za0002 := range z.Props { + o = msgp.AppendString(o, za0001) + o = msgp.AppendString(o, za0002) + } + o = msgp.AppendArrayHeader(o, uint32(len(z.TeamMembers))) + for za0003 := range z.TeamMembers { + if z.TeamMembers[za0003] == nil { + o = msgp.AppendNil(o) + } else { + o, err = z.TeamMembers[za0003].MarshalMsg(o) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + o = msgp.AppendBool(o, z.Local) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *Session) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0001 uint32 + zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 13 { + err = msgp.ArrayError{Wanted: 13, Got: zb0001} + return + } + z.Id, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.Token, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Token") + return + } + z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.ExpiresAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "ExpiresAt") + return + } + z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.UserId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + z.DeviceId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "DeviceId") + return + } + z.Roles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.IsOAuth, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "IsOAuth") + return + } + z.ExpiredNotify, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "ExpiredNotify") + return + } + var zb0002 uint32 + zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + if z.Props == nil { + z.Props = make(StringMap, zb0002) + } else if len(z.Props) > 0 { + for key := range z.Props { + delete(z.Props, key) + } + } + for zb0002 > 0 { + var za0001 string + var za0002 string + zb0002-- + za0001, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + za0002, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + z.Props[za0001] = za0002 + } + var zb0003 uint32 + zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TeamMembers") + return + } + if cap(z.TeamMembers) >= int(zb0003) { + z.TeamMembers = (z.TeamMembers)[:zb0003] + } else { + z.TeamMembers = make([]*TeamMember, zb0003) + } + for za0003 := range z.TeamMembers { + if msgp.IsNil(bts) { + bts, err = msgp.ReadNilBytes(bts) + if err != nil { + return + } + z.TeamMembers[za0003] = nil + } else { + if z.TeamMembers[za0003] == nil { + z.TeamMembers[za0003] = new(TeamMember) + } + bts, err = z.TeamMembers[za0003].UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + z.Local, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Local") + return + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *Session) Msgsize() (s int) { + s = 1 + msgp.StringPrefixSize + len(z.Id) + msgp.StringPrefixSize + len(z.Token) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.UserId) + msgp.StringPrefixSize + len(z.DeviceId) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + msgp.BoolSize + msgp.MapHeaderSize + if z.Props != nil { + for za0001, za0002 := range z.Props { + _ = za0002 + s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) + } + } + s += msgp.ArrayHeaderSize + for za0003 := range z.TeamMembers { + if z.TeamMembers[za0003] == nil { + s += msgp.NilSize + } else { + s += z.TeamMembers[za0003].Msgsize() + } + } + s += msgp.BoolSize + return +} + +// DecodeMsg implements msgp.Decodable +func (z *StringMap) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0003 uint32 + zb0003, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if (*z) == nil { + (*z) = make(StringMap, zb0003) + } else if len((*z)) > 0 { + for key := range *z { + delete((*z), key) + } + } + for zb0003 > 0 { + zb0003-- + var zb0001 string + var zb0002 string + zb0001, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err) + return + } + zb0002, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, zb0001) + return + } + (*z)[zb0001] = zb0002 + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z StringMap) EncodeMsg(en *msgp.Writer) (err error) { + err = en.WriteMapHeader(uint32(len(z))) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0004, zb0005 := range z { + err = en.WriteString(zb0004) + if err != nil { + err = msgp.WrapError(err) + return + } + err = en.WriteString(zb0005) + if err != nil { + err = msgp.WrapError(err, zb0004) + return + } + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z StringMap) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + o = msgp.AppendMapHeader(o, uint32(len(z))) + for zb0004, zb0005 := range z { + o = msgp.AppendString(o, zb0004) + o = msgp.AppendString(o, zb0005) + } + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *StringMap) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0003 uint32 + zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if (*z) == nil { + (*z) = make(StringMap, zb0003) + } else if len((*z)) > 0 { + for key := range *z { + delete((*z), key) + } + } + for zb0003 > 0 { + var zb0001 string + var zb0002 string + zb0003-- + zb0001, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + zb0002, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, zb0001) + return + } + (*z)[zb0001] = zb0002 + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z StringMap) Msgsize() (s int) { + s = msgp.MapHeaderSize + if z != nil { + for zb0004, zb0005 := range z { + _ = zb0005 + s += msgp.StringPrefixSize + len(zb0004) + msgp.StringPrefixSize + len(zb0005) + } + } + return +} + +// DecodeMsg implements msgp.Decodable +func (z *TeamMember) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "TeamId": + z.TeamId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "TeamId") + return + } + case "UserId": + z.UserId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + case "Roles": + z.Roles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + case "DeleteAt": + z.DeleteAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + case "SchemeGuest": + z.SchemeGuest, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "SchemeGuest") + return + } + case "SchemeUser": + z.SchemeUser, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "SchemeUser") + return + } + case "SchemeAdmin": + z.SchemeAdmin, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "SchemeAdmin") + return + } + case "ExplicitRoles": + z.ExplicitRoles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "ExplicitRoles") + return + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *TeamMember) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 8 + // write "TeamId" + err = en.Append(0x88, 0xa6, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64) + if err != nil { + return + } + err = en.WriteString(z.TeamId) + if err != nil { + err = msgp.WrapError(err, "TeamId") + return + } + // write "UserId" + err = en.Append(0xa6, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64) + if err != nil { + return + } + err = en.WriteString(z.UserId) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + // write "Roles" + err = en.Append(0xa5, 0x52, 0x6f, 0x6c, 0x65, 0x73) + if err != nil { + return + } + err = en.WriteString(z.Roles) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + // write "DeleteAt" + err = en.Append(0xa8, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x74) + if err != nil { + return + } + err = en.WriteInt64(z.DeleteAt) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + // write "SchemeGuest" + err = en.Append(0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x47, 0x75, 0x65, 0x73, 0x74) + if err != nil { + return + } + err = en.WriteBool(z.SchemeGuest) + if err != nil { + err = msgp.WrapError(err, "SchemeGuest") + return + } + // write "SchemeUser" + err = en.Append(0xaa, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72) + if err != nil { + return + } + err = en.WriteBool(z.SchemeUser) + if err != nil { + err = msgp.WrapError(err, "SchemeUser") + return + } + // write "SchemeAdmin" + err = en.Append(0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e) + if err != nil { + return + } + err = en.WriteBool(z.SchemeAdmin) + if err != nil { + err = msgp.WrapError(err, "SchemeAdmin") + return + } + // write "ExplicitRoles" + err = en.Append(0xad, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73) + if err != nil { + return + } + err = en.WriteString(z.ExplicitRoles) + if err != nil { + err = msgp.WrapError(err, "ExplicitRoles") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *TeamMember) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 8 + // string "TeamId" + o = append(o, 0x88, 0xa6, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64) + o = msgp.AppendString(o, z.TeamId) + // string "UserId" + o = append(o, 0xa6, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64) + o = msgp.AppendString(o, z.UserId) + // string "Roles" + o = append(o, 0xa5, 0x52, 0x6f, 0x6c, 0x65, 0x73) + o = msgp.AppendString(o, z.Roles) + // string "DeleteAt" + o = append(o, 0xa8, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x74) + o = msgp.AppendInt64(o, z.DeleteAt) + // string "SchemeGuest" + o = append(o, 0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x47, 0x75, 0x65, 0x73, 0x74) + o = msgp.AppendBool(o, z.SchemeGuest) + // string "SchemeUser" + o = append(o, 0xaa, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72) + o = msgp.AppendBool(o, z.SchemeUser) + // string "SchemeAdmin" + o = append(o, 0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e) + o = msgp.AppendBool(o, z.SchemeAdmin) + // string "ExplicitRoles" + o = append(o, 0xad, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73) + o = msgp.AppendString(o, z.ExplicitRoles) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *TeamMember) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "TeamId": + z.TeamId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TeamId") + return + } + case "UserId": + z.UserId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + case "Roles": + z.Roles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + case "DeleteAt": + z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + case "SchemeGuest": + z.SchemeGuest, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "SchemeGuest") + return + } + case "SchemeUser": + z.SchemeUser, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "SchemeUser") + return + } + case "SchemeAdmin": + z.SchemeAdmin, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "SchemeAdmin") + return + } + case "ExplicitRoles": + z.ExplicitRoles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "ExplicitRoles") + return + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *TeamMember) Msgsize() (s int) { + s = 1 + 7 + msgp.StringPrefixSize + len(z.TeamId) + 7 + msgp.StringPrefixSize + len(z.UserId) + 6 + msgp.StringPrefixSize + len(z.Roles) + 9 + msgp.Int64Size + 12 + msgp.BoolSize + 11 + msgp.BoolSize + 12 + msgp.BoolSize + 14 + msgp.StringPrefixSize + len(z.ExplicitRoles) + return +} + +// DecodeMsg implements msgp.Decodable +func (z *User) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0001 uint32 + zb0001, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 31 { + err = msgp.ArrayError{Wanted: 31, Got: zb0001} + return + } + z.Id, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.CreateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.UpdateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "UpdateAt") + return + } + z.DeleteAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + z.Username, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Username") + return + } + z.Password, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Password") + return + } + if dc.IsNil() { + err = dc.ReadNil() + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + z.AuthData = nil + } else { + if z.AuthData == nil { + z.AuthData = new(string) + } + *z.AuthData, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + } + z.AuthService, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "AuthService") + return + } + z.Email, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Email") + return + } + z.EmailVerified, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "EmailVerified") + return + } + z.Nickname, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Nickname") + return + } + z.FirstName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "FirstName") + return + } + z.LastName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "LastName") + return + } + z.Position, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Position") + return + } + z.Roles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.AllowMarketing, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "AllowMarketing") + return + } + var zb0002 uint32 + zb0002, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + if z.Props == nil { + z.Props = make(StringMap, zb0002) + } else if len(z.Props) > 0 { + for key := range z.Props { + delete(z.Props, key) + } + } + for zb0002 > 0 { + zb0002-- + var za0001 string + var za0002 string + za0001, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + za0002, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + z.Props[za0001] = za0002 + } + var zb0003 uint32 + zb0003, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + if z.NotifyProps == nil { + z.NotifyProps = make(StringMap, zb0003) + } else if len(z.NotifyProps) > 0 { + for key := range z.NotifyProps { + delete(z.NotifyProps, key) + } + } + for zb0003 > 0 { + zb0003-- + var za0003 string + var za0004 string + za0003, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + za0004, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "NotifyProps", za0003) + return + } + z.NotifyProps[za0003] = za0004 + } + z.LastPasswordUpdate, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastPasswordUpdate") + return + } + z.LastPictureUpdate, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastPictureUpdate") + return + } + z.FailedAttempts, err = dc.ReadInt() + if err != nil { + err = msgp.WrapError(err, "FailedAttempts") + return + } + z.Locale, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Locale") + return + } + var zb0004 uint32 + zb0004, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + if z.Timezone == nil { + z.Timezone = make(StringMap, zb0004) + } else if len(z.Timezone) > 0 { + for key := range z.Timezone { + delete(z.Timezone, key) + } + } + for zb0004 > 0 { + zb0004-- + var za0005 string + var za0006 string + za0005, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + za0006, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Timezone", za0005) + return + } + z.Timezone[za0005] = za0006 + } + z.MfaActive, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "MfaActive") + return + } + z.MfaSecret, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "MfaSecret") + return + } + z.LastActivityAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.IsBot, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "IsBot") + return + } + z.BotDescription, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "BotDescription") + return + } + z.BotLastIconUpdate, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "BotLastIconUpdate") + return + } + z.TermsOfServiceId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceId") + return + } + z.TermsOfServiceCreateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceCreateAt") + return + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *User) EncodeMsg(en *msgp.Writer) (err error) { + // array header, size 31 + err = en.Append(0xdc, 0x0, 0x1f) + if err != nil { + return + } + err = en.WriteString(z.Id) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + err = en.WriteInt64(z.CreateAt) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + err = en.WriteInt64(z.UpdateAt) + if err != nil { + err = msgp.WrapError(err, "UpdateAt") + return + } + err = en.WriteInt64(z.DeleteAt) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + err = en.WriteString(z.Username) + if err != nil { + err = msgp.WrapError(err, "Username") + return + } + err = en.WriteString(z.Password) + if err != nil { + err = msgp.WrapError(err, "Password") + return + } + if z.AuthData == nil { + err = en.WriteNil() + if err != nil { + return + } + } else { + err = en.WriteString(*z.AuthData) + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + } + err = en.WriteString(z.AuthService) + if err != nil { + err = msgp.WrapError(err, "AuthService") + return + } + err = en.WriteString(z.Email) + if err != nil { + err = msgp.WrapError(err, "Email") + return + } + err = en.WriteBool(z.EmailVerified) + if err != nil { + err = msgp.WrapError(err, "EmailVerified") + return + } + err = en.WriteString(z.Nickname) + if err != nil { + err = msgp.WrapError(err, "Nickname") + return + } + err = en.WriteString(z.FirstName) + if err != nil { + err = msgp.WrapError(err, "FirstName") + return + } + err = en.WriteString(z.LastName) + if err != nil { + err = msgp.WrapError(err, "LastName") + return + } + err = en.WriteString(z.Position) + if err != nil { + err = msgp.WrapError(err, "Position") + return + } + err = en.WriteString(z.Roles) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + err = en.WriteBool(z.AllowMarketing) + if err != nil { + err = msgp.WrapError(err, "AllowMarketing") + return + } + err = en.WriteMapHeader(uint32(len(z.Props))) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + for za0001, za0002 := range z.Props { + err = en.WriteString(za0001) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + err = en.WriteString(za0002) + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + } + err = en.WriteMapHeader(uint32(len(z.NotifyProps))) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + for za0003, za0004 := range z.NotifyProps { + err = en.WriteString(za0003) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + err = en.WriteString(za0004) + if err != nil { + err = msgp.WrapError(err, "NotifyProps", za0003) + return + } + } + err = en.WriteInt64(z.LastPasswordUpdate) + if err != nil { + err = msgp.WrapError(err, "LastPasswordUpdate") + return + } + err = en.WriteInt64(z.LastPictureUpdate) + if err != nil { + err = msgp.WrapError(err, "LastPictureUpdate") + return + } + err = en.WriteInt(z.FailedAttempts) + if err != nil { + err = msgp.WrapError(err, "FailedAttempts") + return + } + err = en.WriteString(z.Locale) + if err != nil { + err = msgp.WrapError(err, "Locale") + return + } + err = en.WriteMapHeader(uint32(len(z.Timezone))) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + for za0005, za0006 := range z.Timezone { + err = en.WriteString(za0005) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + err = en.WriteString(za0006) + if err != nil { + err = msgp.WrapError(err, "Timezone", za0005) + return + } + } + err = en.WriteBool(z.MfaActive) + if err != nil { + err = msgp.WrapError(err, "MfaActive") + return + } + err = en.WriteString(z.MfaSecret) + if err != nil { + err = msgp.WrapError(err, "MfaSecret") + return + } + err = en.WriteInt64(z.LastActivityAt) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + err = en.WriteBool(z.IsBot) + if err != nil { + err = msgp.WrapError(err, "IsBot") + return + } + err = en.WriteString(z.BotDescription) + if err != nil { + err = msgp.WrapError(err, "BotDescription") + return + } + err = en.WriteInt64(z.BotLastIconUpdate) + if err != nil { + err = msgp.WrapError(err, "BotLastIconUpdate") + return + } + err = en.WriteString(z.TermsOfServiceId) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceId") + return + } + err = en.WriteInt64(z.TermsOfServiceCreateAt) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceCreateAt") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *User) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // array header, size 31 + o = append(o, 0xdc, 0x0, 0x1f) + o = msgp.AppendString(o, z.Id) + o = msgp.AppendInt64(o, z.CreateAt) + o = msgp.AppendInt64(o, z.UpdateAt) + o = msgp.AppendInt64(o, z.DeleteAt) + o = msgp.AppendString(o, z.Username) + o = msgp.AppendString(o, z.Password) + if z.AuthData == nil { + o = msgp.AppendNil(o) + } else { + o = msgp.AppendString(o, *z.AuthData) + } + o = msgp.AppendString(o, z.AuthService) + o = msgp.AppendString(o, z.Email) + o = msgp.AppendBool(o, z.EmailVerified) + o = msgp.AppendString(o, z.Nickname) + o = msgp.AppendString(o, z.FirstName) + o = msgp.AppendString(o, z.LastName) + o = msgp.AppendString(o, z.Position) + o = msgp.AppendString(o, z.Roles) + o = msgp.AppendBool(o, z.AllowMarketing) + o = msgp.AppendMapHeader(o, uint32(len(z.Props))) + for za0001, za0002 := range z.Props { + o = msgp.AppendString(o, za0001) + o = msgp.AppendString(o, za0002) + } + o = msgp.AppendMapHeader(o, uint32(len(z.NotifyProps))) + for za0003, za0004 := range z.NotifyProps { + o = msgp.AppendString(o, za0003) + o = msgp.AppendString(o, za0004) + } + o = msgp.AppendInt64(o, z.LastPasswordUpdate) + o = msgp.AppendInt64(o, z.LastPictureUpdate) + o = msgp.AppendInt(o, z.FailedAttempts) + o = msgp.AppendString(o, z.Locale) + o = msgp.AppendMapHeader(o, uint32(len(z.Timezone))) + for za0005, za0006 := range z.Timezone { + o = msgp.AppendString(o, za0005) + o = msgp.AppendString(o, za0006) + } + o = msgp.AppendBool(o, z.MfaActive) + o = msgp.AppendString(o, z.MfaSecret) + o = msgp.AppendInt64(o, z.LastActivityAt) + o = msgp.AppendBool(o, z.IsBot) + o = msgp.AppendString(o, z.BotDescription) + o = msgp.AppendInt64(o, z.BotLastIconUpdate) + o = msgp.AppendString(o, z.TermsOfServiceId) + o = msgp.AppendInt64(o, z.TermsOfServiceCreateAt) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *User) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0001 uint32 + zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 31 { + err = msgp.ArrayError{Wanted: 31, Got: zb0001} + return + } + z.Id, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.UpdateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "UpdateAt") + return + } + z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + z.Username, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Username") + return + } + z.Password, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Password") + return + } + if msgp.IsNil(bts) { + bts, err = msgp.ReadNilBytes(bts) + if err != nil { + return + } + z.AuthData = nil + } else { + if z.AuthData == nil { + z.AuthData = new(string) + } + *z.AuthData, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + } + z.AuthService, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "AuthService") + return + } + z.Email, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Email") + return + } + z.EmailVerified, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "EmailVerified") + return + } + z.Nickname, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Nickname") + return + } + z.FirstName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "FirstName") + return + } + z.LastName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastName") + return + } + z.Position, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Position") + return + } + z.Roles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.AllowMarketing, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "AllowMarketing") + return + } + var zb0002 uint32 + zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + if z.Props == nil { + z.Props = make(StringMap, zb0002) + } else if len(z.Props) > 0 { + for key := range z.Props { + delete(z.Props, key) + } + } + for zb0002 > 0 { + var za0001 string + var za0002 string + zb0002-- + za0001, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + za0002, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + z.Props[za0001] = za0002 + } + var zb0003 uint32 + zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + if z.NotifyProps == nil { + z.NotifyProps = make(StringMap, zb0003) + } else if len(z.NotifyProps) > 0 { + for key := range z.NotifyProps { + delete(z.NotifyProps, key) + } + } + for zb0003 > 0 { + var za0003 string + var za0004 string + zb0003-- + za0003, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + za0004, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "NotifyProps", za0003) + return + } + z.NotifyProps[za0003] = za0004 + } + z.LastPasswordUpdate, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastPasswordUpdate") + return + } + z.LastPictureUpdate, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastPictureUpdate") + return + } + z.FailedAttempts, bts, err = msgp.ReadIntBytes(bts) + if err != nil { + err = msgp.WrapError(err, "FailedAttempts") + return + } + z.Locale, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Locale") + return + } + var zb0004 uint32 + zb0004, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + if z.Timezone == nil { + z.Timezone = make(StringMap, zb0004) + } else if len(z.Timezone) > 0 { + for key := range z.Timezone { + delete(z.Timezone, key) + } + } + for zb0004 > 0 { + var za0005 string + var za0006 string + zb0004-- + za0005, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + za0006, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Timezone", za0005) + return + } + z.Timezone[za0005] = za0006 + } + z.MfaActive, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "MfaActive") + return + } + z.MfaSecret, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "MfaSecret") + return + } + z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.IsBot, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "IsBot") + return + } + z.BotDescription, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "BotDescription") + return + } + z.BotLastIconUpdate, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "BotLastIconUpdate") + return + } + z.TermsOfServiceId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceId") + return + } + z.TermsOfServiceCreateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceCreateAt") + return + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *User) Msgsize() (s int) { + s = 3 + msgp.StringPrefixSize + len(z.Id) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.Username) + msgp.StringPrefixSize + len(z.Password) + if z.AuthData == nil { + s += msgp.NilSize + } else { + s += msgp.StringPrefixSize + len(*z.AuthData) + } + s += msgp.StringPrefixSize + len(z.AuthService) + msgp.StringPrefixSize + len(z.Email) + msgp.BoolSize + msgp.StringPrefixSize + len(z.Nickname) + msgp.StringPrefixSize + len(z.FirstName) + msgp.StringPrefixSize + len(z.LastName) + msgp.StringPrefixSize + len(z.Position) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + msgp.MapHeaderSize + if z.Props != nil { + for za0001, za0002 := range z.Props { + _ = za0002 + s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) + } + } + s += msgp.MapHeaderSize + if z.NotifyProps != nil { + for za0003, za0004 := range z.NotifyProps { + _ = za0004 + s += msgp.StringPrefixSize + len(za0003) + msgp.StringPrefixSize + len(za0004) + } + } + s += msgp.Int64Size + msgp.Int64Size + msgp.IntSize + msgp.StringPrefixSize + len(z.Locale) + msgp.MapHeaderSize + if z.Timezone != nil { + for za0005, za0006 := range z.Timezone { + _ = za0006 + s += msgp.StringPrefixSize + len(za0005) + msgp.StringPrefixSize + len(za0006) + } + } + s += msgp.BoolSize + msgp.StringPrefixSize + len(z.MfaSecret) + msgp.Int64Size + msgp.BoolSize + msgp.StringPrefixSize + len(z.BotDescription) + msgp.Int64Size + msgp.StringPrefixSize + len(z.TermsOfServiceId) + msgp.Int64Size + return +} diff --git a/model/session.go b/model/session.go index 5c53eceb6e..976e1229ca 100644 --- a/model/session.go +++ b/model/session.go @@ -30,6 +30,11 @@ const ( SESSION_USER_ACCESS_TOKEN_EXPIRY = 100 * 365 // 100 years ) +//msgp:tuple Session + +// Session contains the user session details. +// This struct's serializer methods are auto-generated. If a new field is added/removed, +// please run make gen-serialized. type Session struct { Id string `json:"id"` Token string `json:"token"` diff --git a/model/user.go b/model/user.go index 629e83dc15..4e4d067c78 100644 --- a/model/user.go +++ b/model/user.go @@ -59,6 +59,11 @@ const ( USER_LOCALE_MAX_LENGTH = 5 ) +//msgp:tuple User + +// User contains the details about the user. +// This struct's serializer methods are auto-generated. If a new field is added/removed, +// please run make gen-serialized. type User struct { Id string `json:"id"` CreateAt int64 `json:"create_at,omitempty"` diff --git a/services/cache/lru.go b/services/cache/lru.go index b28cfa27ba..0ab71b3d72 100644 --- a/services/cache/lru.go +++ b/services/cache/lru.go @@ -8,6 +8,8 @@ import ( "sync" "time" + "github.com/mattermost/mattermost-server/v5/model" + "github.com/tinylib/msgp/msgp" "github.com/vmihailenco/msgpack/v5" ) @@ -141,9 +143,21 @@ func (l *LRU) set(key string, value interface{}, ttl time.Duration) error { expires = time.Now().Add(ttl) } - buf, err := msgpack.Marshal(value) - if err != nil { - return err + var buf []byte + var err error + + // We use a fast path for hot structs. + if msgpVal, ok := value.(msgp.Marshaler); ok { + buf, err = msgpVal.MarshalMsg(nil) + if err != nil { + return err + } + } else { + // Slow path for other structs. + buf, err = msgpack.Marshal(value) + if err != nil { + return err + } } // Check for existing item, ignoring expiry since we'd update anyway. @@ -182,6 +196,34 @@ func (l *LRU) get(key string, value interface{}) error { l.evictList.MoveToFront(ent) + // We use a fast path for hot structs. + if msgpVal, ok := value.(msgp.Unmarshaler); ok { + _, err := msgpVal.UnmarshalMsg(e.value) + return err + } + + // This is ugly and makes the cache package aware of the model package. + // But this is due to 2 things. + // 1. The msgp package works on methods on structs rather than functions. + // 2. Our cache interface passes pointers to empty pointers, and not pointers + // to values. This is mainly how all our model structs are passed around. + // It might be technically possible to use values _just_ for hot structs + // like these and then return a pointer while returning from the cache function, + // but it will make the codebase inconsistent, and has some edge-cases to take care of. + switch v := value.(type) { + case **model.User: + var u model.User + _, err := u.UnmarshalMsg(e.value) + *v = &u + return err + case **model.Session: + var s model.Session + _, err := s.UnmarshalMsg(e.value) + *v = &s + return err + } + + // Slow path for other structs. return msgpack.Unmarshal(e.value, value) } return ErrKeyNotFound diff --git a/services/cache/lru_test.go b/services/cache/lru_test.go index a11448e096..041b7cce6f 100644 --- a/services/cache/lru_test.go +++ b/services/cache/lru_test.go @@ -205,6 +205,80 @@ func TestLRUMarshalUnMarshal(t *testing.T) { err = l.Get("post", &p) require.Nil(t, err) require.Equal(t, post.Clone(), p.Clone()) + + session := &model.Session{ + Id: "ty7ia14yuty5bmpt8wmz6da1fw", + Token: "79c3iq6nzpycmkkawudanqhg5c", + CreateAt: 1595445296960, + ExpiresAt: 1598296496960, + LastActivityAt: 1595445296960, + UserId: "rpgh1q5ra38y9xjn9z8fjctezr", + Roles: "system_admin system_user", + IsOAuth: false, + ExpiredNotify: false, + Props: map[string]string{ + "csrf": "33zb7h7rk3rfffztojn5pxbkxe", + "isMobile": "false", + "isSaml": "false", + "is_guest": "false", + "os": "", + "platform": "Windows", + }, + } + + err = l.Set("session", session) + require.Nil(t, err) + + var s *model.Session + err = l.Get("session", &s) + require.Nil(t, err) + require.Equal(t, session, s) + + user := &model.User{ + Id: "id", + CreateAt: 11111, + UpdateAt: 11111, + DeleteAt: 11111, + Username: "username", + Password: "password", + AuthService: "AuthService", + AuthData: nil, + Email: "Email", + EmailVerified: true, + Nickname: "Nickname", + FirstName: "FirstName", + LastName: "LastName", + Position: "Position", + Roles: "Roles", + AllowMarketing: true, + Props: map[string]string{ + "key0": "value0", + }, + NotifyProps: map[string]string{ + "key0": "value0", + }, + LastPasswordUpdate: 111111, + LastPictureUpdate: 111111, + FailedAttempts: 111111, + Locale: "Locale", + MfaActive: true, + MfaSecret: "MfaSecret", + LastActivityAt: 111111, + IsBot: true, + TermsOfServiceId: "TermsOfServiceId", + TermsOfServiceCreateAt: 111111, + } + + err = l.Set("user", user) + require.Nil(t, err) + + var u *model.User + err = l.Get("user", &u) + require.Nil(t, err) + // msgp returns an empty map instead of a nil map. + // This does not make an actual difference in terms of functionality. + u.Timezone = nil + require.Equal(t, user, u) } func BenchmarkLRU(b *testing.B) { @@ -458,7 +532,43 @@ func BenchmarkLRU(b *testing.B) { err := l2.Set("test", status) require.Nil(b, err) - var val model.Status + var val *model.Status + err = l2.Get("test", &val) + require.Nil(b, err) + } + }) + + session := model.Session{ + Id: "ty7ia14yuty5bmpt8wmz6da1fw", + Token: "79c3iq6nzpycmkkawudanqhg5c", + CreateAt: 1595445296960, + ExpiresAt: 1598296496960, + LastActivityAt: 1595445296960, + UserId: "rpgh1q5ra38y9xjn9z8fjctezr", + Roles: "system_admin system_user", + IsOAuth: false, + ExpiredNotify: false, + Props: map[string]string{ + "csrf": "33zb7h7rk3rfffztojn5pxbkxe", + "isMobile": "false", + "isSaml": "false", + "is_guest": "false", + "os": "", + "platform": "Windows", + }, + } + + b.Run("Session=new", func(b *testing.B) { + for i := 0; i < b.N; i++ { + l2 := NewLRU(&LRUOptions{ + Size: 1, + DefaultExpiry: 0, + InvalidateClusterEvent: "", + }) + err := l2.Set("test", &session) + require.Nil(b, err) + + var val *model.Session err = l2.Get("test", &val) require.Nil(b, err) } diff --git a/store/localcachelayer/user_layer_test.go b/store/localcachelayer/user_layer_test.go index d789cbbe73..1511832599 100644 --- a/store/localcachelayer/user_layer_test.go +++ b/store/localcachelayer/user_layer_test.go @@ -101,6 +101,8 @@ func TestUserStoreCache(t *testing.T) { cachedUsers, err = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true) require.Nil(t, err) for i := 0; i < len(storedUsers); i++ { + storedUsers[i].Props = model.StringMap{} + storedUsers[i].Timezone = model.StringMap{} assert.Equal(t, storedUsers[i], cachedUsers[i]) if storedUsers[i] == cachedUsers[i] { assert.Fail(t, "should be different pointers") @@ -241,6 +243,8 @@ func TestUserStoreGetCache(t *testing.T) { cachedUser.NotifyProps["key"] = "othervalue" assert.NotEqual(t, storedUser, cachedUser) + storedUser.Props = model.StringMap{} + storedUser.Timezone = model.StringMap{} cachedUser, err = cachedStore.User().Get(fakeUserId) require.Nil(t, err) assert.Equal(t, storedUser, cachedUser) diff --git a/vendor/github.com/tinylib/msgp/.gitignore b/vendor/github.com/tinylib/msgp/.gitignore new file mode 100644 index 0000000000..1acaf6cdd5 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/.gitignore @@ -0,0 +1,10 @@ +_generated/generated.go +_generated/generated_test.go +_generated/*_gen.go +_generated/*_gen_test.go +_generated/embeddedStruct/*_gen.go +_generated/embeddedStruct/*_gen_test.go +msgp/defgen_test.go +msgp/cover.out +*~ +*.coverprofile diff --git a/vendor/github.com/tinylib/msgp/.travis.yml b/vendor/github.com/tinylib/msgp/.travis.yml new file mode 100644 index 0000000000..5f574c093b --- /dev/null +++ b/vendor/github.com/tinylib/msgp/.travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - 1.12.x + - tip + +env: + - GIMME_ARCH=amd64 + - GIMME_ARCH=386 + +script: "make travis" diff --git a/vendor/github.com/tinylib/msgp/Makefile b/vendor/github.com/tinylib/msgp/Makefile new file mode 100644 index 0000000000..4cc2dd281d --- /dev/null +++ b/vendor/github.com/tinylib/msgp/Makefile @@ -0,0 +1,52 @@ + +# NOTE: This Makefile is only necessary if you +# plan on developing the msgp tool and library. +# Installation can still be performed with a +# normal `go install`. + +# generated integration test files +GGEN = ./_generated/generated.go ./_generated/generated_test.go +# generated unit test files +MGEN = ./msgp/defgen_test.go + +SHELL := /bin/bash + +BIN = $(GOBIN)/msgp + +.PHONY: clean wipe install get-deps bench all + +$(BIN): */*.go + @go install ./... + +install: $(BIN) + +$(GGEN): ./_generated/def.go + go generate ./_generated + +$(MGEN): ./msgp/defs_test.go + go generate ./msgp + +test: all + go test ./... ./_generated + +bench: all + go test -bench ./... + +clean: + $(RM) $(GGEN) $(MGEN) + +wipe: clean + $(RM) $(BIN) + +get-deps: + go get -d -t ./... + +all: install $(GGEN) $(MGEN) + +# travis CI enters here +travis: + go get -d -t ./... + go build -o "$${GOPATH%%:*}/bin/msgp" . + go generate ./msgp + go generate ./_generated + go test -v ./... ./_generated diff --git a/vendor/github.com/tinylib/msgp/README.md b/vendor/github.com/tinylib/msgp/README.md new file mode 100644 index 0000000000..1328ccafe4 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/README.md @@ -0,0 +1,102 @@ +MessagePack Code Generator [![Build Status](https://travis-ci.org/tinylib/msgp.svg?branch=master)](https://travis-ci.org/tinylib/msgp) +======= + +This is a code generation tool and serialization library for [MessagePack](http://msgpack.org). You can read more about MessagePack [in the wiki](http://github.com/tinylib/msgp/wiki), or at [msgpack.org](http://msgpack.org). + +### Why? + +- Use Go as your schema language +- Performance +- [JSON interop](http://godoc.org/github.com/tinylib/msgp/msgp#CopyToJSON) +- [User-defined extensions](http://github.com/tinylib/msgp/wiki/Using-Extensions) +- Type safety +- Encoding flexibility + +### Quickstart + +In a source file, include the following directive: + +```go +//go:generate msgp +``` + +The `msgp` command will generate serialization methods for all exported type declarations in the file. + +You can [read more about the code generation options here](http://github.com/tinylib/msgp/wiki/Using-the-Code-Generator). + +### Use + +Field names can be set in much the same way as the `encoding/json` package. For example: + +```go +type Person struct { + Name string `msg:"name"` + Address string `msg:"address"` + Age int `msg:"age"` + Hidden string `msg:"-"` // this field is ignored + unexported bool // this field is also ignored +} +``` + +By default, the code generator will satisfy `msgp.Sizer`, `msgp.Encodable`, `msgp.Decodable`, +`msgp.Marshaler`, and `msgp.Unmarshaler`. Carefully-designed applications can use these methods to do +marshalling/unmarshalling with zero heap allocations. + +While `msgp.Marshaler` and `msgp.Unmarshaler` are quite similar to the standard library's +`json.Marshaler` and `json.Unmarshaler`, `msgp.Encodable` and `msgp.Decodable` are useful for +stream serialization. (`*msgp.Writer` and `*msgp.Reader` are essentially protocol-aware versions +of `*bufio.Writer` and `*bufio.Reader`, respectively.) + +### Features + + - Extremely fast generated code + - Test and benchmark generation + - JSON interoperability (see `msgp.CopyToJSON() and msgp.UnmarshalAsJSON()`) + - Support for complex type declarations + - Native support for Go's `time.Time`, `complex64`, and `complex128` types + - Generation of both `[]byte`-oriented and `io.Reader/io.Writer`-oriented methods + - Support for arbitrary type system extensions + - [Preprocessor directives](http://github.com/tinylib/msgp/wiki/Preprocessor-Directives) + - File-based dependency model means fast codegen regardless of source tree size. + +Consider the following: +```go +const Eight = 8 +type MyInt int +type Data []byte + +type Struct struct { + Which map[string]*MyInt `msg:"which"` + Other Data `msg:"other"` + Nums [Eight]float64 `msg:"nums"` +} +``` +As long as the declarations of `MyInt` and `Data` are in the same file as `Struct`, the parser will determine that the type information for `MyInt` and `Data` can be passed into the definition of `Struct` before its methods are generated. + +#### Extensions + +MessagePack supports defining your own types through "extensions," which are just a tuple of +the data "type" (`int8`) and the raw binary. You [can see a worked example in the wiki.](http://github.com/tinylib/msgp/wiki/Using-Extensions) + +### Status + +Mostly stable, in that no breaking changes have been made to the `/msgp` library in more than a year. Newer versions +of the code may generate different code than older versions for performance reasons. I (@philhofer) am aware of a +number of stability-critical commercial applications that use this code with good results. But, caveat emptor. + +You can read more about how `msgp` maps MessagePack types onto Go types [in the wiki](http://github.com/tinylib/msgp/wiki). + +Here some of the known limitations/restrictions: + +- Identifiers from outside the processed source file are assumed (optimistically) to satisfy the generator's interfaces. If this isn't the case, your code will fail to compile. +- Like most serializers, `chan` and `func` fields are ignored, as well as non-exported fields. +- Encoding of `interface{}` is limited to built-ins or types that have explicit encoding methods. +- _Maps must have `string` keys._ This is intentional (as it preserves JSON interop.) Although non-string map keys are not forbidden by the MessagePack standard, many serializers impose this restriction. (It also means *any* well-formed `struct` can be de-serialized into a `map[string]interface{}`.) The only exception to this rule is that the deserializers will allow you to read map keys encoded as `bin` types, due to the fact that some legacy encodings permitted this. (However, those values will still be cast to Go `string`s, and they will be converted to `str` types when re-encoded. It is the responsibility of the user to ensure that map keys are UTF-8 safe in this case.) The same rules hold true for JSON translation. + +If the output compiles, then there's a pretty good chance things are fine. (Plus, we generate tests for you.) *Please, please, please* file an issue if you think the generator is writing broken code. + +### Performance + +If you like benchmarks, see [here](http://bravenewgeek.com/so-you-wanna-go-fast/) and [here](https://github.com/alecthomas/go_serialization_benchmarks). + +As one might expect, the generated methods that deal with `[]byte` are faster for small objects, but the `io.Reader/Writer` methods are generally more memory-efficient (and, at some point, faster) for large (> 2KB) objects. diff --git a/vendor/github.com/tinylib/msgp/gen/decode.go b/vendor/github.com/tinylib/msgp/gen/decode.go new file mode 100644 index 0000000000..10f3fd8af5 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/gen/decode.go @@ -0,0 +1,231 @@ +package gen + +import ( + "io" + "strconv" +) + +func decode(w io.Writer) *decodeGen { + return &decodeGen{ + p: printer{w: w}, + hasfield: false, + } +} + +type decodeGen struct { + passes + p printer + hasfield bool + ctx *Context +} + +func (d *decodeGen) Method() Method { return Decode } + +func (d *decodeGen) needsField() { + if d.hasfield { + return + } + d.p.print("\nvar field []byte; _ = field") + d.hasfield = true +} + +func (d *decodeGen) Execute(p Elem) error { + p = d.applyall(p) + if p == nil { + return nil + } + d.hasfield = false + if !d.p.ok() { + return d.p.err + } + + if !IsPrintable(p) { + return nil + } + + d.ctx = &Context{} + + d.p.comment("DecodeMsg implements msgp.Decodable") + + d.p.printf("\nfunc (%s %s) DecodeMsg(dc *msgp.Reader) (err error) {", p.Varname(), methodReceiver(p)) + next(d, p) + d.p.nakedReturn() + unsetReceiver(p) + return d.p.err +} + +func (d *decodeGen) gStruct(s *Struct) { + if !d.p.ok() { + return + } + if s.AsTuple { + d.structAsTuple(s) + } else { + d.structAsMap(s) + } + return +} + +func (d *decodeGen) assignAndCheck(name string, typ string) { + if !d.p.ok() { + return + } + d.p.printf("\n%s, err = dc.Read%s()", name, typ) + d.p.wrapErrCheck(d.ctx.ArgsStr()) +} + +func (d *decodeGen) structAsTuple(s *Struct) { + nfields := len(s.Fields) + + sz := randIdent() + d.p.declare(sz, u32) + d.assignAndCheck(sz, arrayHeader) + d.p.arrayCheck(strconv.Itoa(nfields), sz) + for i := range s.Fields { + if !d.p.ok() { + return + } + d.ctx.PushString(s.Fields[i].FieldName) + next(d, s.Fields[i].FieldElem) + d.ctx.Pop() + } +} + +func (d *decodeGen) structAsMap(s *Struct) { + d.needsField() + sz := randIdent() + d.p.declare(sz, u32) + d.assignAndCheck(sz, mapHeader) + + d.p.printf("\nfor %s > 0 {\n%s--", sz, sz) + d.assignAndCheck("field", mapKey) + d.p.print("\nswitch msgp.UnsafeString(field) {") + for i := range s.Fields { + d.ctx.PushString(s.Fields[i].FieldName) + d.p.printf("\ncase \"%s\":", s.Fields[i].FieldTag) + next(d, s.Fields[i].FieldElem) + d.ctx.Pop() + if !d.p.ok() { + return + } + } + d.p.print("\ndefault:\nerr = dc.Skip()") + d.p.wrapErrCheck(d.ctx.ArgsStr()) + + d.p.closeblock() // close switch + d.p.closeblock() // close for loop +} + +func (d *decodeGen) gBase(b *BaseElem) { + if !d.p.ok() { + return + } + + // open block for 'tmp' + var tmp string + if b.Convert { + tmp = randIdent() + d.p.printf("\n{ var %s %s", tmp, b.BaseType()) + } + + vname := b.Varname() // e.g. "z.FieldOne" + bname := b.BaseName() // e.g. "Float64" + + // handle special cases + // for object type. + switch b.Value { + case Bytes: + if b.Convert { + d.p.printf("\n%s, err = dc.ReadBytes([]byte(%s))", tmp, vname) + } else { + d.p.printf("\n%s, err = dc.ReadBytes(%s)", vname, vname) + } + case IDENT: + d.p.printf("\nerr = %s.DecodeMsg(dc)", vname) + case Ext: + d.p.printf("\nerr = dc.ReadExtension(%s)", vname) + default: + if b.Convert { + d.p.printf("\n%s, err = dc.Read%s()", tmp, bname) + } else { + d.p.printf("\n%s, err = dc.Read%s()", vname, bname) + } + } + d.p.wrapErrCheck(d.ctx.ArgsStr()) + + // close block for 'tmp' + if b.Convert { + if b.ShimMode == Cast { + d.p.printf("\n%s = %s(%s)\n}", vname, b.FromBase(), tmp) + } else { + d.p.printf("\n%s, err = %s(%s)\n}", vname, b.FromBase(), tmp) + d.p.wrapErrCheck(d.ctx.ArgsStr()) + } + } +} + +func (d *decodeGen) gMap(m *Map) { + if !d.p.ok() { + return + } + sz := randIdent() + + // resize or allocate map + d.p.declare(sz, u32) + d.assignAndCheck(sz, mapHeader) + d.p.resizeMap(sz, m) + + // for element in map, read string/value + // pair and assign + d.p.printf("\nfor %s > 0 {\n%s--", sz, sz) + d.p.declare(m.Keyidx, "string") + d.p.declare(m.Validx, m.Value.TypeName()) + d.assignAndCheck(m.Keyidx, stringTyp) + d.ctx.PushVar(m.Keyidx) + next(d, m.Value) + d.p.mapAssign(m) + d.ctx.Pop() + d.p.closeblock() +} + +func (d *decodeGen) gSlice(s *Slice) { + if !d.p.ok() { + return + } + sz := randIdent() + d.p.declare(sz, u32) + d.assignAndCheck(sz, arrayHeader) + d.p.resizeSlice(sz, s) + d.p.rangeBlock(d.ctx, s.Index, s.Varname(), d, s.Els) +} + +func (d *decodeGen) gArray(a *Array) { + if !d.p.ok() { + return + } + + // special case if we have [const]byte + if be, ok := a.Els.(*BaseElem); ok && (be.Value == Byte || be.Value == Uint8) { + d.p.printf("\nerr = dc.ReadExactBytes((%s)[:])", a.Varname()) + d.p.wrapErrCheck(d.ctx.ArgsStr()) + return + } + sz := randIdent() + d.p.declare(sz, u32) + d.assignAndCheck(sz, arrayHeader) + d.p.arrayCheck(coerceArraySize(a.Size), sz) + d.p.rangeBlock(d.ctx, a.Index, a.Varname(), d, a.Els) +} + +func (d *decodeGen) gPtr(p *Ptr) { + if !d.p.ok() { + return + } + d.p.print("\nif dc.IsNil() {") + d.p.print("\nerr = dc.ReadNil()") + d.p.wrapErrCheck(d.ctx.ArgsStr()) + d.p.printf("\n%s = nil\n} else {", p.Varname()) + d.p.initPtr(p) + next(d, p.Value) + d.p.closeblock() +} diff --git a/vendor/github.com/tinylib/msgp/gen/elem.go b/vendor/github.com/tinylib/msgp/gen/elem.go new file mode 100644 index 0000000000..50f07e79e5 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/gen/elem.go @@ -0,0 +1,739 @@ +package gen + +import ( + "fmt" + "strings" +) + +var ( + identNext = 0 + identPrefix = "za" +) + +func resetIdent(prefix string) { + identPrefix = prefix + identNext = 0 +} + +// generate a random identifier name +func randIdent() string { + identNext++ + return fmt.Sprintf("%s%04d", identPrefix, identNext) +} + +// This code defines the type declaration tree. +// +// Consider the following: +// +// type Marshaler struct { +// Thing1 *float64 `msg:"thing1"` +// Body []byte `msg:"body"` +// } +// +// A parser using this generator as a backend +// should parse the above into: +// +// var val Elem = &Ptr{ +// name: "z", +// Value: &Struct{ +// Name: "Marshaler", +// Fields: []StructField{ +// { +// FieldTag: "thing1", +// FieldElem: &Ptr{ +// name: "z.Thing1", +// Value: &BaseElem{ +// name: "*z.Thing1", +// Value: Float64, +// Convert: false, +// }, +// }, +// }, +// { +// FieldTag: "body", +// FieldElem: &BaseElem{ +// name: "z.Body", +// Value: Bytes, +// Convert: false, +// }, +// }, +// }, +// }, +// } + +// Base is one of the +// base types +type Primitive uint8 + +// this is effectively the +// list of currently available +// ReadXxxx / WriteXxxx methods. +const ( + Invalid Primitive = iota + Bytes + String + Float32 + Float64 + Complex64 + Complex128 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Byte + Int + Int8 + Int16 + Int32 + Int64 + Bool + Intf // interface{} + Time // time.Time + Ext // extension + + IDENT // IDENT means an unrecognized identifier +) + +// all of the recognized identities +// that map to primitive types +var primitives = map[string]Primitive{ + "[]byte": Bytes, + "string": String, + "float32": Float32, + "float64": Float64, + "complex64": Complex64, + "complex128": Complex128, + "uint": Uint, + "uint8": Uint8, + "uint16": Uint16, + "uint32": Uint32, + "uint64": Uint64, + "byte": Byte, + "rune": Int32, + "int": Int, + "int8": Int8, + "int16": Int16, + "int32": Int32, + "int64": Int64, + "bool": Bool, + "interface{}": Intf, + "time.Time": Time, + "msgp.Extension": Ext, +} + +// types built into the library +// that satisfy all of the +// interfaces. +var builtins = map[string]struct{}{ + "msgp.Raw": struct{}{}, + "msgp.Number": struct{}{}, +} + +// common data/methods for every Elem +type common struct{ vname, alias string } + +func (c *common) SetVarname(s string) { c.vname = s } +func (c *common) Varname() string { return c.vname } +func (c *common) Alias(typ string) { c.alias = typ } +func (c *common) hidden() {} + +func IsPrintable(e Elem) bool { + if be, ok := e.(*BaseElem); ok && !be.Printable() { + return false + } + return true +} + +// Elem is a go type capable of being +// serialized into MessagePack. It is +// implemented by *Ptr, *Struct, *Array, +// *Slice, *Map, and *BaseElem. +type Elem interface { + // SetVarname sets this nodes + // variable name and recursively + // sets the names of all its children. + // In general, this should only be + // called on the parent of the tree. + SetVarname(s string) + + // Varname returns the variable + // name of the element. + Varname() string + + // TypeName is the canonical + // go type name of the node + // e.g. "string", "int", "map[string]float64" + // OR the alias name, if it has been set. + TypeName() string + + // Alias sets a type (alias) name + Alias(typ string) + + // Copy should perform a deep copy of the object + Copy() Elem + + // Complexity returns a measure of the + // complexity of element (greater than + // or equal to 1.) + Complexity() int + + // ZeroExpr returns the expression for the correct zero/empty + // value. Can be used for assignment. + // Returns "" if zero/empty not supported for this Elem. + ZeroExpr() string + + // IfZeroExpr returns the expression to compare to zero/empty + // for this type. It is meant to be used in an if statement + // and may include the simple statement form followed by + // semicolon and then the expression. + // Returns "" if zero/empty not supported for this Elem. + IfZeroExpr() string + + hidden() +} + +// Ident returns the *BaseElem that corresponds +// to the provided identity. +func Ident(id string) *BaseElem { + p, ok := primitives[id] + if ok { + return &BaseElem{Value: p} + } + be := &BaseElem{Value: IDENT} + be.Alias(id) + return be +} + +type Array struct { + common + Index string // index variable name + Size string // array size + Els Elem // child +} + +func (a *Array) SetVarname(s string) { + a.common.SetVarname(s) +ridx: + a.Index = randIdent() + + // try to avoid using the same + // index as a parent slice + if strings.Contains(a.Varname(), a.Index) { + goto ridx + } + + a.Els.SetVarname(fmt.Sprintf("%s[%s]", a.Varname(), a.Index)) +} + +func (a *Array) TypeName() string { + if a.common.alias != "" { + return a.common.alias + } + a.common.Alias(fmt.Sprintf("[%s]%s", a.Size, a.Els.TypeName())) + return a.common.alias +} + +func (a *Array) Copy() Elem { + b := *a + b.Els = a.Els.Copy() + return &b +} + +func (a *Array) Complexity() int { return 1 + a.Els.Complexity() } + +// ZeroExpr returns the zero/empty expression or empty string if not supported. Unsupported for this case. +func (a *Array) ZeroExpr() string { return "" } + +// IfZeroExpr unsupported +func (a *Array) IfZeroExpr() string { return "" } + +// Map is a map[string]Elem +type Map struct { + common + Keyidx string // key variable name + Validx string // value variable name + Value Elem // value element +} + +func (m *Map) SetVarname(s string) { + m.common.SetVarname(s) +ridx: + m.Keyidx = randIdent() + m.Validx = randIdent() + + // just in case + if m.Keyidx == m.Validx { + goto ridx + } + + m.Value.SetVarname(m.Validx) +} + +func (m *Map) TypeName() string { + if m.common.alias != "" { + return m.common.alias + } + m.common.Alias("map[string]" + m.Value.TypeName()) + return m.common.alias +} + +func (m *Map) Copy() Elem { + g := *m + g.Value = m.Value.Copy() + return &g +} + +func (m *Map) Complexity() int { return 2 + m.Value.Complexity() } + +// ZeroExpr returns the zero/empty expression or empty string if not supported. Always "nil" for this case. +func (m *Map) ZeroExpr() string { return "nil" } + +// IfZeroExpr returns the expression to compare to zero/empty. +func (m *Map) IfZeroExpr() string { return m.Varname() + " == nil" } + +type Slice struct { + common + Index string + Els Elem // The type of each element +} + +func (s *Slice) SetVarname(a string) { + s.common.SetVarname(a) + s.Index = randIdent() + varName := s.Varname() + if varName[0] == '*' { + // Pointer-to-slice requires parenthesis for slicing. + varName = "(" + varName + ")" + } + s.Els.SetVarname(fmt.Sprintf("%s[%s]", varName, s.Index)) +} + +func (s *Slice) TypeName() string { + if s.common.alias != "" { + return s.common.alias + } + s.common.Alias("[]" + s.Els.TypeName()) + return s.common.alias +} + +func (s *Slice) Copy() Elem { + z := *s + z.Els = s.Els.Copy() + return &z +} + +func (s *Slice) Complexity() int { + return 1 + s.Els.Complexity() +} + +// ZeroExpr returns the zero/empty expression or empty string if not supported. Always "nil" for this case. +func (s *Slice) ZeroExpr() string { return "nil" } + +// IfZeroExpr returns the expression to compare to zero/empty. +func (s *Slice) IfZeroExpr() string { return s.Varname() + " == nil" } + +type Ptr struct { + common + Value Elem +} + +func (s *Ptr) SetVarname(a string) { + s.common.SetVarname(a) + + // struct fields are dereferenced + // automatically... + switch x := s.Value.(type) { + case *Struct: + // struct fields are automatically dereferenced + x.SetVarname(a) + return + + case *BaseElem: + // identities have pointer receivers + if x.Value == IDENT { + x.SetVarname(a) + } else { + x.SetVarname("*" + a) + } + return + + default: + s.Value.SetVarname("*" + a) + return + } +} + +func (s *Ptr) TypeName() string { + if s.common.alias != "" { + return s.common.alias + } + s.common.Alias("*" + s.Value.TypeName()) + return s.common.alias +} + +func (s *Ptr) Copy() Elem { + v := *s + v.Value = s.Value.Copy() + return &v +} + +func (s *Ptr) Complexity() int { return 1 + s.Value.Complexity() } + +func (s *Ptr) Needsinit() bool { + if be, ok := s.Value.(*BaseElem); ok && be.needsref { + return false + } + return true +} + +// ZeroExpr returns the zero/empty expression or empty string if not supported. Always "nil" for this case. +func (s *Ptr) ZeroExpr() string { return "nil" } + +// IfZeroExpr returns the expression to compare to zero/empty. +func (s *Ptr) IfZeroExpr() string { return s.Varname() + " == nil" } + +type Struct struct { + common + Fields []StructField // field list + AsTuple bool // write as an array instead of a map +} + +func (s *Struct) TypeName() string { + if s.common.alias != "" { + return s.common.alias + } + str := "struct{\n" + for i := range s.Fields { + str += s.Fields[i].FieldName + + " " + s.Fields[i].FieldElem.TypeName() + + " " + s.Fields[i].RawTag + ";\n" + } + str += "}" + s.common.Alias(str) + return s.common.alias +} + +func (s *Struct) SetVarname(a string) { + s.common.SetVarname(a) + writeStructFields(s.Fields, a) +} + +func (s *Struct) Copy() Elem { + g := *s + g.Fields = make([]StructField, len(s.Fields)) + copy(g.Fields, s.Fields) + for i := range s.Fields { + g.Fields[i].FieldElem = s.Fields[i].FieldElem.Copy() + } + return &g +} + +func (s *Struct) Complexity() int { + c := 1 + for i := range s.Fields { + c += s.Fields[i].FieldElem.Complexity() + } + return c +} + +// ZeroExpr returns the zero/empty expression or empty string if not supported. +func (s *Struct) ZeroExpr() string { + if s.alias == "" { + return "" // structs with no names not supported (for now) + } + return "(" + s.TypeName() + "{})" +} + +// IfZeroExpr returns the expression to compare to zero/empty. +func (s *Struct) IfZeroExpr() string { + if s.alias == "" { + return "" // structs with no names not supported (for now) + } + return s.Varname() + " == " + s.ZeroExpr() +} + +// AnyHasTagPart returns true if HasTagPart(p) is true for any field. +func (s *Struct) AnyHasTagPart(pname string) bool { + for _, sf := range s.Fields { + if sf.HasTagPart(pname) { + return true + } + } + return false +} + +type StructField struct { + FieldTag string // the string inside the `msg:""` tag up to the first comma + FieldTagParts []string // the string inside the `msg:""` tag split by commas + RawTag string // the full struct tag + FieldName string // the name of the struct field + FieldElem Elem // the field type +} + +// HasTagPart returns true if the specified tag part (option) is present. +func (sf *StructField) HasTagPart(pname string) bool { + if len(sf.FieldTagParts) < 2 { + return false + } + for _, p := range sf.FieldTagParts[1:] { + if p == pname { + return true + } + } + return false +} + +type ShimMode int + +const ( + Cast ShimMode = iota + Convert +) + +// BaseElem is an element that +// can be represented by a primitive +// MessagePack type. +type BaseElem struct { + common + ShimMode ShimMode // Method used to shim + ShimToBase string // shim to base type, or empty + ShimFromBase string // shim from base type, or empty + Value Primitive // Type of element + Convert bool // should we do an explicit conversion? + mustinline bool // must inline; not printable + needsref bool // needs reference for shim +} + +func (s *BaseElem) Printable() bool { return !s.mustinline } + +func (s *BaseElem) Alias(typ string) { + s.common.Alias(typ) + if s.Value != IDENT { + s.Convert = true + } + if strings.Contains(typ, ".") { + s.mustinline = true + } +} + +func (s *BaseElem) SetVarname(a string) { + // extensions whose parents + // are not pointers need to + // be explicitly referenced + if s.Value == Ext || s.needsref { + if strings.HasPrefix(a, "*") { + s.common.SetVarname(a[1:]) + return + } + s.common.SetVarname("&" + a) + return + } + + s.common.SetVarname(a) +} + +// TypeName returns the syntactically correct Go +// type name for the base element. +func (s *BaseElem) TypeName() string { + if s.common.alias != "" { + return s.common.alias + } + s.common.Alias(s.BaseType()) + return s.common.alias +} + +// ToBase, used if Convert==true, is used as tmp = {{ToBase}}({{Varname}}) +func (s *BaseElem) ToBase() string { + if s.ShimToBase != "" { + return s.ShimToBase + } + return s.BaseType() +} + +// FromBase, used if Convert==true, is used as {{Varname}} = {{FromBase}}(tmp) +func (s *BaseElem) FromBase() string { + if s.ShimFromBase != "" { + return s.ShimFromBase + } + return s.TypeName() +} + +// BaseName returns the string form of the +// base type (e.g. Float64, Ident, etc) +func (s *BaseElem) BaseName() string { + // time is a special case; + // we strip the package prefix + if s.Value == Time { + return "Time" + } + return s.Value.String() +} + +func (s *BaseElem) BaseType() string { + switch s.Value { + case IDENT: + return s.TypeName() + + // exceptions to the naming/capitalization + // rule: + case Intf: + return "interface{}" + case Bytes: + return "[]byte" + case Time: + return "time.Time" + case Ext: + return "msgp.Extension" + + // everything else is base.String() with + // the first letter as lowercase + default: + return strings.ToLower(s.BaseName()) + } +} + +func (s *BaseElem) Needsref(b bool) { + s.needsref = b +} + +func (s *BaseElem) Copy() Elem { + g := *s + return &g +} + +func (s *BaseElem) Complexity() int { + if s.Convert && !s.mustinline { + return 2 + } + // we need to return 1 if !printable(), + // in order to make sure that stuff gets + // inlined appropriately + return 1 +} + +// Resolved returns whether or not +// the type of the element is +// a primitive or a builtin provided +// by the package. +func (s *BaseElem) Resolved() bool { + if s.Value == IDENT { + _, ok := builtins[s.TypeName()] + return ok + } + return true +} + +// ZeroExpr returns the zero/empty expression or empty string if not supported. +func (s *BaseElem) ZeroExpr() string { + + switch s.Value { + case Bytes: + return "nil" + case String: + return "\"\"" + case Complex64, Complex128: + return "complex(0,0)" + case Float32, + Float64, + Uint, + Uint8, + Uint16, + Uint32, + Uint64, + Byte, + Int, + Int8, + Int16, + Int32, + Int64: + return "0" + case Bool: + return "false" + + case Time: + return "(time.Time{})" + + } + + return "" +} + +// IfZeroExpr returns the expression to compare to zero/empty. +func (s *BaseElem) IfZeroExpr() string { + z := s.ZeroExpr() + if z == "" { + return "" + } + return s.Varname() + " == " + z +} + +func (k Primitive) String() string { + switch k { + case String: + return "String" + case Bytes: + return "Bytes" + case Float32: + return "Float32" + case Float64: + return "Float64" + case Complex64: + return "Complex64" + case Complex128: + return "Complex128" + case Uint: + return "Uint" + case Uint8: + return "Uint8" + case Uint16: + return "Uint16" + case Uint32: + return "Uint32" + case Uint64: + return "Uint64" + case Byte: + return "Byte" + case Int: + return "Int" + case Int8: + return "Int8" + case Int16: + return "Int16" + case Int32: + return "Int32" + case Int64: + return "Int64" + case Bool: + return "Bool" + case Intf: + return "Intf" + case Time: + return "time.Time" + case Ext: + return "Extension" + case IDENT: + return "Ident" + default: + return "INVALID" + } +} + +// writeStructFields is a trampoline for writeBase for +// all of the fields in a struct +func writeStructFields(s []StructField, name string) { + for i := range s { + s[i].FieldElem.SetVarname(fmt.Sprintf("%s.%s", name, s[i].FieldName)) + } +} + +// coerceArraySize ensures we can compare constant array lengths. +// +// msgpack array headers are 32 bit unsigned, which is reflected in the +// ArrayHeader implementation in this library using uint32. On the Go side, we +// can declare array lengths as any constant integer width, which breaks when +// attempting a direct comparison to an array header's uint32. +// +func coerceArraySize(asz string) string { + return fmt.Sprintf("uint32(%s)", asz) +} diff --git a/vendor/github.com/tinylib/msgp/gen/encode.go b/vendor/github.com/tinylib/msgp/gen/encode.go new file mode 100644 index 0000000000..a1d0b30739 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/gen/encode.go @@ -0,0 +1,270 @@ +package gen + +import ( + "fmt" + "io" + "strings" + + "github.com/tinylib/msgp/msgp" +) + +func encode(w io.Writer) *encodeGen { + return &encodeGen{ + p: printer{w: w}, + } +} + +type encodeGen struct { + passes + p printer + fuse []byte + ctx *Context +} + +func (e *encodeGen) Method() Method { return Encode } + +func (e *encodeGen) Apply(dirs []string) error { + return nil +} + +func (e *encodeGen) writeAndCheck(typ string, argfmt string, arg interface{}) { + e.p.printf("\nerr = en.Write%s(%s)", typ, fmt.Sprintf(argfmt, arg)) + e.p.wrapErrCheck(e.ctx.ArgsStr()) +} + +func (e *encodeGen) fuseHook() { + if len(e.fuse) > 0 { + e.appendraw(e.fuse) + e.fuse = e.fuse[:0] + } +} + +func (e *encodeGen) Fuse(b []byte) { + if len(e.fuse) > 0 { + e.fuse = append(e.fuse, b...) + } else { + e.fuse = b + } +} + +func (e *encodeGen) Execute(p Elem) error { + if !e.p.ok() { + return e.p.err + } + p = e.applyall(p) + if p == nil { + return nil + } + if !IsPrintable(p) { + return nil + } + + e.ctx = &Context{} + + e.p.comment("EncodeMsg implements msgp.Encodable") + + e.p.printf("\nfunc (%s %s) EncodeMsg(en *msgp.Writer) (err error) {", p.Varname(), imutMethodReceiver(p)) + next(e, p) + e.p.nakedReturn() + return e.p.err +} + +func (e *encodeGen) gStruct(s *Struct) { + if !e.p.ok() { + return + } + if s.AsTuple { + e.tuple(s) + } else { + e.structmap(s) + } + return +} + +func (e *encodeGen) tuple(s *Struct) { + nfields := len(s.Fields) + data := msgp.AppendArrayHeader(nil, uint32(nfields)) + e.p.printf("\n// array header, size %d", nfields) + e.Fuse(data) + if len(s.Fields) == 0 { + e.fuseHook() + } + for i := range s.Fields { + if !e.p.ok() { + return + } + e.ctx.PushString(s.Fields[i].FieldName) + next(e, s.Fields[i].FieldElem) + e.ctx.Pop() + } +} + +func (e *encodeGen) appendraw(bts []byte) { + e.p.print("\nerr = en.Append(") + for i, b := range bts { + if i != 0 { + e.p.print(", ") + } + e.p.printf("0x%x", b) + } + e.p.print(")\nif err != nil { return }") +} + +func (e *encodeGen) structmap(s *Struct) { + + oeIdentPrefix := randIdent() + + var data []byte + nfields := len(s.Fields) + bm := bmask{ + bitlen: nfields, + varname: oeIdentPrefix + "Mask", + } + + omitempty := s.AnyHasTagPart("omitempty") + var fieldNVar string + if omitempty { + + fieldNVar = oeIdentPrefix + "Len" + + e.p.printf("\n// omitempty: check for empty values") + e.p.printf("\n%s := uint32(%d)", fieldNVar, nfields) + e.p.printf("\n%s", bm.typeDecl()) + for i, sf := range s.Fields { + if !e.p.ok() { + return + } + if ize := sf.FieldElem.IfZeroExpr(); ize != "" && sf.HasTagPart("omitempty") { + e.p.printf("\nif %s {", ize) + e.p.printf("\n%s--", fieldNVar) + e.p.printf("\n%s", bm.setStmt(i)) + e.p.printf("\n}") + } + } + + e.p.printf("\n// variable map header, size %s", fieldNVar) + e.p.varWriteMapHeader("en", fieldNVar, nfields) + e.p.print("\nif err != nil { return }") + if !e.p.ok() { + return + } + + // quick return for the case where the entire thing is empty, but only at the top level + if !strings.Contains(s.Varname(), ".") { + e.p.printf("\nif %s == 0 { return }", fieldNVar) + } + + } else { + + // non-omitempty version + data = msgp.AppendMapHeader(nil, uint32(nfields)) + e.p.printf("\n// map header, size %d", nfields) + e.Fuse(data) + if len(s.Fields) == 0 { + e.fuseHook() + } + + } + + for i := range s.Fields { + if !e.p.ok() { + return + } + + // if field is omitempty, wrap with if statement based on the emptymask + oeField := s.Fields[i].HasTagPart("omitempty") && s.Fields[i].FieldElem.IfZeroExpr() != "" + if oeField { + e.p.printf("\nif %s == 0 { // if not empty", bm.readExpr(i)) + } + + data = msgp.AppendString(nil, s.Fields[i].FieldTag) + e.p.printf("\n// write %q", s.Fields[i].FieldTag) + e.Fuse(data) + e.fuseHook() + + e.ctx.PushString(s.Fields[i].FieldName) + next(e, s.Fields[i].FieldElem) + e.ctx.Pop() + + if oeField { + e.p.print("\n}") // close if statement + } + + } +} + +func (e *encodeGen) gMap(m *Map) { + if !e.p.ok() { + return + } + e.fuseHook() + vname := m.Varname() + e.writeAndCheck(mapHeader, lenAsUint32, vname) + + e.p.printf("\nfor %s, %s := range %s {", m.Keyidx, m.Validx, vname) + e.writeAndCheck(stringTyp, literalFmt, m.Keyidx) + e.ctx.PushVar(m.Keyidx) + next(e, m.Value) + e.ctx.Pop() + e.p.closeblock() +} + +func (e *encodeGen) gPtr(s *Ptr) { + if !e.p.ok() { + return + } + e.fuseHook() + e.p.printf("\nif %s == nil { err = en.WriteNil(); if err != nil { return; } } else {", s.Varname()) + next(e, s.Value) + e.p.closeblock() +} + +func (e *encodeGen) gSlice(s *Slice) { + if !e.p.ok() { + return + } + e.fuseHook() + e.writeAndCheck(arrayHeader, lenAsUint32, s.Varname()) + e.p.rangeBlock(e.ctx, s.Index, s.Varname(), e, s.Els) +} + +func (e *encodeGen) gArray(a *Array) { + if !e.p.ok() { + return + } + e.fuseHook() + // shortcut for [const]byte + if be, ok := a.Els.(*BaseElem); ok && (be.Value == Byte || be.Value == Uint8) { + e.p.printf("\nerr = en.WriteBytes((%s)[:])", a.Varname()) + e.p.wrapErrCheck(e.ctx.ArgsStr()) + return + } + + e.writeAndCheck(arrayHeader, literalFmt, coerceArraySize(a.Size)) + e.p.rangeBlock(e.ctx, a.Index, a.Varname(), e, a.Els) +} + +func (e *encodeGen) gBase(b *BaseElem) { + if !e.p.ok() { + return + } + e.fuseHook() + vname := b.Varname() + if b.Convert { + if b.ShimMode == Cast { + vname = tobaseConvert(b) + } else { + vname = randIdent() + e.p.printf("\nvar %s %s", vname, b.BaseType()) + e.p.printf("\n%s, err = %s", vname, tobaseConvert(b)) + e.p.wrapErrCheck(e.ctx.ArgsStr()) + } + } + + if b.Value == IDENT { // unknown identity + e.p.printf("\nerr = %s.EncodeMsg(en)", vname) + e.p.wrapErrCheck(e.ctx.ArgsStr()) + } else { // typical case + e.writeAndCheck(b.BaseName(), literalFmt, vname) + } +} diff --git a/vendor/github.com/tinylib/msgp/gen/marshal.go b/vendor/github.com/tinylib/msgp/gen/marshal.go new file mode 100644 index 0000000000..9a969ffeb0 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/gen/marshal.go @@ -0,0 +1,283 @@ +package gen + +import ( + "fmt" + "io" + "strings" + + "github.com/tinylib/msgp/msgp" +) + +func marshal(w io.Writer) *marshalGen { + return &marshalGen{ + p: printer{w: w}, + } +} + +type marshalGen struct { + passes + p printer + fuse []byte + ctx *Context +} + +func (m *marshalGen) Method() Method { return Marshal } + +func (m *marshalGen) Apply(dirs []string) error { + return nil +} + +func (m *marshalGen) Execute(p Elem) error { + if !m.p.ok() { + return m.p.err + } + p = m.applyall(p) + if p == nil { + return nil + } + if !IsPrintable(p) { + return nil + } + + m.ctx = &Context{} + + m.p.comment("MarshalMsg implements msgp.Marshaler") + + // save the vname before + // calling methodReceiver so + // that z.Msgsize() is printed correctly + c := p.Varname() + + m.p.printf("\nfunc (%s %s) MarshalMsg(b []byte) (o []byte, err error) {", p.Varname(), imutMethodReceiver(p)) + m.p.printf("\no = msgp.Require(b, %s.Msgsize())", c) + next(m, p) + m.p.nakedReturn() + return m.p.err +} + +func (m *marshalGen) rawAppend(typ string, argfmt string, arg interface{}) { + m.p.printf("\no = msgp.Append%s(o, %s)", typ, fmt.Sprintf(argfmt, arg)) +} + +func (m *marshalGen) fuseHook() { + if len(m.fuse) > 0 { + m.rawbytes(m.fuse) + m.fuse = m.fuse[:0] + } +} + +func (m *marshalGen) Fuse(b []byte) { + if len(m.fuse) == 0 { + m.fuse = b + } else { + m.fuse = append(m.fuse, b...) + } +} + +func (m *marshalGen) gStruct(s *Struct) { + if !m.p.ok() { + return + } + + if s.AsTuple { + m.tuple(s) + } else { + m.mapstruct(s) + } + return +} + +func (m *marshalGen) tuple(s *Struct) { + data := make([]byte, 0, 5) + data = msgp.AppendArrayHeader(data, uint32(len(s.Fields))) + m.p.printf("\n// array header, size %d", len(s.Fields)) + m.Fuse(data) + if len(s.Fields) == 0 { + m.fuseHook() + } + for i := range s.Fields { + if !m.p.ok() { + return + } + m.ctx.PushString(s.Fields[i].FieldName) + next(m, s.Fields[i].FieldElem) + m.ctx.Pop() + } +} + +func (m *marshalGen) mapstruct(s *Struct) { + + oeIdentPrefix := randIdent() + + var data []byte + nfields := len(s.Fields) + bm := bmask{ + bitlen: nfields, + varname: oeIdentPrefix + "Mask", + } + + omitempty := s.AnyHasTagPart("omitempty") + var fieldNVar string + if omitempty { + + fieldNVar = oeIdentPrefix + "Len" + + m.p.printf("\n// omitempty: check for empty values") + m.p.printf("\n%s := uint32(%d)", fieldNVar, nfields) + m.p.printf("\n%s", bm.typeDecl()) + for i, sf := range s.Fields { + if !m.p.ok() { + return + } + if ize := sf.FieldElem.IfZeroExpr(); ize != "" && sf.HasTagPart("omitempty") { + m.p.printf("\nif %s {", ize) + m.p.printf("\n%s--", fieldNVar) + m.p.printf("\n%s", bm.setStmt(i)) + m.p.printf("\n}") + } + } + + m.p.printf("\n// variable map header, size %s", fieldNVar) + m.p.varAppendMapHeader("o", fieldNVar, nfields) + if !m.p.ok() { + return + } + + // quick return for the case where the entire thing is empty, but only at the top level + if !strings.Contains(s.Varname(), ".") { + m.p.printf("\nif %s == 0 { return }", fieldNVar) + } + + } else { + + // non-omitempty version + data = make([]byte, 0, 64) + data = msgp.AppendMapHeader(data, uint32(len(s.Fields))) + m.p.printf("\n// map header, size %d", len(s.Fields)) + m.Fuse(data) + if len(s.Fields) == 0 { + m.fuseHook() + } + + } + + for i := range s.Fields { + if !m.p.ok() { + return + } + + // if field is omitempty, wrap with if statement based on the emptymask + oeField := s.Fields[i].HasTagPart("omitempty") && s.Fields[i].FieldElem.IfZeroExpr() != "" + if oeField { + m.p.printf("\nif %s == 0 { // if not empty", bm.readExpr(i)) + } + + data = msgp.AppendString(nil, s.Fields[i].FieldTag) + + m.p.printf("\n// string %q", s.Fields[i].FieldTag) + m.Fuse(data) + m.fuseHook() + + m.ctx.PushString(s.Fields[i].FieldName) + next(m, s.Fields[i].FieldElem) + m.ctx.Pop() + + if oeField { + m.p.printf("\n}") // close if statement + } + + } +} + +// append raw data +func (m *marshalGen) rawbytes(bts []byte) { + m.p.print("\no = append(o, ") + for _, b := range bts { + m.p.printf("0x%x,", b) + } + m.p.print(")") +} + +func (m *marshalGen) gMap(s *Map) { + if !m.p.ok() { + return + } + m.fuseHook() + vname := s.Varname() + m.rawAppend(mapHeader, lenAsUint32, vname) + m.p.printf("\nfor %s, %s := range %s {", s.Keyidx, s.Validx, vname) + m.rawAppend(stringTyp, literalFmt, s.Keyidx) + m.ctx.PushVar(s.Keyidx) + next(m, s.Value) + m.ctx.Pop() + m.p.closeblock() +} + +func (m *marshalGen) gSlice(s *Slice) { + if !m.p.ok() { + return + } + m.fuseHook() + vname := s.Varname() + m.rawAppend(arrayHeader, lenAsUint32, vname) + m.p.rangeBlock(m.ctx, s.Index, vname, m, s.Els) +} + +func (m *marshalGen) gArray(a *Array) { + if !m.p.ok() { + return + } + m.fuseHook() + if be, ok := a.Els.(*BaseElem); ok && be.Value == Byte { + m.rawAppend("Bytes", "(%s)[:]", a.Varname()) + return + } + + m.rawAppend(arrayHeader, literalFmt, coerceArraySize(a.Size)) + m.p.rangeBlock(m.ctx, a.Index, a.Varname(), m, a.Els) +} + +func (m *marshalGen) gPtr(p *Ptr) { + if !m.p.ok() { + return + } + m.fuseHook() + m.p.printf("\nif %s == nil {\no = msgp.AppendNil(o)\n} else {", p.Varname()) + next(m, p.Value) + m.p.closeblock() +} + +func (m *marshalGen) gBase(b *BaseElem) { + if !m.p.ok() { + return + } + m.fuseHook() + vname := b.Varname() + + if b.Convert { + if b.ShimMode == Cast { + vname = tobaseConvert(b) + } else { + vname = randIdent() + m.p.printf("\nvar %s %s", vname, b.BaseType()) + m.p.printf("\n%s, err = %s", vname, tobaseConvert(b)) + m.p.wrapErrCheck(m.ctx.ArgsStr()) + } + } + + var echeck bool + switch b.Value { + case IDENT: + echeck = true + m.p.printf("\no, err = %s.MarshalMsg(o)", vname) + case Intf, Ext: + echeck = true + m.p.printf("\no, err = msgp.Append%s(o, %s)", b.BaseName(), vname) + default: + m.rawAppend(b.BaseName(), literalFmt, vname) + } + + if echeck { + m.p.wrapErrCheck(m.ctx.ArgsStr()) + } +} diff --git a/vendor/github.com/tinylib/msgp/gen/size.go b/vendor/github.com/tinylib/msgp/gen/size.go new file mode 100644 index 0000000000..e96e03198c --- /dev/null +++ b/vendor/github.com/tinylib/msgp/gen/size.go @@ -0,0 +1,292 @@ +package gen + +import ( + "fmt" + "io" + "strconv" + + "github.com/tinylib/msgp/msgp" +) + +type sizeState uint8 + +const ( + // need to write "s = ..." + assign sizeState = iota + + // need to write "s += ..." + add + + // can just append "+ ..." + expr +) + +func sizes(w io.Writer) *sizeGen { + return &sizeGen{ + p: printer{w: w}, + state: assign, + } +} + +type sizeGen struct { + passes + p printer + state sizeState + ctx *Context +} + +func (s *sizeGen) Method() Method { return Size } + +func (s *sizeGen) Apply(dirs []string) error { + return nil +} + +func builtinSize(typ string) string { + return "msgp." + typ + "Size" +} + +// this lets us chain together addition +// operations where possible +func (s *sizeGen) addConstant(sz string) { + if !s.p.ok() { + return + } + + switch s.state { + case assign: + s.p.print("\ns = " + sz) + s.state = expr + return + case add: + s.p.print("\ns += " + sz) + s.state = expr + return + case expr: + s.p.print(" + " + sz) + return + } + + panic("unknown size state") +} + +func (s *sizeGen) Execute(p Elem) error { + if !s.p.ok() { + return s.p.err + } + p = s.applyall(p) + if p == nil { + return nil + } + if !IsPrintable(p) { + return nil + } + + s.ctx = &Context{} + s.ctx.PushString(p.TypeName()) + + s.p.comment("Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message") + + s.p.printf("\nfunc (%s %s) Msgsize() (s int) {", p.Varname(), imutMethodReceiver(p)) + s.state = assign + next(s, p) + s.p.nakedReturn() + return s.p.err +} + +func (s *sizeGen) gStruct(st *Struct) { + if !s.p.ok() { + return + } + + nfields := uint32(len(st.Fields)) + + if st.AsTuple { + data := msgp.AppendArrayHeader(nil, nfields) + s.addConstant(strconv.Itoa(len(data))) + for i := range st.Fields { + if !s.p.ok() { + return + } + next(s, st.Fields[i].FieldElem) + } + } else { + data := msgp.AppendMapHeader(nil, nfields) + s.addConstant(strconv.Itoa(len(data))) + for i := range st.Fields { + data = data[:0] + data = msgp.AppendString(data, st.Fields[i].FieldTag) + s.addConstant(strconv.Itoa(len(data))) + next(s, st.Fields[i].FieldElem) + } + } +} + +func (s *sizeGen) gPtr(p *Ptr) { + s.state = add // inner must use add + s.p.printf("\nif %s == nil {\ns += msgp.NilSize\n} else {", p.Varname()) + next(s, p.Value) + s.state = add // closing block; reset to add + s.p.closeblock() +} + +func (s *sizeGen) gSlice(sl *Slice) { + if !s.p.ok() { + return + } + + s.addConstant(builtinSize(arrayHeader)) + + // if the slice's element is a fixed size + // (e.g. float64, [32]int, etc.), then + // print the length times the element size directly + if str, ok := fixedsizeExpr(sl.Els); ok { + s.addConstant(fmt.Sprintf("(%s * (%s))", lenExpr(sl), str)) + return + } + + // add inside the range block, and immediately after + s.state = add + s.p.rangeBlock(s.ctx, sl.Index, sl.Varname(), s, sl.Els) + s.state = add +} + +func (s *sizeGen) gArray(a *Array) { + if !s.p.ok() { + return + } + + s.addConstant(builtinSize(arrayHeader)) + + // if the array's children are a fixed + // size, we can compile an expression + // that always represents the array's wire size + if str, ok := fixedsizeExpr(a); ok { + s.addConstant(str) + return + } + + s.state = add + s.p.rangeBlock(s.ctx, a.Index, a.Varname(), s, a.Els) + s.state = add +} + +func (s *sizeGen) gMap(m *Map) { + s.addConstant(builtinSize(mapHeader)) + vn := m.Varname() + s.p.printf("\nif %s != nil {", vn) + s.p.printf("\nfor %s, %s := range %s {", m.Keyidx, m.Validx, vn) + s.p.printf("\n_ = %s", m.Validx) // we may not use the value + s.p.printf("\ns += msgp.StringPrefixSize + len(%s)", m.Keyidx) + s.state = expr + s.ctx.PushVar(m.Keyidx) + next(s, m.Value) + s.ctx.Pop() + s.p.closeblock() + s.p.closeblock() + s.state = add +} + +func (s *sizeGen) gBase(b *BaseElem) { + if !s.p.ok() { + return + } + if b.Convert && b.ShimMode == Convert { + s.state = add + vname := randIdent() + s.p.printf("\nvar %s %s", vname, b.BaseType()) + + // ensure we don't get "unused variable" warnings from outer slice iterations + s.p.printf("\n_ = %s", b.Varname()) + + s.p.printf("\ns += %s", basesizeExpr(b.Value, vname, b.BaseName())) + s.state = expr + + } else { + vname := b.Varname() + if b.Convert { + vname = tobaseConvert(b) + } + s.addConstant(basesizeExpr(b.Value, vname, b.BaseName())) + } +} + +// returns "len(slice)" +func lenExpr(sl *Slice) string { + return "len(" + sl.Varname() + ")" +} + +// is a given primitive always the same (max) +// size on the wire? +func fixedSize(p Primitive) bool { + switch p { + case Intf, Ext, IDENT, Bytes, String: + return false + default: + return true + } +} + +// strip reference from string +func stripRef(s string) string { + if s[0] == '&' { + return s[1:] + } + return s +} + +// return a fixed-size expression, if possible. +// only possible for *BaseElem and *Array. +// returns (expr, ok) +func fixedsizeExpr(e Elem) (string, bool) { + switch e := e.(type) { + case *Array: + if str, ok := fixedsizeExpr(e.Els); ok { + return fmt.Sprintf("(%s * (%s))", e.Size, str), true + } + case *BaseElem: + if fixedSize(e.Value) { + return builtinSize(e.BaseName()), true + } + case *Struct: + var str string + for _, f := range e.Fields { + if fs, ok := fixedsizeExpr(f.FieldElem); ok { + if str == "" { + str = fs + } else { + str += "+" + fs + } + } else { + return "", false + } + } + var hdrlen int + mhdr := msgp.AppendMapHeader(nil, uint32(len(e.Fields))) + hdrlen += len(mhdr) + var strbody []byte + for _, f := range e.Fields { + strbody = msgp.AppendString(strbody[:0], f.FieldTag) + hdrlen += len(strbody) + } + return fmt.Sprintf("%d + %s", hdrlen, str), true + } + return "", false +} + +// print size expression of a variable name +func basesizeExpr(value Primitive, vname, basename string) string { + switch value { + case Ext: + return "msgp.ExtensionPrefixSize + " + stripRef(vname) + ".Len()" + case Intf: + return "msgp.GuessSize(" + vname + ")" + case IDENT: + return vname + ".Msgsize()" + case Bytes: + return "msgp.BytesPrefixSize + len(" + vname + ")" + case String: + return "msgp.StringPrefixSize + len(" + vname + ")" + default: + return builtinSize(basename) + } +} diff --git a/vendor/github.com/tinylib/msgp/gen/spec.go b/vendor/github.com/tinylib/msgp/gen/spec.go new file mode 100644 index 0000000000..f3d5818b1d --- /dev/null +++ b/vendor/github.com/tinylib/msgp/gen/spec.go @@ -0,0 +1,519 @@ +package gen + +import ( + "bytes" + "fmt" + "io" +) + +const ( + lenAsUint32 = "uint32(len(%s))" + literalFmt = "%s" + intFmt = "%d" + quotedFmt = `"%s"` + mapHeader = "MapHeader" + arrayHeader = "ArrayHeader" + mapKey = "MapKeyPtr" + stringTyp = "String" + u32 = "uint32" +) + +// Method is a bitfield representing something that the +// generator knows how to print. +type Method uint8 + +// are the bits in 'f' set in 'm'? +func (m Method) isset(f Method) bool { return (m&f == f) } + +// String implements fmt.Stringer +func (m Method) String() string { + switch m { + case 0, invalidmeth: + return "" + case Decode: + return "decode" + case Encode: + return "encode" + case Marshal: + return "marshal" + case Unmarshal: + return "unmarshal" + case Size: + return "size" + case Test: + return "test" + default: + // return e.g. "decode+encode+test" + modes := [...]Method{Decode, Encode, Marshal, Unmarshal, Size, Test} + any := false + nm := "" + for _, mm := range modes { + if m.isset(mm) { + if any { + nm += "+" + mm.String() + } else { + nm += mm.String() + any = true + } + } + } + return nm + + } +} + +func strtoMeth(s string) Method { + switch s { + case "encode": + return Encode + case "decode": + return Decode + case "marshal": + return Marshal + case "unmarshal": + return Unmarshal + case "size": + return Size + case "test": + return Test + default: + return 0 + } +} + +const ( + Decode Method = 1 << iota // msgp.Decodable + Encode // msgp.Encodable + Marshal // msgp.Marshaler + Unmarshal // msgp.Unmarshaler + Size // msgp.Sizer + Test // generate tests + invalidmeth // this isn't a method + encodetest = Encode | Decode | Test // tests for Encodable and Decodable + marshaltest = Marshal | Unmarshal | Test // tests for Marshaler and Unmarshaler +) + +type Printer struct { + gens []generator +} + +func NewPrinter(m Method, out io.Writer, tests io.Writer) *Printer { + if m.isset(Test) && tests == nil { + panic("cannot print tests with 'nil' tests argument!") + } + gens := make([]generator, 0, 7) + if m.isset(Decode) { + gens = append(gens, decode(out)) + } + if m.isset(Encode) { + gens = append(gens, encode(out)) + } + if m.isset(Marshal) { + gens = append(gens, marshal(out)) + } + if m.isset(Unmarshal) { + gens = append(gens, unmarshal(out)) + } + if m.isset(Size) { + gens = append(gens, sizes(out)) + } + if m.isset(marshaltest) { + gens = append(gens, mtest(tests)) + } + if m.isset(encodetest) { + gens = append(gens, etest(tests)) + } + if len(gens) == 0 { + panic("NewPrinter called with invalid method flags") + } + return &Printer{gens: gens} +} + +// TransformPass is a pass that transforms individual +// elements. (Note that if the returned is different from +// the argument, it should not point to the same objects.) +type TransformPass func(Elem) Elem + +// IgnoreTypename is a pass that just ignores +// types of a given name. +func IgnoreTypename(name string) TransformPass { + return func(e Elem) Elem { + if e.TypeName() == name { + return nil + } + return e + } +} + +// ApplyDirective applies a directive to a named pass +// and all of its dependents. +func (p *Printer) ApplyDirective(pass Method, t TransformPass) { + for _, g := range p.gens { + if g.Method().isset(pass) { + g.Add(t) + } + } +} + +// Print prints an Elem. +func (p *Printer) Print(e Elem) error { + for _, g := range p.gens { + // Elem.SetVarname() is called before the Print() step in parse.FileSet.PrintTo(). + // Elem.SetVarname() generates identifiers as it walks the Elem. This can cause + // collisions between idents created during SetVarname and idents created during Print, + // hence the separate prefixes. + resetIdent("zb") + err := g.Execute(e) + resetIdent("za") + + if err != nil { + return err + } + } + return nil +} + +type contextItem interface { + Arg() string +} + +type contextString string + +func (c contextString) Arg() string { + return fmt.Sprintf("%q", c) +} + +type contextVar string + +func (c contextVar) Arg() string { + return string(c) +} + +type Context struct { + path []contextItem +} + +func (c *Context) PushString(s string) { + c.path = append(c.path, contextString(s)) +} + +func (c *Context) PushVar(s string) { + c.path = append(c.path, contextVar(s)) +} + +func (c *Context) Pop() { + c.path = c.path[:len(c.path)-1] +} + +func (c *Context) ArgsStr() string { + var out string + for idx, p := range c.path { + if idx > 0 { + out += ", " + } + out += p.Arg() + } + return out +} + +// generator is the interface through +// which code is generated. +type generator interface { + Method() Method + Add(p TransformPass) + Execute(Elem) error // execute writes the method for the provided object. +} + +type passes []TransformPass + +func (p *passes) Add(t TransformPass) { + *p = append(*p, t) +} + +func (p *passes) applyall(e Elem) Elem { + for _, t := range *p { + e = t(e) + if e == nil { + return nil + } + } + return e +} + +type traversal interface { + gMap(*Map) + gSlice(*Slice) + gArray(*Array) + gPtr(*Ptr) + gBase(*BaseElem) + gStruct(*Struct) +} + +// type-switch dispatch to the correct +// method given the type of 'e' +func next(t traversal, e Elem) { + switch e := e.(type) { + case *Map: + t.gMap(e) + case *Struct: + t.gStruct(e) + case *Slice: + t.gSlice(e) + case *Array: + t.gArray(e) + case *Ptr: + t.gPtr(e) + case *BaseElem: + t.gBase(e) + default: + panic("bad element type") + } +} + +// possibly-immutable method receiver +func imutMethodReceiver(p Elem) string { + switch e := p.(type) { + case *Struct: + // TODO(HACK): actually do real math here. + if len(e.Fields) <= 3 { + for i := range e.Fields { + if be, ok := e.Fields[i].FieldElem.(*BaseElem); !ok || (be.Value == IDENT || be.Value == Bytes) { + goto nope + } + } + return p.TypeName() + } + nope: + return "*" + p.TypeName() + + // gets dereferenced automatically + case *Array: + return "*" + p.TypeName() + + // everything else can be + // by-value. + default: + return p.TypeName() + } +} + +// if necessary, wraps a type +// so that its method receiver +// is of the write type. +func methodReceiver(p Elem) string { + switch p.(type) { + + // structs and arrays are + // dereferenced automatically, + // so no need to alter varname + case *Struct, *Array: + return "*" + p.TypeName() + // set variable name to + // *varname + default: + p.SetVarname("(*" + p.Varname() + ")") + return "*" + p.TypeName() + } +} + +func unsetReceiver(p Elem) { + switch p.(type) { + case *Struct, *Array: + default: + p.SetVarname("z") + } +} + +// shared utility for generators +type printer struct { + w io.Writer + err error +} + +// writes "var {{name}} {{typ}};" +func (p *printer) declare(name string, typ string) { + p.printf("\nvar %s %s", name, typ) +} + +// does: +// +// if m == nil { +// m = make(type, size) +// } else if len(m) > 0 { +// for key := range m { delete(m, key) } +// } +// +func (p *printer) resizeMap(size string, m *Map) { + vn := m.Varname() + if !p.ok() { + return + } + p.printf("\nif %s == nil {", vn) + p.printf("\n%s = make(%s, %s)", vn, m.TypeName(), size) + p.printf("\n} else if len(%s) > 0 {", vn) + p.clearMap(vn) + p.closeblock() +} + +// assign key to value based on varnames +func (p *printer) mapAssign(m *Map) { + if !p.ok() { + return + } + p.printf("\n%s[%s] = %s", m.Varname(), m.Keyidx, m.Validx) +} + +// clear map keys +func (p *printer) clearMap(name string) { + p.printf("\nfor key := range %[1]s { delete(%[1]s, key) }", name) +} + +func (p *printer) wrapErrCheck(ctx string) { + p.print("\nif err != nil {") + p.printf("\nerr = msgp.WrapError(err, %s)", ctx) + p.printf("\nreturn") + p.print("\n}") +} + +func (p *printer) resizeSlice(size string, s *Slice) { + p.printf("\nif cap(%[1]s) >= int(%[2]s) { %[1]s = (%[1]s)[:%[2]s] } else { %[1]s = make(%[3]s, %[2]s) }", s.Varname(), size, s.TypeName()) +} + +func (p *printer) arrayCheck(want string, got string) { + p.printf("\nif %[1]s != %[2]s { err = msgp.ArrayError{Wanted: %[2]s, Got: %[1]s}; return }", got, want) +} + +func (p *printer) closeblock() { p.print("\n}") } + +// does: +// +// for idx := range iter { +// {{generate inner}} +// } +// +func (p *printer) rangeBlock(ctx *Context, idx string, iter string, t traversal, inner Elem) { + ctx.PushVar(idx) + p.printf("\n for %s := range %s {", idx, iter) + next(t, inner) + p.closeblock() + ctx.Pop() +} + +func (p *printer) nakedReturn() { + if p.ok() { + p.print("\nreturn\n}\n") + } +} + +func (p *printer) comment(s string) { + p.print("\n// " + s) +} + +func (p *printer) printf(format string, args ...interface{}) { + if p.err == nil { + _, p.err = fmt.Fprintf(p.w, format, args...) + } +} + +func (p *printer) print(format string) { + if p.err == nil { + _, p.err = io.WriteString(p.w, format) + } +} + +func (p *printer) initPtr(pt *Ptr) { + if pt.Needsinit() { + vname := pt.Varname() + p.printf("\nif %s == nil { %s = new(%s); }", vname, vname, pt.Value.TypeName()) + } +} + +func (p *printer) ok() bool { return p.err == nil } + +func tobaseConvert(b *BaseElem) string { + return b.ToBase() + "(" + b.Varname() + ")" +} + +func (p *printer) varWriteMapHeader(receiver string, sizeVarname string, maxSize int) { + if maxSize <= 15 { + p.printf("\nerr = %s.Append(0x80 | uint8(%s))", receiver, sizeVarname) + } else { + p.printf("\nerr = %s.WriteMapHeader(%s)", receiver, sizeVarname) + } +} + +func (p *printer) varAppendMapHeader(sliceVarname string, sizeVarname string, maxSize int) { + if maxSize <= 15 { + p.printf("\n%s = append(%s, 0x80 | uint8(%s))", sliceVarname, sliceVarname, sizeVarname) + } else { + p.printf("\n%s = msgp.AppendMapHeader(%s, %s)", sliceVarname, sliceVarname, sizeVarname) + } +} + +// bmask is a bitmask of a the specified number of bits +type bmask struct { + bitlen int + varname string +} + +// typeDecl returns the variable declaration as a var statement +func (b *bmask) typeDecl() string { + return fmt.Sprintf("var %s %s /* %d bits */", b.varname, b.typeName(), b.bitlen) +} + +// typeName returns the type, e.g. "uint8" or "[2]uint64" +func (b *bmask) typeName() string { + + if b.bitlen <= 8 { + return "uint8" + } + if b.bitlen <= 16 { + return "uint16" + } + if b.bitlen <= 32 { + return "uint32" + } + if b.bitlen <= 64 { + return "uint64" + } + + return fmt.Sprintf("[%d]uint64", (b.bitlen+64-1)/64) +} + +// readExpr returns the expression to read from a position in the bitmask. +// Compare ==0 for false or !=0 for true. +func (b *bmask) readExpr(bitoffset int) string { + + if bitoffset < 0 || bitoffset >= b.bitlen { + panic(fmt.Errorf("bitoffset %d out of range for bitlen %d", bitoffset, b.bitlen)) + } + + var buf bytes.Buffer + buf.Grow(len(b.varname) + 16) + buf.WriteByte('(') + buf.WriteString(b.varname) + if b.bitlen > 64 { + fmt.Fprintf(&buf, "[%d]", (bitoffset / 64)) + } + buf.WriteByte('&') + fmt.Fprintf(&buf, "0x%X", (uint64(1) << (uint64(bitoffset) % 64))) + buf.WriteByte(')') + + return buf.String() + +} + +// setStmt returns the statement to set the specified bit in the bitmask. +func (b *bmask) setStmt(bitoffset int) string { + + var buf bytes.Buffer + buf.Grow(len(b.varname) + 16) + buf.WriteString(b.varname) + if b.bitlen > 64 { + fmt.Fprintf(&buf, "[%d]", (bitoffset / 64)) + } + fmt.Fprintf(&buf, " |= 0x%X", (uint64(1) << (uint64(bitoffset) % 64))) + + return buf.String() + +} diff --git a/vendor/github.com/tinylib/msgp/gen/testgen.go b/vendor/github.com/tinylib/msgp/gen/testgen.go new file mode 100644 index 0000000000..a80151bc5f --- /dev/null +++ b/vendor/github.com/tinylib/msgp/gen/testgen.go @@ -0,0 +1,182 @@ +package gen + +import ( + "io" + "text/template" +) + +var ( + marshalTestTempl = template.New("MarshalTest") + encodeTestTempl = template.New("EncodeTest") +) + +// TODO(philhofer): +// for simplicity's sake, right now +// we can only generate tests for types +// that can be initialized with the +// "Type{}" syntax. +// we should support all the types. + +func mtest(w io.Writer) *mtestGen { + return &mtestGen{w: w} +} + +type mtestGen struct { + passes + w io.Writer +} + +func (m *mtestGen) Execute(p Elem) error { + p = m.applyall(p) + if p != nil && IsPrintable(p) { + switch p.(type) { + case *Struct, *Array, *Slice, *Map: + return marshalTestTempl.Execute(m.w, p) + } + } + return nil +} + +func (m *mtestGen) Method() Method { return marshaltest } + +type etestGen struct { + passes + w io.Writer +} + +func etest(w io.Writer) *etestGen { + return &etestGen{w: w} +} + +func (e *etestGen) Execute(p Elem) error { + p = e.applyall(p) + if p != nil && IsPrintable(p) { + switch p.(type) { + case *Struct, *Array, *Slice, *Map: + return encodeTestTempl.Execute(e.w, p) + } + } + return nil +} + +func (e *etestGen) Method() Method { return encodetest } + +func init() { + template.Must(marshalTestTempl.Parse(`func TestMarshalUnmarshal{{.TypeName}}(t *testing.T) { + v := {{.TypeName}}{} + bts, err := v.MarshalMsg(nil) + if err != nil { + t.Fatal(err) + } + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func BenchmarkMarshalMsg{{.TypeName}}(b *testing.B) { + v := {{.TypeName}}{} + b.ReportAllocs() + b.ResetTimer() + for i:=0; i m { + t.Log("WARNING: TestEncodeDecode{{.TypeName}} Msgsize() is inaccurate") + } + + vn := {{.TypeName}}{} + err := msgp.Decode(&buf, &vn) + if err != nil { + t.Error(err) + } + + buf.Reset() + msgp.Encode(&buf, &v) + err = msgp.NewReader(&buf).Skip() + if err != nil { + t.Error(err) + } +} + +func BenchmarkEncode{{.TypeName}}(b *testing.B) { + v := {{.TypeName}}{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + en := msgp.NewWriter(msgp.Nowhere) + b.ReportAllocs() + b.ResetTimer() + for i:=0; i 0 {", sz) + u.p.printf("\n%s--; field, bts, err = msgp.ReadMapKeyZC(bts)", sz) + u.p.wrapErrCheck(u.ctx.ArgsStr()) + u.p.print("\nswitch msgp.UnsafeString(field) {") + for i := range s.Fields { + if !u.p.ok() { + return + } + u.p.printf("\ncase \"%s\":", s.Fields[i].FieldTag) + u.ctx.PushString(s.Fields[i].FieldName) + next(u, s.Fields[i].FieldElem) + u.ctx.Pop() + } + u.p.print("\ndefault:\nbts, err = msgp.Skip(bts)") + u.p.wrapErrCheck(u.ctx.ArgsStr()) + u.p.print("\n}\n}") // close switch and for loop +} + +func (u *unmarshalGen) gBase(b *BaseElem) { + if !u.p.ok() { + return + } + + refname := b.Varname() // assigned to + lowered := b.Varname() // passed as argument + if b.Convert { + // begin 'tmp' block + refname = randIdent() + lowered = b.ToBase() + "(" + lowered + ")" + u.p.printf("\n{\nvar %s %s", refname, b.BaseType()) + } + + switch b.Value { + case Bytes: + u.p.printf("\n%s, bts, err = msgp.ReadBytesBytes(bts, %s)", refname, lowered) + case Ext: + u.p.printf("\nbts, err = msgp.ReadExtensionBytes(bts, %s)", lowered) + case IDENT: + u.p.printf("\nbts, err = %s.UnmarshalMsg(bts)", lowered) + default: + u.p.printf("\n%s, bts, err = msgp.Read%sBytes(bts)", refname, b.BaseName()) + } + u.p.wrapErrCheck(u.ctx.ArgsStr()) + + if b.Convert { + // close 'tmp' block + if b.ShimMode == Cast { + u.p.printf("\n%s = %s(%s)\n", b.Varname(), b.FromBase(), refname) + } else { + u.p.printf("\n%s, err = %s(%s)", b.Varname(), b.FromBase(), refname) + u.p.wrapErrCheck(u.ctx.ArgsStr()) + } + u.p.printf("}") + } +} + +func (u *unmarshalGen) gArray(a *Array) { + if !u.p.ok() { + return + } + + // special case for [const]byte objects + // see decode.go for symmetry + if be, ok := a.Els.(*BaseElem); ok && be.Value == Byte { + u.p.printf("\nbts, err = msgp.ReadExactBytes(bts, (%s)[:])", a.Varname()) + u.p.wrapErrCheck(u.ctx.ArgsStr()) + return + } + + sz := randIdent() + u.p.declare(sz, u32) + u.assignAndCheck(sz, arrayHeader) + u.p.arrayCheck(coerceArraySize(a.Size), sz) + u.p.rangeBlock(u.ctx, a.Index, a.Varname(), u, a.Els) +} + +func (u *unmarshalGen) gSlice(s *Slice) { + if !u.p.ok() { + return + } + sz := randIdent() + u.p.declare(sz, u32) + u.assignAndCheck(sz, arrayHeader) + u.p.resizeSlice(sz, s) + u.p.rangeBlock(u.ctx, s.Index, s.Varname(), u, s.Els) +} + +func (u *unmarshalGen) gMap(m *Map) { + if !u.p.ok() { + return + } + sz := randIdent() + u.p.declare(sz, u32) + u.assignAndCheck(sz, mapHeader) + + // allocate or clear map + u.p.resizeMap(sz, m) + + // loop and get key,value + u.p.printf("\nfor %s > 0 {", sz) + u.p.printf("\nvar %s string; var %s %s; %s--", m.Keyidx, m.Validx, m.Value.TypeName(), sz) + u.assignAndCheck(m.Keyidx, stringTyp) + u.ctx.PushVar(m.Keyidx) + next(u, m.Value) + u.ctx.Pop() + u.p.mapAssign(m) + u.p.closeblock() +} + +func (u *unmarshalGen) gPtr(p *Ptr) { + u.p.printf("\nif msgp.IsNil(bts) { bts, err = msgp.ReadNilBytes(bts); if err != nil { return }; %s = nil; } else { ", p.Varname()) + u.p.initPtr(p) + next(u, p.Value) + u.p.closeblock() +} diff --git a/vendor/github.com/tinylib/msgp/main.go b/vendor/github.com/tinylib/msgp/main.go new file mode 100644 index 0000000000..4369d739a2 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/main.go @@ -0,0 +1,119 @@ +// msgp is a code generation tool for +// creating methods to serialize and de-serialize +// Go data structures to and from MessagePack. +// +// This package is targeted at the `go generate` tool. +// To use it, include the following directive in a +// go source file with types requiring source generation: +// +// //go:generate msgp +// +// The go generate tool should set the proper environment variables for +// the generator to execute without any command-line flags. However, the +// following options are supported, if you need them: +// +// -o = output file name (default is {input}_gen.go) +// -file = input file name (or directory; default is $GOFILE, which is set by the `go generate` command) +// -io = satisfy the `msgp.Decodable` and `msgp.Encodable` interfaces (default is true) +// -marshal = satisfy the `msgp.Marshaler` and `msgp.Unmarshaler` interfaces (default is true) +// -tests = generate tests and benchmarks (default is true) +// +// For more information, please read README.md, and the wiki at github.com/tinylib/msgp +// +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/tinylib/msgp/gen" + "github.com/tinylib/msgp/parse" + "github.com/tinylib/msgp/printer" + "github.com/ttacon/chalk" +) + +var ( + out = flag.String("o", "", "output file") + file = flag.String("file", "", "input file") + encode = flag.Bool("io", true, "create Encode and Decode methods") + marshal = flag.Bool("marshal", true, "create Marshal and Unmarshal methods") + tests = flag.Bool("tests", true, "create tests and benchmarks") + unexported = flag.Bool("unexported", false, "also process unexported types") +) + +func main() { + flag.Parse() + + // GOFILE is set by go generate + if *file == "" { + *file = os.Getenv("GOFILE") + if *file == "" { + fmt.Println(chalk.Red.Color("No file to parse.")) + os.Exit(1) + } + } + + var mode gen.Method + if *encode { + mode |= (gen.Encode | gen.Decode | gen.Size) + } + if *marshal { + mode |= (gen.Marshal | gen.Unmarshal | gen.Size) + } + if *tests { + mode |= gen.Test + } + + if mode&^gen.Test == 0 { + fmt.Println(chalk.Red.Color("No methods to generate; -io=false && -marshal=false")) + os.Exit(1) + } + + if err := Run(*file, mode, *unexported); err != nil { + fmt.Println(chalk.Red.Color(err.Error())) + os.Exit(1) + } +} + +// Run writes all methods using the associated file or path, e.g. +// +// err := msgp.Run("path/to/myfile.go", gen.Size|gen.Marshal|gen.Unmarshal|gen.Test, false) +// +func Run(gofile string, mode gen.Method, unexported bool) error { + if mode&^gen.Test == 0 { + return nil + } + fmt.Println(chalk.Magenta.Color("======== MessagePack Code Generator =======")) + fmt.Printf(chalk.Magenta.Color(">>> Input: \"%s\"\n"), gofile) + fs, err := parse.File(gofile, unexported) + if err != nil { + return err + } + + if len(fs.Identities) == 0 { + fmt.Println(chalk.Magenta.Color("No types requiring code generation were found!")) + return nil + } + + return printer.PrintFile(newFilename(gofile, fs.Package), fs, mode) +} + +// picks a new file name based on input flags and input filename(s). +func newFilename(old string, pkg string) string { + if *out != "" { + if pre := strings.TrimPrefix(*out, old); len(pre) > 0 && + !strings.HasSuffix(*out, ".go") { + return filepath.Join(old, *out) + } + return *out + } + + if fi, err := os.Stat(old); err == nil && fi.IsDir() { + old = filepath.Join(old, pkg) + } + // new file name is old file name + _gen.go + return strings.TrimSuffix(old, ".go") + "_gen.go" +} diff --git a/vendor/github.com/tinylib/msgp/parse/directives.go b/vendor/github.com/tinylib/msgp/parse/directives.go new file mode 100644 index 0000000000..73e441eff2 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/parse/directives.go @@ -0,0 +1,130 @@ +package parse + +import ( + "fmt" + "go/ast" + "strings" + + "github.com/tinylib/msgp/gen" +) + +const linePrefix = "//msgp:" + +// func(args, fileset) +type directive func([]string, *FileSet) error + +// func(passName, args, printer) +type passDirective func(gen.Method, []string, *gen.Printer) error + +// map of all recognized directives +// +// to add a directive, define a func([]string, *FileSet) error +// and then add it to this list. +var directives = map[string]directive{ + "shim": applyShim, + "ignore": ignore, + "tuple": astuple, +} + +var passDirectives = map[string]passDirective{ + "ignore": passignore, +} + +func passignore(m gen.Method, text []string, p *gen.Printer) error { + pushstate(m.String()) + for _, a := range text { + p.ApplyDirective(m, gen.IgnoreTypename(a)) + infof("ignoring %s\n", a) + } + popstate() + return nil +} + +// find all comment lines that begin with //msgp: +func yieldComments(c []*ast.CommentGroup) []string { + var out []string + for _, cg := range c { + for _, line := range cg.List { + if strings.HasPrefix(line.Text, linePrefix) { + out = append(out, strings.TrimPrefix(line.Text, linePrefix)) + } + } + } + return out +} + +//msgp:shim {Type} as:{Newtype} using:{toFunc/fromFunc} mode:{Mode} +func applyShim(text []string, f *FileSet) error { + if len(text) < 4 || len(text) > 5 { + return fmt.Errorf("shim directive should have 3 or 4 arguments; found %d", len(text)-1) + } + + name := text[1] + be := gen.Ident(strings.TrimPrefix(strings.TrimSpace(text[2]), "as:")) // parse as::{base} + if name[0] == '*' { + name = name[1:] + be.Needsref(true) + } + be.Alias(name) + + usestr := strings.TrimPrefix(strings.TrimSpace(text[3]), "using:") // parse using::{method/method} + + methods := strings.Split(usestr, "/") + if len(methods) != 2 { + return fmt.Errorf("expected 2 using::{} methods; found %d (%q)", len(methods), text[3]) + } + + be.ShimToBase = methods[0] + be.ShimFromBase = methods[1] + + if len(text) == 5 { + modestr := strings.TrimPrefix(strings.TrimSpace(text[4]), "mode:") // parse mode::{mode} + switch modestr { + case "cast": + be.ShimMode = gen.Cast + case "convert": + be.ShimMode = gen.Convert + default: + return fmt.Errorf("invalid shim mode; found %s, expected 'cast' or 'convert", modestr) + } + } + + infof("%s -> %s\n", name, be.Value.String()) + f.findShim(name, be) + + return nil +} + +//msgp:ignore {TypeA} {TypeB}... +func ignore(text []string, f *FileSet) error { + if len(text) < 2 { + return nil + } + for _, item := range text[1:] { + name := strings.TrimSpace(item) + if _, ok := f.Identities[name]; ok { + delete(f.Identities, name) + infof("ignoring %s\n", name) + } + } + return nil +} + +//msgp:tuple {TypeA} {TypeB}... +func astuple(text []string, f *FileSet) error { + if len(text) < 2 { + return nil + } + for _, item := range text[1:] { + name := strings.TrimSpace(item) + if el, ok := f.Identities[name]; ok { + if st, ok := el.(*gen.Struct); ok { + st.AsTuple = true + infoln(name) + } else { + warnf("%s: only structs can be tuples\n", name) + } + } + } + return nil +} diff --git a/vendor/github.com/tinylib/msgp/parse/getast.go b/vendor/github.com/tinylib/msgp/parse/getast.go new file mode 100644 index 0000000000..f9e1d03910 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/parse/getast.go @@ -0,0 +1,617 @@ +package parse + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "reflect" + "sort" + "strings" + + "github.com/tinylib/msgp/gen" + "github.com/ttacon/chalk" +) + +// A FileSet is the in-memory representation of a +// parsed file. +type FileSet struct { + Package string // package name + Specs map[string]ast.Expr // type specs in file + Identities map[string]gen.Elem // processed from specs + Directives []string // raw preprocessor directives + Imports []*ast.ImportSpec // imports +} + +// File parses a file at the relative path +// provided and produces a new *FileSet. +// If you pass in a path to a directory, the entire +// directory will be parsed. +// If unexport is false, only exported identifiers are included in the FileSet. +// If the resulting FileSet would be empty, an error is returned. +func File(name string, unexported bool) (*FileSet, error) { + pushstate(name) + defer popstate() + fs := &FileSet{ + Specs: make(map[string]ast.Expr), + Identities: make(map[string]gen.Elem), + } + + fset := token.NewFileSet() + finfo, err := os.Stat(name) + if err != nil { + return nil, err + } + if finfo.IsDir() { + pkgs, err := parser.ParseDir(fset, name, nil, parser.ParseComments) + if err != nil { + return nil, err + } + if len(pkgs) != 1 { + return nil, fmt.Errorf("multiple packages in directory: %s", name) + } + var one *ast.Package + for _, nm := range pkgs { + one = nm + break + } + fs.Package = one.Name + for _, fl := range one.Files { + pushstate(fl.Name.Name) + fs.Directives = append(fs.Directives, yieldComments(fl.Comments)...) + if !unexported { + ast.FileExports(fl) + } + fs.getTypeSpecs(fl) + popstate() + } + } else { + f, err := parser.ParseFile(fset, name, nil, parser.ParseComments) + if err != nil { + return nil, err + } + fs.Package = f.Name.Name + fs.Directives = yieldComments(f.Comments) + if !unexported { + ast.FileExports(f) + } + fs.getTypeSpecs(f) + } + + if len(fs.Specs) == 0 { + return nil, fmt.Errorf("no definitions in %s", name) + } + + fs.process() + fs.applyDirectives() + fs.propInline() + + return fs, nil +} + +// applyDirectives applies all of the directives that +// are known to the parser. additional method-specific +// directives remain in f.Directives +func (f *FileSet) applyDirectives() { + newdirs := make([]string, 0, len(f.Directives)) + for _, d := range f.Directives { + chunks := strings.Split(d, " ") + if len(chunks) > 0 { + if fn, ok := directives[chunks[0]]; ok { + pushstate(chunks[0]) + err := fn(chunks, f) + if err != nil { + warnln(err.Error()) + } + popstate() + } else { + newdirs = append(newdirs, d) + } + } + } + f.Directives = newdirs +} + +// A linkset is a graph of unresolved +// identities. +// +// Since gen.Ident can only represent +// one level of type indirection (e.g. Foo -> uint8), +// type declarations like `type Foo Bar` +// aren't resolve-able until we've processed +// everything else. +// +// The goal of this dependency resolution +// is to distill the type declaration +// into just one level of indirection. +// In other words, if we have: +// +// type A uint64 +// type B A +// type C B +// type D C +// +// ... then we want to end up +// figuring out that D is just a uint64. +type linkset map[string]*gen.BaseElem + +func (f *FileSet) resolve(ls linkset) { + progress := true + for progress && len(ls) > 0 { + progress = false + for name, elem := range ls { + real, ok := f.Identities[elem.TypeName()] + if ok { + // copy the old type descriptor, + // alias it to the new value, + // and insert it into the resolved + // identities list + progress = true + nt := real.Copy() + nt.Alias(name) + f.Identities[name] = nt + delete(ls, name) + } + } + } + + // what's left can't be resolved + for name, elem := range ls { + warnf("couldn't resolve type %s (%s)\n", name, elem.TypeName()) + } +} + +// process takes the contents of f.Specs and +// uses them to populate f.Identities +func (f *FileSet) process() { + + deferred := make(linkset) +parse: + for name, def := range f.Specs { + pushstate(name) + el := f.parseExpr(def) + if el == nil { + warnln("failed to parse") + popstate() + continue parse + } + // push unresolved identities into + // the graph of links and resolve after + // we've handled every possible named type. + if be, ok := el.(*gen.BaseElem); ok && be.Value == gen.IDENT { + deferred[name] = be + popstate() + continue parse + } + el.Alias(name) + f.Identities[name] = el + popstate() + } + + if len(deferred) > 0 { + f.resolve(deferred) + } +} + +func strToMethod(s string) gen.Method { + switch s { + case "encode": + return gen.Encode + case "decode": + return gen.Decode + case "test": + return gen.Test + case "size": + return gen.Size + case "marshal": + return gen.Marshal + case "unmarshal": + return gen.Unmarshal + default: + return 0 + } +} + +func (f *FileSet) applyDirs(p *gen.Printer) { + // apply directives of the form + // + // //msgp:encode ignore {{TypeName}} + // +loop: + for _, d := range f.Directives { + chunks := strings.Split(d, " ") + if len(chunks) > 1 { + for i := range chunks { + chunks[i] = strings.TrimSpace(chunks[i]) + } + m := strToMethod(chunks[0]) + if m == 0 { + warnf("unknown pass name: %q\n", chunks[0]) + continue loop + } + if fn, ok := passDirectives[chunks[1]]; ok { + pushstate(chunks[1]) + err := fn(m, chunks[2:], p) + if err != nil { + warnf("error applying directive: %s\n", err) + } + popstate() + } else { + warnf("unrecognized directive %q\n", chunks[1]) + } + } else { + warnf("empty directive: %q\n", d) + } + } +} + +func (f *FileSet) PrintTo(p *gen.Printer) error { + f.applyDirs(p) + names := make([]string, 0, len(f.Identities)) + for name := range f.Identities { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + el := f.Identities[name] + el.SetVarname("z") + pushstate(el.TypeName()) + err := p.Print(el) + popstate() + if err != nil { + return err + } + } + return nil +} + +// getTypeSpecs extracts all of the *ast.TypeSpecs in the file +// into fs.Identities, but does not set the actual element +func (fs *FileSet) getTypeSpecs(f *ast.File) { + + // collect all imports... + fs.Imports = append(fs.Imports, f.Imports...) + + // check all declarations... + for i := range f.Decls { + + // for GenDecls... + if g, ok := f.Decls[i].(*ast.GenDecl); ok { + + // and check the specs... + for _, s := range g.Specs { + + // for ast.TypeSpecs.... + if ts, ok := s.(*ast.TypeSpec); ok { + switch ts.Type.(type) { + + // this is the list of parse-able + // type specs + case *ast.StructType, + *ast.ArrayType, + *ast.StarExpr, + *ast.MapType, + *ast.Ident: + fs.Specs[ts.Name.Name] = ts.Type + + } + } + } + } + } +} + +func fieldName(f *ast.Field) string { + switch len(f.Names) { + case 0: + return stringify(f.Type) + case 1: + return f.Names[0].Name + default: + return f.Names[0].Name + " (and others)" + } +} + +func (fs *FileSet) parseFieldList(fl *ast.FieldList) []gen.StructField { + if fl == nil || fl.NumFields() == 0 { + return nil + } + out := make([]gen.StructField, 0, fl.NumFields()) + for _, field := range fl.List { + pushstate(fieldName(field)) + fds := fs.getField(field) + if len(fds) > 0 { + out = append(out, fds...) + } else { + warnln("ignored.") + } + popstate() + } + return out +} + +// translate *ast.Field into []gen.StructField +func (fs *FileSet) getField(f *ast.Field) []gen.StructField { + sf := make([]gen.StructField, 1) + var extension, flatten bool + // parse tag; otherwise field name is field tag + if f.Tag != nil { + body := reflect.StructTag(strings.Trim(f.Tag.Value, "`")).Get("msg") + if body == "" { + body = reflect.StructTag(strings.Trim(f.Tag.Value, "`")).Get("msgpack") + } + tags := strings.Split(body, ",") + if len(tags) >= 2 { + switch tags[1] { + case "extension": + extension = true + case "flatten": + flatten = true + } + } + // ignore "-" fields + if tags[0] == "-" { + return nil + } + sf[0].FieldTag = tags[0] + sf[0].FieldTagParts = tags + sf[0].RawTag = f.Tag.Value + } + + ex := fs.parseExpr(f.Type) + if ex == nil { + return nil + } + + // parse field name + switch len(f.Names) { + case 0: + if flatten { + return fs.getFieldsFromEmbeddedStruct(f.Type) + } else { + sf[0].FieldName = embedded(f.Type) + } + case 1: + sf[0].FieldName = f.Names[0].Name + default: + // this is for a multiple in-line declaration, + // e.g. type A struct { One, Two int } + sf = sf[0:0] + for _, nm := range f.Names { + sf = append(sf, gen.StructField{ + FieldTag: nm.Name, + FieldName: nm.Name, + FieldElem: ex.Copy(), + }) + } + return sf + } + sf[0].FieldElem = ex + if sf[0].FieldTag == "" { + sf[0].FieldTag = sf[0].FieldName + sf[0].FieldTagParts = []string{sf[0].FieldName} + } + + // validate extension + if extension { + switch ex := ex.(type) { + case *gen.Ptr: + if b, ok := ex.Value.(*gen.BaseElem); ok { + b.Value = gen.Ext + } else { + warnln("couldn't cast to extension.") + return nil + } + case *gen.BaseElem: + ex.Value = gen.Ext + default: + warnln("couldn't cast to extension.") + return nil + } + } + return sf +} + +func (fs *FileSet) getFieldsFromEmbeddedStruct(f ast.Expr) []gen.StructField { + switch f := f.(type) { + case *ast.Ident: + s := fs.Specs[f.Name] + switch s := s.(type) { + case *ast.StructType: + return fs.parseFieldList(s.Fields) + default: + return nil + } + default: + // other possibilities are disallowed + return nil + } +} + +// extract embedded field name +// +// so, for a struct like +// +// type A struct { +// io.Writer +// } +// +// we want "Writer" +func embedded(f ast.Expr) string { + switch f := f.(type) { + case *ast.Ident: + return f.Name + case *ast.StarExpr: + return embedded(f.X) + case *ast.SelectorExpr: + return f.Sel.Name + default: + // other possibilities are disallowed + return "" + } +} + +// stringify a field type name +func stringify(e ast.Expr) string { + switch e := e.(type) { + case *ast.Ident: + return e.Name + case *ast.StarExpr: + return "*" + stringify(e.X) + case *ast.SelectorExpr: + return stringify(e.X) + "." + e.Sel.Name + case *ast.ArrayType: + if e.Len == nil { + return "[]" + stringify(e.Elt) + } + return fmt.Sprintf("[%s]%s", stringify(e.Len), stringify(e.Elt)) + case *ast.InterfaceType: + if e.Methods == nil || e.Methods.NumFields() == 0 { + return "interface{}" + } + } + return "" +} + +// recursively translate ast.Expr to gen.Elem; nil means type not supported +// expected input types: +// - *ast.MapType (map[T]J) +// - *ast.Ident (name) +// - *ast.ArrayType ([(sz)]T) +// - *ast.StarExpr (*T) +// - *ast.StructType (struct {}) +// - *ast.SelectorExpr (a.B) +// - *ast.InterfaceType (interface {}) +func (fs *FileSet) parseExpr(e ast.Expr) gen.Elem { + switch e := e.(type) { + + case *ast.MapType: + if k, ok := e.Key.(*ast.Ident); ok && k.Name == "string" { + if in := fs.parseExpr(e.Value); in != nil { + return &gen.Map{Value: in} + } + } + return nil + + case *ast.Ident: + b := gen.Ident(e.Name) + + // work to resove this expression + // can be done later, once we've resolved + // everything else. + if b.Value == gen.IDENT { + if _, ok := fs.Specs[e.Name]; !ok { + warnf("non-local identifier: %s\n", e.Name) + } + } + return b + + case *ast.ArrayType: + + // special case for []byte + if e.Len == nil { + if i, ok := e.Elt.(*ast.Ident); ok && i.Name == "byte" { + return &gen.BaseElem{Value: gen.Bytes} + } + } + + // return early if we don't know + // what the slice element type is + els := fs.parseExpr(e.Elt) + if els == nil { + return nil + } + + // array and not a slice + if e.Len != nil { + switch s := e.Len.(type) { + case *ast.BasicLit: + return &gen.Array{ + Size: s.Value, + Els: els, + } + + case *ast.Ident: + return &gen.Array{ + Size: s.String(), + Els: els, + } + + case *ast.SelectorExpr: + return &gen.Array{ + Size: stringify(s), + Els: els, + } + + default: + return nil + } + } + return &gen.Slice{Els: els} + + case *ast.StarExpr: + if v := fs.parseExpr(e.X); v != nil { + return &gen.Ptr{Value: v} + } + return nil + + case *ast.StructType: + return &gen.Struct{Fields: fs.parseFieldList(e.Fields)} + + case *ast.SelectorExpr: + return gen.Ident(stringify(e)) + + case *ast.InterfaceType: + // support `interface{}` + if len(e.Methods.List) == 0 { + return &gen.BaseElem{Value: gen.Intf} + } + return nil + + default: // other types not supported + return nil + } +} + +func infof(s string, v ...interface{}) { + pushstate(s) + fmt.Printf(chalk.Green.Color(strings.Join(logctx, ": ")), v...) + popstate() +} + +func infoln(s string) { + pushstate(s) + fmt.Println(chalk.Green.Color(strings.Join(logctx, ": "))) + popstate() +} + +func warnf(s string, v ...interface{}) { + pushstate(s) + fmt.Printf(chalk.Yellow.Color(strings.Join(logctx, ": ")), v...) + popstate() +} + +func warnln(s string) { + pushstate(s) + fmt.Println(chalk.Yellow.Color(strings.Join(logctx, ": "))) + popstate() +} + +func fatalf(s string, v ...interface{}) { + pushstate(s) + fmt.Printf(chalk.Red.Color(strings.Join(logctx, ": ")), v...) + popstate() +} + +var logctx []string + +// push logging state +func pushstate(s string) { + logctx = append(logctx, s) +} + +// pop logging state +func popstate() { + logctx = logctx[:len(logctx)-1] +} diff --git a/vendor/github.com/tinylib/msgp/parse/inline.go b/vendor/github.com/tinylib/msgp/parse/inline.go new file mode 100644 index 0000000000..469793be3e --- /dev/null +++ b/vendor/github.com/tinylib/msgp/parse/inline.go @@ -0,0 +1,169 @@ +package parse + +import ( + "sort" + + "github.com/tinylib/msgp/gen" +) + +// This file defines when and how we +// propagate type information from +// one type declaration to another. +// After the processing pass, every +// non-primitive type is marshalled/unmarshalled/etc. +// through a function call. Here, we propagate +// the type information into the caller's type +// tree *if* the child type is simple enough. +// +// For example, types like +// +// type A [4]int +// +// will get pushed into parent methods, +// whereas types like +// +// type B [3]map[string]struct{A, B [4]string} +// +// will not. + +// this is an approximate measure +// of the number of children in a node +const maxComplex = 5 + +// begin recursive search for identities with the +// given name and replace them with be +func (f *FileSet) findShim(id string, be *gen.BaseElem) { + for name, el := range f.Identities { + pushstate(name) + switch el := el.(type) { + case *gen.Struct: + for i := range el.Fields { + f.nextShim(&el.Fields[i].FieldElem, id, be) + } + case *gen.Array: + f.nextShim(&el.Els, id, be) + case *gen.Slice: + f.nextShim(&el.Els, id, be) + case *gen.Map: + f.nextShim(&el.Value, id, be) + case *gen.Ptr: + f.nextShim(&el.Value, id, be) + } + popstate() + } + // we'll need this at the top level as well + f.Identities[id] = be +} + +func (f *FileSet) nextShim(ref *gen.Elem, id string, be *gen.BaseElem) { + if (*ref).TypeName() == id { + vn := (*ref).Varname() + *ref = be.Copy() + (*ref).SetVarname(vn) + } else { + switch el := (*ref).(type) { + case *gen.Struct: + for i := range el.Fields { + f.nextShim(&el.Fields[i].FieldElem, id, be) + } + case *gen.Array: + f.nextShim(&el.Els, id, be) + case *gen.Slice: + f.nextShim(&el.Els, id, be) + case *gen.Map: + f.nextShim(&el.Value, id, be) + case *gen.Ptr: + f.nextShim(&el.Value, id, be) + } + } +} + +// propInline identifies and inlines candidates +func (f *FileSet) propInline() { + type gelem struct { + name string + el gen.Elem + } + + all := make([]gelem, 0, len(f.Identities)) + + for name, el := range f.Identities { + all = append(all, gelem{name: name, el: el}) + } + + // make sure we process inlining determinstically: + // start with the least-complex elems; + // use identifier names as a tie-breaker + sort.Slice(all, func(i, j int) bool { + ig, jg := &all[i], &all[j] + ic, jc := ig.el.Complexity(), jg.el.Complexity() + return ic < jc || (ic == jc && ig.name < jg.name) + }) + + for i := range all { + name := all[i].name + pushstate(name) + switch el := all[i].el.(type) { + case *gen.Struct: + for i := range el.Fields { + f.nextInline(&el.Fields[i].FieldElem, name) + } + case *gen.Array: + f.nextInline(&el.Els, name) + case *gen.Slice: + f.nextInline(&el.Els, name) + case *gen.Map: + f.nextInline(&el.Value, name) + case *gen.Ptr: + f.nextInline(&el.Value, name) + } + popstate() + } +} + +const fatalloop = `detected infinite recursion in inlining loop! +Please file a bug at github.com/tinylib/msgp/issues! +Thanks! +` + +func (f *FileSet) nextInline(ref *gen.Elem, root string) { + switch el := (*ref).(type) { + case *gen.BaseElem: + // ensure that we're not inlining + // a type into itself + typ := el.TypeName() + if el.Value == gen.IDENT && typ != root { + if node, ok := f.Identities[typ]; ok && node.Complexity() < maxComplex { + infof("inlining %s\n", typ) + + // This should never happen; it will cause + // infinite recursion. + if node == *ref { + panic(fatalloop) + } + + *ref = node.Copy() + f.nextInline(ref, node.TypeName()) + } else if !ok && !el.Resolved() { + // this is the point at which we're sure that + // we've got a type that isn't a primitive, + // a library builtin, or a processed type + warnf("unresolved identifier: %s\n", typ) + } + } + case *gen.Struct: + for i := range el.Fields { + f.nextInline(&el.Fields[i].FieldElem, root) + } + case *gen.Array: + f.nextInline(&el.Els, root) + case *gen.Slice: + f.nextInline(&el.Els, root) + case *gen.Map: + f.nextInline(&el.Value, root) + case *gen.Ptr: + f.nextInline(&el.Value, root) + default: + panic("bad elem type") + } +} diff --git a/vendor/github.com/tinylib/msgp/printer/print.go b/vendor/github.com/tinylib/msgp/printer/print.go new file mode 100644 index 0000000000..9d1dde4a34 --- /dev/null +++ b/vendor/github.com/tinylib/msgp/printer/print.go @@ -0,0 +1,132 @@ +package printer + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "strings" + + "github.com/tinylib/msgp/gen" + "github.com/tinylib/msgp/parse" + "github.com/ttacon/chalk" + "golang.org/x/tools/imports" +) + +func infof(s string, v ...interface{}) { + fmt.Printf(chalk.Magenta.Color(s), v...) +} + +// PrintFile prints the methods for the provided list +// of elements to the given file name and canonical +// package path. +func PrintFile(file string, f *parse.FileSet, mode gen.Method) error { + out, tests, err := generate(f, mode) + if err != nil { + return err + } + + // we'll run goimports on the main file + // in another goroutine, and run it here + // for the test file. empirically, this + // takes about the same amount of time as + // doing them in serial when GOMAXPROCS=1, + // and faster otherwise. + res := goformat(file, out.Bytes()) + if tests != nil { + testfile := strings.TrimSuffix(file, ".go") + "_test.go" + err = format(testfile, tests.Bytes()) + if err != nil { + return err + } + infof(">>> Wrote and formatted \"%s\"\n", testfile) + } + err = <-res + if err != nil { + return err + } + return nil +} + +func format(file string, data []byte) error { + out, err := imports.Process(file, data, nil) + if err != nil { + return err + } + return ioutil.WriteFile(file, out, 0600) +} + +func goformat(file string, data []byte) <-chan error { + out := make(chan error, 1) + go func(file string, data []byte, end chan error) { + end <- format(file, data) + infof(">>> Wrote and formatted \"%s\"\n", file) + }(file, data, out) + return out +} + +func dedupImports(imp []string) []string { + m := make(map[string]struct{}) + for i := range imp { + m[imp[i]] = struct{}{} + } + r := []string{} + for k := range m { + r = append(r, k) + } + return r +} + +func generate(f *parse.FileSet, mode gen.Method) (*bytes.Buffer, *bytes.Buffer, error) { + outbuf := bytes.NewBuffer(make([]byte, 0, 4096)) + writePkgHeader(outbuf, f.Package) + + myImports := []string{"github.com/tinylib/msgp/msgp"} + for _, imp := range f.Imports { + if imp.Name != nil { + // have an alias, include it. + myImports = append(myImports, imp.Name.Name+` `+imp.Path.Value) + } else { + myImports = append(myImports, imp.Path.Value) + } + } + dedup := dedupImports(myImports) + writeImportHeader(outbuf, dedup...) + + var testbuf *bytes.Buffer + var testwr io.Writer + if mode&gen.Test == gen.Test { + testbuf = bytes.NewBuffer(make([]byte, 0, 4096)) + writePkgHeader(testbuf, f.Package) + if mode&(gen.Encode|gen.Decode) != 0 { + writeImportHeader(testbuf, "bytes", "github.com/tinylib/msgp/msgp", "testing") + } else { + writeImportHeader(testbuf, "github.com/tinylib/msgp/msgp", "testing") + } + testwr = testbuf + } + return outbuf, testbuf, f.PrintTo(gen.NewPrinter(mode, outbuf, testwr)) +} + +func writePkgHeader(b *bytes.Buffer, name string) { + b.WriteString("package ") + b.WriteString(name) + b.WriteByte('\n') + // write generated code marker + // https://github.com/tinylib/msgp/issues/229 + // https://golang.org/s/generatedcode + b.WriteString("// Code generated by github.com/tinylib/msgp DO NOT EDIT.\n\n") +} + +func writeImportHeader(b *bytes.Buffer, imports ...string) { + b.WriteString("import (\n") + for _, im := range imports { + if im[len(im)-1] == '"' { + // support aliased imports + fmt.Fprintf(b, "\t%s\n", im) + } else { + fmt.Fprintf(b, "\t%q\n", im) + } + } + b.WriteString(")\n\n") +} diff --git a/vendor/github.com/ttacon/chalk/.gitignore b/vendor/github.com/ttacon/chalk/.gitignore new file mode 100644 index 0000000000..836562412f --- /dev/null +++ b/vendor/github.com/ttacon/chalk/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/vendor/github.com/ttacon/chalk/LICENSE b/vendor/github.com/ttacon/chalk/LICENSE new file mode 100644 index 0000000000..949ba5de0f --- /dev/null +++ b/vendor/github.com/ttacon/chalk/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Trey Tacon + +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. \ No newline at end of file diff --git a/vendor/github.com/ttacon/chalk/README.md b/vendor/github.com/ttacon/chalk/README.md new file mode 100644 index 0000000000..a85f1d4ae3 --- /dev/null +++ b/vendor/github.com/ttacon/chalk/README.md @@ -0,0 +1,67 @@ +chalk +============= + +Chalk is a go package for styling console/terminal output. + +Check out godoc for some example usage: +http://godoc.org/github.com/ttacon/chalk + +The api is pretty clean, there are default Colors and TextStyles +which can be mixed to create more intense Styles. Styles and Colors +can be printed in normal strings (i.e. ```fmt.Sprintf(chalk.Red)```), but +Styles, Colors and TextStyles are more meant to be used to style specific +text segments (i.e. ```fmt.Println(chalk.Red.Color("this is red")```) or +```fmt.Println(myStyle.Style("this is blue text that is underlined"))```). + +Examples +============= + +There are a few examples in the examples directory if you want to see a very +simplified version of what you can do with chalk. + +The following code: +```go +package main + +import ( + "fmt" + + "github.com/ttacon/chalk" +) + +func main() { + // You can just use colors + fmt.Println(chalk.Red, "Writing in colors", chalk.Cyan, "is so much fun", chalk.Reset) + fmt.Println(chalk.Magenta.Color("You can use colors to color specific phrases")) + + // You can just use text styles + fmt.Println(chalk.Bold.TextStyle("We can have bold text")) + fmt.Println(chalk.Underline.TextStyle("We can have underlined text")) + fmt.Println(chalk.Bold, "But text styles don't work quite like colors :(") + + // Or you can use styles + blueOnWhite := chalk.Blue.NewStyle().WithBackground(chalk.White) + fmt.Printf("%s%s%s\n", blueOnWhite, "And they also have backgrounds!", chalk.Reset) + fmt.Println( + blueOnWhite.Style("You can style strings the same way you can color them!")) + fmt.Println( + blueOnWhite.WithTextStyle(chalk.Bold). + Style("You can mix text styles with colors, too!")) + + // You can also easily make styling functions thanks to go's functional side + lime := chalk.Green.NewStyle(). + WithBackground(chalk.Black). + WithTextStyle(chalk.Bold). + Style + fmt.Println(lime("look at this cool lime text!")) +} + +``` +Outputs +![screenshot](https://raw.githubusercontent.com/ttacon/chalk/master/img/chalk_example.png) + + +WARNING +============= + +This package should be pretty stable (I don't forsee backwards incompatible changes), but I'm not making any promises :) diff --git a/vendor/github.com/ttacon/chalk/chalk.go b/vendor/github.com/ttacon/chalk/chalk.go new file mode 100644 index 0000000000..8003678568 --- /dev/null +++ b/vendor/github.com/ttacon/chalk/chalk.go @@ -0,0 +1,162 @@ +package chalk + +import "fmt" + +// Color represents one of the ANSI color escape codes. +// http://en.wikipedia.org/wiki/ANSI_escape_code#Colors +type Color struct { + value int +} + +// Value returns the individual value for this color +// (Actually it's really just its index in the list +// of color escape codes with the list being +// [black, red, green, yellow, blue, magenta, cyan, white]. +func (c Color) Value() int { + return c.value +} + +// Color colors the foreground of the given string +// (whatever the previous background color was, it is +// left alone). +func (c Color) Color(val string) string { + return fmt.Sprintf("%s%s%s", c, val, ResetColor) +} + +func (c Color) String() string { + return fmt.Sprintf("\u001b[%dm", 30+c.value) +} + +// NewStyle creates a style with a foreground of the +// color we're creating the style from. +func (c Color) NewStyle() Style { + return &style{foreground: c} +} + +type textStyleDemarcation int + +func (t textStyleDemarcation) String() string { + return fmt.Sprintf("\u001b[%dm", t) +} + +// A TextStyle represents the ways we can style the text: +// bold, dim, italic, underline, inverse, hidden or strikethrough. +type TextStyle struct { + start, stop textStyleDemarcation +} + +// TextStyle styles the given string using the desired text style. +func (t TextStyle) TextStyle(val string) string { + if t == emptyTextStyle { + return val + } + return fmt.Sprintf("%s%s%s", t.start, val, t.stop) +} + +// NOTE: this function specifically does not work as desired because +// text styles must be wrapped around the text they are meant to style. +// As such, use TextStyle() or Style.Style() instead. +func (t TextStyle) String() string { + return fmt.Sprintf("%s%s", t.start, t.stop) +} + +// NewStyle creates a style starting with the current TextStyle +// as its text style. +func (t TextStyle) NewStyle() Style { + return &style{textStyle: t} +} + +// A Style is how we want our text to look in the console. +// Consequently, we can set the foreground and background +// to specific colors, we can style specific strings and +// can also use this style in a builder pattern should we +// wish (these will be more useful once styles such as +// italics are supported). +type Style interface { + // Foreground sets the foreground of the style to the specific color. + Foreground(Color) + // Background sets the background of the style to the specific color. + Background(Color) + // Style styles the given string with the current style. + Style(string) string + // WithBackground allows us to set the background in a builder + // pattern style. + WithBackground(Color) Style + // WithForeground allows us to set the foreground in a builder + // pattern style. + WithForeground(Color) Style + // WithStyle allows us to set the text style in a builder pattern + // style. + WithTextStyle(TextStyle) Style + String() string +} + +type style struct { + foreground Color + background Color + textStyle TextStyle +} + +func (s *style) WithBackground(col Color) Style { + s.Background(col) + return s +} + +func (s *style) WithForeground(col Color) Style { + s.Foreground(col) + return s +} + +func (s *style) String() string { + var toReturn string + toReturn = fmt.Sprintf("\u001b[%dm", 40+s.background.Value()) + return toReturn + fmt.Sprintf("\u001b[%dm", 30+s.foreground.Value()) +} + +func (s *style) Style(val string) string { + return fmt.Sprintf("%s%s%s", s, s.textStyle.TextStyle(val), Reset) +} + +func (s *style) Foreground(col Color) { + s.foreground = col +} + +func (s *style) Background(col Color) { + s.background = col +} + +func (s *style) WithTextStyle(textStyle TextStyle) Style { + s.textStyle = textStyle + return s +} + +var ( + // Colors + + Black = Color{0} + Red = Color{1} + Green = Color{2} + Yellow = Color{3} + Blue = Color{4} + Magenta = Color{5} + Cyan = Color{6} + White = Color{7} + ResetColor = Color{9} + + // Text Styles + + Bold = TextStyle{1, 22} + Dim = TextStyle{2, 22} + Italic = TextStyle{3, 23} + Underline = TextStyle{4, 24} + Inverse = TextStyle{7, 27} + Hidden = TextStyle{8, 28} + Strikethrough = TextStyle{9, 29} + + Reset = &style{ + foreground: ResetColor, + background: ResetColor, + } + + emptyTextStyle = TextStyle{} +) diff --git a/vendor/github.com/ttacon/chalk/doc.go b/vendor/github.com/ttacon/chalk/doc.go new file mode 100644 index 0000000000..d5e4e091d8 --- /dev/null +++ b/vendor/github.com/ttacon/chalk/doc.go @@ -0,0 +1,59 @@ +// Package chalk is a package for styling terminal/console output. +// There are three main components: +// +// +// Colors +// +// There are eight default colors: black, red, green, yellow, blue, +// magenta, cyan and white. You can use them in two main ways +// (note the need for the reset color if you don't use Color()): +// +// fmt.Println(chalk.Red, "this is red text", chalk.ResetColor) +// fmt.Println(chalk.Red.Color("this is red text") +// +// +// TextStyles +// +// There are seven default text styles: bold, dim, italic, underline, +// inverse, hidden and strikethrough. Unlike colors, you should only +// really use TextStyles in the following manner: +// +// fmt.Println(chalk.Bold.TextStyle("this is bold text")) +// +// +// Styles +// +// Styles are where all the business really is. Styles can have a +// foreground color, a background color and a text style (sweet!). +// They're also pretty simply to make, you just need a starting point: +// +// blue := chalk.Blue.NewStyle() +// bold := chalk.Bold.NewStyle() +// +// When a color is your starting point for a style, it will be the +// foreground color, when a style is your starting point, well, yeah, +// it's your style's text style. You can also alter a style's foreground, +// background or text style in a builder-esque pattern. +// +// blueOnWhite := blue.WithBackground(chalk.White) +// awesomeness := blueOnWhite.WithTextStyle(chalk.Underline).WithForeground(chalk.Green) +// +// Like both Colors and TextStyles you can style specific segments of text +// with: +// +// fmt.Println(awesomeness.Style("this is so pretty!")) +// +// Like Colors, you can also print styles explicitly, but you'll need to +// reset your console's colors with chalk.Reset if you use them this way: +// +// fmt.Println(awesomeness, "this is so pretty", chalk.Reset) +// +// Be aware though, that this (second) way of using styles will not add the +// text style (as text styles require more specific end codes). So if you want +// to fully utilize styles, use myStyle.Style() (unless you only care about +// print your text with a specific foreground and background, then printing +// the style is awesome too!). +// +// Have fun! +// +package chalk diff --git a/vendor/modules.txt b/vendor/modules.txt index c4c95cb102..db82d76695 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -471,7 +471,14 @@ github.com/throttled/throttled github.com/throttled/throttled/store/memstore # github.com/tinylib/msgp v1.1.2 ## explicit +github.com/tinylib/msgp +github.com/tinylib/msgp/gen github.com/tinylib/msgp/msgp +github.com/tinylib/msgp/parse +github.com/tinylib/msgp/printer +# github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 +## explicit +github.com/ttacon/chalk # github.com/tylerb/graceful v1.2.15 ## explicit github.com/tylerb/graceful