diff --git a/go.mod b/go.mod index 1b90c00e..c39780cb 100644 --- a/go.mod +++ b/go.mod @@ -1,133 +1,127 @@ module github.com/datarhei/core/v16 -go 1.18 +go 1.21 + +toolchain go1.22.1 require ( - github.com/99designs/gqlgen v0.17.36 + github.com/99designs/gqlgen v0.17.45 github.com/Masterminds/semver/v3 v3.2.1 - github.com/adhocore/gronx v1.6.5 + github.com/adhocore/gronx v1.8.1 github.com/andybalholm/brotli v1.1.0 github.com/atrox/haikunatorgo/v2 v2.0.1 - github.com/caddyserver/certmagic v0.19.2 - github.com/casbin/casbin/v2 v2.77.2 + github.com/caddyserver/certmagic v0.20.0 + github.com/casbin/casbin/v2 v2.88.0 github.com/datarhei/core-client-go/v16 v16.11.1-0.20240424105158-86a7f261b92c - github.com/datarhei/gosrt v0.5.4 - github.com/datarhei/joy4 v0.0.0-20230505074825-fde05957445a + github.com/datarhei/gosrt v0.6.0 + github.com/datarhei/joy4 v0.0.0-20240229100136-43bcaf8ef5e7 github.com/fujiwara/shapeio v1.0.0 - github.com/go-playground/validator/v10 v10.15.3 + github.com/go-playground/validator/v10 v10.19.0 github.com/gobwas/glob v0.2.3 github.com/goccy/go-json v0.10.2 - github.com/golang-jwt/jwt/v5 v5.0.0 + github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/gops v0.3.28 - github.com/google/uuid v1.3.1 - github.com/hashicorp/go-hclog v1.5.0 - github.com/hashicorp/raft v1.5.0 - github.com/hashicorp/raft-boltdb/v2 v2.2.2 + github.com/google/uuid v1.6.0 + github.com/hashicorp/go-hclog v1.6.3 + github.com/hashicorp/raft v1.6.1 + github.com/hashicorp/raft-boltdb/v2 v2.3.0 github.com/invopop/jsonschema v0.4.0 github.com/joho/godotenv v1.5.1 - github.com/klauspost/compress v1.16.7 - github.com/klauspost/cpuid/v2 v2.2.5 - github.com/labstack/echo/v4 v4.11.1 + github.com/klauspost/compress v1.17.8 + github.com/klauspost/cpuid/v2 v2.2.7 + github.com/labstack/echo/v4 v4.12.0 github.com/lestrrat-go/strftime v1.0.6 github.com/lithammer/shortuuid/v4 v4.0.0 - github.com/mattn/go-isatty v0.0.19 - github.com/minio/minio-go/v7 v7.0.63 + github.com/mattn/go-isatty v0.0.20 + github.com/minio/minio-go/v7 v7.0.70 github.com/prep/average v0.0.0-20200506183628-d26c465f48c3 - github.com/prometheus/client_golang v1.16.0 + github.com/prometheus/client_golang v1.19.0 github.com/puzpuzpuz/xsync/v3 v3.1.0 - github.com/shirou/gopsutil/v3 v3.23.8 - github.com/stretchr/testify v1.8.4 + github.com/shirou/gopsutil/v3 v3.24.3 + github.com/stretchr/testify v1.9.0 github.com/swaggo/echo-swagger v1.4.1 - github.com/swaggo/swag v1.16.2 - github.com/vektah/gqlparser/v2 v2.5.8 + github.com/swaggo/swag v1.16.3 + github.com/vektah/gqlparser/v2 v2.5.11 github.com/xeipuuv/gojsonschema v1.2.0 - go.etcd.io/bbolt v1.3.7 + go.etcd.io/bbolt v1.3.9 go.uber.org/automaxprocs v1.5.3 - go.uber.org/zap v1.25.0 - golang.org/x/crypto v0.12.0 - golang.org/x/mod v0.12.0 + go.uber.org/zap v1.27.0 + golang.org/x/crypto v0.22.0 + golang.org/x/mod v0.17.0 ) //replace github.com/datarhei/core-client-go/v16 => ../core-client-go require ( - github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/boltdb/bolt v1.3.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/casbin/govaluate v1.1.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.6 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/iancoleman/orderedmap v0.2.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/labstack/gommon v0.4.0 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/libdns/libdns v0.2.1 // indirect - github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect + github.com/labstack/gommon v0.4.2 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/libdns/libdns v0.2.2 // indirect + github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mholt/acmez v1.2.0 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/miekg/dns v1.1.59 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.53.0 // indirect + github.com/prometheus/procfs v0.14.0 // indirect github.com/rs/xid v1.5.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sosodev/duration v1.3.0 // indirect github.com/swaggo/files/v2 v2.0.0 // indirect - github.com/tidwall/gjson v1.16.0 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.1 // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect - github.com/urfave/cli/v2 v2.25.5 // indirect + github.com/tklauser/go-sysconf v0.3.14 // indirect + github.com/tklauser/numcpus v0.8.0 // indirect + github.com/urfave/cli/v2 v2.27.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.14.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.12.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.20.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index f3405cd9..24b8ed00 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,14 @@ -github.com/99designs/gqlgen v0.17.36 h1:u/o/rv2SZ9s5280dyUOOrkpIIkr/7kITMXYD3rkJ9go= -github.com/99designs/gqlgen v0.17.36/go.mod h1:6RdyY8puhCoWAQVr2qzF2OMVfudQzc8ACxzpzluoQm4= -github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik= +github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/adhocore/gronx v1.6.5 h1:/pryEagBKz3WqUgpgvtL51eBN2rJLXowuW7rpS+jrew= -github.com/adhocore/gronx v1.6.5/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= +github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= +github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= +github.com/adhocore/gronx v1.8.1 h1:F2mLTG5sB11z7vplwD4iydz3YCEjstSfYmCrdSm3t6A= +github.com/adhocore/gronx v1.8.1/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -20,14 +19,14 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/atrox/haikunatorgo/v2 v2.0.1 h1:FCVx2KL2YvZtI1rI9WeEHxeLRrKGr0Dd4wfCJiUXupc= github.com/atrox/haikunatorgo/v2 v2.0.1/go.mod h1:BBQmx2o+1Z5poziaHRgddAZKOpijwfKdAmMnSYlFK70= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYhJeJ2aZxADI2tGADS15AzIF8MQ8XAhT4= github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -36,24 +35,26 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/caddyserver/certmagic v0.19.2 h1:HZd1AKLx4592MalEGQS39DKs2ZOAJCEM/xYPMQ2/ui0= -github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8= -github.com/casbin/casbin/v2 v2.77.2 h1:yQinn/w9x8AswiwqwtrXz93VU48R1aYTXdHEx4RI3jM= -github.com/casbin/casbin/v2 v2.77.2/go.mod h1:mzGx0hYW9/ksOSpw3wNjk3NRAroq5VMFYUQ6G43iGPk= +github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc= +github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= +github.com/casbin/casbin/v2 v2.88.0 h1:JFHId/aIFvNvPnTwUP+tTtVAjSh3eidslFzy+5LpSeU= +github.com/casbin/casbin/v2 v2.88.0/go.mod h1:jX8uoN4veP85O/n2674r2qtfSXI6myvxW85f6TH50fw= +github.com/casbin/govaluate v1.1.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= +github.com/casbin/govaluate v1.1.1 h1:J1rFKIBhiC5xr0APd5HP6rDL+xt+BRoyq1pa4o2i/5c= +github.com/casbin/govaluate v1.1.1/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/datarhei/core-client-go/v16 v16.11.1-0.20240424105158-86a7f261b92c h1:RIzMclqmSYwpMZxyW7nLg0XyKjY6prQWcuIdgm97U8o= github.com/datarhei/core-client-go/v16 v16.11.1-0.20240424105158-86a7f261b92c/go.mod h1:7XrUOUlB165Gs8JUE4lzVuNve6HW90Yz3/+lTY2EV4A= -github.com/datarhei/gosrt v0.5.4 h1:dE3mmSB+n1GeviGM8xQAW3+UD3mKeFmd84iefDul5Vs= -github.com/datarhei/gosrt v0.5.4/go.mod h1:MiUCwCG+LzFMzLM/kTA+3wiTtlnkVvGbW/F0XzyhtG8= -github.com/datarhei/joy4 v0.0.0-20230505074825-fde05957445a h1:Tf4DSHY1xruBglr+yYP5Wct7czM86GKMYgbXH8a7OFo= -github.com/datarhei/joy4 v0.0.0-20230505074825-fde05957445a/go.mod h1:Jcw/6jZDQQmPx8A7INEkXmuEF7E9jjBbSTfVSLwmiQw= +github.com/datarhei/gosrt v0.6.0 h1:HrrXAw90V78ok4WMIhX6se1aTHPCn82Sg2hj+PhdmGc= +github.com/datarhei/gosrt v0.6.0/go.mod h1:fsOWdLSHUHShHjgi/46h6wjtdQrtnSdAQFnlas8ONxs= +github.com/datarhei/joy4 v0.0.0-20240229100136-43bcaf8ef5e7 h1:MG5XQMTTDPcuvvRzc1c37QbwgDbYPhKmPFo9gSaPdBE= +github.com/datarhei/joy4 v0.0.0-20240229100136-43bcaf8ef5e7/go.mod h1:Jcw/6jZDQQmPx8A7INEkXmuEF7E9jjBbSTfVSLwmiQw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -63,12 +64,12 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fujiwara/shapeio v1.0.0 h1:xG5D9oNqCSUUbryZ/jQV3cqe1v2suEjwPIcEg1gKM8M= github.com/fujiwara/shapeio v1.0.0/go.mod h1:LmEmu6L/8jetyj1oewewFb7bZCNRwE7wLCUNzDLaLVA= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -78,28 +79,22 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.3 h1:S+sSpunYjNPDuXkWbK+x+bA7iXiW296KG4dL3X7xUZo= -github.com/go-playground/validator/v10 v10.15.3/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= +github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= @@ -110,54 +105,51 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gops v0.3.28 h1:2Xr57tqKAmQYRAfG12E+yLcoa2Y42UJo2lOrUFL9ark= github.com/google/gops v0.3.28/go.mod h1:6f6+Nl8LcHrzJwi8+p0ii+vmBFSlB4f8cOOkTJ7sk4c= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= +github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= -github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= -github.com/hashicorp/raft v1.5.0 h1:uNs9EfJ4FwiArZRxxfd/dQ5d33nV31/CdCHArH89hT8= -github.com/hashicorp/raft v1.5.0/go.mod h1:pKHB2mf/Y25u3AHNSXVRv+yT+WAnmeTX0BwVppVQV+M= -github.com/hashicorp/raft-boltdb v0.0.0-20210409134258-03c10cc3d4ea h1:RxcPJuutPRM8PUOyiweMmkuNO+RJyfy2jds2gfvgNmU= -github.com/hashicorp/raft-boltdb v0.0.0-20210409134258-03c10cc3d4ea/go.mod h1:qRd6nFJYYS6Iqnc/8HcUmko2/2Gw8qTFEmxDLii6W5I= -github.com/hashicorp/raft-boltdb/v2 v2.2.2 h1:rlkPtOllgIcKLxVT4nutqlTH2NRFn+tO1wwZk/4Dxqw= -github.com/hashicorp/raft-boltdb/v2 v2.2.2/go.mod h1:N8YgaZgNJLpZC+h+by7vDu5rzsRgONThTEeUS3zWbfY= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/raft v1.6.1 h1:v/jm5fcYHvVkL0akByAp+IDdDSzCNCGhdO6VdB56HIM= +github.com/hashicorp/raft v1.6.1/go.mod h1:N1sKh6Vn47mrWvEArQgILTyng8GoDRNYlgKyK7PMjs0= +github.com/hashicorp/raft-boltdb v0.0.0-20230125174641-2a8082862702 h1:RLKEcCuKcZ+qp2VlaaZsYZfLOmIiuJNpEi48Rl8u9cQ= +github.com/hashicorp/raft-boltdb v0.0.0-20230125174641-2a8082862702/go.mod h1:nTakvJ4XYq45UXtn0DbwR4aU9ZdjlnIenpbs6Cd+FM0= +github.com/hashicorp/raft-boltdb/v2 v2.3.0 h1:fPpQR1iGEVYjZ2OELvUHX600VAK5qmdnDEv3eXOwZUA= +github.com/hashicorp/raft-boltdb/v2 v2.3.0/go.mod h1:YHukhB04ChJsLHLJEUD6vjFyLX2L3dsX3wPBZcX4tmc= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA= github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= @@ -169,80 +161,66 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= -github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= -github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= -github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= +github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= -github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= -github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= +github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= +github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw7k08o4c= github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= -github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 h1:1KuuSOy4ZNgW0KA2oYIngXVFhQcXxhLqCVK7cBcldkk= +github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= +github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.63 h1:GbZ2oCvaUdgT5640WJOpyDhhDxvknAJU2/T3yurwcbQ= -github.com/minio/minio-go/v7 v7.0.63/go.mod h1:Q6X7Qjb7WMhvG65qKf4gUgA5XaiSox74kR1uAEjxRS4= -github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= -github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/minio/minio-go/v7 v7.0.70 h1:1u9NtMgfK1U42kUxcsl5v0yj6TEOPR497OAQxpJnn2g= +github.com/minio/minio-go/v7 v7.0.70/go.mod h1:4yBA8v80xGA30cfM3fz0DKYMXunWl/AV/6tWEs9ryzo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -253,97 +231,87 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= -github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prep/average v0.0.0-20200506183628-d26c465f48c3 h1:Y7qCvg282QmlyrVQuL2fgGwebuw7zvfnRym09r+dUGc= github.com/prep/average v0.0.0-20200506183628-d26c465f48c3/go.mod h1:0ZE5gcyWKS151WBDIpmLshHY0l+3edpuKnBUWVVbWKk= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= +github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s= +github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ= github.com/puzpuzpuz/xsync/v3 v3.1.0 h1:EewKT7/LNac5SLiEblJeUu8z5eERHrmRLnMQL2d7qX4= github.com/puzpuzpuz/xsync/v3 v3.1.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= -github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= +github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sosodev/duration v1.3.0 h1:g3E6mto+hFdA2uZXeNDYff8LYeg7v5D4YKP/Ng/NUkE= +github.com/sosodev/duration v1.3.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO/TUk= github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc= github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= -github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= -github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= -github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= +github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= +github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc= -github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= +github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/vektah/gqlparser/v2 v2.5.8 h1:pm6WOnGdzFOCfcQo9L3+xzW51mKrlwTEg4Wr7AH1JW4= -github.com/vektah/gqlparser/v2 v2.5.8/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME= +github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= +github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -353,41 +321,41 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -395,41 +363,35 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -441,7 +403,5 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/99designs/gqlgen/.gitignore b/vendor/github.com/99designs/gqlgen/.gitignore index cbc986fb..22af48fb 100644 --- a/vendor/github.com/99designs/gqlgen/.gitignore +++ b/vendor/github.com/99designs/gqlgen/.gitignore @@ -16,3 +16,5 @@ *.out gqlgen *.exe + +node_modules diff --git a/vendor/github.com/99designs/gqlgen/CHANGELOG.md b/vendor/github.com/99designs/gqlgen/CHANGELOG.md index 662377f1..6357842b 100644 --- a/vendor/github.com/99designs/gqlgen/CHANGELOG.md +++ b/vendor/github.com/99designs/gqlgen/CHANGELOG.md @@ -5,10 +5,555 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased](https://github.com/99designs/gqlgen/compare/v0.17.35...HEAD) +## [Unreleased](https://github.com/99designs/gqlgen/compare/v0.17.42...HEAD) + +## [v0.17.42](https://github.com/99designs/gqlgen/compare/v0.17.41...v0.17.42) - 2023-12-29 +- 7bf0c223 release v0.17.42 + +
c811d47e fix: avoid panic from tracing on bad request (#2871) + +This fixes a panic which arises from the tracing components when a request has some defect which results in an error when creating the operation context. The transports consistently handle this by calling `DispatchError(graphql.WithOperationContext(ctx, rc), err)` where `rc` is the OperationContext which was not correctly constructed. This seems dangerous, because middleware may assume that if there in an `OperationContext` in the `context.Context` than they are being invoked on a normal codepath and can assume their other interceptors have been invoked in the normal order. Also, using a value returned by a function which also returned a non-nil error is very unusual. However, I have no idea what the impact of changing that dangerous behavior in the transports would be, so I opted to make the tracing component more resilient instead. + +
+ +- 13bb4152 fix for entity interfce code gen with related test (#2868) + +- 0354649c Remove archived dependency appdash (#2866) + +- 0d43599c Update examples go.mod with appdash replacements (#2863) + +- 7dd971c8 Use defer wg.Done() in FieldSet Dispatch (#2861) + +
24ea195c vikstrous/dataloadgen replaces recommended dataloader package in example docs (#2770) + +* update example for dataloadgen + +* improved example with link to example repo + +* undo unnecessary changes + +* fix wrong signature + +* fix creation of loader + +* Update docs/content/reference/dataloaders.md + +
+ +
42f6e39d Allow fields that return root level definitions (#2858) + +* generate structs for root level definitions to support fields that return Query, Mutation or Subscription + +* removed unnecessary comment + +* re-ran go generate + +--------- + +
+ +- 682a58dd Add go generate for examples so contributors never forget (#2859) + +
e080a96d Modify to prevent unreachable code from occurring (#2846) + +* fix: åž‹ã®æ•°ã§ã‚½ãƒ¼ãƒˆã™ã‚‹å‡¦ç†ã‚’追加 + +* 戻㗠+ +* fix: caseæ–‡ã®æœ€åˆã«ã‚¹ãƒ¼ãƒ‘ãƒ¼ã‚¯ãƒ©ã‚¹ãŒæ¥ãªã„よã†ã«ã™ã‚‹ + +* testdata追加 + +* fix: Added sorting by number of types. +* fix: Prevent superclass from appearing at the beginning of case statement + +
+ +- 68744ad2 Bump changelog + +- e4cf21d2 v0.17.41 postrelease bump + + + + + + +## [v0.17.41](https://github.com/99designs/gqlgen/compare/v0.17.40...v0.17.41) - 2023-12-03 +- fe60938c release v0.17.41 + +
5e98a16a fix fieldset.New bug when prefix slice has len < cap (#2851) + +* fix fieldset.New bug when prefix slice has len < cap + +* ignore gocritic warning + +
+ +
bd9657f3 Improve ResolverImplementer.Implment (#2850) + +* improve resolver implement render + +* add error when multiple implementors + +* add initial test + +
+ +
cb3c1c89 Updated apollo sandbox (#2849) + +Added all supported options to new window.EmbeddedSandbox object + +
+ +
eb5cea72 Small template fix to save space in the generated file (#2841) + +* Small template fix to save space in the generated file + +* Re-generate + + +--------- + +
+ +- c0ca5091 Omittable can now be serialized as json (#2839) + +- dcb76191 fix: sample program indentation (#2840) + +
132ec1ce Updated GraphiQL 3.0.1 => 3.0.6 (#2837) + +* Updated GraphiQL 3.0.1 => 3.0.6 + +* Added unit tests to cover integrity of playgrounds + +* Updated vulnerable dependency + +* Close response body + +
+ +- 91740700 v0.17.40 postrelease bump + + + + + + +## [v0.17.40](https://github.com/99designs/gqlgen/compare/v0.17.39...v0.17.40) - 2023-10-24 +- c5ad14bf release v0.17.40 + +
74e918f9 Map based input types fields are now coerced to the right type (#2830) + +* Input maps now unmarshals and checks nested fields + +* Added unit tests + +* Tested required fields in input maps + +* Docs updated with disclaimer + +* Added test for nested inputs + +
+ +
1e5fa72a Bump [@babel](https://github.com/babel)/traverse from 7.22.5 to 7.23.2 in /integration (#2831) + +- [Release notes](https://github.com/babel/babel/releases) +- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) +- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) + +--- +updated-dependencies: + dependency-type: indirect +... + +
+ +
e5c17d63 resolver: fix case-insensitive file name collision (#2829) + +for compatibility with Windows/Mac OS X, Go does not allow files with +identical case-insensitive names. +this commit changes the key of the 'files' map to use the lower case +file name, keeping the original file name as a property on the File +object. + +
+ +- 9c5fc302 v0.17.39 postrelease bump + + + + + + +## [v0.17.39](https://github.com/99designs/gqlgen/compare/v0.17.38...v0.17.39) - 2023-10-05 +- eed94e8c release v0.17.39 + +
a863d645 Add [@interfaceObject](https://github.com/interfaceObject) and [@composeDirective](https://github.com/composeDirective) at Federation 2 directive lists. (#2821) + +This commit just adding those directives into the list. + +
+ +
3ff523ba Bump postcss from 8.4.24 to 8.4.31 in /integration (#2819) + +Bumps [postcss](https://github.com/postcss/postcss) from 8.4.24 to 8.4.31. +- [Release notes](https://github.com/postcss/postcss/releases) +- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) +- [Commits](https://github.com/postcss/postcss/compare/8.4.24...8.4.31) + +--- +updated-dependencies: +- dependency-name: postcss + dependency-type: indirect +... + +
+ +
59258642 Adding duration scalar conforming to ISO8601 standard (#2800) + +* Adding duration scalar + +* simple Duration scalar docs + +* using MarshalString, to add proper double quotes + +* adding deps and running go mod tidy on _examples + +* Re-organize imports + + +* Fix test now that imports are sorted + + +--------- + +
+ +
37f8e4eb Add ability to not fail when pong is not received. (#2815) + +I also changed how the read deadline set works a little, the reason for +this is that the protocol allows for pong to be sent without a ping. + +So setting a read deadline on receiving pong isn't great. Instead we +should always set the read deadline on sending ping. Though to do this +we need to know whether we have received a pong or not. Because if we +set the read deadline when the previous ping still hasn't received the +pong. Then it will never hit the deadline. + +
+ +
89ac736f Store parsed Schema on ExecutableSchema rather than use global variable (#2811) + +* codegen: executableSchema schema configurable + +* feat + +* feat + +* codegen: add schema property on Config and executableSchema + +* fix: fmt + +* regenerate + + +--------- + +
+ +
919aded6 Add a pong only keep alive for the new protcol (#2814) + +The protocol allows for this and this eliminates the potential for +over-agressive triggers of the read deadline set for using the ping/pong +flow. + +https://github.com/enisdenjo/graphql-ws/blob/50d5a512d0d7252d41c079e6716b884a191b1ddc/PROTOCOL.md#pong + +
+ +- 001c296a Update auto-generated files with latest results. (#2813) + +
f6fa3aae Consider go type name when autobinding (#2812) + +Currently, generated schema type names are normalized, for instance - SomeTYPE in the schema will be generated as SomeType in the model. + +When autobinding, however, we only consider the schema type name when searching for it in the relevant package(s), +thus type names that differ post normalizations aren't auto-bound properly and are instead re-generated. + +This commit suggests a fix where we'd try to autobind for both the schema type name (first, to maintain back compat), or the go type name if the former isn't found. + +
+ +
4e8d8c70 Feature: Support Apollo Federation Auth Directives (#2809) + +* local version working + +* gofmt + +* tabs + +
+ +- 66709d89 feat: update getting-started CreateTodo mutationResolver (#2810) + +
2c9f9c5f fix: CodeGen for omit_slice_element_pointers and GetMany Entity Resolvers (#2802) + +* remove ! from reps definition + +* adding tests + +* fixing tests + +* adding documentation + +* addressing lint + +* commit after go gonerate + +* gofmt + + +--------- + +
+ +
3e2393f3 add close flag into wsConnection to avoid duplicate calls of CloseFunc (#2803) + +* add close flag into wsConnection to avoid duplicate calls of CloseFunc + +* add test + +* Fix linter error + +
+ +
af4d3943 Allow WebsocketInitFunc to add payload to Ack (#4) (#2791) + +* Allow WebsocketInitFunc to add payload to Ack + +The connection ACK message in the protocol for both +graphql-ws and graphql-transport-ws allows for a payload in the +connection ack message. + +We really wanted to use this to establish better telemetry in our use of +websockets in graphql. + +* Fix lint error in test + +* Switch argument ordering. + +--------- + +
+ +- f3b86033 v0.17.38 postrelease bump + + + + + + +## [v0.17.38](https://github.com/99designs/gqlgen/compare/v0.17.37...v0.17.38) - 2023-09-19 +- d9077fac release v0.17.38 + +- 5f452ce2 Update gqlparser to 2.5.10 (#2798) + +- c89860bd refactor: return `null` instead of zero value uuid (#2794) + +- 625ca2e5 Make it possible to pass UI headers (#2793) + +- fceb3311 Fix rand int docs link in Getting Started (#2789) + +- f01d5805 Add new changelog (#2787) + +
9930e574 Ability to use forceGenerate and extraFields together (#2788) + +* Ability to user forceGenerate and extraFields together + +* Some docs for forceGenerate added + +--------- + +
+ +- f90ac05e v0.17.37 postrelease bump + + + + + + +## [v0.17.37](https://github.com/99designs/gqlgen/compare/v0.17.36...v0.17.37) - 2023-09-08 +- ccae370e release v0.17.37 + +- 6505f8be Update gqlparser (#2785) + +
153ec470 add uuid type (#2751) (closes #2749) + +* add uuid type + +* add uuid example + +* add uuid scalar doc + +* strconv.Quote + +* Apply suggestions from code review + +* fix + + + +--------- + +
+ +
fa471180 ForceGenerate parameter to [@goModel](https://github.com/goModel) added. (#2780) + +* forceGenerate to docs added + +--------- + +
+ +
11bb9b18 codegen: add support for `go_build_tags` option in gqlgen.yaml (#2784) + +* codegen: support go_build_tags option in gqlgen.yaml + +* chore: added test + +* docs/content: update config example + +* chore: more comment + +
+ +
bee47dcf fix flaky test TestSubscriptions (#2779) + +* fix flaky test TestSubscriptions + +* update other copy of the test + +
+ +- a41f4daa docs: short-lived loader (#2778) + +- cc4e0ba2 ensure HasOperationContext checks for nil (#2776) + +
a1ca2204 fix typo in TESTING.md server path (#2774) + +following TESTING.md instructions, I got an error: +"stat ./server/server.go: no such file or directory" + +server.go path is: integration/server/cmd/integration/server.go + +
+ +
1cde8c3f return internal types in schema introspection (#2773) + +according to graphql spec: +``` +types: return the set of all named types contained within this schema. +Any named type which can be found through a field of any introspection type must be included in this set. +``` +source: https://github.com/graphql/graphql-spec/blob/main/spec/Section%204%20--%20Introspection.md#the-__schema-type + +some clients libs (like HotChocolate for C#) depends on this behavior. + +
+ +- 065aea3e Fix gqlgen truncates tag value with colon (#2759) + +- d6270e4f Update subsciptions documentation to correctly close channel (#2753) + +- 2d8673a6 Add Model references to Interface (#2738) + +- 790d7a75 Allow GraphiQL headers to be set when creating the playground handler (#2740) (closes #2739) + +- 0eb95dc4 v0.17.36 postrelease bump + + + + + + +## [v0.17.36](https://github.com/99designs/gqlgen/compare/v0.17.35...v0.17.36) - 2023-07-27 +- bd6cfd31 release v0.17.36 + +
60ec0d86 Fix plugin template resolution (#2733) (closes #2262) + +- According to the documentation comment for [templates.Options], if the + `Template` and `TemplateFS` fields are empty, it `Render` should find + the `.gotpl` files from the calling plugin. However, it looks like + helper function. This results in broken behavior in consumers such as + [infiotinc/gqlgenc](https://github.com/infiotinc/gqlgenc) when they + use the latest version of `gqlgen` as instead of finding the template + from the plugin, the test template from this package is used which + outputs only: `this is my test package`. +- The cause for this is that `runtime.Caller` was still only skipping + one stack level which means that it was finding the `Render` function + instead of its caller. + +
+ +- 76d444c1 Make models configurable via template (#2730) + +- abe3ffde Don't set the package variable for the new Resolver Template (#2725) + +
febf9566 Make the resolver implementation configurable via a new template resolver.gotpl (#2720) + +* Make an optional resolver.gotpl ResolverTemplate to implement a custom resolver + +* Add test + +* Add documetation for the new resolver option + +* Change the tab to spaces + +* remove unecessary test assertion :/ + +
+ +
bda30260 Fixed Data Loader docs (#2723) + +Also updated to v7 + +
+ +
16c9eb64 Fix docs (#2722) + +* docs: fix variable names in dataloader sample + +* fix: request-scoped middleware + +
+ +
b233a01b docs: update dataloader docs (#2719) + +* docs: update example + +* docs: update example + +* fix: import + +
+ +- cccc7389 Added go mod tidy to quick start guide (#2718) (closes #2717, #2651, #2641, #2614, #2576) + +- 9adc7b81 Update gqlparser to v2.5.8 (#2716) + +- b442fbf4 Post v0.17.35 changelog update + +- 57c12199 v0.17.35 postrelease bump + + + + + ## [v0.17.35](https://github.com/99designs/gqlgen/compare/v0.17.34...v0.17.35) - 2023-07-15 - 05006bf1 release v0.17.35 diff --git a/vendor/github.com/99designs/gqlgen/README.md b/vendor/github.com/99designs/gqlgen/README.md index b11ab553..34656595 100644 --- a/vendor/github.com/99designs/gqlgen/README.md +++ b/vendor/github.com/99designs/gqlgen/README.md @@ -86,7 +86,7 @@ models: - #### Using Explicit Resolvers -If you want to Keep using the generated model, mark the field as requiring a resolver explicitly in `gqlgen.yml` like this: +If you want to keep using the generated model, mark the field as requiring a resolver explicitly in `gqlgen.yml` like this: ```yaml # gqlgen.yml diff --git a/vendor/github.com/99designs/gqlgen/TESTING.md b/vendor/github.com/99designs/gqlgen/TESTING.md index b8adadd6..2677b33e 100644 --- a/vendor/github.com/99designs/gqlgen/TESTING.md +++ b/vendor/github.com/99designs/gqlgen/TESTING.md @@ -25,7 +25,7 @@ Setting up the integration environment is a little tricky: ```bash cd integration go generate ./... -go run ./server/server.go +go run ./server/cmd/integration/server.go ``` in another terminal ```bash diff --git a/vendor/github.com/99designs/gqlgen/api/generate.go b/vendor/github.com/99designs/gqlgen/api/generate.go index 8aecc4ca..8193f2fb 100644 --- a/vendor/github.com/99designs/gqlgen/api/generate.go +++ b/vendor/github.com/99designs/gqlgen/api/generate.go @@ -27,14 +27,18 @@ func Generate(cfg *config.Config, option ...Option) error { if cfg.Federation.IsDefined() { if cfg.Federation.Version == 0 { // default to using the user's choice of version, but if unset, try to sort out which federation version to use urlRegex := regexp.MustCompile(`(?s)@link.*\(.*url:.*?"(.*?)"[^)]+\)`) // regex to grab the url of a link directive, should it exist - + versionRegex := regexp.MustCompile(`v(\d+).(\d+)$`) // regex to grab the version number from a url // check the sources, and if one is marked as federation v2, we mark the entirety to be generated using that format for _, v := range cfg.Sources { cfg.Federation.Version = 1 urlString := urlRegex.FindStringSubmatch(v.Input) - if urlString != nil && urlString[1] == "https://specs.apollo.dev/federation/v2.0" { - cfg.Federation.Version = 2 - break + // e.g. urlString[1] == "https://specs.apollo.dev/federation/v2.7" + if urlString != nil { + matches := versionRegex.FindStringSubmatch(urlString[1]) + if matches[1] == "2" { + cfg.Federation.Version = 2 + break + } } } } diff --git a/vendor/github.com/99designs/gqlgen/codegen/args.go b/vendor/github.com/99designs/gqlgen/codegen/args.go index c4cecea9..2f174332 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/args.go +++ b/vendor/github.com/99designs/gqlgen/codegen/args.go @@ -5,9 +5,10 @@ import ( "go/types" "strings" + "github.com/vektah/gqlparser/v2/ast" + "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" - "github.com/vektah/gqlparser/v2/ast" ) type ArgSet struct { diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go index 0483afdb..a50de90a 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go @@ -5,12 +5,12 @@ import ( "fmt" "go/token" "go/types" - "strings" + "github.com/vektah/gqlparser/v2/ast" "golang.org/x/tools/go/packages" + "github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/internal/code" - "github.com/vektah/gqlparser/v2/ast" ) var ErrTypeNotFound = errors.New("unable to find type") @@ -203,6 +203,7 @@ type TypeReference struct { IsOmittable bool // Is the type wrapped with Omittable IsContext bool // Is the Marshaler/Unmarshaller the context version; applies to either the method or interface variety. PointersInUmarshalInput bool // Inverse values and pointers in return. + IsRoot bool // Is the type a root level definition such as Query, Mutation or Subscription } func (ref *TypeReference) Elem() *TypeReference { @@ -274,6 +275,10 @@ func (ref *TypeReference) IsScalar() bool { return ref.Definition.Kind == ast.Scalar } +func (ref *TypeReference) IsMap() bool { + return ref.GO == MapType +} + func (ref *TypeReference) UniquenessKey() string { nullability := "O" if ref.GQL.NonNull { @@ -285,7 +290,7 @@ func (ref *TypeReference) UniquenessKey() string { // Fix for #896 elemNullability = "áš„" } - return nullability + ref.Definition.Name + "2" + TypeIdentifier(ref.GO) + elemNullability + return nullability + ref.Definition.Name + "2" + templates.TypeIdentifier(ref.GO) + elemNullability } func (ref *TypeReference) MarshalFunc() string { @@ -391,6 +396,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret Definition: def, GQL: schemaType, GO: MapType, + IsRoot: b.cfg.IsRoot(def), }, nil } @@ -402,6 +408,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret Definition: def, GQL: schemaType, GO: InterfaceType, + IsRoot: b.cfg.IsRoot(def), }, nil } @@ -413,6 +420,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret ref := &TypeReference{ Definition: def, GQL: schemaType, + IsRoot: b.cfg.IsRoot(def), } obj, err := b.FindObject(pkgName, typeName) @@ -540,41 +548,3 @@ func basicUnderlying(it types.Type) *types.Basic { return nil } - -var pkgReplacer = strings.NewReplacer( - "/", "áš‹", - ".", "áš—", - "-", "áš‘", - "~", "×", -) - -func TypeIdentifier(t types.Type) string { - res := "" - for { - switch it := t.(type) { - case *types.Pointer: - t.Underlying() - res += "áš–" - t = it.Elem() - case *types.Slice: - res += "áš•" - t = it.Elem() - case *types.Named: - res += pkgReplacer.Replace(it.Obj().Pkg().Path()) - res += "áš" - res += it.Obj().Name() - return res - case *types.Basic: - res += it.Name() - return res - case *types.Map: - res += "map" - return res - case *types.Interface: - res += "interface" - return res - default: - panic(fmt.Errorf("unexpected type %T", it)) - } - } -} diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/config.go b/vendor/github.com/99designs/gqlgen/codegen/config/config.go index 8a7205f0..d1c6fe86 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/config.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/config.go @@ -3,6 +3,7 @@ package config import ( "bytes" "fmt" + "go/types" "io" "os" "path/filepath" @@ -10,10 +11,13 @@ import ( "sort" "strings" - "github.com/99designs/gqlgen/internal/code" "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" + "golang.org/x/tools/go/packages" "gopkg.in/yaml.v3" + + "github.com/99designs/gqlgen/codegen/templates" + "github.com/99designs/gqlgen/internal/code" ) type Config struct { @@ -26,6 +30,7 @@ type Config struct { Models TypeMap `yaml:"models,omitempty"` StructTag string `yaml:"struct_tag,omitempty"` Directives map[string]DirectiveConfig `yaml:"directives,omitempty"` + GoBuildTags StringList `yaml:"go_build_tags,omitempty"` GoInitialisms GoInitialismsConfig `yaml:"go_initialisms,omitempty"` OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"` OmitGetters bool `yaml:"omit_getters,omitempty"` @@ -33,6 +38,8 @@ type Config struct { OmitComplexity bool `yaml:"omit_complexity,omitempty"` OmitGQLGenFileNotice bool `yaml:"omit_gqlgen_file_notice,omitempty"` OmitGQLGenVersionInFileNotice bool `yaml:"omit_gqlgen_version_in_file_notice,omitempty"` + OmitRootModels bool `yaml:"omit_root_models,omitempty"` + OmitResolverFields bool `yaml:"omit_resolver_fields,omitempty"` StructFieldsAlwaysPointers bool `yaml:"struct_fields_always_pointers,omitempty"` ReturnPointersInUmarshalInput bool `yaml:"return_pointers_in_unmarshalinput,omitempty"` ResolversAlwaysReturnPointers bool `yaml:"resolvers_always_return_pointers,omitempty"` @@ -211,7 +218,9 @@ func CompleteConfig(config *Config) error { func (c *Config) Init() error { if c.Packages == nil { - c.Packages = &code.Packages{} + c.Packages = code.NewPackages( + code.WithBuildTags(c.GoBuildTags...), + ) } if c.Schema == nil { @@ -257,6 +266,10 @@ func (c *Config) ReloadAllPackages() { c.Packages.ReloadAll(c.packageList()...) } +func (c *Config) IsRoot(def *ast.Definition) bool { + return def == c.Schema.Query || def == c.Schema.Mutation || def == c.Schema.Subscription +} + func (c *Config) injectTypesFromSchema() error { c.Directives["goModel"] = DirectiveConfig{ SkipRuntime: true, @@ -271,7 +284,7 @@ func (c *Config) injectTypesFromSchema() error { } for _, schemaType := range c.Schema.Types { - if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription { + if c.IsRoot(schemaType) { continue } @@ -281,6 +294,7 @@ func (c *Config) injectTypesFromSchema() error { c.Models.Add(schemaType.Name, mv.(string)) } } + if ma := bd.Arguments.ForName("models"); ma != nil { if mvs, err := ma.Value.Value(nil); err == nil { for _, mv := range mvs.([]interface{}) { @@ -288,6 +302,12 @@ func (c *Config) injectTypesFromSchema() error { } } } + + if fg := bd.Arguments.ForName("forceGenerate"); fg != nil { + if mv, err := fg.Value.Value(nil); err == nil { + c.Models.ForceGenerate(schemaType.Name, mv.(bool)) + } + } } if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject { @@ -329,8 +349,9 @@ func (c *Config) injectTypesFromSchema() error { } type TypeMapEntry struct { - Model StringList `yaml:"model"` - Fields map[string]TypeMapField `yaml:"fields,omitempty"` + Model StringList `yaml:"model,omitempty"` + ForceGenerate bool `yaml:"forceGenerate,omitempty"` + Fields map[string]TypeMapField `yaml:"fields,omitempty"` // Key is the Go name of the field. ExtraFields map[string]ModelExtraField `yaml:"extraFields,omitempty"` @@ -529,6 +550,12 @@ func (tm TypeMap) Add(name string, goType string) { tm[name] = modelCfg } +func (tm TypeMap) ForceGenerate(name string, forceGenerate bool) { + modelCfg := tm[name] + modelCfg.ForceGenerate = forceGenerate + tm[name] = modelCfg +} + type DirectiveConfig struct { SkipRuntime bool `yaml:"skip_runtime"` } @@ -583,7 +610,7 @@ func (c *Config) autobind() error { ps := c.Packages.LoadAll(c.AutoBind...) for _, t := range c.Schema.Types { - if c.Models.UserDefined(t.Name) { + if c.Models.UserDefined(t.Name) || c.Models[t.Name].ForceGenerate { continue } @@ -591,14 +618,20 @@ func (c *Config) autobind() error { if p == nil || p.Module == nil { return fmt.Errorf("unable to load %s - make sure you're using an import path to a package that exists", c.AutoBind[i]) } - if t := p.Types.Scope().Lookup(t.Name); t != nil { - c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name()) + + autobindType := c.lookupAutobindType(p, t) + if autobindType != nil { + c.Models.Add(t.Name, autobindType.Pkg().Path()+"."+autobindType.Name()) break } } } for i, t := range c.Models { + if t.ForceGenerate { + continue + } + for j, m := range t.Model { pkg, typename := code.PkgAndType(m) @@ -622,6 +655,17 @@ func (c *Config) autobind() error { return nil } +func (c *Config) lookupAutobindType(p *packages.Package, schemaType *ast.Definition) types.Object { + // Try binding to either the original schema type name, or the normalized go type name + for _, lookupName := range []string{schemaType.Name, templates.ToGo(schemaType.Name)} { + if t := p.Types.Scope().Lookup(lookupName); t != nil { + return t + } + } + + return nil +} + func (c *Config) injectBuiltins() { builtins := TypeMap{ "__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}}, @@ -671,7 +715,9 @@ func (c *Config) injectBuiltins() { func (c *Config) LoadSchema() error { if c.Packages != nil { - c.Packages = &code.Packages{} + c.Packages = code.NewPackages( + code.WithBuildTags(c.GoBuildTags...), + ) } if err := c.check(); err != nil { diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/initialisms.go b/vendor/github.com/99designs/gqlgen/codegen/config/initialisms.go index 5c169c89..25e7331f 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/initialisms.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/initialisms.go @@ -1,62 +1,10 @@ package config -import "strings" +import ( + "strings" -// commonInitialisms is a set of common initialisms. -// Only add entries that are highly unlikely to be non-initialisms. -// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. -var commonInitialisms = map[string]bool{ - "ACL": true, - "API": true, - "ASCII": true, - "CPU": true, - "CSS": true, - "CSV": true, - "DNS": true, - "EOF": true, - "GUID": true, - "HTML": true, - "HTTP": true, - "HTTPS": true, - "ICMP": true, - "ID": true, - "IP": true, - "JSON": true, - "KVK": true, - "LHS": true, - "PDF": true, - "PGP": true, - "QPS": true, - "QR": true, - "RAM": true, - "RHS": true, - "RPC": true, - "SLA": true, - "SMTP": true, - "SQL": true, - "SSH": true, - "SVG": true, - "TCP": true, - "TLS": true, - "TTL": true, - "UDP": true, - "UI": true, - "UID": true, - "URI": true, - "URL": true, - "UTF8": true, - "UUID": true, - "VM": true, - "XML": true, - "XMPP": true, - "XSRF": true, - "XSS": true, -} - -// GetInitialisms returns the initialisms to capitalize in Go names. If unchanged, default initialisms will be returned -var GetInitialisms = func() map[string]bool { - return commonInitialisms -} + "github.com/99designs/gqlgen/codegen/templates" +) // GoInitialismsConfig allows to modify the default behavior of naming Go methods, types and properties type GoInitialismsConfig struct { @@ -69,7 +17,7 @@ type GoInitialismsConfig struct { // setInitialisms adjustes GetInitialisms based on its settings. func (i GoInitialismsConfig) setInitialisms() { toUse := i.determineGoInitialisms() - GetInitialisms = func() map[string]bool { + templates.GetInitialisms = func() map[string]bool { return toUse } } @@ -82,8 +30,8 @@ func (i GoInitialismsConfig) determineGoInitialisms() (initialismsToUse map[stri initialismsToUse[strings.ToUpper(initialism)] = true } } else { - initialismsToUse = make(map[string]bool, len(commonInitialisms)+len(i.Initialisms)) - for initialism, value := range commonInitialisms { + initialismsToUse = make(map[string]bool, len(templates.CommonInitialisms)+len(i.Initialisms)) + for initialism, value := range templates.CommonInitialisms { initialismsToUse[strings.ToUpper(initialism)] = value } for _, initialism := range i.Initialisms { diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/package.go b/vendor/github.com/99designs/gqlgen/codegen/config/package.go index 37692ece..05e178b4 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/package.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/package.go @@ -10,10 +10,11 @@ import ( ) type PackageConfig struct { - Filename string `yaml:"filename,omitempty"` - Package string `yaml:"package,omitempty"` - Version int `yaml:"version,omitempty"` - ModelTemplate string `yaml:"model_template,omitempty"` + Filename string `yaml:"filename,omitempty"` + Package string `yaml:"package,omitempty"` + Version int `yaml:"version,omitempty"` + ModelTemplate string `yaml:"model_template,omitempty"` + Options map[string]bool `yaml:"options,omitempty"` } func (c *PackageConfig) ImportPath() string { diff --git a/vendor/github.com/99designs/gqlgen/codegen/directive.go b/vendor/github.com/99designs/gqlgen/codegen/directive.go index 97306112..f955665b 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/directive.go +++ b/vendor/github.com/99designs/gqlgen/codegen/directive.go @@ -5,8 +5,9 @@ import ( "strconv" "strings" - "github.com/99designs/gqlgen/codegen/templates" "github.com/vektah/gqlparser/v2/ast" + + "github.com/99designs/gqlgen/codegen/templates" ) type DirectiveList map[string]*Directive diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.go b/vendor/github.com/99designs/gqlgen/codegen/field.go index a7e1fb2b..1af2d836 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/field.go +++ b/vendor/github.com/99designs/gqlgen/codegen/field.go @@ -10,11 +10,12 @@ import ( "strconv" "strings" - "github.com/99designs/gqlgen/codegen/config" - "github.com/99designs/gqlgen/codegen/templates" "github.com/vektah/gqlparser/v2/ast" "golang.org/x/text/cases" "golang.org/x/text/language" + + "github.com/99designs/gqlgen/codegen/config" + "github.com/99designs/gqlgen/codegen/templates" ) type Field struct { @@ -152,6 +153,11 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) { switch target := target.(type) { case nil: + // Skips creating a resolver for any root types + if b.Config.IsRoot(b.Schema.Types[f.Type.Name()]) { + return nil + } + objPos := b.Binder.TypePosition(obj.Type) return fmt.Errorf( "%s:%d adding resolver method for %s.%s, nothing matched", diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl index f974b597..de031769 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl @@ -16,49 +16,59 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex ret = {{ $null }} } }() - {{- if $.AllDirectives.LocationDirectives "FIELD" }} - resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) { - {{ template "field" $field }} - }) - {{ else }} - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - {{ template "field" $field }} - }) - if err != nil { - ec.Error(ctx, err) - return {{ $null }} - } - {{- end }} - if resTmp == nil { - {{- if $field.TypeReference.GQL.NonNull }} - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - {{- end }} - return {{ $null }} - } - {{- if $object.Stream }} - return func(ctx context.Context) graphql.Marshaler { - select { - case res, ok := <-resTmp.(<-chan {{$field.TypeReference.GO | ref}}): - if !ok { - return nil - } - return graphql.WriterFunc(func(w io.Writer) { - w.Write([]byte{'{'}) - graphql.MarshalString(field.Alias).MarshalGQL(w) - w.Write([]byte{':'}) - ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res).MarshalGQL(w) - w.Write([]byte{'}'}) - }) - case <-ctx.Done(): - return nil - } - } - {{- else }} - res := resTmp.({{$field.TypeReference.GO | ref}}) + {{- if $field.TypeReference.IsRoot }} + {{- if $field.TypeReference.IsPtr }} + res := &{{ $field.TypeReference.Elem.GO | ref }}{} + {{- else }} + res := {{ $field.TypeReference.GO | ref }}{} + {{- end }} fc.Result = res return ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res) + {{- else}} + {{- if $.AllDirectives.LocationDirectives "FIELD" }} + resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) { + {{ template "field" $field }} + }) + {{ else }} + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + {{ template "field" $field }} + }) + if err != nil { + ec.Error(ctx, err) + return {{ $null }} + } + {{- end }} + if resTmp == nil { + {{- if $field.TypeReference.GQL.NonNull }} + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + {{- end }} + return {{ $null }} + } + {{- if $object.Stream }} + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan {{$field.TypeReference.GO | ref}}): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } + {{- else }} + res := resTmp.({{$field.TypeReference.GO | ref}}) + fc.Result = res + return ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res) + {{- end }} {{- end }} } diff --git a/vendor/github.com/99designs/gqlgen/codegen/generate.go b/vendor/github.com/99designs/gqlgen/codegen/generate.go index 1ce8c329..d63758ab 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/generate.go +++ b/vendor/github.com/99designs/gqlgen/codegen/generate.go @@ -9,9 +9,10 @@ import ( "runtime" "strings" + "github.com/vektah/gqlparser/v2/ast" + "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" - "github.com/vektah/gqlparser/v2/ast" ) //go:embed *.gotpl diff --git a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl index 42e84b65..b343e626 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl @@ -18,6 +18,7 @@ // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { return &executableSchema{ + schema: cfg.Schema, resolvers: cfg.Resolvers, directives: cfg.Directives, complexity: cfg.Complexity, @@ -25,6 +26,7 @@ } type Config struct { + Schema *ast.Schema Resolvers ResolverRoot Directives DirectiveRoot Complexity ComplexityRoot @@ -93,12 +95,16 @@ {{ if eq .Config.Exec.Layout "single-file" }} type executableSchema struct { + schema *ast.Schema resolvers ResolverRoot directives DirectiveRoot complexity ComplexityRoot } func (e *executableSchema) Schema() *ast.Schema { + if e.schema != nil { + return e.schema + } return parsedSchema } @@ -268,14 +274,14 @@ if ec.DisableIntrospection { return nil, errors.New("introspection disabled") } - return introspection.WrapSchema(parsedSchema), nil + return introspection.WrapSchema(ec.Schema()), nil } func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { if ec.DisableIntrospection { return nil, errors.New("introspection disabled") } - return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil + return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil } {{if .HasEmbeddableSources }} diff --git a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl index 126ff661..9240b56c 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl @@ -5,7 +5,11 @@ {{- $it = "&it" }} {{- end }} func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{ if .PointersInUmarshalInput }}*{{ end }}{{.Type | ref}}, error) { - var it {{.Type | ref}} + {{- if $input.IsMap }} + it := make(map[string]interface{}, len(obj.(map[string]interface{}))) + {{- else }} + var it {{.Type | ref}} + {{- end }} asMap := map[string]interface{}{} for k, v := range obj.(map[string]interface{}) { asMap[k] = v @@ -27,8 +31,10 @@ switch k { {{- range $field := .Fields }} case {{$field.Name|quote}}: - var err error - + {{- $lhs := (printf "it.%s" $field.GoFieldName) }} + {{- if $input.IsMap }} + {{- $lhs = (printf "it[%q]" $field.Name) }} + {{- end }} ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField({{$field.Name|quote}})) {{- if $field.ImplDirectives }} directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) } @@ -44,18 +50,18 @@ } {{- else }} {{- if $field.TypeReference.IsOmittable }} - it.{{$field.GoFieldName}} = graphql.OmittableOf(data) + {{ $lhs }} = graphql.OmittableOf(data) {{- else }} - it.{{$field.GoFieldName}} = data + {{ $lhs }} = data {{- end }} {{- end }} {{- if $field.TypeReference.IsNilable }} {{- if not $field.IsResolver }} } else if tmp == nil { {{- if $field.TypeReference.IsOmittable }} - it.{{$field.GoFieldName}} = graphql.OmittableOf[{{ $field.TypeReference.GO | ref }}](nil) + {{ $lhs }} = graphql.OmittableOf[{{ $field.TypeReference.GO | ref }}](nil) {{- else }} - it.{{$field.GoFieldName}} = nil + {{ $lhs }} = nil {{- end }} {{- end }} {{- end }} @@ -78,9 +84,9 @@ return {{$it}}, err } {{- if $field.TypeReference.IsOmittable }} - it.{{$field.GoFieldName}} = graphql.OmittableOf(data) + {{ $lhs }} = graphql.OmittableOf(data) {{- else }} - it.{{$field.GoFieldName}} = data + {{ $lhs }} = data {{- end }} {{- end }} {{- end }} diff --git a/vendor/github.com/99designs/gqlgen/codegen/interface.go b/vendor/github.com/99designs/gqlgen/codegen/interface.go index cdc4d4d3..1ddcf408 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/interface.go +++ b/vendor/github.com/99designs/gqlgen/codegen/interface.go @@ -3,6 +3,7 @@ package codegen import ( "fmt" "go/types" + "sort" "github.com/vektah/gqlparser/v2/ast" @@ -40,7 +41,13 @@ func (b *builder) buildInterface(typ *ast.Definition) (*Interface, error) { return nil, fmt.Errorf("%s is not an interface", i.Type) } - for _, implementor := range b.Schema.GetPossibleTypes(typ) { + // Sort so that more specific types are evaluated first. + implementors := b.Schema.GetPossibleTypes(typ) + sort.Slice(implementors, func(i, j int) bool { + return len(implementors[i].Interfaces) > len(implementors[j].Interfaces) + }) + + for _, implementor := range implementors { obj, err := b.Binder.DefaultUserObject(implementor.Name) if err != nil { return nil, fmt.Errorf("%s has no backing go type", implementor.Name) diff --git a/vendor/github.com/99designs/gqlgen/codegen/object.go b/vendor/github.com/99designs/gqlgen/codegen/object.go index 86092327..eee43849 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/object.go +++ b/vendor/github.com/99designs/gqlgen/codegen/object.go @@ -7,10 +7,11 @@ import ( "strings" "unicode" - "github.com/99designs/gqlgen/codegen/config" "github.com/vektah/gqlparser/v2/ast" "golang.org/x/text/cases" "golang.org/x/text/language" + + "github.com/99designs/gqlgen/codegen/config" ) type GoFieldType int @@ -44,7 +45,7 @@ func (b *builder) buildObject(typ *ast.Definition) (*Object, error) { caser := cases.Title(language.English, cases.NoLower) obj := &Object{ Definition: typ, - Root: b.Schema.Query == typ || b.Schema.Mutation == typ || b.Schema.Subscription == typ, + Root: b.Config.IsRoot(typ), DisableConcurrency: typ == b.Schema.Mutation, Stream: typ == b.Schema.Subscription, Directives: dirs, @@ -112,8 +113,8 @@ func (o *Object) HasResolvers() bool { } func (o *Object) HasUnmarshal() bool { - if o.Type == config.MapType { - return true + if o.IsMap() { + return false } for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ { if o.Type.(*types.Named).Method(i).Name() == "UnmarshalGQL" { @@ -149,6 +150,10 @@ func (o *Object) IsReserved() bool { return strings.HasPrefix(o.Definition.Name, "__") } +func (o *Object) IsMap() bool { + return o.Type == config.MapType +} + func (o *Object) Description() string { return o.Definition.Description } diff --git a/vendor/github.com/99designs/gqlgen/codegen/root_.gotpl b/vendor/github.com/99designs/gqlgen/codegen/root_.gotpl index dcfc84d0..0b90ad53 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/root_.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/root_.gotpl @@ -17,6 +17,7 @@ // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { return &executableSchema{ + schema: cfg.Schema, resolvers: cfg.Resolvers, directives: cfg.Directives, complexity: cfg.Complexity, @@ -24,6 +25,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { } type Config struct { + Schema *ast.Schema Resolvers ResolverRoot Directives DirectiveRoot Complexity ComplexityRoot @@ -66,12 +68,16 @@ type ComplexityRoot struct { } type executableSchema struct { + schema *ast.Schema resolvers ResolverRoot directives DirectiveRoot complexity ComplexityRoot } func (e *executableSchema) Schema() *ast.Schema { + if e.schema != nil { + return e.schema + } return parsedSchema } @@ -241,14 +247,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { if ec.DisableIntrospection { return nil, errors.New("introspection disabled") } - return introspection.WrapSchema(parsedSchema), nil + return introspection.WrapSchema(ec.Schema()), nil } func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { if ec.DisableIntrospection { return nil, errors.New("introspection disabled") } - return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil + return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil } diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go index 97652757..4a4e9159 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go +++ b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go @@ -17,7 +17,6 @@ import ( "text/template" "unicode" - "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/internal/code" "github.com/99designs/gqlgen/internal/imports" ) @@ -202,7 +201,7 @@ func Funcs() template.FuncMap { "rawQuote": rawQuote, "dump": Dump, "ref": ref, - "ts": config.TypeIdentifier, + "ts": TypeIdentifier, "call": Call, "prefixLines": prefixLines, "notNil": notNil, @@ -465,7 +464,7 @@ func wordWalker(str string, f func(*wordInfo)) { } i++ - initialisms := config.GetInitialisms() + initialisms := GetInitialisms() // [w,i) is a word. word := string(runes[w:i]) if !eow && initialisms[word] && !unicode.IsLower(runes[i]) { @@ -668,3 +667,97 @@ func write(filename string, b []byte, packages *code.Packages) error { return nil } + +var pkgReplacer = strings.NewReplacer( + "/", "áš‹", + ".", "áš—", + "-", "áš‘", + "~", "×", +) + +func TypeIdentifier(t types.Type) string { + res := "" + for { + switch it := t.(type) { + case *types.Pointer: + t.Underlying() + res += "áš–" + t = it.Elem() + case *types.Slice: + res += "áš•" + t = it.Elem() + case *types.Named: + res += pkgReplacer.Replace(it.Obj().Pkg().Path()) + res += "áš" + res += it.Obj().Name() + return res + case *types.Basic: + res += it.Name() + return res + case *types.Map: + res += "map" + return res + case *types.Interface: + res += "interface" + return res + default: + panic(fmt.Errorf("unexpected type %T", it)) + } + } +} + +// CommonInitialisms is a set of common initialisms. +// Only add entries that are highly unlikely to be non-initialisms. +// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. +var CommonInitialisms = map[string]bool{ + "ACL": true, + "API": true, + "ASCII": true, + "CPU": true, + "CSS": true, + "CSV": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTP": true, + "HTTPS": true, + "ICMP": true, + "ID": true, + "IP": true, + "JSON": true, + "KVK": true, + "LHS": true, + "PDF": true, + "PGP": true, + "QPS": true, + "QR": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SQL": true, + "SSH": true, + "SVG": true, + "TCP": true, + "TLS": true, + "TTL": true, + "UDP": true, + "UI": true, + "UID": true, + "URI": true, + "URL": true, + "UTF8": true, + "UUID": true, + "VM": true, + "XML": true, + "XMPP": true, + "XSRF": true, + "XSS": true, +} + +// GetInitialisms returns the initialisms to capitalize in Go names. If unchanged, default initialisms will be returned +var GetInitialisms = func() map[string]bool { + return CommonInitialisms +} diff --git a/vendor/github.com/99designs/gqlgen/codegen/type.gotpl b/vendor/github.com/99designs/gqlgen/codegen/type.gotpl index 5cbd737c..272f3db3 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/type.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/type.gotpl @@ -59,8 +59,6 @@ {{- else}} return res, graphql.ErrorOnPath(ctx, err) {{- end }} - {{- else if eq ($type.GO | ref) "map[string]interface{}" }} - return v.(map[string]interface{}), nil {{- else if $type.IsMarshaler }} {{- if and $type.IsNilable $type.Elem }} var res = new({{ $type.Elem.GO | ref }}) @@ -75,7 +73,7 @@ return res, graphql.ErrorOnPath(ctx, err) {{- else }} res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v) - {{- if and $type.IsNilable (not $type.PointersInUmarshalInput) }} + {{- if and $type.IsNilable (not $type.IsMap) (not $type.PointersInUmarshalInput) }} return &res, graphql.ErrorOnPath(ctx, err) {{- else if and (not $type.IsNilable) $type.PointersInUmarshalInput }} return *res, graphql.ErrorOnPath(ctx, err) @@ -185,6 +183,13 @@ {{- else }} return res {{- end }} + {{- else if $type.IsRoot }} + {{- if eq $type.Definition.Name "Subscription" }} + res := ec._{{$type.Definition.Name}}(ctx, sel) + return res(ctx) + {{- else }} + return ec._{{$type.Definition.Name}}(ctx, sel) + {{- end }} {{- else }} return ec._{{$type.Definition.Name}}(ctx, sel, {{ if not $type.IsNilable}}&{{end}} v) {{- end }} diff --git a/vendor/github.com/99designs/gqlgen/complexity/complexity.go b/vendor/github.com/99designs/gqlgen/complexity/complexity.go index e3ecf761..aa0f8643 100644 --- a/vendor/github.com/99designs/gqlgen/complexity/complexity.go +++ b/vendor/github.com/99designs/gqlgen/complexity/complexity.go @@ -1,8 +1,9 @@ package complexity import ( - "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/ast" + + "github.com/99designs/gqlgen/graphql" ) func Calculate(es graphql.ExecutableSchema, op *ast.OperationDefinition, vars map[string]interface{}) int { diff --git a/vendor/github.com/99designs/gqlgen/generate_examples.sh b/vendor/github.com/99designs/gqlgen/generate_examples.sh new file mode 100644 index 00000000..814a8d85 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/generate_examples.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +cd ./_examples +go generate ./... || return 0 diff --git a/vendor/github.com/99designs/gqlgen/graphql/context_operation.go b/vendor/github.com/99designs/gqlgen/graphql/context_operation.go index 77a42b84..3e6a221b 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/context_operation.go +++ b/vendor/github.com/99designs/gqlgen/graphql/context_operation.go @@ -73,8 +73,8 @@ func WithOperationContext(ctx context.Context, rc *OperationContext) context.Con // // Some errors can happen outside of an operation, eg json unmarshal errors. func HasOperationContext(ctx context.Context) bool { - _, ok := ctx.Value(operationCtx).(*OperationContext) - return ok + val, ok := ctx.Value(operationCtx).(*OperationContext) + return ok && val != nil } // This is just a convenient wrapper method for CollectFields diff --git a/vendor/github.com/99designs/gqlgen/graphql/duration.go b/vendor/github.com/99designs/gqlgen/graphql/duration.go new file mode 100644 index 00000000..3eb392db --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/duration.go @@ -0,0 +1,27 @@ +package graphql + +import ( + "fmt" + "time" + + dur "github.com/sosodev/duration" +) + +// UnmarshalDuration returns the duration from a string in ISO8601 format +func UnmarshalDuration(v interface{}) (time.Duration, error) { + input, ok := v.(string) + if !ok { + return 0, fmt.Errorf("input must be a string") + } + + d2, err := dur.Parse(input) + if err != nil { + return 0, err + } + return d2.ToTimeDuration(), nil +} + +// MarshalDuration returns the duration on ISO8601 format +func MarshalDuration(d time.Duration) Marshaler { + return MarshalString(dur.Format(d)) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/executor/executor.go b/vendor/github.com/99designs/gqlgen/graphql/executor/executor.go index c46a007b..ef0603ea 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/executor/executor.go +++ b/vendor/github.com/99designs/gqlgen/graphql/executor/executor.go @@ -3,12 +3,13 @@ package executor import ( "context" - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/errcode" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/parser" "github.com/vektah/gqlparser/v2/validator" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" ) // Executor executes graphql queries against a schema. diff --git a/vendor/github.com/99designs/gqlgen/graphql/fieldset.go b/vendor/github.com/99designs/gqlgen/graphql/fieldset.go index 3ba28582..2c9e3dc9 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/fieldset.go +++ b/vendor/github.com/99designs/gqlgen/graphql/fieldset.go @@ -46,8 +46,8 @@ func (m *FieldSet) Dispatch(ctx context.Context) { for _, d := range m.delayed[1:] { wg.Add(1) go func(d delayedResult) { + defer wg.Done() m.Values[d.i] = d.f(ctx) - wg.Done() }(d) } diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go index 866276ee..465c2ada 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go @@ -6,12 +6,11 @@ import ( "encoding/hex" "fmt" - "github.com/99designs/gqlgen/graphql/errcode" - + "github.com/mitchellh/mapstructure" "github.com/vektah/gqlparser/v2/gqlerror" "github.com/99designs/gqlgen/graphql" - "github.com/mitchellh/mapstructure" + "github.com/99designs/gqlgen/graphql/errcode" ) const ( diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go index e88848d1..a5b6a604 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go @@ -4,10 +4,11 @@ import ( "context" "fmt" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/99designs/gqlgen/complexity" "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/errcode" - "github.com/vektah/gqlparser/v2/gqlerror" ) const errComplexityLimit = "COMPLEXITY_LIMIT_EXCEEDED" diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go index acc5db2f..8e391265 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go @@ -3,8 +3,9 @@ package extension import ( "context" - "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/gqlerror" + + "github.com/99designs/gqlgen/graphql" ) // EnableIntrospection enables clients to reflect all of the types available on the graph. diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go b/vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go index 68241aba..6ae8a38e 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go @@ -3,8 +3,9 @@ package lru import ( "context" - "github.com/99designs/gqlgen/graphql" lru "github.com/hashicorp/golang-lru/v2" + + "github.com/99designs/gqlgen/graphql" ) type LRU struct { diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/server.go b/vendor/github.com/99designs/gqlgen/graphql/handler/server.go index b6524d8d..fd365ccb 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/server.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/server.go @@ -7,12 +7,13 @@ import ( "net/http" "time" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/executor" "github.com/99designs/gqlgen/graphql/handler/extension" "github.com/99designs/gqlgen/graphql/handler/lru" "github.com/99designs/gqlgen/graphql/handler/transport" - "github.com/vektah/gqlparser/v2/gqlerror" ) type ( diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go index b1aeaf14..18f09f55 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go @@ -5,8 +5,9 @@ import ( "fmt" "net/http" - "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/gqlerror" + + "github.com/99designs/gqlgen/graphql" ) // SendError sends a best effort error to a raw response writer. It assumes the client can understand the standard diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go index 324fd986..9a47bfbe 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go @@ -7,10 +7,11 @@ import ( "net/url" "strings" - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/errcode" "github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/gqlerror" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" ) // GET implements the GET side of the default HTTP transport diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go index ce845c19..19b7521c 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go @@ -5,8 +5,9 @@ import ( "fmt" "io" - "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/gqlerror" + + "github.com/99designs/gqlgen/graphql" ) func writeJson(w io.Writer, response *graphql.Response) { diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go index acd124fe..e1334b92 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go @@ -12,10 +12,11 @@ import ( "sync" "time" - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/errcode" "github.com/gorilla/websocket" "github.com/vektah/gqlparser/v2/gqlerror" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" ) type ( @@ -26,7 +27,17 @@ type ( ErrorFunc WebsocketErrorFunc CloseFunc WebsocketCloseFunc KeepAlivePingInterval time.Duration + PongOnlyInterval time.Duration PingPongInterval time.Duration + /* If PingPongInterval has a non-0 duration, then when the server sends a ping + * it sets a ReadDeadline of PingPongInterval*2 and if the client doesn't respond + * with pong before that deadline is reached then the connection will die with a + * 1006 error code. + * + * MissingPongOk if true, tells the server to not use a ReadDeadline such that a + * missing/slow pong response from the client doesn't kill the connection. + */ + MissingPongOk bool didInjectSubprotocols bool } @@ -38,13 +49,16 @@ type ( active map[string]context.CancelFunc mu sync.Mutex keepAliveTicker *time.Ticker + pongOnlyTicker *time.Ticker pingPongTicker *time.Ticker + receivedPong bool exec graphql.GraphExecutor + closed bool initPayload InitPayload } - WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error) + WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, *InitPayload, error) WebsocketErrorFunc func(ctx context.Context, err error) // Callback called when websocket is closed. @@ -179,8 +193,10 @@ func (c *wsConnection) init() bool { } } + var initAckPayload *InitPayload = nil if c.InitFunc != nil { - ctx, err := c.InitFunc(c.ctx, c.initPayload) + var ctx context.Context + ctx, initAckPayload, err = c.InitFunc(c.ctx, c.initPayload) if err != nil { c.sendConnectionError(err.Error()) c.close(websocket.CloseNormalClosure, "terminated") @@ -189,7 +205,15 @@ func (c *wsConnection) init() bool { c.ctx = ctx } - c.write(&message{t: connectionAckMessageType}) + if initAckPayload != nil { + initJsonAckPayload, err := json.Marshal(*initAckPayload) + if err != nil { + panic(err) + } + c.write(&message{t: connectionAckMessageType, payload: initJsonAckPayload}) + } else { + c.write(&message{t: connectionAckMessageType}) + } c.write(&message{t: keepAliveMessageType}) case connectionCloseMessageType: c.close(websocket.CloseNormalClosure, "terminated") @@ -228,16 +252,28 @@ func (c *wsConnection) run() { go c.keepAlive(ctx) } + // If we're running in graphql-transport-ws mode, create a timer that will trigger a + // just a pong message every interval + if c.conn.Subprotocol() == graphqltransportwsSubprotocol && c.PongOnlyInterval != 0 { + c.mu.Lock() + c.pongOnlyTicker = time.NewTicker(c.PongOnlyInterval) + c.mu.Unlock() + + go c.keepAlivePongOnly(ctx) + } + // If we're running in graphql-transport-ws mode, create a timer that will - // trigger a ping message every interval + // trigger a ping message every interval and expect a pong! if c.conn.Subprotocol() == graphqltransportwsSubprotocol && c.PingPongInterval != 0 { c.mu.Lock() c.pingPongTicker = time.NewTicker(c.PingPongInterval) c.mu.Unlock() - // Note: when the connection is closed by this deadline, the client - // will receive an "invalid close code" - c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval)) + if !c.MissingPongOk { + // Note: when the connection is closed by this deadline, the client + // will receive an "invalid close code" + c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval)) + } go c.ping(ctx) } @@ -272,7 +308,11 @@ func (c *wsConnection) run() { case pingMessageType: c.write(&message{t: pongMessageType, payload: m.payload}) case pongMessageType: - c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval)) + c.mu.Lock() + c.receivedPong = true + c.mu.Unlock() + // Clear ReadTimeout -- 0 time val clears. + c.conn.SetReadDeadline(time.Time{}) default: c.sendConnectionError("unexpected message %s", m.t) c.close(websocket.CloseProtocolError, "unexpected message") @@ -281,6 +321,18 @@ func (c *wsConnection) run() { } } +func (c *wsConnection) keepAlivePongOnly(ctx context.Context) { + for { + select { + case <-ctx.Done(): + c.pongOnlyTicker.Stop() + return + case <-c.pongOnlyTicker.C: + c.write(&message{t: pongMessageType, payload: json.RawMessage{}}) + } + } +} + func (c *wsConnection) keepAlive(ctx context.Context) { for { select { @@ -301,6 +353,14 @@ func (c *wsConnection) ping(ctx context.Context) { return case <-c.pingPongTicker.C: c.write(&message{t: pingMessageType, payload: json.RawMessage{}}) + // The initial deadline for this method is set in run() + // if we have not yet received a pong, don't reset the deadline. + c.mu.Lock() + if !c.MissingPongOk && c.receivedPong { + c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval)) + } + c.receivedPong = false + c.mu.Unlock() } } } @@ -431,10 +491,15 @@ func (c *wsConnection) sendConnectionError(format string, args ...interface{}) { func (c *wsConnection) close(closeCode int, message string) { c.mu.Lock() + if c.closed { + c.mu.Unlock() + return + } _ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message)) for _, closer := range c.active { closer() } + c.closed = true c.mu.Unlock() _ = c.conn.Close() diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go index b7b0ad94..897b1a09 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go +++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go @@ -2,7 +2,6 @@ package introspection import ( "sort" - "strings" "github.com/vektah/gqlparser/v2/ast" ) @@ -22,9 +21,6 @@ func (s *Schema) Types() []Type { typeIndex := map[string]Type{} typeNames := make([]string, 0, len(s.schema.Types)) for _, typ := range s.schema.Types { - if strings.HasPrefix(typ.Name, "__") { - continue - } typeNames = append(typeNames, typ.Name) typeIndex[typ.Name] = *WrapTypeFromDef(s.schema, typ) } diff --git a/vendor/github.com/99designs/gqlgen/graphql/omittable.go b/vendor/github.com/99designs/gqlgen/graphql/omittable.go index 3d1e3279..89716400 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/omittable.go +++ b/vendor/github.com/99designs/gqlgen/graphql/omittable.go @@ -1,5 +1,7 @@ package graphql +import "encoding/json" + // Omittable is a wrapper around a value that also stores whether it is set // or not. type Omittable[T any] struct { @@ -7,6 +9,11 @@ type Omittable[T any] struct { set bool } +var ( + _ json.Marshaler = Omittable[struct{}]{} + _ json.Unmarshaler = (*Omittable[struct{}])(nil) +) + func OmittableOf[T any](value T) Omittable[T] { return Omittable[T]{ value: value, @@ -33,3 +40,19 @@ func (o Omittable[T]) ValueOK() (T, bool) { func (o Omittable[T]) IsSet() bool { return o.set } + +func (o Omittable[T]) MarshalJSON() ([]byte, error) { + if !o.set { + return []byte("null"), nil + } + return json.Marshal(o.value) +} + +func (o *Omittable[T]) UnmarshalJSON(bytes []byte) error { + err := json.Unmarshal(bytes, &o.value) + if err != nil { + return err + } + o.set = true + return nil +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/playground/apollo_sandbox_playground.go b/vendor/github.com/99designs/gqlgen/graphql/playground/apollo_sandbox_playground.go index 63b60743..750420b4 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/playground/apollo_sandbox_playground.go +++ b/vendor/github.com/99designs/gqlgen/graphql/playground/apollo_sandbox_playground.go @@ -1,10 +1,13 @@ package playground import ( + "encoding/json" + "fmt" "html/template" "net/http" ) +// NOTE: New version available at https://embeddable-sandbox.cdn.apollographql.com/ --> var apolloSandboxPage = template.Must(template.New("ApolloSandbox").Parse(` @@ -23,40 +26,161 @@ var apolloSandboxPage = template.Must(template.New("ApolloSandbox").Parse(`
- - + - `)) -// ApolloSandboxHandler responsible for setting up the altair playground -func ApolloSandboxHandler(title, endpoint string) http.HandlerFunc { +// ApolloSandboxHandler responsible for setting up the apollo sandbox playground +func ApolloSandboxHandler(title, endpoint string, opts ...ApolloSandboxOption) http.HandlerFunc { + options := &apolloSandboxOptions{ + HideCookieToggle: true, + InitialState: apolloSandboxInitialState{ + IncludeCookies: true, + PollForSchemaUpdates: false, + }, + } + + for _, opt := range opts { + opt(options) + } + + optionsBytes, err := json.Marshal(options) + if err != nil { + panic(fmt.Errorf("failed to marshal apollo sandbox options: %w", err)) + } + return func(w http.ResponseWriter, r *http.Request) { err := apolloSandboxPage.Execute(w, map[string]interface{}{ "title": title, "endpoint": endpoint, "endpointIsAbsolute": endpointHasScheme(endpoint), - "mainSRI": "sha256-ldbSJ7EovavF815TfCN50qKB9AMvzskb9xiG71bmg2I=", + "mainSRI": "sha256-pYhw/8TGkZxk960PMMpDtjhw9YtKXUzGv6XQQaMJSh8=", + "options": string(optionsBytes), }) if err != nil { panic(err) } } } + +// See https://www.apollographql.com/docs/graphos/explorer/sandbox/#options --> +type apolloSandboxOptions struct { + HideCookieToggle bool `json:"hideCookieToggle"` + EndpointIsEditable bool `json:"endpointIsEditable"` + InitialState apolloSandboxInitialState `json:"initialState,omitempty"` +} + +type apolloSandboxInitialState struct { + IncludeCookies bool `json:"includeCookies"` + Document string `json:"document,omitempty"` + Variables map[string]any `json:"variables,omitempty"` + Headers map[string]any `json:"headers,omitempty"` + CollectionId string `json:"collectionId,omitempty"` + OperationId string `json:"operationId,omitempty"` + PollForSchemaUpdates bool `json:"pollForSchemaUpdates"` + SharedHeaders map[string]any `json:"sharedHeaders,omitempty"` +} + +type ApolloSandboxOption func(options *apolloSandboxOptions) + +// WithApolloSandboxHideCookieToggle By default, the embedded Sandbox does not show the Include cookies toggle in its connection settings. +// +// Set hideCookieToggle to false to enable users of your embedded Sandbox instance to toggle the Include cookies setting. +func WithApolloSandboxHideCookieToggle(hideCookieToggle bool) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.HideCookieToggle = hideCookieToggle + } +} + +// WithApolloSandboxEndpointIsEditable By default, the embedded Sandbox has a URL input box that is editable by users. +// +// Set endpointIsEditable to false to prevent users of your embedded Sandbox instance from changing the endpoint URL. +func WithApolloSandboxEndpointIsEditable(endpointIsEditable bool) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.EndpointIsEditable = endpointIsEditable + } +} + +// WithApolloSandboxInitialStateIncludeCookies Set this value to true if you want the Sandbox to pass { credentials: 'include' } for its requests by default. +// +// If you set hideCookieToggle to false, users can override this default setting with the Include cookies toggle. (By default, the embedded Sandbox does not show the Include cookies toggle in its connection settings.) +// +// If you also pass the handleRequest option, this option is ignored. +// +// Read more about the fetch API and credentials here https://developer.mozilla.org/en-US/docs/Web/API/fetch#credentials +func WithApolloSandboxInitialStateIncludeCookies(includeCookies bool) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.InitialState.IncludeCookies = includeCookies + } +} + +// WithApolloSandboxInitialStateDocument Document operation to populate in the Sandbox's editor on load. +// +// If you omit this, the Sandbox initially loads an example query based on your schema. +func WithApolloSandboxInitialStateDocument(document string) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.InitialState.Document = document + } +} + +// WithApolloSandboxInitialStateVariables Variables containing initial variable values to populate in the Sandbox on load. +// +// If provided, these variables should apply to the initial query you provide for document. +func WithApolloSandboxInitialStateVariables(variables map[string]any) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.InitialState.Variables = variables + } +} + +// WithApolloSandboxInitialStateHeaders Headers containing initial variable values to populate in the Sandbox on load. +// +// If provided, these variables should apply to the initial query you provide for document. +func WithApolloSandboxInitialStateHeaders(headers map[string]any) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.InitialState.Headers = headers + } +} + +// WithApolloSandboxInitialStateCollectionIdAndOperationId The ID of a collection, paired with an operation ID to populate in the Sandbox on load. +// +// You can find these values from a registered graph in Studio by clicking the ... menu next to an operation in the Explorer of that graph and selecting View operation details. +func WithApolloSandboxInitialStateCollectionIdAndOperationId(collectionId, operationId string) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.InitialState.CollectionId = collectionId + options.InitialState.OperationId = operationId + } +} + +// WithApolloSandboxInitialStatePollForSchemaUpdates If true, the embedded Sandbox periodically polls your initialEndpoint for schema updates. +// +// The default value is false. +func WithApolloSandboxInitialStatePollForSchemaUpdates(pollForSchemaUpdates bool) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.InitialState.PollForSchemaUpdates = pollForSchemaUpdates + } +} + +// WithApolloSandboxInitialStateSharedHeaders Headers that are applied by default to every operation executed by the embedded Sandbox. +// +// Users can disable the application of these headers, but they can't modify their values. +// +// The embedded Sandbox always includes these headers in its introspection queries to your initialEndpoint. +func WithApolloSandboxInitialStateSharedHeaders(sharedHeaders map[string]any) ApolloSandboxOption { + return func(options *apolloSandboxOptions) { + options.InitialState.SharedHeaders = sharedHeaders + } +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/playground/playground.go b/vendor/github.com/99designs/gqlgen/graphql/playground/playground.go index da17ca62..05ad0233 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/playground/playground.go +++ b/vendor/github.com/99designs/gqlgen/graphql/playground/playground.go @@ -58,13 +58,24 @@ var page = template.Must(template.New("graphiql").Parse(` const wsProto = location.protocol == 'https:' ? 'wss:' : 'ws:'; const subscriptionUrl = wsProto + '//' + location.host + {{.endpoint}}; {{- end}} +{{- if .fetcherHeaders}} + const fetcherHeaders = {{.fetcherHeaders}}; +{{- else}} + const fetcherHeaders = undefined; +{{- end}} +{{- if .uiHeaders}} + const uiHeaders = {{.uiHeaders}}; +{{- else}} + const uiHeaders = undefined; +{{- end}} - const fetcher = GraphiQL.createFetcher({ url, subscriptionUrl }); + const fetcher = GraphiQL.createFetcher({ url, subscriptionUrl, headers: fetcherHeaders }); ReactDOM.render( React.createElement(GraphiQL, { fetcher: fetcher, isHeadersEditorEnabled: true, - shouldPersistHeaders: true + shouldPersistHeaders: true, + headers: JSON.stringify(uiHeaders, null, 2) }), document.getElementById('graphiql'), ); @@ -75,16 +86,25 @@ var page = template.Must(template.New("graphiql").Parse(` // Handler responsible for setting up the playground func Handler(title string, endpoint string) http.HandlerFunc { + return HandlerWithHeaders(title, endpoint, nil, nil) +} + +// HandlerWithHeaders sets up the playground. +// fetcherHeaders are used by the playground's fetcher instance and will not be visible in the UI. +// uiHeaders are default headers that will show up in the UI headers editor. +func HandlerWithHeaders(title string, endpoint string, fetcherHeaders map[string]string, uiHeaders map[string]string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "text/html; charset=UTF-8") err := page.Execute(w, map[string]interface{}{ "title": title, "endpoint": endpoint, + "fetcherHeaders": fetcherHeaders, + "uiHeaders": uiHeaders, "endpointIsAbsolute": endpointHasScheme(endpoint), "subscriptionEndpoint": getSubscriptionEndpoint(endpoint), - "version": "3.0.1", + "version": "3.0.6", "cssSRI": "sha256-wTzfn13a+pLMB5rMeysPPR1hO7x0SwSeQI+cnw7VdbE=", - "jsSRI": "sha256-dLnxjV+d2rFUCtYKjbPy413/8O+Ahy7QqAhaPNlL8fk=", + "jsSRI": "sha256-eNxH+Ah7Z9up9aJYTQycgyNuy953zYZwE9Rqf5rH+r4=", "reactSRI": "sha256-S0lp+k7zWUMk2ixteM6HZvu8L9Eh//OVrt+ZfbCpmgY=", "reactDOMSRI": "sha256-IXWO0ITNDjfnNXIu5POVfqlgYoop36bDzhodR6LW5Pc=", }) diff --git a/vendor/github.com/99designs/gqlgen/graphql/uint.go b/vendor/github.com/99designs/gqlgen/graphql/uint.go index 26e6aa6b..8730d900 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/uint.go +++ b/vendor/github.com/99designs/gqlgen/graphql/uint.go @@ -2,6 +2,7 @@ package graphql import ( "encoding/json" + "errors" "fmt" "io" "strconv" @@ -19,8 +20,16 @@ func UnmarshalUint(v interface{}) (uint, error) { u64, err := strconv.ParseUint(v, 10, 64) return uint(u64), err case int: + if v < 0 { + return 0, errors.New("cannot convert negative numbers to uint") + } + return uint(v), nil case int64: + if v < 0 { + return 0, errors.New("cannot convert negative numbers to uint") + } + return uint(v), nil case json.Number: u64, err := strconv.ParseUint(string(v), 10, 64) @@ -41,8 +50,16 @@ func UnmarshalUint64(v interface{}) (uint64, error) { case string: return strconv.ParseUint(v, 10, 64) case int: + if v < 0 { + return 0, errors.New("cannot convert negative numbers to uint64") + } + return uint64(v), nil case int64: + if v < 0 { + return 0, errors.New("cannot convert negative numbers to uint64") + } + return uint64(v), nil case json.Number: return strconv.ParseUint(string(v), 10, 64) @@ -66,8 +83,16 @@ func UnmarshalUint32(v interface{}) (uint32, error) { } return uint32(iv), nil case int: + if v < 0 { + return 0, errors.New("cannot convert negative numbers to uint32") + } + return uint32(v), nil case int64: + if v < 0 { + return 0, errors.New("cannot convert negative numbers to uint32") + } + return uint32(v), nil case json.Number: iv, err := strconv.ParseUint(string(v), 10, 32) diff --git a/vendor/github.com/99designs/gqlgen/graphql/uuid.go b/vendor/github.com/99designs/gqlgen/graphql/uuid.go new file mode 100644 index 00000000..e9f22dcc --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/uuid.go @@ -0,0 +1,25 @@ +package graphql + +import ( + "fmt" + + "github.com/google/uuid" +) + +func MarshalUUID(id uuid.UUID) Marshaler { + if id == uuid.Nil { + return Null + } + return MarshalString(id.String()) +} + +func UnmarshalUUID(v any) (uuid.UUID, error) { + switch v := v.(type) { + case string: + return uuid.Parse(v) + case []byte: + return uuid.ParseBytes(v) + default: + return uuid.Nil, fmt.Errorf("%T is not a uuid", v) + } +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/version.go b/vendor/github.com/99designs/gqlgen/graphql/version.go index be565643..93f58b54 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/version.go +++ b/vendor/github.com/99designs/gqlgen/graphql/version.go @@ -1,3 +1,3 @@ package graphql -const Version = "v0.17.36" +const Version = "v0.17.45" diff --git a/vendor/github.com/99designs/gqlgen/internal/code/packages.go b/vendor/github.com/99designs/gqlgen/internal/code/packages.go index 6cb6ef23..e7f8655a 100644 --- a/vendor/github.com/99designs/gqlgen/internal/code/packages.go +++ b/vendor/github.com/99designs/gqlgen/internal/code/packages.go @@ -28,15 +28,37 @@ var mode = packages.NeedName | packages.NeedModule | packages.NeedDeps -// Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages -// that can be invalidated as writes are made and packages are known to change. -type Packages struct { - packages map[string]*packages.Package - importToName map[string]string - loadErrors []error +type ( + // Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages + // that can be invalidated as writes are made and packages are known to change. + Packages struct { + packages map[string]*packages.Package + importToName map[string]string + loadErrors []error + buildFlags []string - numLoadCalls int // stupid test steam. ignore. - numNameCalls int // stupid test steam. ignore. + numLoadCalls int // stupid test steam. ignore. + numNameCalls int // stupid test steam. ignore. + } + // Option is a function that can be passed to NewPackages to configure the package loader + Option func(p *Packages) +) + +// WithBuildTags adds build tags to the packages.Load call +func WithBuildTags(tags ...string) func(p *Packages) { + return func(p *Packages) { + p.buildFlags = append(p.buildFlags, "-tags", strings.Join(tags, ",")) + } +} + +// NewPackages creates a new packages cache +// It will load all packages in the current module, and any packages that are passed to Load or LoadAll +func NewPackages(opts ...Option) *Packages { + p := &Packages{} + for _, opt := range opts { + opt(p) + } + return p } func (p *Packages) CleanupUserPackages() { @@ -47,8 +69,8 @@ func (p *Packages) CleanupUserPackages() { modInfo = nil } }) - - // Don't cleanup github.com/99designs/gqlgen prefixed packages, they haven't changed and do not need to be reloaded + // Don't cleanup github.com/99designs/gqlgen prefixed packages, + // they haven't changed and do not need to be reloaded if modInfo != nil { var toRemove []string for k := range p.packages { @@ -56,7 +78,6 @@ func (p *Packages) CleanupUserPackages() { toRemove = append(toRemove, k) } } - for _, k := range toRemove { delete(p.packages, k) } @@ -91,7 +112,10 @@ func (p *Packages) LoadAll(importPaths ...string) []*packages.Package { if len(missing) > 0 { p.numLoadCalls++ - pkgs, err := packages.Load(&packages.Config{Mode: mode}, missing...) + pkgs, err := packages.Load(&packages.Config{ + Mode: mode, + BuildFlags: p.buildFlags, + }, missing...) if err != nil { p.loadErrors = append(p.loadErrors, err) } @@ -140,7 +164,10 @@ func (p *Packages) LoadWithTypes(importPath string) *packages.Package { pkg := p.Load(importPath) if pkg == nil || pkg.TypesInfo == nil { p.numLoadCalls++ - pkgs, err := packages.Load(&packages.Config{Mode: mode}, importPath) + pkgs, err := packages.Load(&packages.Config{ + Mode: mode, + BuildFlags: p.buildFlags, + }, importPath) if err != nil { p.loadErrors = append(p.loadErrors, err) return nil @@ -173,7 +200,10 @@ func (p *Packages) NameForPackage(importPath string) string { if pkg == nil { // otherwise do a name only lookup for it but don't put it in the package cache. p.numNameCalls++ - pkgs, err := packages.Load(&packages.Config{Mode: packages.NeedName}, importPath) + pkgs, err := packages.Load(&packages.Config{ + Mode: packages.NeedName, + BuildFlags: p.buildFlags, + }, importPath) if err != nil { p.loadErrors = append(p.loadErrors, err) } else { diff --git a/vendor/github.com/99designs/gqlgen/internal/imports/prune.go b/vendor/github.com/99designs/gqlgen/internal/imports/prune.go index d42a4157..f5fc71c6 100644 --- a/vendor/github.com/99designs/gqlgen/internal/imports/prune.go +++ b/vendor/github.com/99designs/gqlgen/internal/imports/prune.go @@ -10,10 +10,10 @@ import ( "go/token" "strings" - "github.com/99designs/gqlgen/internal/code" - "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/imports" + + "github.com/99designs/gqlgen/internal/code" ) type visitFn func(node ast.Node) diff --git a/vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go b/vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go index 1ca722dc..7e68e55d 100644 --- a/vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go +++ b/vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go @@ -10,8 +10,9 @@ import ( "strconv" "strings" - "github.com/99designs/gqlgen/internal/code" "golang.org/x/tools/go/packages" + + "github.com/99designs/gqlgen/internal/code" ) type Rewriter struct { diff --git a/vendor/github.com/99designs/gqlgen/main.go b/vendor/github.com/99designs/gqlgen/main.go index af365bfe..a50f1e27 100644 --- a/vendor/github.com/99designs/gqlgen/main.go +++ b/vendor/github.com/99designs/gqlgen/main.go @@ -1,5 +1,7 @@ package main +//go:generate sh generate_examples.sh + import ( "bytes" _ "embed" @@ -12,12 +14,13 @@ import ( "os" "path/filepath" + "github.com/urfave/cli/v2" + "github.com/99designs/gqlgen/api" "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/internal/code" "github.com/99designs/gqlgen/plugin/servergen" - "github.com/urfave/cli/v2" ) //go:embed init-templates/schema.graphqls diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/entity.go b/vendor/github.com/99designs/gqlgen/plugin/federation/entity.go index 04a3c033..4e9e1afc 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/federation/entity.go +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/entity.go @@ -3,10 +3,11 @@ package federation import ( "go/types" + "github.com/vektah/gqlparser/v2/ast" + "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/plugin/federation/fieldset" - "github.com/vektah/gqlparser/v2/ast" ) // Entity represents a federated type @@ -17,6 +18,7 @@ type Entity struct { Resolvers []*EntityResolver Requires []*Requires Multi bool + Type types.Type } type EntityResolver struct { @@ -115,3 +117,8 @@ func (e *Entity) keyFields() []string { } return keyFields } + +// GetTypeInfo - get the imported package & type name combo. package.TypeName +func (e Entity) GetTypeInfo() string { + return templates.CurrentImports.LookupType(e.Type) +} diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/federation.go b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.go index d0ee8435..240311ac 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/federation/federation.go +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.go @@ -11,6 +11,7 @@ import ( "github.com/99designs/gqlgen/codegen" "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" + "github.com/99designs/gqlgen/internal/rewrite" "github.com/99designs/gqlgen/plugin" "github.com/99designs/gqlgen/plugin/federation/fieldset" ) @@ -18,9 +19,13 @@ import ( //go:embed federation.gotpl var federationTemplate string +//go:embed requires.gotpl +var explicitRequiresTemplate string + type federation struct { - Entities []*Entity - Version int + Entities []*Entity + Version int + PackageOptions map[string]bool } // New returns a federation plugin that injects @@ -59,6 +64,12 @@ func (f *federation) MutateConfig(cfg *config.Config) error { "_Any": { Model: config.StringList{"github.com/99designs/gqlgen/graphql.Map"}, }, + "federation__Scope": { + Model: config.StringList{"github.com/99designs/gqlgen/graphql.String"}, + }, + "federation__Policy": { + Model: config.StringList{"github.com/99designs/gqlgen/graphql.String"}, + }, } for typeName, entry := range builtins { @@ -80,6 +91,11 @@ func (f *federation) MutateConfig(cfg *config.Config) error { cfg.Directives["tag"] = config.DirectiveConfig{SkipRuntime: true} cfg.Directives["override"] = config.DirectiveConfig{SkipRuntime: true} cfg.Directives["inaccessible"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["authenticated"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["requiresScopes"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["policy"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["interfaceObject"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["composeDirective"] = config.DirectiveConfig{SkipRuntime: true} } return nil @@ -101,6 +117,7 @@ func (f *federation) InjectSourceEarly() *ast.Source { ` } else if f.Version == 2 { input += ` + directive @authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM directive @composeDirective(name: String!) repeatable on SCHEMA directive @extends on OBJECT | INTERFACE directive @external on OBJECT | FIELD_DEFINITION @@ -118,9 +135,21 @@ func (f *federation) InjectSourceEarly() *ast.Source { | UNION directive @interfaceObject on OBJECT directive @link(import: [String!], url: String!) repeatable on SCHEMA - directive @override(from: String!) on FIELD_DEFINITION + directive @override(from: String!, label: String) on FIELD_DEFINITION + directive @policy(policies: [[federation__Policy!]!]!) on + | FIELD_DEFINITION + | OBJECT + | INTERFACE + | SCALAR + | ENUM directive @provides(fields: FieldSet!) on FIELD_DEFINITION directive @requires(fields: FieldSet!) on FIELD_DEFINITION + directive @requiresScopes(scopes: [[federation__Scope!]!]!) on + | FIELD_DEFINITION + | OBJECT + | INTERFACE + | SCALAR + | ENUM directive @shareable repeatable on FIELD_DEFINITION | OBJECT directive @tag(name: String!) repeatable on | ARGUMENT_DEFINITION @@ -135,6 +164,8 @@ func (f *federation) InjectSourceEarly() *ast.Source { | UNION scalar _Any scalar FieldSet + scalar federation__Policy + scalar federation__Scope ` } return &ast.Source{ @@ -170,10 +201,14 @@ func (f *federation) InjectSourceLate(schema *ast.Schema) *ast.Source { } entityResolverInputDefinitions += "input " + r.InputTypeName + " {\n" for _, keyField := range r.KeyFields { - entityResolverInputDefinitions += fmt.Sprintf("\t%s: %s\n", keyField.Field.ToGo(), keyField.Definition.Type.String()) + entityResolverInputDefinitions += fmt.Sprintf( + "\t%s: %s\n", + keyField.Field.ToGo(), + keyField.Definition.Type.String(), + ) } entityResolverInputDefinitions += "}" - resolvers += fmt.Sprintf("\t%s(reps: [%s!]!): [%s]\n", r.ResolverName, r.InputTypeName, e.Name) + resolvers += fmt.Sprintf("\t%s(reps: [%s]!): [%s]\n", r.ResolverName, r.InputTypeName, e.Name) } else { resolverArgs := "" for _, keyField := range r.KeyFields { @@ -233,6 +268,16 @@ type Entity { } func (f *federation) GenerateCode(data *codegen.Data) error { + // requires imports + requiresImports := make(map[string]bool, 0) + requiresImports["context"] = true + requiresImports["fmt"] = true + + requiresEntities := make(map[string]*Entity, 0) + + // Save package options on f for template use + f.PackageOptions = data.Config.Federation.Options + if len(f.Entities) > 0 { if data.Objects.ByName("Entity") != nil { data.Objects.ByName("Entity").Root = true @@ -272,9 +317,19 @@ func (f *federation) GenerateCode(data *codegen.Data) error { fmt.Println("skipping @requires field " + reqField.Name + " in " + e.Def.Name) continue } + // keep track of which entities have requires + requiresEntities[e.Def.Name] = e + // make a proper import path + typeString := strings.Split(obj.Type.String(), ".") + requiresImports[strings.Join(typeString[:len(typeString)-1], ".")] = true + cgField := reqField.Field.TypeReference(obj, data.Objects) reqField.Type = cgField.TypeReference } + + // add type info to entity + e.Type = obj.Type + } } @@ -295,10 +350,82 @@ func (f *federation) GenerateCode(data *codegen.Data) error { } } + if data.Config.Federation.Options["explicit_requires"] && len(requiresEntities) > 0 { + // check for existing requires functions + type Populator struct { + FuncName string + Exists bool + Comment string + Implementation string + Entity *Entity + } + populators := make([]Populator, 0) + + rewriter, err := rewrite.New(data.Config.Federation.Dir()) + if err != nil { + return err + } + + for name, entity := range requiresEntities { + populator := Populator{ + FuncName: fmt.Sprintf("Populate%sRequires", name), + Entity: entity, + } + + populator.Comment = strings.TrimSpace(strings.TrimLeft(rewriter.GetMethodComment("executionContext", populator.FuncName), `\`)) + populator.Implementation = strings.TrimSpace(rewriter.GetMethodBody("executionContext", populator.FuncName)) + + if populator.Implementation == "" { + populator.Exists = false + populator.Implementation = fmt.Sprintf("panic(fmt.Errorf(\"not implemented: %v\"))", populator.FuncName) + } + populators = append(populators, populator) + } + + sort.Slice(populators, func(i, j int) bool { + return populators[i].FuncName < populators[j].FuncName + }) + + requiresFile := data.Config.Federation.Dir() + "/federation.requires.go" + existingImports := rewriter.ExistingImports(requiresFile) + for _, imp := range existingImports { + if imp.Alias == "" { + // import exists in both places, remove + delete(requiresImports, imp.ImportPath) + } + } + + for k := range requiresImports { + existingImports = append(existingImports, rewrite.Import{ImportPath: k}) + } + + // render requires populators + err = templates.Render(templates.Options{ + PackageName: data.Config.Federation.Package, + Filename: requiresFile, + Data: struct { + federation + ExistingImports []rewrite.Import + Populators []Populator + OriginalSource string + }{*f, existingImports, populators, ""}, + GeneratedHeader: false, + Packages: data.Config.Packages, + Template: explicitRequiresTemplate, + }) + if err != nil { + return err + } + + } + return templates.Render(templates.Options{ - PackageName: data.Config.Federation.Package, - Filename: data.Config.Federation.Filename, - Data: f, + PackageName: data.Config.Federation.Package, + Filename: data.Config.Federation.Filename, + Data: struct { + federation + UsePointers bool + }{*f, data.Config.ResolversAlwaysReturnPointers}, GeneratedHeader: true, Packages: data.Config.Packages, Template: federationTemplate, diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl index 7cf84287..ca0e6e2d 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl @@ -5,6 +5,8 @@ {{ reserveImport "sync" }} {{ reserveImport "github.com/99designs/gqlgen/plugin/federation/fedruntime" }} +{{ $options := .PackageOptions }} +{{ $usePointers := .UsePointers }} var ( ErrUnknownType = errors.New("unknown type") @@ -103,11 +105,18 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati if err != nil { return fmt.Errorf(`resolving Entity "{{$entity.Def.Name}}": %w`, err) } - {{ range $entity.Requires }} - entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"]) + {{ if and (index $options "explicit_requires") $entity.Requires }} + err = ec.Populate{{$entity.Def.Name}}Requires(ctx, {{- if (not $usePointers) -}}&{{- end -}}entity, rep) if err != nil { - return err + return fmt.Errorf(`populating requires for Entity "{{$entity.Def.Name}}": %w`, err) } + {{- else }} + {{ range $entity.Requires }} + entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"]) + if err != nil { + return err + } + {{- end }} {{- end }} list[idx[i]] = entity return nil @@ -132,7 +141,13 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati {{ range $_, $entity := .Entities }} {{ if and .Resolvers .Multi -}} case "{{.Def.Name}}": - {{range $i, $_ := .Resolvers -}} + resolverName, err := entityResolverNameFor{{.Def.Name}}(ctx, reps[0]) + if err != nil { + return fmt.Errorf(`finding resolver for Entity "{{.Def.Name}}": %w`, err) + } + switch resolverName { + {{ range $i, $resolver := .Resolvers }} + case "{{.ResolverName}}": _reps := make([]*{{.LookupInputType}}, len(reps)) for i, rep := range reps { @@ -166,6 +181,9 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati } return nil {{ end }} + default: + return fmt.Errorf("unknown resolver: %s", resolverName) + } {{ end }} {{- end }} default: diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/fieldset/fieldset.go b/vendor/github.com/99designs/gqlgen/plugin/federation/fieldset/fieldset.go index 059a3c83..8ff53cd2 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/federation/fieldset/fieldset.go +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/fieldset/fieldset.go @@ -4,9 +4,10 @@ import ( "fmt" "strings" + "github.com/vektah/gqlparser/v2/ast" + "github.com/99designs/gqlgen/codegen" "github.com/99designs/gqlgen/codegen/templates" - "github.com/vektah/gqlparser/v2/ast" ) // Set represents a FieldSet that is used in federation directives @key and @requires. @@ -99,6 +100,7 @@ func (f Field) ToGoPrivate() string { for i, field := range f { if i == 0 { + field = trimArgumentFromFieldName(field) ret += templates.ToGoPrivate(field) continue } @@ -133,7 +135,7 @@ func parseUnnestedKeyFieldSet(raw string, prefix []string) Set { ret := Set{} for _, s := range strings.Fields(raw) { - next := append(prefix[:], s) //nolint:gocritic // slicing out on purpose + next := append(prefix[0:len(prefix):len(prefix)], s) //nolint:gocritic // set cap=len in order to force slice reallocation ret = append(ret, next) } return ret @@ -147,7 +149,7 @@ func extractSubs(str string) (string, string, string) { if start < 0 || end < 0 { panic("invalid key fieldSet: " + str) } - return strings.TrimSpace(str[:start]), strings.TrimSpace(str[start+1 : end]), strings.TrimSpace(str[end+1:]) + return trimArgumentFromFieldName(strings.TrimSpace(str[:start])), strings.TrimSpace(str[start+1 : end]), strings.TrimSpace(str[end+1:]) } // matchingBracketIndex returns the index of the closing bracket, assuming an open bracket at start. @@ -173,9 +175,16 @@ func matchingBracketIndex(str string, start int) int { func fieldByName(obj *codegen.Object, name string) *codegen.Field { for _, field := range obj.Fields { + field.Name = trimArgumentFromFieldName(field.Name) if field.Name == name { return field } } return nil } + +// trimArgumentFromFieldName removes any arguments from the field name. +// It removes any suffixes from the raw string, starting from the argument-open character `(` +func trimArgumentFromFieldName(raw string) string { + return strings.Split(raw, "(")[0] +} diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/readme.md b/vendor/github.com/99designs/gqlgen/plugin/federation/readme.md index 4333ed47..d5dd0628 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/federation/readme.md +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/readme.md @@ -37,3 +37,6 @@ func (r *entityResolver) FindManyMultiHellosByName(ctx context.Context, reps []* /// } ``` + +**Note:** +If you are using `omit_slice_element_pointers: true` option in your config yaml, your `GetMany` resolver will still generate in the example above the same signature `FindManyMultiHellosByName(ctx context.Context, reps []*generated.ManyMultiHellosByNameInput) ([]*generated.MultiHello, error)`. But all other instances will continue to honor `omit_slice_element_pointers: true` \ No newline at end of file diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/requires.gotpl b/vendor/github.com/99designs/gqlgen/plugin/federation/requires.gotpl new file mode 100644 index 00000000..17377104 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/requires.gotpl @@ -0,0 +1,20 @@ +{{ range .ExistingImports }} +{{ if ne .Alias "" }} +{{ reserveImport .ImportPath .Alias }} +{{ else }} +{{ reserveImport .ImportPath }} +{{ end }} +{{ end }} + +{{ range .Populators -}} +{{ if .Comment -}} +// {{.Comment}} +{{- else -}} +// {{.FuncName}} is the requires populator for the {{.Entity.Def.Name}} entity. +{{- end }} +func (ec *executionContext) {{.FuncName}}(ctx context.Context, entity *{{.Entity.GetTypeInfo}}, reps map[string]interface{}) error { + {{.Implementation}} +} +{{ end }} + +{{ .OriginalSource }} diff --git a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go index 23c2e334..f59991a0 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go +++ b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go @@ -9,10 +9,11 @@ import ( "strings" "text/template" + "github.com/vektah/gqlparser/v2/ast" + "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/plugin" - "github.com/vektah/gqlparser/v2/ast" ) //go:embed models.gotpl @@ -52,6 +53,7 @@ type Interface struct { Fields []*Field Implements []string OmitCheck bool + Models []*Object } type Object struct { @@ -66,10 +68,11 @@ type Field struct { // Name is the field's name as it appears in the schema Name string // GoName is the field's name as it appears in the generated Go code - GoName string - Type types.Type - Tag string - Omittable bool + GoName string + Type types.Type + Tag string + IsResolver bool + Omittable bool } type Enum struct { @@ -129,9 +132,20 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { OmitCheck: cfg.OmitInterfaceChecks, } + // if the interface has a key directive as an entity interface, allow it to implement _Entity + if schemaType.Directives.ForName("key") != nil { + it.Implements = append(it.Implements, "_Entity") + } + b.Interfaces = append(b.Interfaces, it) case ast.Object, ast.InputObject: - if schemaType == cfg.Schema.Query || schemaType == cfg.Schema.Mutation || schemaType == cfg.Schema.Subscription { + if cfg.IsRoot(schemaType) { + if !cfg.OmitRootModels { + b.Models = append(b.Models, &Object{ + Description: schemaType.Description, + Name: schemaType.Name, + }) + } continue } @@ -162,6 +176,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { uniqueMap[iface] = true } } + } b.Models = append(b.Models, it) @@ -200,6 +215,18 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { cfg.Models.Add(it.Name, cfg.Model.ImportPath()+"."+templates.ToGo(it.Name)) } for _, it := range b.Interfaces { + // On a given interface we want to keep a reference to all the models that implement it + for _, model := range b.Models { + for _, impl := range model.Implements { + if impl == it.Name { + // check if this isn't an implementation of an entity interface + if impl != "_Entity" { + // If this model has an implementation, add it to the Interface's Models + it.Models = append(it.Models, model) + } + } + } + } cfg.Models.Add(it.Name, cfg.Model.ImportPath()+"."+templates.ToGo(it.Name)) } for _, it := range b.Scalars { @@ -393,6 +420,10 @@ func (m *Plugin) generateFields(cfg *config.Config, schemaType *ast.Definition) f = mf } + if f.IsResolver && cfg.OmitResolverFields { + continue + } + if f.Omittable { if schemaType.Kind != ast.InputObject || field.Type.NonNull { return nil, fmt.Errorf("generror: field %v.%v: omittable is only applicable to nullable input fields", schemaType.Name, field.Name) @@ -558,17 +589,19 @@ func removeDuplicateTags(t string) string { continue } - processed[kv[0]] = true + key := kv[0] + value := strings.Join(kv[1:], ":") + processed[key] = true if len(returnTags) > 0 { returnTags = " " + returnTags } - isContained := containsInvalidSpace(kv[1]) + isContained := containsInvalidSpace(value) if isContained { - panic(fmt.Errorf("tag value should not contain any leading or trailing spaces: %s", kv[1])) + panic(fmt.Errorf("tag value should not contain any leading or trailing spaces: %s", value)) } - returnTags = kv[0] + ":" + kv[1] + returnTags + returnTags = key + ":" + value + returnTags } return returnTags @@ -585,6 +618,12 @@ func GoFieldHook(td *ast.Definition, fd *ast.FieldDefinition, f *Field) (*Field, } } + if arg := goField.Arguments.ForName("forceResolver"); arg != nil { + if k, err := arg.Value.Value(nil); err == nil { + f.IsResolver = k.(bool) + } + } + if arg := goField.Arguments.ForName("omittable"); arg != nil { if k, err := arg.Value.Value(nil); err == nil { f.Omittable = k.(bool) diff --git a/vendor/github.com/99designs/gqlgen/plugin/plugin.go b/vendor/github.com/99designs/gqlgen/plugin/plugin.go index 69801c88..ccb8f8b9 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/plugin.go +++ b/vendor/github.com/99designs/gqlgen/plugin/plugin.go @@ -3,9 +3,10 @@ package plugin import ( + "github.com/vektah/gqlparser/v2/ast" + "github.com/99designs/gqlgen/codegen" "github.com/99designs/gqlgen/codegen/config" - "github.com/vektah/gqlparser/v2/ast" ) type Plugin interface { @@ -30,7 +31,7 @@ type LateSourceInjector interface { InjectSourceLate(schema *ast.Schema) *ast.Source } -// Implementer is used to generate code inside resolvers +// ResolverImplementer is used to generate code inside resolvers type ResolverImplementer interface { Implement(field *codegen.Field) string } diff --git a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go index d5515da3..085c2958 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go +++ b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go @@ -68,7 +68,7 @@ func (m *Plugin) generateSingleFile(data *codegen.Data) error { continue } - resolver := Resolver{o, f, nil, "", `panic("not implemented")`} + resolver := Resolver{o, f, nil, "", `panic("not implemented")`, nil} file.Resolvers = append(file.Resolvers, &resolver) } } @@ -110,9 +110,12 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error { for _, o := range objects { if o.HasResolvers() { - fn := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate) + fnCase := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate) + fn := strings.ToLower(fnCase) if files[fn] == nil { - files[fn] = &File{} + files[fn] = &File{ + name: fnCase, + } } caser := cases.Title(language.English, cases.NoLower) @@ -127,48 +130,46 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error { structName := templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type) comment := strings.TrimSpace(strings.TrimLeft(rewriter.GetMethodComment(structName, f.GoFieldName), `\`)) - implementation := strings.TrimSpace(rewriter.GetMethodBody(structName, f.GoFieldName)) if implementation == "" { - // Check for Implementer Plugin - var resolver_implementer plugin.ResolverImplementer - var exists bool - for _, p := range data.Plugins { - if p_cast, ok := p.(plugin.ResolverImplementer); ok { - resolver_implementer = p_cast - exists = true - break - } - } - - if exists { - implementation = resolver_implementer.Implement(f) - } else { - implementation = fmt.Sprintf("panic(fmt.Errorf(\"not implemented: %v - %v\"))", f.GoFieldName, f.Name) - } - + // use default implementation, if no implementation was previously used + implementation = fmt.Sprintf("panic(fmt.Errorf(\"not implemented: %v - %v\"))", f.GoFieldName, f.Name) } - - resolver := Resolver{o, f, rewriter.GetPrevDecl(structName, f.GoFieldName), comment, implementation} - fn := gqlToResolverName(data.Config.Resolver.Dir(), f.Position.Src.Name, data.Config.Resolver.FilenameTemplate) + resolver := Resolver{o, f, rewriter.GetPrevDecl(structName, f.GoFieldName), comment, implementation, nil} + var implExists bool + for _, p := range data.Plugins { + rImpl, ok := p.(plugin.ResolverImplementer) + if !ok { + continue + } + if implExists { + return fmt.Errorf("multiple plugins implement ResolverImplementer") + } + implExists = true + resolver.ImplementationRender = rImpl.Implement + } + fnCase := gqlToResolverName(data.Config.Resolver.Dir(), f.Position.Src.Name, data.Config.Resolver.FilenameTemplate) + fn := strings.ToLower(fnCase) if files[fn] == nil { - files[fn] = &File{} + files[fn] = &File{ + name: fnCase, + } } files[fn].Resolvers = append(files[fn].Resolvers, &resolver) } } - for filename, file := range files { - file.imports = rewriter.ExistingImports(filename) - file.RemainingSource = rewriter.RemainingSource(filename) + for _, file := range files { + file.imports = rewriter.ExistingImports(file.name) + file.RemainingSource = rewriter.RemainingSource(file.name) } newResolverTemplate := resolverTemplate if data.Config.Resolver.ResolverTemplate != "" { newResolverTemplate = readResolverTemplate(data.Config.Resolver.ResolverTemplate) } - for filename, file := range files { + for _, file := range files { resolverBuild := &ResolverBuild{ File: file, PackageName: data.Config.Resolver.Package, @@ -192,7 +193,7 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error { err := templates.Render(templates.Options{ PackageName: data.Config.Resolver.Package, FileNotice: fileNotice.String(), - Filename: filename, + Filename: file.name, Data: resolverBuild, Packages: data.Config.Packages, Template: newResolverTemplate, @@ -230,6 +231,7 @@ type ResolverBuild struct { } type File struct { + name string // These are separated because the type definition of the resolver object may live in a different file from the // resolver method implementations, for example when extending a type in a different graphql schema file Objects []*codegen.Object @@ -250,11 +252,19 @@ func (f *File) Imports() string { } type Resolver struct { - Object *codegen.Object - Field *codegen.Field - PrevDecl *ast.FuncDecl - Comment string - Implementation string + Object *codegen.Object + Field *codegen.Field + PrevDecl *ast.FuncDecl + Comment string + ImplementationStr string + ImplementationRender func(r *codegen.Field) string +} + +func (r *Resolver) Implementation() string { + if r.ImplementationRender != nil { + return r.ImplementationRender(r.Field) + } + return r.ImplementationStr } func gqlToResolverName(base string, gqlname, filenameTmpl string) string { diff --git a/vendor/github.com/Knetic/govaluate/.travis.yml b/vendor/github.com/Knetic/govaluate/.travis.yml deleted file mode 100644 index f6c430f1..00000000 --- a/vendor/github.com/Knetic/govaluate/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go - -script: ./test.sh - -go: - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 diff --git a/vendor/github.com/adhocore/gronx/README.md b/vendor/github.com/adhocore/gronx/README.md index 7d53ad0d..0b3b78f5 100644 --- a/vendor/github.com/adhocore/gronx/README.md +++ b/vendor/github.com/adhocore/gronx/README.md @@ -75,12 +75,12 @@ gron.BatchDue(exprs, ref) To find out when is the cron due next (in near future): ```go allowCurrent = true // includes current time as well -nextTime, err := gron.NextTick(expr, allowCurrent) // gives time.Time, error +nextTime, err := gronx.NextTick(expr, allowCurrent) // gives time.Time, error // OR, next tick after certain reference time refTime = time.Date(2022, time.November, 1, 1, 1, 0, 0, time.UTC) allowCurrent = false // excludes the ref time -nextTime, err := gron.NextTickAfter(expr, refTime, allowCurrent) // gives time.Time, error +nextTime, err := gronx.NextTickAfter(expr, refTime, allowCurrent) // gives time.Time, error ``` ### Prev Tick @@ -88,12 +88,12 @@ nextTime, err := gron.NextTickAfter(expr, refTime, allowCurrent) // gives time.T To find out when was the cron due previously (in near past): ```go allowCurrent = true // includes current time as well -prevTime, err := gron.PrevTick(expr, allowCurrent) // gives time.Time, error +prevTime, err := gronx.PrevTick(expr, allowCurrent) // gives time.Time, error // OR, prev tick before certain reference time refTime = time.Date(2022, time.November, 1, 1, 1, 0, 0, time.UTC) allowCurrent = false // excludes the ref time -nextTime, err := gron.PrevTickBefore(expr, refTime, allowCurrent) // gives time.Time, error +nextTime, err := gronx.PrevTickBefore(expr, refTime, allowCurrent) // gives time.Time, error ``` > The working of `PrevTick*()` and `NextTick*()` are mostly the same except the direction. @@ -304,8 +304,8 @@ Following modifiers supported - `L` stands for last day of month (eg: `L` could mean 29th for February in leap year) - `W` stands for closest week day (eg: `10W` is closest week days (MON-FRI) to 10th date) - *Day of Week / 5th of 5 segments / 6th of 6+ segments:* - - `L` stands for last weekday of month (eg: `2L` is last monday) - - `#` stands for nth day of week in the month (eg: `1#2` is second sunday) + - `L` stands for last weekday of month (eg: `2L` is last tuesday) + - `#` stands for nth day of week in the month (eg: `1#2` is second monday) --- ## License diff --git a/vendor/github.com/adhocore/gronx/checker.go b/vendor/github.com/adhocore/gronx/checker.go index 789570d4..8ce1d9d9 100644 --- a/vendor/github.com/adhocore/gronx/checker.go +++ b/vendor/github.com/adhocore/gronx/checker.go @@ -34,10 +34,10 @@ func (c *SegmentChecker) SetRef(ref time.Time) { func (c *SegmentChecker) CheckDue(segment string, pos int) (due bool, err error) { ref, last := c.GetRef(), -1 val, loc := valueByPos(ref, pos), ref.Location() - isMonth, isWeekDay := pos == 3, pos == 5 + isMonthDay, isWeekDay := pos == 3, pos == 5 for _, offset := range strings.Split(segment, ",") { - mod := (isMonth || isWeekDay) && strings.ContainsAny(offset, "LW#") + mod := (isMonthDay || isWeekDay) && strings.ContainsAny(offset, "LW#") if due, err = c.isOffsetDue(offset, val, pos); due || (!mod && err != nil) { return } @@ -45,9 +45,9 @@ func (c *SegmentChecker) CheckDue(segment string, pos int) (due bool, err error) continue } if last == -1 { - last = time.Date(ref.Year(), ref.Month(), 1, 0, 0, 0, 0, loc).AddDate(0, 1, 0).Add(-time.Nanosecond).Day() + last = time.Date(ref.Year(), ref.Month(), 1, 0, 0, 0, 0, loc).AddDate(0, 1, 0).Add(-time.Second).Day() } - if isMonth { + if isMonthDay { due, err = isValidMonthDay(offset, last, ref) } else if isWeekDay { due, err = isValidWeekDay(offset, last, ref) @@ -81,14 +81,14 @@ func (c *SegmentChecker) isOffsetDue(offset string, val, pos int) (bool, error) return false, err } - if !isWeekDay && (val == 0 || nval == 0) { - return nval == 0 && val == 0, nil - } - if nval < bounds[0] || nval > bounds[1] { return false, fmt.Errorf("segment#%d: '%s' out of bounds(%d, %d)", pos, offset, bounds[0], bounds[1]) } + if !isWeekDay && (val == 0 || nval == 0) { + return nval == 0 && val == 0, nil + } + return nval == val || (isWeekDay && nval == 7 && val == 0), nil } @@ -126,7 +126,7 @@ func boundsByPos(pos int) (bounds []int) { case 5: bounds = []int{0, 7} case 6: - bounds = []int{1, 9999} + bounds = []int{0, 9999} } return } diff --git a/vendor/github.com/adhocore/gronx/gronx.go b/vendor/github.com/adhocore/gronx/gronx.go index f86f904d..958d8fb1 100644 --- a/vendor/github.com/adhocore/gronx/gronx.go +++ b/vendor/github.com/adhocore/gronx/gronx.go @@ -29,6 +29,23 @@ var expressions = map[string]string{ "@everysecond": "* * * * * *", } +// AddTag adds a new custom tag representing given expr +func AddTag(tag, expr string) error { + _, ok := expressions[tag] + if ok { + return errors.New("conflict tag") + } + + segs, err := Segments(expr) + if err != nil { + return err + } + expr = strings.Join(segs, " ") + + expressions[tag] = expr + return nil +} + // SpaceRe is regex for whitespace. var SpaceRe = regexp.MustCompile(`\s+`) var yearRe = regexp.MustCompile(`\d{4}`) @@ -51,8 +68,8 @@ type Gronx struct { } // New initializes Gronx with factory defaults. -func New() Gronx { - return Gronx{&SegmentChecker{}} +func New() *Gronx { + return &Gronx{&SegmentChecker{}} } // IsDue checks if cron expression is due for given reference time (or now). @@ -96,11 +113,42 @@ func Segments(expr string) ([]string, error) { // SegmentsDue checks if all cron parts are due. // It returns bool. You should use IsDue(expr) instead. func (g *Gronx) SegmentsDue(segs []string) (bool, error) { - for pos, seg := range segs { + skipMonthDayCheck := false + for i := 0; i < len(segs); i++ { + pos := len(segs) - 1 - i + seg := segs[pos] + isMonthDay, isWeekday := pos == 3, pos == 5 + if seg == "*" || seg == "?" { continue } + if isMonthDay && skipMonthDayCheck { + continue + } + + if isWeekday { + monthDaySeg := segs[3] + intersect := strings.Index(seg, "*/") == 0 || strings.Index(monthDaySeg, "*") == 0 || monthDaySeg == "?" + + if !intersect { + due, err := g.C.CheckDue(seg, pos) + if err != nil { + return false, err + } + + monthDayDue, err := g.C.CheckDue(monthDaySeg, 3) + if due || monthDayDue { + skipMonthDayCheck = true + continue + } + + if err != nil { + return false, err + } + } + } + if due, err := g.C.CheckDue(seg, pos); !due { return due, err } @@ -109,6 +157,9 @@ func (g *Gronx) SegmentsDue(segs []string) (bool, error) { return true, nil } +// checker for validity +var checker = &SegmentChecker{ref: time.Now()} + // IsValid checks if cron expression is valid. // It returns bool. func (g *Gronx) IsValid(expr string) bool { @@ -117,9 +168,8 @@ func (g *Gronx) IsValid(expr string) bool { return false } - g.C.SetRef(time.Now()) for pos, seg := range segs { - if _, err := g.C.CheckDue(seg, pos); err != nil { + if _, err := checker.CheckDue(seg, pos); err != nil { return false } } diff --git a/vendor/github.com/adhocore/gronx/next.go b/vendor/github.com/adhocore/gronx/next.go index 9b940ffb..3643374a 100644 --- a/vendor/github.com/adhocore/gronx/next.go +++ b/vendor/github.com/adhocore/gronx/next.go @@ -41,25 +41,79 @@ func NextTickAfter(expr string, start time.Time, inclRefTime bool) (time.Time, e return next, err } -func loop(gron Gronx, segments []string, start time.Time, incl bool, reverse bool) (next time.Time, err error) { +func loop(gron *Gronx, segments []string, start time.Time, incl bool, reverse bool) (next time.Time, err error) { iter, next, bumped := 500, start, false over: for iter > 0 { iter-- - for pos, seg := range segments { + skipMonthDayForIter := false + for i := 0; i < len(segments); i++ { + pos := len(segments) - 1 - i + seg := segments[pos] + isMonthDay, isWeekday := pos == 3, pos == 5 + if seg == "*" || seg == "?" { continue } - if next, bumped, err = bumpUntilDue(gron.C, seg, pos, next, reverse); bumped { + + if !isWeekday { + if isMonthDay && skipMonthDayForIter { + continue + } + if next, bumped, err = bumpUntilDue(gron.C, seg, pos, next, reverse); bumped { + goto over + } + continue + } + // From here we process the weekday segment in case it is neither * nor ? + + monthDaySeg := segments[3] + intersect := strings.Index(seg, "*/") == 0 || strings.Index(monthDaySeg, "*") == 0 || monthDaySeg == "?" + + nextForWeekDay := next + nextForWeekDay, bumped, err = bumpUntilDue(gron.C, seg, pos, nextForWeekDay, reverse) + if !bumped { + // Weekday seg is specific and next is already at right weekday, so no need to process month day if union case + next = nextForWeekDay + if !intersect { + skipMonthDayForIter = true + } + continue + } + // Weekday was bumped, so we need to check for month day + + if intersect { + // We need intersection so we keep bumped weekday and go over + next = nextForWeekDay goto over } + // Month day seg is specific and a number/list/range, so we need to check and keep the closest to next + + nextForMonthDay := next + nextForMonthDay, bumped, err = bumpUntilDue(gron.C, monthDaySeg, 3, nextForMonthDay, reverse) + + monthDayIsClosestToNextThanWeekDay := reverse && nextForMonthDay.After(nextForWeekDay) || + !reverse && nextForMonthDay.Before(nextForWeekDay) + + if monthDayIsClosestToNextThanWeekDay { + next = nextForMonthDay + if !bumped { + // Month day seg is specific and next is already at right month day, we can continue + skipMonthDayForIter = true + continue + } + } else { + next = nextForWeekDay + } + goto over } + if !incl && next.Format(FullDateFormat) == start.Format(FullDateFormat) { delta := time.Second if reverse { delta = -time.Second } - next, _, err = bumpUntilDue(gron.C, segments[0], 0, next.Add(delta), reverse) + next = next.Add(delta) continue } return @@ -105,31 +159,37 @@ func bumpUntilDue(c Checker, segment string, pos int, ref time.Time, reverse boo if ok, _ := c.CheckDue(segment, pos); ok { return ref, iter != limit[pos], nil } - ref = bump(ref, pos, reverse) + if reverse { + ref = bumpReverse(ref, pos) + } else { + ref = bump(ref, pos) + } iter-- } return ref, false, errors.New("tried so hard") } -func bump(ref time.Time, pos int, reverse bool) time.Time { - factor := 1 - if reverse { - factor = -1 - } +func bump(ref time.Time, pos int) time.Time { + loc := ref.Location() switch pos { case 0: - ref = ref.Add(time.Duration(factor) * time.Second) + ref = ref.Add(time.Second) case 1: - ref = ref.Add(time.Duration(factor) * time.Minute) + minTime := ref.Add(time.Minute) + ref = time.Date(minTime.Year(), minTime.Month(), minTime.Day(), minTime.Hour(), minTime.Minute(), 0, 0, loc) case 2: - ref = ref.Add(time.Duration(factor) * time.Hour) + hTime := ref.Add(time.Hour) + ref = time.Date(hTime.Year(), hTime.Month(), hTime.Day(), hTime.Hour(), 0, 0, 0, loc) case 3, 5: - ref = ref.AddDate(0, 0, factor) + dTime := ref.AddDate(0, 0, 1) + ref = time.Date(dTime.Year(), dTime.Month(), dTime.Day(), 0, 0, 0, 0, loc) case 4: - ref = ref.AddDate(0, factor, 0) + ref = time.Date(ref.Year(), ref.Month(), 1, 0, 0, 0, 0, loc) + ref = ref.AddDate(0, 1, 0) case 6: - ref = ref.AddDate(factor, 0, 0) + yTime := ref.AddDate(1, 0, 0) + ref = time.Date(yTime.Year(), 1, 1, 0, 0, 0, 0, loc) } return ref } diff --git a/vendor/github.com/adhocore/gronx/prev.go b/vendor/github.com/adhocore/gronx/prev.go index d900bf73..cc2fc942 100644 --- a/vendor/github.com/adhocore/gronx/prev.go +++ b/vendor/github.com/adhocore/gronx/prev.go @@ -30,3 +30,28 @@ func PrevTickBefore(expr string, start time.Time, inclRefTime bool) (time.Time, } return prev, err } + +func bumpReverse(ref time.Time, pos int) time.Time { + loc := ref.Location() + + switch pos { + case 0: + ref = ref.Add(-time.Second) + case 1: + minTime := ref.Add(-time.Minute) + ref = time.Date(minTime.Year(), minTime.Month(), minTime.Day(), minTime.Hour(), minTime.Minute(), 59, 0, loc) + case 2: + hTime := ref.Add(-time.Hour) + ref = time.Date(hTime.Year(), hTime.Month(), hTime.Day(), hTime.Hour(), 59, 59, 0, loc) + case 3, 5: + dTime := ref.AddDate(0, 0, -1) + ref = time.Date(dTime.Year(), dTime.Month(), dTime.Day(), 23, 59, 59, 0, loc) + case 4: + ref = time.Date(ref.Year(), ref.Month(), 1, 0, 0, 0, 0, loc) + ref = ref.Add(-time.Second) + case 6: + yTime := ref.AddDate(-1, 0, 0) + ref = time.Date(yTime.Year(), 12, 31, 23, 59, 59, 0, loc) + } + return ref +} diff --git a/vendor/github.com/adhocore/gronx/validator.go b/vendor/github.com/adhocore/gronx/validator.go index e5b1eb27..62c3a363 100644 --- a/vendor/github.com/adhocore/gronx/validator.go +++ b/vendor/github.com/adhocore/gronx/validator.go @@ -18,7 +18,10 @@ func inStep(val int, s string, bounds []int) (bool, error) { return false, errors.New("step can't be 0") } - if strings.Index(s, "*/") == 0 || strings.Index(s, "0/") == 0 { + if strings.Index(s, "*/") == 0 { + return (val-bounds[0])%step == 0, nil + } + if strings.Index(s, "0/") == 0 { return val%step == 0, nil } @@ -104,22 +107,20 @@ func isValidMonthDay(val string, last int, ref time.Time) (valid bool, err error func isValidWeekDay(val string, last int, ref time.Time) (bool, error) { loc := ref.Location() - if pos := strings.Index(strings.ReplaceAll(val, "7L", "0L"), "L"); pos > 0 { + + if pos := strings.Index(val, "L"); pos > 0 { nval, err := strconv.Atoi(val[0:pos]) if err != nil { return false, err } for i := 0; i < 7; i++ { - decr := last - i - dref := time.Date(ref.Year(), ref.Month(), decr, ref.Hour(), ref.Minute(), ref.Second(), ref.Nanosecond(), loc) - - if int(dref.Weekday()) == nval { - return ref.Day() == decr, nil + day := last - i + dref := time.Date(ref.Year(), ref.Month(), day, ref.Hour(), ref.Minute(), ref.Second(), 0, loc) + if int(dref.Weekday()) == nval%7 { + return ref.Day() == day, nil } } - - return false, nil } pos := strings.Index(val, "#") diff --git a/vendor/github.com/caddyserver/certmagic/README.md b/vendor/github.com/caddyserver/certmagic/README.md index aba3ad14..8e3b145d 100644 --- a/vendor/github.com/caddyserver/certmagic/README.md +++ b/vendor/github.com/caddyserver/certmagic/README.md @@ -233,6 +233,9 @@ tlsConfig, err := certmagic.TLS([]string{"example.com"}) if err != nil { return err } +// be sure to customize NextProtos if serving a specific +// application protocol after the TLS handshake, for example: +tlsConfig.NextProtos = append([]string{"h2", "http/1.1"}, tlsConfig.NextProtos...) ``` diff --git a/vendor/github.com/caddyserver/certmagic/async.go b/vendor/github.com/caddyserver/certmagic/async.go index 584a9c2e..e61343c8 100644 --- a/vendor/github.com/caddyserver/certmagic/async.go +++ b/vendor/github.com/caddyserver/certmagic/async.go @@ -155,8 +155,8 @@ var AttemptsCtxKey retryStateCtxKey // front. We figure that intermittent errors would be // resolved after the first retry, but any errors after // that would probably require at least a few minutes -// to clear up: either for DNS to propagate, for the -// administrator to fix their DNS or network properties, +// or hours to clear up: either for DNS to propagate, for +// the administrator to fix their DNS or network config, // or some other external factor needs to change. We // chose intervals that we think will be most useful // without introducing unnecessary delay. The last @@ -168,13 +168,26 @@ var retryIntervals = []time.Duration{ 2 * time.Minute, 5 * time.Minute, // elapsed: 10 min 10 * time.Minute, - 20 * time.Minute, + 10 * time.Minute, + 10 * time.Minute, 20 * time.Minute, // elapsed: 1 hr + 20 * time.Minute, + 20 * time.Minute, + 20 * time.Minute, // elapsed: 2 hr 30 * time.Minute, - 30 * time.Minute, // elapsed: 2 hr + 30 * time.Minute, // elapsed: 3 hr + 30 * time.Minute, + 30 * time.Minute, // elapsed: 4 hr + 30 * time.Minute, + 30 * time.Minute, // elapsed: 5 hr + 1 * time.Hour, // elapsed: 6 hr 1 * time.Hour, - 3 * time.Hour, // elapsed: 6 hr - 6 * time.Hour, // for up to maxRetryDuration + 1 * time.Hour, // elapsed: 8 hr + 2 * time.Hour, + 2 * time.Hour, // elapsed: 12 hr + 3 * time.Hour, + 3 * time.Hour, // elapsed: 18 hr + 6 * time.Hour, // repeat for up to maxRetryDuration } // maxRetryDuration is the maximum duration to try diff --git a/vendor/github.com/caddyserver/certmagic/certificates.go b/vendor/github.com/caddyserver/certmagic/certificates.go index 16e51aaf..dbee2aaf 100644 --- a/vendor/github.com/caddyserver/certmagic/certificates.go +++ b/vendor/github.com/caddyserver/certmagic/certificates.go @@ -410,7 +410,8 @@ func SubjectIsIP(subj string) bool { func SubjectIsInternal(subj string) bool { return subj == "localhost" || strings.HasSuffix(subj, ".localhost") || - strings.HasSuffix(subj, ".local") + strings.HasSuffix(subj, ".local") || + strings.HasSuffix(subj, ".home.arpa") } // MatchWildcard returns true if subject (a candidate DNS name) diff --git a/vendor/github.com/caddyserver/certmagic/certmagic.go b/vendor/github.com/caddyserver/certmagic/certmagic.go index 6bc33d58..860f5e76 100644 --- a/vendor/github.com/caddyserver/certmagic/certmagic.go +++ b/vendor/github.com/caddyserver/certmagic/certmagic.go @@ -268,7 +268,7 @@ type OnDemandConfig struct { // whether a certificate can be obtained or renewed // for the given name. If an error is returned, the // request will be denied. - DecisionFunc func(name string) error + DecisionFunc func(ctx context.Context, name string) error // Sources for getting new, unmanaged certificates. // They will be invoked only during TLS handshakes diff --git a/vendor/github.com/caddyserver/certmagic/handshake.go b/vendor/github.com/caddyserver/certmagic/handshake.go index 1e9928ba..9c923f69 100644 --- a/vendor/github.com/caddyserver/certmagic/handshake.go +++ b/vendor/github.com/caddyserver/certmagic/handshake.go @@ -50,7 +50,7 @@ func (cfg *Config) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certif } func (cfg *Config) GetCertificateWithContext(ctx context.Context, clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { - if err := cfg.emit(ctx, "tls_get_certificate", map[string]any{"client_hello": clientHello}); err != nil { + if err := cfg.emit(ctx, "tls_get_certificate", map[string]any{"client_hello": clientHelloWithoutConn(clientHello)}); err != nil { cfg.Logger.Error("TLS handshake aborted by event handler", zap.String("server_name", clientHello.ServerName), zap.String("remote", clientHello.Conn.RemoteAddr().String()), @@ -58,6 +58,12 @@ func (cfg *Config) GetCertificateWithContext(ctx context.Context, clientHello *t return nil, fmt.Errorf("handshake aborted by event handler: %w", err) } + if ctx == nil { + // tests can't set context on a tls.ClientHelloInfo because it's unexported :( + ctx = context.Background() + } + ctx = context.WithValue(ctx, ClientHelloInfoCtxKey, clientHello) + // special case: serve up the certificate for a TLS-ALPN ACME challenge // (https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05) for _, proto := range clientHello.SupportedProtos { @@ -313,8 +319,8 @@ func (cfg *Config) getCertDuringHandshake(ctx context.Context, hello *tls.Client // Make sure a certificate is allowed for the given name. If not, it doesn't // make sense to try loading one from storage (issue #185), getting it from a // certificate manager, or obtaining one from an issuer. - if err := cfg.checkIfCertShouldBeObtained(name, false); err != nil { - return Certificate{}, fmt.Errorf("certificate is not allowed for server name %s: %v", name, err) + if err := cfg.checkIfCertShouldBeObtained(ctx, name, false); err != nil { + return Certificate{}, fmt.Errorf("certificate is not allowed for server name %s: %w", name, err) } // If an external Manager is configured, try to get it from them. @@ -438,7 +444,7 @@ func (cfg *Config) optionalMaintenance(ctx context.Context, log *zap.Logger, cer // checkIfCertShouldBeObtained checks to see if an on-demand TLS certificate // should be obtained for a given domain based upon the config settings. If // a non-nil error is returned, do not issue a new certificate for name. -func (cfg *Config) checkIfCertShouldBeObtained(name string, requireOnDemand bool) error { +func (cfg *Config) checkIfCertShouldBeObtained(ctx context.Context, name string, requireOnDemand bool) error { if requireOnDemand && cfg.OnDemand == nil { return fmt.Errorf("not configured for on-demand certificate issuance") } @@ -447,7 +453,7 @@ func (cfg *Config) checkIfCertShouldBeObtained(name string, requireOnDemand bool } if cfg.OnDemand != nil { if cfg.OnDemand.DecisionFunc != nil { - if err := cfg.OnDemand.DecisionFunc(name); err != nil { + if err := cfg.OnDemand.DecisionFunc(ctx, name); err != nil { return fmt.Errorf("decision func: %w", err) } return nil @@ -685,7 +691,7 @@ func (cfg *Config) renewDynamicCertificate(ctx context.Context, hello *tls.Clien defer cancel() // Make sure a certificate for this name should be renewed on-demand - err := cfg.checkIfCertShouldBeObtained(name, true) + err := cfg.checkIfCertShouldBeObtained(ctx, name, true) if err != nil { // if not, remove from cache (it will be deleted from storage later) cfg.certCache.mu.Lock() @@ -875,3 +881,52 @@ var ( certLoadWaitChans = make(map[string]chan struct{}) certLoadWaitChansMu sync.Mutex ) + +type serializableClientHello struct { + CipherSuites []uint16 + ServerName string + SupportedCurves []tls.CurveID + SupportedPoints []uint8 + SignatureSchemes []tls.SignatureScheme + SupportedProtos []string + SupportedVersions []uint16 + + RemoteAddr, LocalAddr net.Addr // values copied from the Conn as they are still useful/needed + conn net.Conn // unexported so it's not serialized +} + +// clientHelloWithoutConn returns the data from the ClientHelloInfo without the +// pesky exported Conn field, which often causes an error when serializing because +// the underlying type may be unserializable. +func clientHelloWithoutConn(hello *tls.ClientHelloInfo) serializableClientHello { + if hello == nil { + return serializableClientHello{} + } + var remote, local net.Addr + if hello.Conn != nil { + remote = hello.Conn.RemoteAddr() + local = hello.Conn.LocalAddr() + } + return serializableClientHello{ + CipherSuites: hello.CipherSuites, + ServerName: hello.ServerName, + SupportedCurves: hello.SupportedCurves, + SupportedPoints: hello.SupportedPoints, + SignatureSchemes: hello.SignatureSchemes, + SupportedProtos: hello.SupportedProtos, + SupportedVersions: hello.SupportedVersions, + RemoteAddr: remote, + LocalAddr: local, + conn: hello.Conn, + } +} + +type helloInfoCtxKey string + +// ClientHelloInfoCtxKey is the key by which the ClientHelloInfo can be extracted from +// a context.Context within a DecisionFunc. However, be advised that it is best practice +// that the decision whether to obtain a certificate is be based solely on the name, +// not other properties of the specific connection/client requesting the connection. +// For example, it is not adviseable to use a client's IP address to decide whether to +// allow a certificate. Instead, the ClientHello can be useful for logging, etc. +const ClientHelloInfoCtxKey helloInfoCtxKey = "certmagic:ClientHelloInfo" diff --git a/vendor/github.com/caddyserver/certmagic/maintain.go b/vendor/github.com/caddyserver/certmagic/maintain.go index 475bb6df..9ffb7310 100644 --- a/vendor/github.com/caddyserver/certmagic/maintain.go +++ b/vendor/github.com/caddyserver/certmagic/maintain.go @@ -17,9 +17,11 @@ package certmagic import ( "context" "crypto/x509" + "encoding/json" "encoding/pem" + "errors" "fmt" - "log" + "io/fs" "path" "runtime" "strings" @@ -390,30 +392,117 @@ func (certCache *Cache) updateOCSPStaples(ctx context.Context) { // CleanStorageOptions specifies how to clean up a storage unit. type CleanStorageOptions struct { - OCSPStaples bool + // Optional custom logger. + Logger *zap.Logger + + // Optional ID of the instance initiating the cleaning. + InstanceID string + + // If set, cleaning will be skipped if it was performed + // more recently than this interval. + Interval time.Duration + + // Whether to clean cached OCSP staples. + OCSPStaples bool + + // Whether to cleanup expired certificates, and if so, + // how long to let them stay after they've expired. ExpiredCerts bool ExpiredCertGracePeriod time.Duration } // CleanStorage removes assets which are no longer useful, // according to opts. -func CleanStorage(ctx context.Context, storage Storage, opts CleanStorageOptions) { +func CleanStorage(ctx context.Context, storage Storage, opts CleanStorageOptions) error { + const ( + lockName = "storage_clean" + storageKey = "last_clean.json" + ) + + if opts.Logger == nil { + opts.Logger = defaultLogger.Named("clean_storage") + } + opts.Logger = opts.Logger.With(zap.Any("storage", storage)) + + // storage cleaning should be globally exclusive + if err := storage.Lock(ctx, lockName); err != nil { + return fmt.Errorf("unable to acquire %s lock: %v", lockName, err) + } + defer func() { + if err := storage.Unlock(ctx, lockName); err != nil { + opts.Logger.Error("unable to release lock", zap.Error(err)) + return + } + }() + + // cleaning should not happen more often than the interval + if opts.Interval > 0 { + lastCleanBytes, err := storage.Load(ctx, storageKey) + if !errors.Is(err, fs.ErrNotExist) { + if err != nil { + return fmt.Errorf("loading last clean timestamp: %v", err) + } + + var lastClean lastCleanPayload + err = json.Unmarshal(lastCleanBytes, &lastClean) + if err != nil { + return fmt.Errorf("decoding last clean data: %v", err) + } + + lastTLSClean := lastClean["tls"] + if time.Since(lastTLSClean.Timestamp) < opts.Interval { + nextTime := time.Now().Add(opts.Interval) + opts.Logger.Warn("storage cleaning happened too recently; skipping for now", + zap.String("instance", lastTLSClean.InstanceID), + zap.Time("try_again", nextTime), + zap.Duration("try_again_in", time.Until(nextTime)), + ) + return nil + } + } + } + + opts.Logger.Info("cleaning storage unit") + if opts.OCSPStaples { - err := deleteOldOCSPStaples(ctx, storage) + err := deleteOldOCSPStaples(ctx, storage, opts.Logger) if err != nil { - log.Printf("[ERROR] Deleting old OCSP staples: %v", err) + opts.Logger.Error("deleting old OCSP staples", zap.Error(err)) } } if opts.ExpiredCerts { - err := deleteExpiredCerts(ctx, storage, opts.ExpiredCertGracePeriod) + err := deleteExpiredCerts(ctx, storage, opts.Logger, opts.ExpiredCertGracePeriod) if err != nil { - log.Printf("[ERROR] Deleting expired certificates: %v", err) + opts.Logger.Error("deleting expired certificates staples", zap.Error(err)) } } // TODO: delete stale locks? + + // update the last-clean time + lastCleanBytes, err := json.Marshal(lastCleanPayload{ + "tls": lastCleaned{ + Timestamp: time.Now(), + InstanceID: opts.InstanceID, + }, + }) + if err != nil { + return fmt.Errorf("encoding last cleaned info: %v", err) + } + if err := storage.Store(ctx, storageKey, lastCleanBytes); err != nil { + return fmt.Errorf("storing last clean info: %v", err) + } + + return nil } -func deleteOldOCSPStaples(ctx context.Context, storage Storage) error { +type lastCleanPayload map[string]lastCleaned + +type lastCleaned struct { + Timestamp time.Time `json:"timestamp"` + InstanceID string `json:"instance_id,omitempty"` +} + +func deleteOldOCSPStaples(ctx context.Context, storage Storage, logger *zap.Logger) error { ocspKeys, err := storage.List(ctx, prefixOCSP, false) if err != nil { // maybe just hasn't been created yet; no big deal @@ -428,7 +517,7 @@ func deleteOldOCSPStaples(ctx context.Context, storage Storage) error { } ocspBytes, err := storage.Load(ctx, key) if err != nil { - log.Printf("[ERROR] While deleting old OCSP staples, unable to load staple file: %v", err) + logger.Error("while deleting old OCSP staples, unable to load staple file", zap.Error(err)) continue } resp, err := ocsp.ParseResponse(ocspBytes, nil) @@ -436,7 +525,7 @@ func deleteOldOCSPStaples(ctx context.Context, storage Storage) error { // contents are invalid; delete it err = storage.Delete(ctx, key) if err != nil { - log.Printf("[ERROR] Purging corrupt staple file %s: %v", key, err) + logger.Error("purging corrupt staple file", zap.String("storage_key", key), zap.Error(err)) } continue } @@ -444,14 +533,14 @@ func deleteOldOCSPStaples(ctx context.Context, storage Storage) error { // response has expired; delete it err = storage.Delete(ctx, key) if err != nil { - log.Printf("[ERROR] Purging expired staple file %s: %v", key, err) + logger.Error("purging expired staple file", zap.String("storage_key", key), zap.Error(err)) } } } return nil } -func deleteExpiredCerts(ctx context.Context, storage Storage, gracePeriod time.Duration) error { +func deleteExpiredCerts(ctx context.Context, storage Storage, logger *zap.Logger, gracePeriod time.Duration) error { issuerKeys, err := storage.List(ctx, prefixCerts, false) if err != nil { // maybe just hasn't been created yet; no big deal @@ -461,7 +550,7 @@ func deleteExpiredCerts(ctx context.Context, storage Storage, gracePeriod time.D for _, issuerKey := range issuerKeys { siteKeys, err := storage.List(ctx, issuerKey, false) if err != nil { - log.Printf("[ERROR] Listing contents of %s: %v", issuerKey, err) + logger.Error("listing contents", zap.String("issuer_key", issuerKey), zap.Error(err)) continue } @@ -475,7 +564,7 @@ func deleteExpiredCerts(ctx context.Context, storage Storage, gracePeriod time.D siteAssets, err := storage.List(ctx, siteKey, false) if err != nil { - log.Printf("[ERROR] Listing contents of %s: %v", siteKey, err) + logger.Error("listing site contents", zap.String("site_key", siteKey), zap.Error(err)) continue } @@ -498,18 +587,23 @@ func deleteExpiredCerts(ctx context.Context, storage Storage, gracePeriod time.D } if expiredTime := time.Since(expiresAt(cert)); expiredTime >= gracePeriod { - log.Printf("[INFO] Certificate %s expired %s ago; cleaning up", assetKey, expiredTime) + logger.Info("certificate expired beyond grace period; cleaning up", + zap.String("asset_key", assetKey), + zap.Duration("expired_for", expiredTime), + zap.Duration("grace_period", gracePeriod)) baseName := strings.TrimSuffix(assetKey, ".crt") for _, relatedAsset := range []string{ assetKey, baseName + ".key", baseName + ".json", } { - log.Printf("[INFO] Deleting %s because resource expired", relatedAsset) + logger.Info("deleting asset because resource expired", zap.String("asset_key", relatedAsset)) err := storage.Delete(ctx, relatedAsset) if err != nil { - log.Printf("[ERROR] Cleaning up asset related to expired certificate for %s: %s: %v", - baseName, relatedAsset, err) + logger.Error("could not clean up asset related to expired certificate", + zap.String("base_name", baseName), + zap.String("related_asset", relatedAsset), + zap.Error(err)) } } } @@ -521,7 +615,7 @@ func deleteExpiredCerts(ctx context.Context, storage Storage, gracePeriod time.D continue } if len(siteAssets) == 0 { - log.Printf("[INFO] Deleting %s because key is empty", siteKey) + logger.Info("deleting site folder because key is empty", zap.String("site_key", siteKey)) err := storage.Delete(ctx, siteKey) if err != nil { return fmt.Errorf("deleting empty site folder %s: %v", siteKey, err) diff --git a/vendor/github.com/caddyserver/certmagic/solvers.go b/vendor/github.com/caddyserver/certmagic/solvers.go index a7132ee3..51ef096b 100644 --- a/vendor/github.com/caddyserver/certmagic/solvers.go +++ b/vendor/github.com/caddyserver/certmagic/solvers.go @@ -629,21 +629,23 @@ func robustTryListen(addr string) (net.Listener, error) { return nil, nil } - // hmm, we couldn't connect to the socket, so something else must - // be wrong, right? wrong!! we've had reports across multiple OSes - // now that sometimes connections fail even though the OS told us - // that the address was already in use; either the listener is - // fluctuating between open and closed very, very quickly, or the - // OS is inconsistent and contradicting itself; I have been unable - // to reproduce this, so I'm now resorting to hard-coding substring - // matching in error messages as a really hacky and unreliable - // safeguard against this, until we can idenify exactly what was - // happening; see the following threads for more info: + // Hmm, we couldn't connect to the socket, so something else must + // be wrong, right? wrong!! Apparently if a port is bound by another + // listener with a specific host, i.e. 'x:1234', we cannot bind to + // ':1234' -- it is considered a conflict, but 'y:1234' is not. + // I guess we need to assume the conflicting listener is properly + // configured and continue. But we should tell the user to specify + // the correct ListenHost to avoid conflict or at least so we can + // know that the user is intentional about that port and hopefully + // has an ACME solver on it. + // + // History: // https://caddy.community/t/caddy-retry-error/7317 // https://caddy.community/t/v2-upgrade-to-caddy2-failing-with-errors/7423 + // https://github.com/caddyserver/certmagic/issues/250 if strings.Contains(listenErr.Error(), "address already in use") || strings.Contains(listenErr.Error(), "one usage of each socket address") { - log.Printf("[WARNING] OS reports a contradiction: %v - but we cannot connect to it, with this error: %v; continuing anyway 🤞 (I don't know what causes this... if you do, please help?)", listenErr, connectErr) + log.Printf("[WARNING] %v - be sure to set the ACMEIssuer.ListenHost field; assuming conflicting listener is correctly configured and continuing", listenErr) return nil, nil } } diff --git a/vendor/github.com/caddyserver/certmagic/storage.go b/vendor/github.com/caddyserver/certmagic/storage.go index 6089bb9b..3d88f2e0 100644 --- a/vendor/github.com/caddyserver/certmagic/storage.go +++ b/vendor/github.com/caddyserver/certmagic/storage.go @@ -133,7 +133,7 @@ type Locker interface { // is released or becomes stale. // // If the named lock represents an idempotent operation, callers - // should awlays check to make sure the work still needs to be + // should always check to make sure the work still needs to be // completed after acquiring the lock. You never know if another // process already completed the task while you were waiting to // acquire it. diff --git a/vendor/github.com/casbin/casbin/v2/.golangci.yml b/vendor/github.com/casbin/casbin/v2/.golangci.yml new file mode 100644 index 00000000..b8d36201 --- /dev/null +++ b/vendor/github.com/casbin/casbin/v2/.golangci.yml @@ -0,0 +1,354 @@ +# Based on https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322 +# This code is licensed under the terms of the MIT license https://opensource.org/license/mit +# Copyright (c) 2021 Marat Reymers + +## Golden config for golangci-lint v1.56.2 +# +# This is the best config for golangci-lint based on my experience and opinion. +# It is very strict, but not extremely strict. +# Feel free to adapt and change it for your needs. + +run: + # Timeout for analysis, e.g. 30s, 5m. + # Default: 1m + timeout: 3m + + +# This file contains only configs which differ from defaults. +# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml +linters-settings: + cyclop: + # The maximal code complexity to report. + # Default: 10 + max-complexity: 30 + # The maximal average package complexity. + # If it's higher than 0.0 (float) the check is enabled + # Default: 0.0 + package-average: 10.0 + + errcheck: + # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. + # Such cases aren't reported by default. + # Default: false + check-type-assertions: true + + exhaustive: + # Program elements to check for exhaustiveness. + # Default: [ switch ] + check: + - switch + - map + + exhaustruct: + # List of regular expressions to exclude struct packages and their names from checks. + # Regular expressions must match complete canonical struct package/name/structname. + # Default: [] + exclude: + # std libs + - "^net/http.Client$" + - "^net/http.Cookie$" + - "^net/http.Request$" + - "^net/http.Response$" + - "^net/http.Server$" + - "^net/http.Transport$" + - "^net/url.URL$" + - "^os/exec.Cmd$" + - "^reflect.StructField$" + # public libs + - "^github.com/Shopify/sarama.Config$" + - "^github.com/Shopify/sarama.ProducerMessage$" + - "^github.com/mitchellh/mapstructure.DecoderConfig$" + - "^github.com/prometheus/client_golang/.+Opts$" + - "^github.com/spf13/cobra.Command$" + - "^github.com/spf13/cobra.CompletionOptions$" + - "^github.com/stretchr/testify/mock.Mock$" + - "^github.com/testcontainers/testcontainers-go.+Request$" + - "^github.com/testcontainers/testcontainers-go.FromDockerfile$" + - "^golang.org/x/tools/go/analysis.Analyzer$" + - "^google.golang.org/protobuf/.+Options$" + - "^gopkg.in/yaml.v3.Node$" + + funlen: + # Checks the number of lines in a function. + # If lower than 0, disable the check. + # Default: 60 + lines: 100 + # Checks the number of statements in a function. + # If lower than 0, disable the check. + # Default: 40 + statements: 50 + # Ignore comments when counting lines. + # Default false + ignore-comments: true + + gocognit: + # Minimal code complexity to report. + # Default: 30 (but we recommend 10-20) + min-complexity: 20 + + gocritic: + # Settings passed to gocritic. + # The settings key is the name of a supported gocritic checker. + # The list of supported checkers can be find in https://go-critic.github.io/overview. + settings: + captLocal: + # Whether to restrict checker to params only. + # Default: true + paramsOnly: false + underef: + # Whether to skip (*x).method() calls where x is a pointer receiver. + # Default: true + skipRecvDeref: false + + gomnd: + # List of function patterns to exclude from analysis. + # Values always ignored: `time.Date`, + # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, + # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. + # Default: [] + ignored-functions: + - flag.Arg + - flag.Duration.* + - flag.Float.* + - flag.Int.* + - flag.Uint.* + - os.Chmod + - os.Mkdir.* + - os.OpenFile + - os.WriteFile + - prometheus.ExponentialBuckets.* + - prometheus.LinearBuckets + + gomodguard: + blocked: + # List of blocked modules. + # Default: [] + modules: + - github.com/golang/protobuf: + recommendations: + - google.golang.org/protobuf + reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules" + - github.com/satori/go.uuid: + recommendations: + - github.com/google/uuid + reason: "satori's package is not maintained" + - github.com/gofrs/uuid: + recommendations: + - github.com/gofrs/uuid/v5 + reason: "gofrs' package was not go module before v5" + + govet: + # Enable all analyzers. + # Default: false + enable-all: true + # Disable analyzers by name. + # Run `go tool vet help` to see all analyzers. + # Default: [] + disable: + - fieldalignment # too strict + # Settings per analyzer. + settings: + shadow: + # Whether to be strict about shadowing; can be noisy. + # Default: false + #strict: true + + inamedparam: + # Skips check for interface methods with only a single parameter. + # Default: false + skip-single-param: true + + nakedret: + # Make an issue if func has more lines of code than this setting, and it has naked returns. + # Default: 30 + max-func-lines: 0 + + nolintlint: + # Exclude following linters from requiring an explanation. + # Default: [] + allow-no-explanation: [ funlen, gocognit, lll ] + # Enable to require an explanation of nonzero length after each nolint directive. + # Default: false + require-explanation: true + # Enable to require nolint directives to mention the specific linter being suppressed. + # Default: false + require-specific: true + + perfsprint: + # Optimizes into strings concatenation. + # Default: true + strconcat: false + + rowserrcheck: + # database/sql is always checked + # Default: [] + packages: + - github.com/jmoiron/sqlx + + tenv: + # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures. + # Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked. + # Default: false + all: true + + stylecheck: + # STxxxx checks in https://staticcheck.io/docs/configuration/options/#checks + # Default: ["*"] + checks: ["all", "-ST1003"] + + revive: + rules: + # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter + - name: unused-parameter + disabled: true + +linters: + disable-all: true + enable: + ## enabled by default + #- errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases + - gosimple # specializes in simplifying a code + - govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string + - ineffassign # detects when assignments to existing variables are not used + - staticcheck # is a go vet on steroids, applying a ton of static analysis checks + - typecheck # like the front-end of a Go compiler, parses and type-checks Go code + - unused # checks for unused constants, variables, functions and types + ## disabled by default + - asasalint # checks for pass []any as any in variadic func(...any) + - asciicheck # checks that your code does not contain non-ASCII identifiers + - bidichk # checks for dangerous unicode character sequences + - bodyclose # checks whether HTTP response body is closed successfully + - cyclop # checks function and package cyclomatic complexity + - dupl # tool for code clone detection + - durationcheck # checks for two durations multiplied together + - errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error + #- errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13 + - execinquery # checks query string in Query function which reads your Go src files and warning it finds + - exhaustive # checks exhaustiveness of enum switch statements + - exportloopref # checks for pointers to enclosing loop variables + #- forbidigo # forbids identifiers + - funlen # tool for detection of long functions + - gocheckcompilerdirectives # validates go compiler directive comments (//go:) + #- gochecknoglobals # checks that no global variables exist + - gochecknoinits # checks that no init functions are present in Go code + - gochecksumtype # checks exhaustiveness on Go "sum types" + #- gocognit # computes and checks the cognitive complexity of functions + #- goconst # finds repeated strings that could be replaced by a constant + #- gocritic # provides diagnostics that check for bugs, performance and style issues + - gocyclo # computes and checks the cyclomatic complexity of functions + - godot # checks if comments end in a period + - goimports # in addition to fixing imports, goimports also formats your code in the same style as gofmt + #- gomnd # detects magic numbers + - gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod + - gomodguard # allow and block lists linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations + - goprintffuncname # checks that printf-like functions are named with f at the end + - gosec # inspects source code for security problems + #- lll # reports long lines + - loggercheck # checks key value pairs for common logger libraries (kitlog,klog,logr,zap) + - makezero # finds slice declarations with non-zero initial length + - mirror # reports wrong mirror patterns of bytes/strings usage + - musttag # enforces field tags in (un)marshaled structs + - nakedret # finds naked returns in functions greater than a specified function length + - nestif # reports deeply nested if statements + - nilerr # finds the code that returns nil even if it checks that the error is not nil + #- nilnil # checks that there is no simultaneous return of nil error and an invalid value + - noctx # finds sending http request without context.Context + - nolintlint # reports ill-formed or insufficient nolint directives + #- nonamedreturns # reports all named returns + - nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL + #- perfsprint # checks that fmt.Sprintf can be replaced with a faster alternative + - predeclared # finds code that shadows one of Go's predeclared identifiers + - promlinter # checks Prometheus metrics naming via promlint + - protogetter # reports direct reads from proto message fields when getters should be used + - reassign # checks that package variables are not reassigned + - revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint + - rowserrcheck # checks whether Err of rows is checked successfully + - sloglint # ensure consistent code style when using log/slog + - spancheck # checks for mistakes with OpenTelemetry/Census spans + - sqlclosecheck # checks that sql.Rows and sql.Stmt are closed + - stylecheck # is a replacement for golint + - tenv # detects using os.Setenv instead of t.Setenv since Go1.17 + - testableexamples # checks if examples are testable (have an expected output) + - testifylint # checks usage of github.com/stretchr/testify + #- testpackage # makes you use a separate _test package + - tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes + - unconvert # removes unnecessary type conversions + #- unparam # reports unused function parameters + - usestdlibvars # detects the possibility to use variables/constants from the Go standard library + - wastedassign # finds wasted assignment statements + - whitespace # detects leading and trailing whitespace + + ## you may want to enable + #- decorder # checks declaration order and count of types, constants, variables and functions + #- exhaustruct # [highly recommend to enable] checks if all structure fields are initialized + #- gci # controls golang package import order and makes it always deterministic + #- ginkgolinter # [if you use ginkgo/gomega] enforces standards of using ginkgo and gomega + #- godox # detects FIXME, TODO and other comment keywords + #- goheader # checks is file header matches to pattern + #- inamedparam # [great idea, but too strict, need to ignore a lot of cases by default] reports interfaces with unnamed method parameters + #- interfacebloat # checks the number of methods inside an interface + #- ireturn # accept interfaces, return concrete types + #- prealloc # [premature optimization, but can be used in some cases] finds slice declarations that could potentially be preallocated + #- tagalign # checks that struct tags are well aligned + #- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope + #- wrapcheck # checks that errors returned from external packages are wrapped + #- zerologlint # detects the wrong usage of zerolog that a user forgets to dispatch zerolog.Event + + ## disabled + #- containedctx # detects struct contained context.Context field + #- contextcheck # [too many false positives] checks the function whether use a non-inherited context + #- depguard # [replaced by gomodguard] checks if package imports are in a list of acceptable packages + #- dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) + #- dupword # [useless without config] checks for duplicate words in the source code + #- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted + #- forcetypeassert # [replaced by errcheck] finds forced type assertions + #- goerr113 # [too strict] checks the errors handling expressions + #- gofmt # [replaced by goimports] checks whether code was gofmt-ed + #- gofumpt # [replaced by goimports, gofumports is not available yet] checks whether code was gofumpt-ed + #- gosmopolitan # reports certain i18n/l10n anti-patterns in your Go codebase + #- grouper # analyzes expression groups + #- importas # enforces consistent import aliases + #- maintidx # measures the maintainability index of each function + #- misspell # [useless] finds commonly misspelled English words in comments + #- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity + #- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test + #- tagliatelle # checks the struct tags + #- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers + #- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines + + ## deprecated + #- deadcode # [deprecated, replaced by unused] finds unused code + #- exhaustivestruct # [deprecated, replaced by exhaustruct] checks if all struct's fields are initialized + #- golint # [deprecated, replaced by revive] golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes + #- ifshort # [deprecated] checks that your code uses short syntax for if-statements whenever possible + #- interfacer # [deprecated] suggests narrower interface types + #- maligned # [deprecated, replaced by govet fieldalignment] detects Go structs that would take less memory if their fields were sorted + #- nosnakecase # [deprecated, replaced by revive var-naming] detects snake case of variable naming and function name + #- scopelint # [deprecated, replaced by exportloopref] checks for unpinned variables in go programs + #- structcheck # [deprecated, replaced by unused] finds unused struct fields + #- varcheck # [deprecated, replaced by unused] finds unused global variables and constants + + +issues: + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 50 + + exclude-rules: + - source: "(noinspection|TODO)" + linters: [ godot ] + - source: "//noinspection" + linters: [ gocritic ] + - path: "_test\\.go" + linters: + - bodyclose + - dupl + - funlen + - goconst + - gosec + - noctx + - wrapcheck + # TODO: remove after PR is released https://github.com/golangci/golangci-lint/pull/4386 + - text: "fmt.Sprintf can be replaced with string addition" + linters: [ perfsprint ] \ No newline at end of file diff --git a/vendor/github.com/casbin/casbin/v2/README.md b/vendor/github.com/casbin/casbin/v2/README.md index 141f14ff..36549f55 100644 --- a/vendor/github.com/casbin/casbin/v2/README.md +++ b/vendor/github.com/casbin/casbin/v2/README.md @@ -9,25 +9,37 @@ Casbin [![Discord](https://img.shields.io/discord/1022748306096537660?logo=discord&label=discord&color=5865F2)](https://discord.gg/S5UjpzGZjN) [![Sourcegraph](https://sourcegraph.com/github.com/casbin/casbin/-/badge.svg)](https://sourcegraph.com/github.com/casbin/casbin?badge) -[![image](https://door.casdoor.com/image.png)](https://door.casdoor.com/redirect) - **News**: still worry about how to write the correct Casbin policy? ``Casbin online editor`` is coming to help! Try it at: https://casbin.org/editor/ ![casbin Logo](casbin-logo.png) Casbin is a powerful and efficient open-source access control library for Golang projects. It provides support for enforcing authorization based on various [access control models](https://en.wikipedia.org/wiki/Computer_security_model). +

+ Sponsored by +
+ + + + + + +
+ Build auth with fraud prevention, faster.
Try Stytch for API-first authentication, user & org management, multi-tenant SSO, MFA, device fingerprinting, and more.
+
+

+ ## All the languages supported by Casbin: -[![golang](https://casbin.org/img/langs/golang.png)](https://github.com/casbin/casbin) | [![java](https://casbin.org/img/langs/java.png)](https://github.com/casbin/jcasbin) | [![nodejs](https://casbin.org/img/langs/nodejs.png)](https://github.com/casbin/node-casbin) | [![php](https://casbin.org/img/langs/php.png)](https://github.com/php-casbin/php-casbin) -----|----|----|---- -[Casbin](https://github.com/casbin/casbin) | [jCasbin](https://github.com/casbin/jcasbin) | [node-Casbin](https://github.com/casbin/node-casbin) | [PHP-Casbin](https://github.com/php-casbin/php-casbin) -production-ready | production-ready | production-ready | production-ready +| [![golang](https://casbin.org/img/langs/golang.png)](https://github.com/casbin/casbin) | [![java](https://casbin.org/img/langs/java.png)](https://github.com/casbin/jcasbin) | [![nodejs](https://casbin.org/img/langs/nodejs.png)](https://github.com/casbin/node-casbin) | [![php](https://casbin.org/img/langs/php.png)](https://github.com/php-casbin/php-casbin) | +|----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------| +| [Casbin](https://github.com/casbin/casbin) | [jCasbin](https://github.com/casbin/jcasbin) | [node-Casbin](https://github.com/casbin/node-casbin) | [PHP-Casbin](https://github.com/php-casbin/php-casbin) | +| production-ready | production-ready | production-ready | production-ready | -[![python](https://casbin.org/img/langs/python.png)](https://github.com/casbin/pycasbin) | [![dotnet](https://casbin.org/img/langs/dotnet.png)](https://github.com/casbin-net/Casbin.NET) | [![c++](https://casbin.org/img/langs/cpp.png)](https://github.com/casbin/casbin-cpp) | [![rust](https://casbin.org/img/langs/rust.png)](https://github.com/casbin/casbin-rs) -----|----|----|---- -[PyCasbin](https://github.com/casbin/pycasbin) | [Casbin.NET](https://github.com/casbin-net/Casbin.NET) | [Casbin-CPP](https://github.com/casbin/casbin-cpp) | [Casbin-RS](https://github.com/casbin/casbin-rs) -production-ready | production-ready | beta-test | production-ready +| [![python](https://casbin.org/img/langs/python.png)](https://github.com/casbin/pycasbin) | [![dotnet](https://casbin.org/img/langs/dotnet.png)](https://github.com/casbin-net/Casbin.NET) | [![c++](https://casbin.org/img/langs/cpp.png)](https://github.com/casbin/casbin-cpp) | [![rust](https://casbin.org/img/langs/rust.png)](https://github.com/casbin/casbin-rs) | +|------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------| +| [PyCasbin](https://github.com/casbin/pycasbin) | [Casbin.NET](https://github.com/casbin-net/Casbin.NET) | [Casbin-CPP](https://github.com/casbin/casbin-cpp) | [Casbin-RS](https://github.com/casbin/casbin-rs) | +| production-ready | production-ready | production-ready | production-ready | ## Table of contents @@ -118,7 +130,7 @@ m = r.obj == p.obj && r.act == p.act || r.obj in ('data2', 'data3') But you **SHOULD** make sure that the length of the array is **MORE** than **1**, otherwise there will cause it to panic. -For more operators, you may take a look at [govaluate](https://github.com/Knetic/govaluate) +For more operators, you may take a look at [govaluate](https://github.com/casbin/govaluate) ## Features @@ -216,19 +228,19 @@ https://casbin.org/docs/benchmark ## Examples -Model | Model file | Policy file -----|------|---- -ACL | [basic_model.conf](https://github.com/casbin/casbin/blob/master/examples/basic_model.conf) | [basic_policy.csv](https://github.com/casbin/casbin/blob/master/examples/basic_policy.csv) -ACL with superuser | [basic_model_with_root.conf](https://github.com/casbin/casbin/blob/master/examples/basic_with_root_model.conf) | [basic_policy.csv](https://github.com/casbin/casbin/blob/master/examples/basic_policy.csv) -ACL without users | [basic_model_without_users.conf](https://github.com/casbin/casbin/blob/master/examples/basic_without_users_model.conf) | [basic_policy_without_users.csv](https://github.com/casbin/casbin/blob/master/examples/basic_without_users_policy.csv) -ACL without resources | [basic_model_without_resources.conf](https://github.com/casbin/casbin/blob/master/examples/basic_without_resources_model.conf) | [basic_policy_without_resources.csv](https://github.com/casbin/casbin/blob/master/examples/basic_without_resources_policy.csv) -RBAC | [rbac_model.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_model.conf) | [rbac_policy.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_policy.csv) -RBAC with resource roles | [rbac_model_with_resource_roles.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_resource_roles_model.conf) | [rbac_policy_with_resource_roles.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_resource_roles_policy.csv) -RBAC with domains/tenants | [rbac_model_with_domains.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_domains_model.conf) | [rbac_policy_with_domains.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_domains_policy.csv) -ABAC | [abac_model.conf](https://github.com/casbin/casbin/blob/master/examples/abac_model.conf) | N/A -RESTful | [keymatch_model.conf](https://github.com/casbin/casbin/blob/master/examples/keymatch_model.conf) | [keymatch_policy.csv](https://github.com/casbin/casbin/blob/master/examples/keymatch_policy.csv) -Deny-override | [rbac_model_with_deny.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_deny_model.conf) | [rbac_policy_with_deny.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_deny_policy.csv) -Priority | [priority_model.conf](https://github.com/casbin/casbin/blob/master/examples/priority_model.conf) | [priority_policy.csv](https://github.com/casbin/casbin/blob/master/examples/priority_policy.csv) +| Model | Model file | Policy file | +|---------------------------|----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| +| ACL | [basic_model.conf](https://github.com/casbin/casbin/blob/master/examples/basic_model.conf) | [basic_policy.csv](https://github.com/casbin/casbin/blob/master/examples/basic_policy.csv) | +| ACL with superuser | [basic_model_with_root.conf](https://github.com/casbin/casbin/blob/master/examples/basic_with_root_model.conf) | [basic_policy.csv](https://github.com/casbin/casbin/blob/master/examples/basic_policy.csv) | +| ACL without users | [basic_model_without_users.conf](https://github.com/casbin/casbin/blob/master/examples/basic_without_users_model.conf) | [basic_policy_without_users.csv](https://github.com/casbin/casbin/blob/master/examples/basic_without_users_policy.csv) | +| ACL without resources | [basic_model_without_resources.conf](https://github.com/casbin/casbin/blob/master/examples/basic_without_resources_model.conf) | [basic_policy_without_resources.csv](https://github.com/casbin/casbin/blob/master/examples/basic_without_resources_policy.csv) | +| RBAC | [rbac_model.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_model.conf) | [rbac_policy.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_policy.csv) | +| RBAC with resource roles | [rbac_model_with_resource_roles.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_resource_roles_model.conf) | [rbac_policy_with_resource_roles.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_resource_roles_policy.csv) | +| RBAC with domains/tenants | [rbac_model_with_domains.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_domains_model.conf) | [rbac_policy_with_domains.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_domains_policy.csv) | +| ABAC | [abac_model.conf](https://github.com/casbin/casbin/blob/master/examples/abac_model.conf) | N/A | +| RESTful | [keymatch_model.conf](https://github.com/casbin/casbin/blob/master/examples/keymatch_model.conf) | [keymatch_policy.csv](https://github.com/casbin/casbin/blob/master/examples/keymatch_policy.csv) | +| Deny-override | [rbac_model_with_deny.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_deny_model.conf) | [rbac_policy_with_deny.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_deny_policy.csv) | +| Priority | [priority_model.conf](https://github.com/casbin/casbin/blob/master/examples/priority_model.conf) | [priority_policy.csv](https://github.com/casbin/casbin/blob/master/examples/priority_policy.csv) | ## Middlewares diff --git a/vendor/github.com/casbin/casbin/v2/config/config.go b/vendor/github.com/casbin/casbin/v2/config/config.go index e9f83030..57d40d84 100644 --- a/vendor/github.com/casbin/casbin/v2/config/config.go +++ b/vendor/github.com/casbin/casbin/v2/config/config.go @@ -26,17 +26,17 @@ import ( ) var ( - // DEFAULT_SECTION specifies the name of a section if no name provided + // DEFAULT_SECTION specifies the name of a section if no name provided. DEFAULT_SECTION = "default" - // DEFAULT_COMMENT defines what character(s) indicate a comment `#` + // DEFAULT_COMMENT defines what character(s) indicate a comment `#`. DEFAULT_COMMENT = []byte{'#'} - // DEFAULT_COMMENT_SEM defines what alternate character(s) indicate a comment `;` + // DEFAULT_COMMENT_SEM defines what alternate character(s) indicate a comment `;`. DEFAULT_COMMENT_SEM = []byte{';'} - // DEFAULT_MULTI_LINE_SEPARATOR defines what character indicates a multi-line content + // DEFAULT_MULTI_LINE_SEPARATOR defines what character indicates a multi-line content. DEFAULT_MULTI_LINE_SEPARATOR = []byte{'\\'} ) -// ConfigInterface defines the behavior of a Config implementation +// ConfigInterface defines the behavior of a Config implementation. type ConfigInterface interface { String(key string) string Strings(key string) []string @@ -47,7 +47,7 @@ type ConfigInterface interface { Set(key string, value string) error } -// Config represents an implementation of the ConfigInterface +// Config represents an implementation of the ConfigInterface. type Config struct { // Section:key=value data map[string]map[string]string @@ -116,7 +116,7 @@ func (c *Config) parseBuffer(buf *bufio.Reader) error { if err == io.EOF { // force write when buffer is not flushed yet if buffer.Len() > 0 { - if err := c.write(section, lineNum, &buffer); err != nil { + if err = c.write(section, lineNum, &buffer); err != nil { return err } } @@ -185,33 +185,33 @@ func (c *Config) write(section string, lineNum int, b *bytes.Buffer) error { return nil } -// Bool lookups up the value using the provided key and converts the value to a bool +// Bool lookups up the value using the provided key and converts the value to a bool. func (c *Config) Bool(key string) (bool, error) { return strconv.ParseBool(c.get(key)) } -// Int lookups up the value using the provided key and converts the value to a int +// Int lookups up the value using the provided key and converts the value to a int. func (c *Config) Int(key string) (int, error) { return strconv.Atoi(c.get(key)) } -// Int64 lookups up the value using the provided key and converts the value to a int64 +// Int64 lookups up the value using the provided key and converts the value to a int64. func (c *Config) Int64(key string) (int64, error) { return strconv.ParseInt(c.get(key), 10, 64) } -// Float64 lookups up the value using the provided key and converts the value to a float64 +// Float64 lookups up the value using the provided key and converts the value to a float64. func (c *Config) Float64(key string) (float64, error) { return strconv.ParseFloat(c.get(key), 64) } -// String lookups up the value using the provided key and converts the value to a string +// String lookups up the value using the provided key and converts the value to a string. func (c *Config) String(key string) string { return c.get(key) } // Strings lookups up the value using the provided key and converts the value to an array of string -// by splitting the string by comma +// by splitting the string by comma. func (c *Config) Strings(key string) []string { v := c.get(key) if v == "" { @@ -220,7 +220,7 @@ func (c *Config) Strings(key string) []string { return strings.Split(v, ",") } -// Set sets the value for the specific key in the Config +// Set sets the value for the specific key in the Config. func (c *Config) Set(key string, value string) error { if len(key) == 0 { return errors.New("key is empty") @@ -243,7 +243,7 @@ func (c *Config) Set(key string, value string) error { return nil } -// section.key or key +// section.key or key. func (c *Config) get(key string) string { var ( section string diff --git a/vendor/github.com/casbin/casbin/v2/effector/effector.go b/vendor/github.com/casbin/casbin/v2/effector/effector.go index 665848b5..49b84c3e 100644 --- a/vendor/github.com/casbin/casbin/v2/effector/effector.go +++ b/vendor/github.com/casbin/casbin/v2/effector/effector.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package effector +package effector //nolint:cyclop // TODO // Effect is the result for a policy rule. type Effect int diff --git a/vendor/github.com/casbin/casbin/v2/enforcer.go b/vendor/github.com/casbin/casbin/v2/enforcer.go index 5bbf982b..2d90d31c 100644 --- a/vendor/github.com/casbin/casbin/v2/enforcer.go +++ b/vendor/github.com/casbin/casbin/v2/enforcer.go @@ -17,7 +17,6 @@ package casbin import ( "errors" "fmt" - "regexp" "runtime/debug" "strings" "sync" @@ -31,8 +30,7 @@ import ( defaultrolemanager "github.com/casbin/casbin/v2/rbac/default-role-manager" "github.com/casbin/casbin/v2/util" - "github.com/Knetic/govaluate" - "github.com/tidwall/gjson" + "github.com/casbin/govaluate" ) // Enforcer is the main interface for authorization enforcement and policy management. @@ -59,7 +57,7 @@ type Enforcer struct { logger log.Logger } -// EnforceContext is used as the first element of the parameter "rvals" in method "enforce" +// EnforceContext is used as the first element of the parameter "rvals" in method "enforce". type EnforceContext struct { RType string PType string @@ -102,7 +100,8 @@ func NewEnforcer(params ...interface{}) (*Enforcer, error) { } } - if paramLen-parsedParamLen == 2 { + switch paramLen - parsedParamLen { + case 2: switch p0 := params[0].(type) { case string: switch p1 := params[1].(type) { @@ -128,7 +127,7 @@ func NewEnforcer(params ...interface{}) (*Enforcer, error) { } } } - } else if paramLen-parsedParamLen == 1 { + case 1: switch p0 := params[0].(type) { case string: err := e.InitWithFile(p0, "") @@ -141,9 +140,9 @@ func NewEnforcer(params ...interface{}) (*Enforcer, error) { return nil, err } } - } else if paramLen-parsedParamLen == 0 { + case 0: return e, nil - } else { + default: return nil, errors.New("invalid parameters for enforcer") } @@ -202,6 +201,9 @@ func (e *Enforcer) SetLogger(logger log.Logger) { for k := range e.rmMap { e.rmMap[k].SetLogger(e.logger) } + for k := range e.condRmMap { + e.condRmMap[k].SetLogger(e.logger) + } } func (e *Enforcer) initialize() { @@ -275,12 +277,20 @@ func (e *Enforcer) SetWatcher(watcher persist.Watcher) error { // GetRoleManager gets the current role manager. func (e *Enforcer) GetRoleManager() rbac.RoleManager { - return e.rmMap["g"] + if e.rmMap != nil && e.rmMap["g"] != nil { + return e.rmMap["g"] + } else { + return nil + } } // GetNamedRoleManager gets the role manager for the named policy. func (e *Enforcer) GetNamedRoleManager(ptype string) rbac.RoleManager { - return e.rmMap[ptype] + if e.rmMap != nil && e.rmMap[ptype] != nil { + return e.rmMap[ptype] + } else { + return nil + } } // SetRoleManager sets the current role manager. @@ -313,8 +323,6 @@ func (e *Enforcer) ClearPolicy() { // LoadPolicy reloads the policy from file/database. func (e *Enforcer) LoadPolicy() error { - e.invalidateMatcherMap() - needToRebuild := false newModel := e.model.Copy() newModel.ClearPolicy() @@ -351,6 +359,7 @@ func (e *Enforcer) LoadPolicy() error { } } e.model = newModel + e.invalidateMatcherMap() return nil } @@ -530,13 +539,16 @@ func (e *Enforcer) EnableAutoBuildRoleLinks(autoBuildRoleLinks bool) { e.autoBuildRoleLinks = autoBuildRoleLinks } -// EnableAcceptJsonRequest controls whether to accept json as a request parameter +// EnableAcceptJsonRequest controls whether to accept json as a request parameter. func (e *Enforcer) EnableAcceptJsonRequest(acceptJsonRequest bool) { e.acceptJsonRequest = acceptJsonRequest } // BuildRoleLinks manually rebuild the role inheritance relations. func (e *Enforcer) BuildRoleLinks() error { + if e.rmMap == nil { + return errors.New("rmMap is nil") + } for _, rm := range e.rmMap { err := rm.Clear() if err != nil { @@ -559,7 +571,7 @@ func (e *Enforcer) BuildIncrementalConditionalRoleLinks(op model.PolicyOp, ptype return e.model.BuildIncrementalConditionalRoleLinks(e.condRmMap, op, "g", ptype, rules) } -// NewEnforceContext Create a default structure based on the suffix +// NewEnforceContext Create a default structure based on the suffix. func NewEnforceContext(suffix string) EnforceContext { return EnforceContext{ RType: "r" + suffix, @@ -574,7 +586,7 @@ func (e *Enforcer) invalidateMatcherMap() { } // enforce use a custom matcher to decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is "". -func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interface{}) (ok bool, err error) { +func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interface{}) (ok bool, err error) { //nolint:funlen,cyclop,gocyclo // TODO: reduce function complexity defer func() { if r := recover(); r != nil { err = fmt.Errorf("panic: %v\n%s", r, debug.Stack()) @@ -637,7 +649,18 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac } if e.acceptJsonRequest { - expString = requestJsonReplace(expString, rTokens, rvals) + // try to parse all request values from json to map[string]interface{} + // skip if there is an error + for i, rval := range rvals { + switch rval := rval.(type) { + case string: + var mapValue map[string]interface{} + mapValue, err = util.JsonToMap(rval) + if err == nil { + rvals[i] = mapValue + } + } + } } parameters := enforceParameters{ @@ -671,7 +694,7 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac var effect effector.Effect var explainIndex int - if policyLen := len(e.model["p"][pType].Policy); policyLen != 0 && strings.Contains(expString, pType+"_") { + if policyLen := len(e.model["p"][pType].Policy); policyLen != 0 && strings.Contains(expString, pType+"_") { //nolint:nestif // TODO: reduce function complexity policyEffects = make([]effector.Effect, policyLen) matcherResults = make([]float64, policyLen) @@ -685,16 +708,7 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac pvals) } - if e.acceptJsonRequest { - pvalsCopy := make([]string, len(pvals)) - copy(pvalsCopy, pvals) - for i, pStr := range pvalsCopy { - pvalsCopy[i] = requestJsonReplace(util.EscapeAssertion(pStr), rTokens, rvals) - } - parameters.pVals = pvalsCopy - } else { - parameters.pVals = pvals - } + parameters.pVals = pvals result, err := expression.Eval(parameters) // log.LogPrint("Result: ", result) @@ -744,7 +758,6 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac } } } else { - if hasEval && len(e.model["p"][pType].Policy) == 0 { return false, errors.New("please make sure rule exists in policy when using eval() in matcher") } @@ -796,31 +809,6 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac return result, nil } -var requestObjectRegex = regexp.MustCompile(`r[_.][A-Za-z_0-9]+\.[A-Za-z_0-9.]+[A-Za-z_0-9]`) -var requestObjectRegexPrefix = regexp.MustCompile(`r[_.][A-Za-z_0-9]+\.`) - -// requestJsonReplace used to support request parameters of type json -// It will replace the access of the request object in matchers or policy with the actual value in the request json parameter -// For example: request sub = `{"Owner": "alice", "Age": 30}` -// policy: p, r.sub.Age > 18, /data1, read ==> p, 30 > 18, /data1, read -// matchers: m = r.sub == r.obj.Owner ==> m = r.sub == "alice" -func requestJsonReplace(str string, rTokens map[string]int, rvals []interface{}) string { - matches := requestObjectRegex.FindAllString(str, -1) - for _, matchesStr := range matches { - prefix := requestObjectRegexPrefix.FindString(matchesStr) - jsonPath := strings.TrimPrefix(matchesStr, prefix) - tokenIndex := rTokens[prefix[:len(prefix)-1]] - if jsonStr, ok := rvals[tokenIndex].(string); ok { - newStr := gjson.Get(jsonStr, jsonPath).String() - if !util.IsNumeric(newStr) { - newStr = `"` + newStr + `"` - } - str = strings.Replace(str, matchesStr, newStr, -1) - } - } - return str -} - func (e *Enforcer) getAndStoreMatcherExpression(hasEval bool, expString string, functions map[string]govaluate.ExpressionFunction) (*govaluate.EvaluableExpression, error) { var expression *govaluate.EvaluableExpression var err error @@ -848,21 +836,21 @@ func (e *Enforcer) EnforceWithMatcher(matcher string, rvals ...interface{}) (boo return e.enforce(matcher, nil, rvals...) } -// EnforceEx explain enforcement by informing matched rules +// EnforceEx explain enforcement by informing matched rules. func (e *Enforcer) EnforceEx(rvals ...interface{}) (bool, []string, error) { explain := []string{} result, err := e.enforce("", &explain, rvals...) return result, explain, err } -// EnforceExWithMatcher use a custom matcher and explain enforcement by informing matched rules +// EnforceExWithMatcher use a custom matcher and explain enforcement by informing matched rules. func (e *Enforcer) EnforceExWithMatcher(matcher string, rvals ...interface{}) (bool, []string, error) { explain := []string{} result, err := e.enforce(matcher, &explain, rvals...) return result, explain, err } -// BatchEnforce enforce in batches +// BatchEnforce enforce in batches. func (e *Enforcer) BatchEnforce(requests [][]interface{}) ([]bool, error) { var results []bool for _, request := range requests { @@ -875,7 +863,7 @@ func (e *Enforcer) BatchEnforce(requests [][]interface{}) ([]bool, error) { return results, nil } -// BatchEnforceWithMatcher enforce with matcher in batches +// BatchEnforceWithMatcher enforce with matcher in batches. func (e *Enforcer) BatchEnforceWithMatcher(matcher string, requests [][]interface{}) ([]bool, error) { var results []bool for _, request := range requests { @@ -888,7 +876,7 @@ func (e *Enforcer) BatchEnforceWithMatcher(matcher string, requests [][]interfac return results, nil } -// AddNamedMatchingFunc add MatchingFunc by ptype RoleManager +// AddNamedMatchingFunc add MatchingFunc by ptype RoleManager. func (e *Enforcer) AddNamedMatchingFunc(ptype, name string, fn rbac.MatchingFunc) bool { if rm, ok := e.rmMap[ptype]; ok { rm.AddMatchingFunc(name, fn) @@ -897,7 +885,7 @@ func (e *Enforcer) AddNamedMatchingFunc(ptype, name string, fn rbac.MatchingFunc return false } -// AddNamedDomainMatchingFunc add MatchingFunc by ptype to RoleManager +// AddNamedDomainMatchingFunc add MatchingFunc by ptype to RoleManager. func (e *Enforcer) AddNamedDomainMatchingFunc(ptype, name string, fn rbac.MatchingFunc) bool { if rm, ok := e.rmMap[ptype]; ok { rm.AddDomainMatchingFunc(name, fn) @@ -907,7 +895,7 @@ func (e *Enforcer) AddNamedDomainMatchingFunc(ptype, name string, fn rbac.Matchi } // AddNamedLinkConditionFunc Add condition function fn for Link userName->roleName, -// when fn returns true, Link is valid, otherwise invalid +// when fn returns true, Link is valid, otherwise invalid. func (e *Enforcer) AddNamedLinkConditionFunc(ptype, user, role string, fn rbac.LinkConditionFunc) bool { if rm, ok := e.condRmMap[ptype]; ok { rm.AddLinkConditionFunc(user, role, fn) @@ -917,7 +905,7 @@ func (e *Enforcer) AddNamedLinkConditionFunc(ptype, user, role string, fn rbac.L } // AddNamedDomainLinkConditionFunc Add condition function fn for Link userName-> {roleName, domain}, -// when fn returns true, Link is valid, otherwise invalid +// when fn returns true, Link is valid, otherwise invalid. func (e *Enforcer) AddNamedDomainLinkConditionFunc(ptype, user, role string, domain string, fn rbac.LinkConditionFunc) bool { if rm, ok := e.condRmMap[ptype]; ok { rm.AddDomainLinkConditionFunc(user, role, domain, fn) @@ -926,7 +914,7 @@ func (e *Enforcer) AddNamedDomainLinkConditionFunc(ptype, user, role string, dom return false } -// SetNamedLinkConditionFuncParams Sets the parameters of the condition function fn for Link userName->roleName +// SetNamedLinkConditionFuncParams Sets the parameters of the condition function fn for Link userName->roleName. func (e *Enforcer) SetNamedLinkConditionFuncParams(ptype, user, role string, params ...string) bool { if rm, ok := e.condRmMap[ptype]; ok { rm.SetLinkConditionFuncParams(user, role, params...) @@ -936,7 +924,7 @@ func (e *Enforcer) SetNamedLinkConditionFuncParams(ptype, user, role string, par } // SetNamedDomainLinkConditionFuncParams Sets the parameters of the condition function fn -// for Link userName->{roleName, domain} +// for Link userName->{roleName, domain}. func (e *Enforcer) SetNamedDomainLinkConditionFuncParams(ptype, user, role, domain string, params ...string) bool { if rm, ok := e.condRmMap[ptype]; ok { rm.SetDomainLinkConditionFuncParams(user, role, domain, params...) @@ -945,7 +933,7 @@ func (e *Enforcer) SetNamedDomainLinkConditionFuncParams(ptype, user, role, doma return false } -// assumes bounds have already been checked +// assumes bounds have already been checked. type enforceParameters struct { rTokens map[string]int rVals []interface{} @@ -954,7 +942,7 @@ type enforceParameters struct { pVals []string } -// implements govaluate.Parameters +// implements govaluate.Parameters. func (p enforceParameters) Get(name string) (interface{}, error) { if name == "" { return nil, nil diff --git a/vendor/github.com/casbin/casbin/v2/enforcer_cached.go b/vendor/github.com/casbin/casbin/v2/enforcer_cached.go index b5294637..1e72a976 100644 --- a/vendor/github.com/casbin/casbin/v2/enforcer_cached.go +++ b/vendor/github.com/casbin/casbin/v2/enforcer_cached.go @@ -23,7 +23,7 @@ import ( "github.com/casbin/casbin/v2/persist/cache" ) -// CachedEnforcer wraps Enforcer and provides decision cache +// CachedEnforcer wraps Enforcer and provides decision cache. type CachedEnforcer struct { *Enforcer expireTime time.Duration @@ -61,7 +61,7 @@ func (e *CachedEnforcer) EnableCache(enableCache bool) { } // Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). -// if rvals is not string , ingore the cache +// if rvals is not string , ignore the cache. func (e *CachedEnforcer) Enforce(rvals ...interface{}) (bool, error) { if atomic.LoadInt32(&e.enableCache) == 0 { return e.Enforcer.Enforce(rvals...) @@ -127,8 +127,8 @@ func (e *CachedEnforcer) RemovePolicies(rules [][]string) (bool, error) { } func (e *CachedEnforcer) getCachedResult(key string) (res bool, err error) { - e.locker.RLock() - defer e.locker.RUnlock() + e.locker.Lock() + defer e.locker.Unlock() return e.cache.Get(key) } diff --git a/vendor/github.com/casbin/casbin/v2/enforcer_cached_synced.go b/vendor/github.com/casbin/casbin/v2/enforcer_cached_synced.go index 84157ea8..0032460f 100644 --- a/vendor/github.com/casbin/casbin/v2/enforcer_cached_synced.go +++ b/vendor/github.com/casbin/casbin/v2/enforcer_cached_synced.go @@ -22,7 +22,7 @@ import ( "github.com/casbin/casbin/v2/persist/cache" ) -// SyncedCachedEnforcer wraps Enforcer and provides decision sync cache +// SyncedCachedEnforcer wraps Enforcer and provides decision sync cache. type SyncedCachedEnforcer struct { *SyncedEnforcer expireTime time.Duration @@ -56,7 +56,7 @@ func (e *SyncedCachedEnforcer) EnableCache(enableCache bool) { } // Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). -// if rvals is not string , ingore the cache +// if rvals is not string , ignore the cache. func (e *SyncedCachedEnforcer) Enforce(rvals ...interface{}) (bool, error) { if atomic.LoadInt32(&e.enableCache) == 0 { return e.SyncedEnforcer.Enforce(rvals...) @@ -129,7 +129,7 @@ func (e *SyncedCachedEnforcer) SetExpireTime(expireTime time.Duration) { e.expireTime = expireTime } -// SetCache need to be sync cache +// SetCache need to be sync cache. func (e *SyncedCachedEnforcer) SetCache(c cache.Cache) { e.locker.Lock() defer e.locker.Unlock() diff --git a/vendor/github.com/casbin/casbin/v2/enforcer_distributed.go b/vendor/github.com/casbin/casbin/v2/enforcer_distributed.go index c8743c4e..2ff85e80 100644 --- a/vendor/github.com/casbin/casbin/v2/enforcer_distributed.go +++ b/vendor/github.com/casbin/casbin/v2/enforcer_distributed.go @@ -22,8 +22,8 @@ func NewDistributedEnforcer(params ...interface{}) (*DistributedEnforcer, error) } // SetDispatcher sets the current dispatcher. -func (e *DistributedEnforcer) SetDispatcher(dispatcher persist.Dispatcher) { - e.dispatcher = dispatcher +func (d *DistributedEnforcer) SetDispatcher(dispatcher persist.Dispatcher) { + d.dispatcher = dispatcher } // AddPoliciesSelf provides a method for dispatcher to add authorization rules to the current policy. @@ -64,7 +64,7 @@ func (d *DistributedEnforcer) RemovePoliciesSelf(shouldPersist func() bool, sec d.m.Lock() defer d.m.Unlock() if shouldPersist != nil && shouldPersist() { - if err := d.adapter.(persist.BatchAdapter).RemovePolicies(sec, ptype, rules); err != nil { + if err = d.adapter.(persist.BatchAdapter).RemovePolicies(sec, ptype, rules); err != nil { if err.Error() != notImplemented { return nil, err } @@ -74,7 +74,7 @@ func (d *DistributedEnforcer) RemovePoliciesSelf(shouldPersist func() bool, sec affected = d.model.RemovePoliciesWithAffected(sec, ptype, rules) if sec == "g" { - err := d.BuildIncrementalRoleLinks(model.PolicyRemove, ptype, affected) + err = d.BuildIncrementalRoleLinks(model.PolicyRemove, ptype, affected) if err != nil { return affected, err } diff --git a/vendor/github.com/casbin/casbin/v2/enforcer_interface.go b/vendor/github.com/casbin/casbin/v2/enforcer_interface.go index bec14093..11cc9e4f 100644 --- a/vendor/github.com/casbin/casbin/v2/enforcer_interface.go +++ b/vendor/github.com/casbin/casbin/v2/enforcer_interface.go @@ -15,18 +15,18 @@ package casbin import ( - "github.com/Knetic/govaluate" "github.com/casbin/casbin/v2/effector" "github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/persist" "github.com/casbin/casbin/v2/rbac" + "github.com/casbin/govaluate" ) var _ IEnforcer = &Enforcer{} var _ IEnforcer = &SyncedEnforcer{} var _ IEnforcer = &CachedEnforcer{} -// IEnforcer is the API interface of Enforcer +// IEnforcer is the API interface of Enforcer. type IEnforcer interface { /* Enforcer API */ InitWithFile(modelPath string, policyPath string) error @@ -69,7 +69,7 @@ type IEnforcer interface { AddPermissionsForUser(user string, permissions ...[]string) (bool, error) DeletePermissionForUser(user string, permission ...string) (bool, error) DeletePermissionsForUser(user string) (bool, error) - GetPermissionsForUser(user string, domain ...string) [][]string + GetPermissionsForUser(user string, domain ...string) ([][]string, error) HasPermissionForUser(user string, permission ...string) bool GetImplicitRolesForUser(name string, domain ...string) ([]string, error) GetImplicitPermissionsForUser(user string, domain ...string) ([][]string, error) @@ -86,6 +86,12 @@ type IEnforcer interface { GetPermissionsForUserInDomain(user string, domain string) [][]string AddRoleForUserInDomain(user string, role string, domain string) (bool, error) DeleteRoleForUserInDomain(user string, role string, domain string) (bool, error) + GetAllUsersByDomain(domain string) []string + DeleteRolesForUserInDomain(user string, domain string) (bool, error) + DeleteAllUsersByDomain(domain string) (bool, error) + DeleteDomains(domains ...string) (bool, error) + GetAllDomains() ([]string, error) + GetAllRolesByDomain(domain string) []string /* Management API */ GetAllSubjects() []string diff --git a/vendor/github.com/casbin/casbin/v2/enforcer_synced.go b/vendor/github.com/casbin/casbin/v2/enforcer_synced.go index db9de5b3..743f26c7 100644 --- a/vendor/github.com/casbin/casbin/v2/enforcer_synced.go +++ b/vendor/github.com/casbin/casbin/v2/enforcer_synced.go @@ -19,14 +19,14 @@ import ( "sync/atomic" "time" - "github.com/Knetic/govaluate" + "github.com/casbin/govaluate" "github.com/casbin/casbin/v2/persist" "github.com/casbin/casbin/v2/rbac" defaultrolemanager "github.com/casbin/casbin/v2/rbac/default-role-manager" ) -// SyncedEnforcer wraps Enforcer and provides synchronized access +// SyncedEnforcer wraps Enforcer and provides synchronized access. type SyncedEnforcer struct { *Enforcer m sync.RWMutex @@ -48,17 +48,17 @@ func NewSyncedEnforcer(params ...interface{}) (*SyncedEnforcer, error) { return e, nil } -// GetLock return the private RWMutex lock +// GetLock return the private RWMutex lock. func (e *SyncedEnforcer) GetLock() *sync.RWMutex { return &e.m } -// IsAutoLoadingRunning check if SyncedEnforcer is auto loading policies +// IsAutoLoadingRunning check if SyncedEnforcer is auto loading policies. func (e *SyncedEnforcer) IsAutoLoadingRunning() bool { return atomic.LoadInt32(&(e.autoLoadRunning)) != 0 } -// StartAutoLoadPolicy starts a go routine that will every specified duration call LoadPolicy +// StartAutoLoadPolicy starts a go routine that will every specified duration call LoadPolicy. func (e *SyncedEnforcer) StartAutoLoadPolicy(d time.Duration) { // Don't start another goroutine if there is already one running if !atomic.CompareAndSwapInt32(&e.autoLoadRunning, 0, 1) { @@ -204,28 +204,28 @@ func (e *SyncedEnforcer) EnforceWithMatcher(matcher string, rvals ...interface{} return e.Enforcer.EnforceWithMatcher(matcher, rvals...) } -// EnforceEx explain enforcement by informing matched rules +// EnforceEx explain enforcement by informing matched rules. func (e *SyncedEnforcer) EnforceEx(rvals ...interface{}) (bool, []string, error) { e.m.RLock() defer e.m.RUnlock() return e.Enforcer.EnforceEx(rvals...) } -// EnforceExWithMatcher use a custom matcher and explain enforcement by informing matched rules +// EnforceExWithMatcher use a custom matcher and explain enforcement by informing matched rules. func (e *SyncedEnforcer) EnforceExWithMatcher(matcher string, rvals ...interface{}) (bool, []string, error) { e.m.RLock() defer e.m.RUnlock() return e.Enforcer.EnforceExWithMatcher(matcher, rvals...) } -// BatchEnforce enforce in batches +// BatchEnforce enforce in batches. func (e *SyncedEnforcer) BatchEnforce(requests [][]interface{}) ([]bool, error) { e.m.RLock() defer e.m.RUnlock() return e.Enforcer.BatchEnforce(requests) } -// BatchEnforceWithMatcher enforce with matcher in batches +// BatchEnforceWithMatcher enforce with matcher in batches. func (e *SyncedEnforcer) BatchEnforceWithMatcher(matcher string, requests [][]interface{}) ([]bool, error) { e.m.RLock() defer e.m.RUnlock() @@ -378,7 +378,7 @@ func (e *SyncedEnforcer) AddPolicies(rules [][]string) (bool, error) { // AddPoliciesEx adds authorization rules to the current policy. // If the rule already exists, the rule will not be added. -// But unlike AddPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddPolicies, other non-existent rules are added instead of returning false directly. func (e *SyncedEnforcer) AddPoliciesEx(rules [][]string) (bool, error) { e.m.Lock() defer e.m.Unlock() @@ -405,7 +405,7 @@ func (e *SyncedEnforcer) AddNamedPolicies(ptype string, rules [][]string) (bool, // AddNamedPoliciesEx adds authorization rules to the current named policy. // If the rule already exists, the rule will not be added. -// But unlike AddNamedPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddNamedPolicies, other non-existent rules are added instead of returning false directly. func (e *SyncedEnforcer) AddNamedPoliciesEx(ptype string, rules [][]string) (bool, error) { e.m.Lock() defer e.m.Unlock() @@ -526,7 +526,7 @@ func (e *SyncedEnforcer) AddGroupingPolicies(rules [][]string) (bool, error) { // AddGroupingPoliciesEx adds role inheritance rules to the current policy. // If the rule already exists, the rule will not be added. -// But unlike AddGroupingPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddGroupingPolicies, other non-existent rules are added instead of returning false directly. func (e *SyncedEnforcer) AddGroupingPoliciesEx(rules [][]string) (bool, error) { e.m.Lock() defer e.m.Unlock() @@ -553,7 +553,7 @@ func (e *SyncedEnforcer) AddNamedGroupingPolicies(ptype string, rules [][]string // AddNamedGroupingPoliciesEx adds named role inheritance rules to the current policy. // If the rule already exists, the rule will not be added. -// But unlike AddNamedGroupingPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddNamedGroupingPolicies, other non-existent rules are added instead of returning false directly. func (e *SyncedEnforcer) AddNamedGroupingPoliciesEx(ptype string, rules [][]string) (bool, error) { e.m.Lock() defer e.m.Unlock() diff --git a/vendor/github.com/casbin/casbin/v2/errors/rbac_errors.go b/vendor/github.com/casbin/casbin/v2/errors/rbac_errors.go index 2f8974b4..2f358b37 100644 --- a/vendor/github.com/casbin/casbin/v2/errors/rbac_errors.go +++ b/vendor/github.com/casbin/casbin/v2/errors/rbac_errors.go @@ -16,7 +16,7 @@ package errors import "errors" -// Global errors for rbac defined here +// Global errors for rbac defined here. var ( ErrNameNotFound = errors.New("error: name does not exist") ErrDomainParameter = errors.New("error: domain should be 1 parameter") @@ -24,7 +24,7 @@ var ( ErrUseDomainParameter = errors.New("error: useDomain should be 1 parameter") ErrInvalidFieldValuesParameter = errors.New("fieldValues requires at least one parameter") - // GetAllowedObjectConditions errors + // GetAllowedObjectConditions errors. ErrObjCondition = errors.New("need to meet the prefix required by the object condition") ErrEmptyCondition = errors.New("GetAllowedObjectConditions have an empty condition") ) diff --git a/vendor/github.com/casbin/casbin/v2/internal_api.go b/vendor/github.com/casbin/casbin/v2/internal_api.go index 42991b54..d8183ed0 100644 --- a/vendor/github.com/casbin/casbin/v2/internal_api.go +++ b/vendor/github.com/casbin/casbin/v2/internal_api.go @@ -66,7 +66,7 @@ func (e *Enforcer) addPolicyWithoutNotify(sec string, ptype string, rule []strin // addPoliciesWithoutNotify adds rules to the current policy without notify // If autoRemoveRepeat == true, existing rules are automatically filtered -// Otherwise, false is returned directly +// Otherwise, false is returned directly. func (e *Enforcer) addPoliciesWithoutNotify(sec string, ptype string, rules [][]string, autoRemoveRepeat bool) (bool, error) { if e.dispatcher != nil && e.autoNotifyDispatcher { return true, e.dispatcher.AddPolicies(sec, ptype, rules) @@ -329,7 +329,7 @@ func (e *Enforcer) addPolicy(sec string, ptype string, rule []string) (bool, err // addPolicies adds rules to the current policy. // If autoRemoveRepeat == true, existing rules are automatically filtered -// Otherwise, false is returned directly +// Otherwise, false is returned directly. func (e *Enforcer) addPolicies(sec string, ptype string, rules [][]string, autoRemoveRepeat bool) (bool, error) { ok, err := e.addPoliciesWithoutNotify(sec, ptype, rules, autoRemoveRepeat) if !ok || err != nil { @@ -364,7 +364,6 @@ func (e *Enforcer) removePolicy(sec string, ptype string, rule []string) (bool, err = e.watcher.Update() } return true, err - } return true, nil diff --git a/vendor/github.com/casbin/casbin/v2/log/log_util.go b/vendor/github.com/casbin/casbin/v2/log/log_util.go index 617c0393..7edabf89 100644 --- a/vendor/github.com/casbin/casbin/v2/log/log_util.go +++ b/vendor/github.com/casbin/casbin/v2/log/log_util.go @@ -46,7 +46,7 @@ func LogPolicy(policy map[string][][]string) { logger.LogPolicy(policy) } -// LogError logs the error information +// LogError logs the error information. func LogError(err error, msg ...string) { logger.LogError(err, msg...) } diff --git a/vendor/github.com/casbin/casbin/v2/management_api.go b/vendor/github.com/casbin/casbin/v2/management_api.go index 0797743c..de2e81fe 100644 --- a/vendor/github.com/casbin/casbin/v2/management_api.go +++ b/vendor/github.com/casbin/casbin/v2/management_api.go @@ -19,8 +19,8 @@ import ( "fmt" "strings" - "github.com/Knetic/govaluate" "github.com/casbin/casbin/v2/util" + "github.com/casbin/govaluate" ) // GetAllSubjects gets the list of subjects that show up in the current policy. @@ -111,8 +111,15 @@ func (e *Enforcer) GetFilteredNamedPolicyWithMatcher(ptype string, matcher strin functions := e.fm.GetFunctions() if _, ok := e.model["g"]; ok { for key, ast := range e.model["g"] { - rm := ast.RM - functions[key] = util.GenerateGFunction(rm) + // g must be a normal role definition (ast.RM != nil) + // or a conditional role definition (ast.CondRM != nil) + // ast.RM and ast.CondRM shouldn't be nil at the same time + if ast.RM != nil { + functions[key] = util.GenerateGFunction(ast.RM) + } + if ast.CondRM != nil { + functions[key] = util.GenerateConditionalGFunction(ast.CondRM) + } } } @@ -209,7 +216,7 @@ func (e *Enforcer) AddPolicies(rules [][]string) (bool, error) { // AddPoliciesEx adds authorization rules to the current policy. // If the rule already exists, the rule will not be added. -// But unlike AddPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddPolicies, other non-existent rules are added instead of returning false directly. func (e *Enforcer) AddPoliciesEx(rules [][]string) (bool, error) { return e.AddNamedPoliciesEx("p", rules) } @@ -239,7 +246,7 @@ func (e *Enforcer) AddNamedPolicies(ptype string, rules [][]string) (bool, error // AddNamedPoliciesEx adds authorization rules to the current named policy. // If the rule already exists, the rule will not be added. -// But unlike AddNamedPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddNamedPolicies, other non-existent rules are added instead of returning false directly. func (e *Enforcer) AddNamedPoliciesEx(ptype string, rules [][]string) (bool, error) { return e.addPolicies("p", ptype, rules, true) } @@ -343,7 +350,7 @@ func (e *Enforcer) AddGroupingPolicies(rules [][]string) (bool, error) { // AddGroupingPoliciesEx adds role inheritance rules to the current policy. // If the rule already exists, the rule will not be added. -// But unlike AddGroupingPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddGroupingPolicies, other non-existent rules are added instead of returning false directly. func (e *Enforcer) AddGroupingPoliciesEx(rules [][]string) (bool, error) { return e.AddNamedGroupingPoliciesEx("g", rules) } @@ -377,7 +384,7 @@ func (e *Enforcer) AddNamedGroupingPolicies(ptype string, rules [][]string) (boo // AddNamedGroupingPoliciesEx adds named role inheritance rules to the current policy. // If the rule already exists, the rule will not be added. -// But unlike AddNamedGroupingPolicies, other non-existent rules are added instead of returning false directly +// But unlike AddNamedGroupingPolicies, other non-existent rules are added instead of returning false directly. func (e *Enforcer) AddNamedGroupingPoliciesEx(ptype string, rules [][]string) (bool, error) { return e.addPolicies("g", ptype, rules, true) } diff --git a/vendor/github.com/casbin/casbin/v2/model/assertion.go b/vendor/github.com/casbin/casbin/v2/model/assertion.go index cbe0edd7..7c5381d7 100644 --- a/vendor/github.com/casbin/casbin/v2/model/assertion.go +++ b/vendor/github.com/casbin/casbin/v2/model/assertion.go @@ -23,7 +23,7 @@ import ( ) // Assertion represents an expression in a section of the model. -// For example: r = sub, obj, act +// For example: r = sub, obj, act. type Assertion struct { Key string Value string @@ -147,7 +147,7 @@ func (ast *Assertion) buildConditionalRoleLinks(condRM rbac.ConditionalRoleManag return nil } -// addConditionalRoleLinks adds Link to rbac.ConditionalRoleManager and sets the parameters for LinkConditionFunc +// addConditionalRoleLink adds Link to rbac.ConditionalRoleManager and sets the parameters for LinkConditionFunc. func (ast *Assertion) addConditionalRoleLink(rule []string, domainRule []string) error { var err error if len(domainRule) == 0 { diff --git a/vendor/github.com/casbin/casbin/v2/model/function.go b/vendor/github.com/casbin/casbin/v2/model/function.go index 0ae12460..f1a8d007 100644 --- a/vendor/github.com/casbin/casbin/v2/model/function.go +++ b/vendor/github.com/casbin/casbin/v2/model/function.go @@ -17,8 +17,8 @@ package model import ( "sync" - "github.com/Knetic/govaluate" "github.com/casbin/casbin/v2/util" + "github.com/casbin/govaluate" ) // FunctionMap represents the collection of Function. @@ -53,7 +53,7 @@ func LoadFunctionMap() FunctionMap { return *fm } -// GetFunctions return a map with all the functions +// GetFunctions return a map with all the functions. func (fm *FunctionMap) GetFunctions() map[string]govaluate.ExpressionFunction { ret := make(map[string]govaluate.ExpressionFunction) diff --git a/vendor/github.com/casbin/casbin/v2/model/model.go b/vendor/github.com/casbin/casbin/v2/model/model.go index 5db4c2c3..bf751bc0 100644 --- a/vendor/github.com/casbin/casbin/v2/model/model.go +++ b/vendor/github.com/casbin/casbin/v2/model/model.go @@ -46,7 +46,7 @@ var sectionNameMap = map[string]string{ "m": "matchers", } -// Minimal required sections for a model to be valid +// Minimal required sections for a model to be valid. var requiredSections = []string{"r", "p", "e", "m"} func loadAssertion(model Model, cfg config.ConfigInterface, sec string, key string) bool { @@ -56,7 +56,7 @@ func loadAssertion(model Model, cfg config.ConfigInterface, sec string, key stri var paramsRegex = regexp.MustCompile(`\((.*?)\)`) -// getParamsToken Get ParamsToken from Assertion.Value +// getParamsToken Get ParamsToken from Assertion.Value. func getParamsToken(value string) []string { paramsString := paramsRegex.FindString(value) if paramsString == "" { diff --git a/vendor/github.com/casbin/casbin/v2/model/policy.go b/vendor/github.com/casbin/casbin/v2/model/policy.go index 48dcb13d..d2cadbf6 100644 --- a/vendor/github.com/casbin/casbin/v2/model/policy.go +++ b/vendor/github.com/casbin/casbin/v2/model/policy.go @@ -207,15 +207,11 @@ func (model Model) AddPolicy(sec string, ptype string, rule []string) { i := len(assertion.Policy) - 1 for ; i > 0; i-- { idx, err := strconv.Atoi(assertion.Policy[i-1][assertion.FieldIndexMap[constant.PriorityIndex]]) - if err != nil { - break - } - if idx > idxInsert { - assertion.Policy[i] = assertion.Policy[i-1] - assertion.PolicyMap[strings.Join(assertion.Policy[i-1], DefaultSep)]++ - } else { + if err != nil || idx <= idxInsert { break } + assertion.Policy[i] = assertion.Policy[i-1] + assertion.PolicyMap[strings.Join(assertion.Policy[i-1], DefaultSep)]++ } assertion.Policy[i] = rule assertion.PolicyMap[strings.Join(rule, DefaultSep)] = i diff --git a/vendor/github.com/casbin/casbin/v2/persist/adapter_context.go b/vendor/github.com/casbin/casbin/v2/persist/adapter_context.go index 8e54ad0d..bda78a7e 100644 --- a/vendor/github.com/casbin/casbin/v2/persist/adapter_context.go +++ b/vendor/github.com/casbin/casbin/v2/persist/adapter_context.go @@ -22,8 +22,6 @@ import ( // ContextAdapter provides a context-aware interface for Casbin adapters. type ContextAdapter interface { - Adapter - // LoadPolicyCtx loads all policy rules from the storage with context. LoadPolicyCtx(ctx context.Context, model model.Model) error // SavePolicyCtx saves all policy rules to the storage with context. diff --git a/vendor/github.com/casbin/casbin/v2/persist/dispatcher.go b/vendor/github.com/casbin/casbin/v2/persist/dispatcher.go index 3eb4605b..ceaed838 100644 --- a/vendor/github.com/casbin/casbin/v2/persist/dispatcher.go +++ b/vendor/github.com/casbin/casbin/v2/persist/dispatcher.go @@ -14,7 +14,7 @@ package persist -// Dispatcher is the interface for Casbin dispatcher +// Dispatcher is the interface for Casbin dispatcher. type Dispatcher interface { // AddPolicies adds policies rule to all instance. AddPolicies(sec string, ptype string, rules [][]string) error diff --git a/vendor/github.com/casbin/casbin/v2/persist/file-adapter/adapter_mock.go b/vendor/github.com/casbin/casbin/v2/persist/file-adapter/adapter_mock.go index 8f8632b8..fcc5f821 100644 --- a/vendor/github.com/casbin/casbin/v2/persist/file-adapter/adapter_mock.go +++ b/vendor/github.com/casbin/casbin/v2/persist/file-adapter/adapter_mock.go @@ -73,12 +73,12 @@ func (a *AdapterMock) loadPolicyFile(model model.Model, handler func(string, mod } } -// SetMockErr sets string to be returned by of the mock during testing +// SetMockErr sets string to be returned by of the mock during testing. func (a *AdapterMock) SetMockErr(errorToSet string) { a.errorValue = errorToSet } -// GetMockErr returns a mock error or nil +// GetMockErr returns a mock error or nil. func (a *AdapterMock) GetMockErr() error { var returnError error if a.errorValue != "" { diff --git a/vendor/github.com/casbin/casbin/v2/rbac/default-role-manager/role_manager.go b/vendor/github.com/casbin/casbin/v2/rbac/default-role-manager/role_manager.go index 3b6ad8b4..a6ae8693 100644 --- a/vendor/github.com/casbin/casbin/v2/rbac/default-role-manager/role_manager.go +++ b/vendor/github.com/casbin/casbin/v2/rbac/default-role-manager/role_manager.go @@ -59,12 +59,12 @@ func (r *Role) removeRole(role *Role) { role.removeUser(r) } -// should only be called inside addRole +// should only be called inside addRole. func (r *Role) addUser(user *Role) { r.users.Store(user.name, user) } -// should only be called inside removeRole +// should only be called inside removeRole. func (r *Role) removeUser(user *Role) { r.users.Delete(user.name) } @@ -195,7 +195,7 @@ func (r *Role) getLinkConditionFuncParams(role *Role, domain string) ([]string, return params.([]string), ok } -// RoleManagerImpl provides a default implementation for the RoleManager interface +// RoleManagerImpl provides a default implementation for the RoleManager interface. type RoleManagerImpl struct { allRoles *sync.Map maxHierarchyLevel int @@ -209,20 +209,20 @@ type RoleManagerImpl struct { // default RoleManager implementation. func NewRoleManagerImpl(maxHierarchyLevel int) *RoleManagerImpl { rm := RoleManagerImpl{} - _ = rm.Clear() //init allRoles and matchingFuncCache + _ = rm.Clear() // init allRoles and matchingFuncCache rm.maxHierarchyLevel = maxHierarchyLevel rm.SetLogger(&log.DefaultLogger{}) return &rm } -// use this constructor to avoid rebuild of AddMatchingFunc +// use this constructor to avoid rebuild of AddMatchingFunc. func newRoleManagerWithMatchingFunc(maxHierarchyLevel int, fn rbac.MatchingFunc) *RoleManagerImpl { rm := NewRoleManagerImpl(maxHierarchyLevel) rm.matchingFunc = fn return rm } -// rebuilds role cache +// rebuilds role cache. func (rm *RoleManagerImpl) rebuild() { roles := rm.allRoles _ = rm.Clear() @@ -263,7 +263,7 @@ func (rm *RoleManagerImpl) load(name interface{}) (value *Role, ok bool) { return nil, false } -// loads or creates a role +// loads or creates a role. func (rm *RoleManagerImpl) getRole(name string) (r *Role, created bool) { var role *Role var ok bool @@ -302,13 +302,13 @@ func (rm *RoleManagerImpl) removeRole(name string) { } } -// AddMatchingFunc support use pattern in g +// AddMatchingFunc support use pattern in g. func (rm *RoleManagerImpl) AddMatchingFunc(name string, fn rbac.MatchingFunc) { rm.matchingFunc = fn rm.rebuild() } -// AddDomainMatchingFunc support use domain pattern in g +// AddDomainMatchingFunc support use domain pattern in g. func (rm *RoleManagerImpl) AddDomainMatchingFunc(name string, fn rbac.MatchingFunc) { rm.domainMatchingFunc = fn } @@ -424,13 +424,13 @@ func (rm *RoleManagerImpl) PrintRoles() error { return nil } -// GetDomains gets domains that a user has +// GetDomains gets domains that a user has. func (rm *RoleManagerImpl) GetDomains(name string) ([]string, error) { domains := []string{defaultDomain} return domains, nil } -// GetAllDomains gets all domains +// GetAllDomains gets all domains. func (rm *RoleManagerImpl) GetAllDomains() ([]string, error) { domains := []string{defaultDomain} return domains, nil @@ -458,7 +458,7 @@ func (rm *RoleManagerImpl) Range(fn func(name1, name2 string, domain ...string) rangeLinks(rm.allRoles, fn) } -// Deprecated: BuildRelationship is no longer required +// Deprecated: BuildRelationship is no longer required. func (rm *RoleManagerImpl) BuildRelationship(name1 string, name2 string, domain ...string) error { return nil } @@ -486,7 +486,7 @@ func (dm *DomainManager) SetLogger(logger log.Logger) { dm.logger = logger } -// AddMatchingFunc support use pattern in g +// AddMatchingFunc support use pattern in g. func (dm *DomainManager) AddMatchingFunc(name string, fn rbac.MatchingFunc) { dm.matchingFunc = fn dm.rmMap.Range(func(key, value interface{}) bool { @@ -495,7 +495,7 @@ func (dm *DomainManager) AddMatchingFunc(name string, fn rbac.MatchingFunc) { }) } -// AddDomainMatchingFunc support use domain pattern in g +// AddDomainMatchingFunc support use domain pattern in g. func (dm *DomainManager) AddDomainMatchingFunc(name string, fn rbac.MatchingFunc) { dm.domainMatchingFunc = fn dm.rmMap.Range(func(key, value interface{}) bool { @@ -505,7 +505,7 @@ func (dm *DomainManager) AddDomainMatchingFunc(name string, fn rbac.MatchingFunc dm.rebuild() } -// clears the map of RoleManagers +// clears the map of RoleManagers. func (dm *DomainManager) rebuild() { rmMap := dm.rmMap _ = dm.Clear() @@ -568,7 +568,7 @@ func (dm *DomainManager) load(name interface{}) (value *RoleManagerImpl, ok bool return nil, false } -// load or create a RoleManager instance of domain +// load or create a RoleManager instance of domain. func (dm *DomainManager) getRoleManager(domain string, store bool) *RoleManagerImpl { var rm *RoleManagerImpl var ok bool @@ -599,7 +599,7 @@ func (dm *DomainManager) AddLink(name1 string, name2 string, domains ...string) if err != nil { return err } - roleManager := dm.getRoleManager(domain, true) //create role manager if it does not exist + roleManager := dm.getRoleManager(domain, true) // create role manager if it does not exist _ = roleManager.AddLink(name1, name2, domains...) dm.rangeAffectedRoleManagers(domain, func(rm *RoleManagerImpl) { @@ -615,7 +615,7 @@ func (dm *DomainManager) DeleteLink(name1 string, name2 string, domains ...strin if err != nil { return err } - roleManager := dm.getRoleManager(domain, true) //create role manager if it does not exist + roleManager := dm.getRoleManager(domain, true) // create role manager if it does not exist _ = roleManager.DeleteLink(name1, name2, domains...) dm.rangeAffectedRoleManagers(domain, func(rm *RoleManagerImpl) { @@ -679,7 +679,7 @@ func (dm *DomainManager) PrintRoles() error { return nil } -// GetDomains gets domains that a user has +// GetDomains gets domains that a user has. func (dm *DomainManager) GetDomains(name string) ([]string, error) { var domains []string dm.rmMap.Range(func(key, value interface{}) bool { @@ -697,18 +697,18 @@ func (dm *DomainManager) GetDomains(name string) ([]string, error) { return domains, nil } -// GetAllDomains gets all domains -func (rm *DomainManager) GetAllDomains() ([]string, error) { +// GetAllDomains gets all domains. +func (dm *DomainManager) GetAllDomains() ([]string, error) { var domains []string - rm.rmMap.Range(func(key, value interface{}) bool { + dm.rmMap.Range(func(key, value interface{}) bool { domains = append(domains, key.(string)) return true }) return domains, nil } -// Deprecated: BuildRelationship is no longer required -func (rm *DomainManager) BuildRelationship(name1 string, name2 string, domain ...string) error { +// Deprecated: BuildRelationship is no longer required. +func (dm *DomainManager) BuildRelationship(name1 string, name2 string, domain ...string) error { return nil } @@ -733,7 +733,7 @@ func (crm *ConditionalRoleManager) copyFrom(other *ConditionalRoleManager) { }) } -// use this constructor to avoid rebuild of AddMatchingFunc +// use this constructor to avoid rebuild of AddMatchingFunc. func newConditionalRoleManagerWithMatchingFunc(maxHierarchyLevel int, fn rbac.MatchingFunc) *ConditionalRoleManager { rm := NewConditionalRoleManager(maxHierarchyLevel) rm.matchingFunc = fn @@ -744,7 +744,7 @@ func newConditionalRoleManagerWithMatchingFunc(maxHierarchyLevel int, fn rbac.Ma // ConditionalRoleManager implementation. func NewConditionalRoleManager(maxHierarchyLevel int) *ConditionalRoleManager { rm := ConditionalRoleManager{} - _ = rm.Clear() //init allRoles and matchingFuncCache + _ = rm.Clear() // init allRoles and matchingFuncCache rm.maxHierarchyLevel = maxHierarchyLevel rm.SetLogger(&log.DefaultLogger{}) return &rm @@ -770,7 +770,7 @@ func (crm *ConditionalRoleManager) HasLink(name1 string, name2 string, domains . } // hasLinkHelper use the Breadth First Search algorithm to traverse the Role tree -// Judging whether the user has a role (has link) is to judge whether the role node can be reached from the user node +// Judging whether the user has a role (has link) is to judge whether the role node can be reached from the user node. func (crm *ConditionalRoleManager) hasLinkHelper(targetName string, roles map[string]*Role, level int, domains ...string) bool { if level < 0 || len(roles) == 0 { return false @@ -817,12 +817,12 @@ func (crm *ConditionalRoleManager) getNextRoles(currentRole, nextRole *Role, dom return true } -// GetLinkConditionFunc get LinkConditionFunc based on userName, roleName +// GetLinkConditionFunc get LinkConditionFunc based on userName, roleName. func (crm *ConditionalRoleManager) GetLinkConditionFunc(userName, roleName string) (rbac.LinkConditionFunc, bool) { return crm.GetDomainLinkConditionFunc(userName, roleName, defaultDomain) } -// GetDomainLinkConditionFunc get LinkConditionFunc based on userName, roleName, domain +// GetDomainLinkConditionFunc get LinkConditionFunc based on userName, roleName, domain. func (crm *ConditionalRoleManager) GetDomainLinkConditionFunc(userName, roleName, domain string) (rbac.LinkConditionFunc, bool) { user, userCreated := crm.getRole(userName) role, roleCreated := crm.getRole(roleName) @@ -840,7 +840,7 @@ func (crm *ConditionalRoleManager) GetDomainLinkConditionFunc(userName, roleName return user.getLinkConditionFunc(role, domain) } -// GetLinkConditionFuncParams gets parameters of LinkConditionFunc based on userName, roleName, domain +// GetLinkConditionFuncParams gets parameters of LinkConditionFunc based on userName, roleName, domain. func (crm *ConditionalRoleManager) GetLinkConditionFuncParams(userName, roleName string, domain ...string) ([]string, bool) { user, userCreated := crm.getRole(userName) role, roleCreated := crm.getRole(roleName) @@ -867,12 +867,12 @@ func (crm *ConditionalRoleManager) GetLinkConditionFuncParams(userName, roleName } } -// AddLinkConditionFunc is based on userName, roleName, add LinkConditionFunc +// AddLinkConditionFunc is based on userName, roleName, add LinkConditionFunc. func (crm *ConditionalRoleManager) AddLinkConditionFunc(userName, roleName string, fn rbac.LinkConditionFunc) { crm.AddDomainLinkConditionFunc(userName, roleName, defaultDomain, fn) } -// AddDomainLinkConditionFunc is based on userName, roleName, domain, add LinkConditionFunc +// AddDomainLinkConditionFunc is based on userName, roleName, domain, add LinkConditionFunc. func (crm *ConditionalRoleManager) AddDomainLinkConditionFunc(userName, roleName, domain string, fn rbac.LinkConditionFunc) { user, _ := crm.getRole(userName) role, _ := crm.getRole(roleName) @@ -880,12 +880,12 @@ func (crm *ConditionalRoleManager) AddDomainLinkConditionFunc(userName, roleName user.addLinkConditionFunc(role, domain, fn) } -// SetLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName, domain +// SetLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName, domain. func (crm *ConditionalRoleManager) SetLinkConditionFuncParams(userName, roleName string, params ...string) { crm.SetDomainLinkConditionFuncParams(userName, roleName, defaultDomain, params...) } -// SetDomainLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName, domain +// SetDomainLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName, domain. func (crm *ConditionalRoleManager) SetDomainLinkConditionFuncParams(userName, roleName, domain string, params ...string) { user, _ := crm.getRole(userName) role, _ := crm.getRole(roleName) @@ -902,20 +902,20 @@ type ConditionalDomainManager struct { // ConditionalDomainManager implementation. func NewConditionalDomainManager(maxHierarchyLevel int) *ConditionalDomainManager { rm := ConditionalDomainManager{} - _ = rm.Clear() //init allRoles and matchingFuncCache + _ = rm.Clear() // init allRoles and matchingFuncCache rm.maxHierarchyLevel = maxHierarchyLevel rm.SetLogger(&log.DefaultLogger{}) return &rm } -func (dm *ConditionalDomainManager) load(name interface{}) (value *ConditionalRoleManager, ok bool) { - if r, ok := dm.rmMap.Load(name); ok { +func (cdm *ConditionalDomainManager) load(name interface{}) (value *ConditionalRoleManager, ok bool) { + if r, ok := cdm.rmMap.Load(name); ok { return r.(*ConditionalRoleManager), true } return nil, false } -// load or create a ConditionalRoleManager instance of domain +// load or create a ConditionalRoleManager instance of domain. func (cdm *ConditionalDomainManager) getConditionalRoleManager(domain string, store bool) *ConditionalRoleManager { var rm *ConditionalRoleManager var ok bool @@ -956,7 +956,7 @@ func (cdm *ConditionalDomainManager) AddLink(name1 string, name2 string, domains if err != nil { return err } - conditionalRoleManager := cdm.getConditionalRoleManager(domain, true) //create role manager if it does not exist + conditionalRoleManager := cdm.getConditionalRoleManager(domain, true) // create role manager if it does not exist _ = conditionalRoleManager.AddLink(name1, name2, domain) cdm.rangeAffectedRoleManagers(domain, func(rm *RoleManagerImpl) { @@ -972,7 +972,7 @@ func (cdm *ConditionalDomainManager) DeleteLink(name1 string, name2 string, doma if err != nil { return err } - conditionalRoleManager := cdm.getConditionalRoleManager(domain, true) //create role manager if it does not exist + conditionalRoleManager := cdm.getConditionalRoleManager(domain, true) // create role manager if it does not exist _ = conditionalRoleManager.DeleteLink(name1, name2, domain) cdm.rangeAffectedRoleManagers(domain, func(rm *RoleManagerImpl) { @@ -981,7 +981,7 @@ func (cdm *ConditionalDomainManager) DeleteLink(name1 string, name2 string, doma return nil } -// AddLinkConditionFunc is based on userName, roleName, add LinkConditionFunc +// AddLinkConditionFunc is based on userName, roleName, add LinkConditionFunc. func (cdm *ConditionalDomainManager) AddLinkConditionFunc(userName, roleName string, fn rbac.LinkConditionFunc) { cdm.rmMap.Range(func(key, value interface{}) bool { value.(*ConditionalRoleManager).AddLinkConditionFunc(userName, roleName, fn) @@ -989,7 +989,7 @@ func (cdm *ConditionalDomainManager) AddLinkConditionFunc(userName, roleName str }) } -// AddDomainLinkConditionFunc is based on userName, roleName, domain, add LinkConditionFunc +// AddDomainLinkConditionFunc is based on userName, roleName, domain, add LinkConditionFunc. func (cdm *ConditionalDomainManager) AddDomainLinkConditionFunc(userName, roleName, domain string, fn rbac.LinkConditionFunc) { cdm.rmMap.Range(func(key, value interface{}) bool { value.(*ConditionalRoleManager).AddDomainLinkConditionFunc(userName, roleName, domain, fn) @@ -997,7 +997,7 @@ func (cdm *ConditionalDomainManager) AddDomainLinkConditionFunc(userName, roleNa }) } -// SetLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName +// SetLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName. func (cdm *ConditionalDomainManager) SetLinkConditionFuncParams(userName, roleName string, params ...string) { cdm.rmMap.Range(func(key, value interface{}) bool { value.(*ConditionalRoleManager).SetLinkConditionFuncParams(userName, roleName, params...) @@ -1005,7 +1005,7 @@ func (cdm *ConditionalDomainManager) SetLinkConditionFuncParams(userName, roleNa }) } -// SetDomainLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName, domain +// SetDomainLinkConditionFuncParams sets parameters of LinkConditionFunc based on userName, roleName, domain. func (cdm *ConditionalDomainManager) SetDomainLinkConditionFuncParams(userName, roleName, domain string, params ...string) { cdm.rmMap.Range(func(key, value interface{}) bool { value.(*ConditionalRoleManager).SetDomainLinkConditionFuncParams(userName, roleName, domain, params...) diff --git a/vendor/github.com/casbin/casbin/v2/rbac/role_manager.go b/vendor/github.com/casbin/casbin/v2/rbac/role_manager.go index d8a36691..28b40a35 100644 --- a/vendor/github.com/casbin/casbin/v2/rbac/role_manager.go +++ b/vendor/github.com/casbin/casbin/v2/rbac/role_manager.go @@ -58,7 +58,7 @@ type RoleManager interface { } // ConditionalRoleManager provides interface to define the operations for managing roles. -// Link with conditions is supported +// Link with conditions is supported. type ConditionalRoleManager interface { RoleManager diff --git a/vendor/github.com/casbin/casbin/v2/rbac_api.go b/vendor/github.com/casbin/casbin/v2/rbac_api.go index bc1abb10..fc0106d3 100644 --- a/vendor/github.com/casbin/casbin/v2/rbac_api.go +++ b/vendor/github.com/casbin/casbin/v2/rbac_api.go @@ -15,6 +15,7 @@ package casbin import ( + "fmt" "strings" "github.com/casbin/casbin/v2/constant" @@ -24,13 +25,21 @@ import ( // GetRolesForUser gets the roles that a user has. func (e *Enforcer) GetRolesForUser(name string, domain ...string) ([]string, error) { - res, err := e.model["g"]["g"].RM.GetRoles(name, domain...) + rm := e.GetRoleManager() + if rm == nil { + return nil, fmt.Errorf("role manager is not initialized") + } + res, err := rm.GetRoles(name, domain...) return res, err } // GetUsersForRole gets the users that has a role. func (e *Enforcer) GetUsersForRole(name string, domain ...string) ([]string, error) { - res, err := e.model["g"]["g"].RM.GetUsers(name, domain...) + rm := e.GetRoleManager() + if rm == nil { + return nil, fmt.Errorf("role manager is not initialized") + } + res, err := rm.GetUsers(name, domain...) return res, err } @@ -114,7 +123,12 @@ func (e *Enforcer) DeleteUser(user string) (bool, error) { // Returns false if the role does not exist (aka not affected). func (e *Enforcer) DeleteRole(role string) (bool, error) { var err error - res1, err := e.RemoveFilteredGroupingPolicy(1, role) + res1, err := e.RemoveFilteredGroupingPolicy(0, role) + if err != nil { + return res1, err + } + + res2, err := e.RemoveFilteredGroupingPolicy(1, role) if err != nil { return res1, err } @@ -123,8 +137,8 @@ func (e *Enforcer) DeleteRole(role string) (bool, error) { if err != nil { return false, err } - res2, err := e.RemoveFilteredPolicy(subIndex, role) - return res1 || res2, err + res3, err := e.RemoveFilteredPolicy(subIndex, role) + return res1 || res2 || res3, err } // DeletePermission deletes a permission. @@ -166,12 +180,12 @@ func (e *Enforcer) DeletePermissionsForUser(user string) (bool, error) { } // GetPermissionsForUser gets permissions for a user or role. -func (e *Enforcer) GetPermissionsForUser(user string, domain ...string) [][]string { +func (e *Enforcer) GetPermissionsForUser(user string, domain ...string) ([][]string, error) { return e.GetNamedPermissionsForUser("p", user, domain...) } // GetNamedPermissionsForUser gets permissions for a user or role by named policy. -func (e *Enforcer) GetNamedPermissionsForUser(ptype string, user string, domain ...string) [][]string { +func (e *Enforcer) GetNamedPermissionsForUser(ptype string, user string, domain ...string) ([][]string, error) { permission := make([][]string, 0) for pType, assertion := range e.model["p"] { if pType != ptype { @@ -187,14 +201,14 @@ func (e *Enforcer) GetNamedPermissionsForUser(ptype string, user string, domain if len(domain) > 0 { index, err := e.GetFieldIndex(ptype, constant.DomainIndex) if err != nil { - return permission + return permission, err } args[index] = domain[0] } perm := e.GetFilteredNamedPolicy(ptype, 0, args...) permission = append(permission, perm...) } - return permission + return permission, nil } // HasPermissionForUser determines whether a user has a permission. @@ -214,7 +228,6 @@ func (e *Enforcer) GetImplicitRolesForUser(name string, domain ...string) ([]str res := []string{} for _, rm := range e.rmMap { - roleSet := make(map[string]bool) roleSet[name] = true q := make([]string, 0) @@ -246,7 +259,6 @@ func (e *Enforcer) GetImplicitUsersForRole(name string, domain ...string) ([]str res := []string{} for _, rm := range e.rmMap { - roleSet := make(map[string]bool) roleSet[name] = true q := make([]string, 0) @@ -294,10 +306,13 @@ func (e *Enforcer) GetImplicitPermissionsForUser(user string, domain ...string) // g, alice, admin // // GetImplicitPermissionsForUser("alice") can only get: [["admin", "data1", "read"]], whose policy is default policy "p" -// But you can specify the named policy "p2" to get: [["admin", "create"]] by GetNamedImplicitPermissionsForUser("p2","alice") +// But you can specify the named policy "p2" to get: [["admin", "create"]] by GetNamedImplicitPermissionsForUser("p2","alice"). func (e *Enforcer) GetNamedImplicitPermissionsForUser(ptype string, user string, domain ...string) ([][]string, error) { permission := make([][]string, 0) rm := e.GetRoleManager() + if rm == nil { + return nil, fmt.Errorf("role manager is not initialized") + } domainIndex, _ := e.GetFieldIndex(ptype, constant.DomainIndex) for _, rule := range e.model["p"][ptype].Policy { if len(domain) == 0 { @@ -305,20 +320,21 @@ func (e *Enforcer) GetNamedImplicitPermissionsForUser(ptype string, user string, if matched { permission = append(permission, deepCopyPolicy(rule)) } - } else if len(domain) > 1 { + continue + } + if len(domain) > 1 { return nil, errors.ErrDomainParameter - } else { - d := domain[0] - matched := rm.Match(d, rule[domainIndex]) - if !matched { - continue - } - matched, _ = rm.HasLink(user, rule[0], d) - if matched { - newRule := deepCopyPolicy(rule) - newRule[domainIndex] = d - permission = append(permission, newRule) - } + } + d := domain[0] + matched := rm.Match(d, rule[domainIndex]) + if !matched { + continue + } + matched, _ = rm.HasLink(user, rule[0], d) + if matched { + newRule := deepCopyPolicy(rule) + newRule[domainIndex] = d + permission = append(permission, newRule) } } return permission, nil @@ -358,7 +374,7 @@ func (e *Enforcer) GetImplicitUsersForPermission(permission ...string) ([]string return res, nil } -// GetDomainsForUser gets all domains +// GetDomainsForUser gets all domains. func (e *Enforcer) GetDomainsForUser(user string) ([]string, error) { var domains []string for _, rm := range e.rmMap { @@ -371,7 +387,7 @@ func (e *Enforcer) GetDomainsForUser(user string) ([]string, error) { return domains, nil } -// GetImplicitResourcesForUser returns all policies that user obtaining in domain +// GetImplicitResourcesForUser returns all policies that user obtaining in domain. func (e *Enforcer) GetImplicitResourcesForUser(user string, domain ...string) ([][]string, error) { permissions, err := e.GetImplicitPermissionsForUser(user, domain...) if err != nil { @@ -410,7 +426,7 @@ func (e *Enforcer) GetImplicitResourcesForUser(user string, domain ...string) ([ return res, nil } -// deepCopyPolicy returns a deepcopy version of the policy to prevent changing policies through returned slice +// deepCopyPolicy returns a deepcopy version of the policy to prevent changing policies through returned slice. func deepCopyPolicy(src []string) []string { newRule := make([]string, len(src)) copy(newRule, src) @@ -483,6 +499,9 @@ func (e *Enforcer) GetImplicitUsersForResource(resource string) ([][]string, err subjectIndex, _ := e.GetFieldIndex("p", "sub") objectIndex, _ := e.GetFieldIndex("p", "obj") rm := e.GetRoleManager() + if rm == nil { + return nil, fmt.Errorf("role manager is not initialized") + } isRole := make(map[string]bool) for _, role := range e.GetAllRoles() { @@ -518,13 +537,16 @@ func (e *Enforcer) GetImplicitUsersForResource(resource string) ([][]string, err } // GetImplicitUsersForResourceByDomain return implicit user based on resource and domain. -// Compared to GetImplicitUsersForResource, domain is supported +// Compared to GetImplicitUsersForResource, domain is supported. func (e *Enforcer) GetImplicitUsersForResourceByDomain(resource string, domain string) ([][]string, error) { permissions := make([][]string, 0) subjectIndex, _ := e.GetFieldIndex("p", "sub") objectIndex, _ := e.GetFieldIndex("p", "obj") domIndex, _ := e.GetFieldIndex("p", "dom") rm := e.GetRoleManager() + if rm == nil { + return nil, fmt.Errorf("role manager is not initialized") + } isRole := make(map[string]bool) diff --git a/vendor/github.com/casbin/casbin/v2/rbac_api_synced.go b/vendor/github.com/casbin/casbin/v2/rbac_api_synced.go index 7ee8b8be..0bbf7384 100644 --- a/vendor/github.com/casbin/casbin/v2/rbac_api_synced.go +++ b/vendor/github.com/casbin/casbin/v2/rbac_api_synced.go @@ -124,14 +124,14 @@ func (e *SyncedEnforcer) DeletePermissionsForUser(user string) (bool, error) { } // GetPermissionsForUser gets permissions for a user or role. -func (e *SyncedEnforcer) GetPermissionsForUser(user string, domain ...string) [][]string { +func (e *SyncedEnforcer) GetPermissionsForUser(user string, domain ...string) ([][]string, error) { e.m.RLock() defer e.m.RUnlock() return e.Enforcer.GetPermissionsForUser(user, domain...) } // GetNamedPermissionsForUser gets permissions for a user or role by named policy. -func (e *SyncedEnforcer) GetNamedPermissionsForUser(ptype string, user string, domain ...string) [][]string { +func (e *SyncedEnforcer) GetNamedPermissionsForUser(ptype string, user string, domain ...string) ([][]string, error) { e.m.RLock() defer e.m.RUnlock() return e.Enforcer.GetNamedPermissionsForUser(ptype, user, domain...) @@ -181,7 +181,7 @@ func (e *SyncedEnforcer) GetImplicitPermissionsForUser(user string, domain ...st // g, alice, admin // // GetImplicitPermissionsForUser("alice") can only get: [["admin", "data1", "read"]], whose policy is default policy "p" -// But you can specify the named policy "p2" to get: [["admin", "create"]] by GetNamedImplicitPermissionsForUser("p2","alice") +// But you can specify the named policy "p2" to get: [["admin", "create"]] by GetNamedImplicitPermissionsForUser("p2","alice"). func (e *SyncedEnforcer) GetNamedImplicitPermissionsForUser(ptype string, user string, domain ...string) ([][]string, error) { e.m.RLock() defer e.m.RUnlock() diff --git a/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains.go b/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains.go index be65a146..c96ec73c 100644 --- a/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains.go +++ b/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains.go @@ -14,17 +14,27 @@ package casbin -import "github.com/casbin/casbin/v2/constant" +import ( + "fmt" -// GetUsersForRoleInDomain gets the users that has a role inside a domain. Add by Gordon + "github.com/casbin/casbin/v2/constant" +) + +// GetUsersForRoleInDomain gets the users that has a role inside a domain. Add by Gordon. func (e *Enforcer) GetUsersForRoleInDomain(name string, domain string) []string { - res, _ := e.model["g"]["g"].RM.GetUsers(name, domain) + if e.GetRoleManager() == nil { + return nil + } + res, _ := e.GetRoleManager().GetUsers(name, domain) return res } // GetRolesForUserInDomain gets the roles that a user has inside a domain. func (e *Enforcer) GetRolesForUserInDomain(name string, domain string) []string { - res, _ := e.model["g"]["g"].RM.GetRoles(name, domain) + if e.GetRoleManager() == nil { + return nil + } + res, _ := e.GetRoleManager().GetRoles(name, domain) return res } @@ -49,7 +59,10 @@ func (e *Enforcer) DeleteRoleForUserInDomain(user string, role string, domain st // DeleteRolesForUserInDomain deletes all roles for a user inside a domain. // Returns false if the user does not have any roles (aka not affected). func (e *Enforcer) DeleteRolesForUserInDomain(user string, domain string) (bool, error) { - roles, err := e.model["g"]["g"].RM.GetRoles(user, domain) + if e.GetRoleManager() == nil { + return false, fmt.Errorf("role manager is not initialized") + } + roles, err := e.GetRoleManager().GetRoles(user, domain) if err != nil { return false, err } @@ -142,7 +155,10 @@ func (e *Enforcer) DeleteDomains(domains ...string) (bool, error) { // GetAllDomains would get all domains. func (e *Enforcer) GetAllDomains() ([]string, error) { - return e.model["g"]["g"].RM.GetAllDomains() + if e.GetRoleManager() == nil { + return nil, fmt.Errorf("role manager is not initialized") + } + return e.GetRoleManager().GetAllDomains() } // GetAllRolesByDomain would get all roles associated with the domain. diff --git a/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains_synced.go b/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains_synced.go index bf194e05..26f6ce4b 100644 --- a/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains_synced.go +++ b/vendor/github.com/casbin/casbin/v2/rbac_api_with_domains_synced.go @@ -14,7 +14,7 @@ package casbin -// GetUsersForRoleInDomain gets the users that has a role inside a domain. Add by Gordon +// GetUsersForRoleInDomain gets the users that has a role inside a domain. Add by Gordon. func (e *SyncedEnforcer) GetUsersForRoleInDomain(name string, domain string) []string { e.m.RLock() defer e.m.RUnlock() diff --git a/vendor/github.com/casbin/casbin/v2/util/builtin_operators.go b/vendor/github.com/casbin/casbin/v2/util/builtin_operators.go index 2206d076..bab9b0b3 100644 --- a/vendor/github.com/casbin/casbin/v2/util/builtin_operators.go +++ b/vendor/github.com/casbin/casbin/v2/util/builtin_operators.go @@ -26,14 +26,14 @@ import ( "github.com/casbin/casbin/v2/rbac" - "github.com/Knetic/govaluate" + "github.com/casbin/govaluate" ) var ( keyMatch4Re *regexp.Regexp = regexp.MustCompile(`{([^/]+)}`) ) -// validate the variadic parameter size and type as string +// validate the variadic parameter size and type as string. func validateVariadicArgs(expectedLen int, args ...interface{}) error { if len(args) != expectedLen { return fmt.Errorf("expected %d arguments, but got %d", expectedLen, len(args)) @@ -49,7 +49,7 @@ func validateVariadicArgs(expectedLen int, args ...interface{}) error { return nil } -// validate the variadic string parameter size +// validate the variadic string parameter size. func validateVariadicStringArgs(expectedLen int, args ...string) error { if len(args) != expectedLen { return fmt.Errorf("expected %d arguments, but got %d", expectedLen, len(args)) @@ -58,7 +58,7 @@ func validateVariadicStringArgs(expectedLen int, args ...string) error { } // KeyMatch determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *. -// For example, "/foo/bar" matches "/foo/*" +// For example, "/foo/bar" matches "/foo/*". func KeyMatch(key1 string, key2 string) bool { i := strings.Index(key2, "*") if i == -1 { @@ -74,18 +74,18 @@ func KeyMatch(key1 string, key2 string) bool { // KeyMatchFunc is the wrapper for KeyMatch. func KeyMatchFunc(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyMatch", err) + return false, fmt.Errorf("%s: %w", "keyMatch", err) } name1 := args[0].(string) name2 := args[1].(string) - return bool(KeyMatch(name1, name2)), nil + return KeyMatch(name1, name2), nil } // KeyGet returns the matched part // For example, "/foo/bar/foo" matches "/foo/*" -// "bar/foo" will been returned +// "bar/foo" will been returned. func KeyGet(key1, key2 string) string { i := strings.Index(key2, "*") if i == -1 { @@ -99,10 +99,10 @@ func KeyGet(key1, key2 string) string { return "" } -// KeyGetFunc is the wrapper for KeyGet +// KeyGetFunc is the wrapper for KeyGet. func KeyGetFunc(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyGet", err) + return false, fmt.Errorf("%s: %w", "keyGet", err) } name1 := args[0].(string) @@ -112,7 +112,7 @@ func KeyGetFunc(args ...interface{}) (interface{}, error) { } // KeyMatch2 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *. -// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource" +// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource". func KeyMatch2(key1 string, key2 string) bool { key2 = strings.Replace(key2, "/*", "/.*", -1) @@ -125,18 +125,18 @@ func KeyMatch2(key1 string, key2 string) bool { // KeyMatch2Func is the wrapper for KeyMatch2. func KeyMatch2Func(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyMatch2", err) + return false, fmt.Errorf("%s: %w", "keyMatch2", err) } name1 := args[0].(string) name2 := args[1].(string) - return bool(KeyMatch2(name1, name2)), nil + return KeyMatch2(name1, name2), nil } // KeyGet2 returns value matched pattern // For example, "/resource1" matches "/:resource" -// if the pathVar == "resource", then "resource1" will be returned +// if the pathVar == "resource", then "resource1" will be returned. func KeyGet2(key1, key2 string, pathVar string) string { key2 = strings.Replace(key2, "/*", "/.*", -1) @@ -157,10 +157,10 @@ func KeyGet2(key1, key2 string, pathVar string) string { return "" } -// KeyGet2Func is the wrapper for KeyGet2 +// KeyGet2Func is the wrapper for KeyGet2. func KeyGet2Func(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(3, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyGet2", err) + return false, fmt.Errorf("%s: %w", "keyGet2", err) } name1 := args[0].(string) @@ -171,7 +171,7 @@ func KeyGet2Func(args ...interface{}) (interface{}, error) { } // KeyMatch3 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *. -// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}" +// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}". func KeyMatch3(key1 string, key2 string) bool { key2 = strings.Replace(key2, "/*", "/.*", -1) @@ -184,18 +184,18 @@ func KeyMatch3(key1 string, key2 string) bool { // KeyMatch3Func is the wrapper for KeyMatch3. func KeyMatch3Func(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyMatch3", err) + return false, fmt.Errorf("%s: %w", "keyMatch3", err) } name1 := args[0].(string) name2 := args[1].(string) - return bool(KeyMatch3(name1, name2)), nil + return KeyMatch3(name1, name2), nil } // KeyGet3 returns value matched pattern // For example, "project/proj_project1_admin/" matches "project/proj_{project}_admin/" -// if the pathVar == "project", then "project1" will be returned +// if the pathVar == "project", then "project1" will be returned. func KeyGet3(key1, key2 string, pathVar string) string { key2 = strings.Replace(key2, "/*", "/.*", -1) @@ -216,10 +216,10 @@ func KeyGet3(key1, key2 string, pathVar string) string { return "" } -// KeyGet3Func is the wrapper for KeyGet3 +// KeyGet3Func is the wrapper for KeyGet3. func KeyGet3Func(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(3, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyGet3", err) + return false, fmt.Errorf("%s: %w", "keyGet3", err) } name1 := args[0].(string) @@ -273,20 +273,20 @@ func KeyMatch4(key1 string, key2 string) bool { // KeyMatch4Func is the wrapper for KeyMatch4. func KeyMatch4Func(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyMatch4", err) + return false, fmt.Errorf("%s: %w", "keyMatch4", err) } name1 := args[0].(string) name2 := args[1].(string) - return bool(KeyMatch4(name1, name2)), nil + return KeyMatch4(name1, name2), nil } // KeyMatch5 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a * // For example, // - "/foo/bar?status=1&type=2" matches "/foo/bar" // - "/parent/child1" and "/parent/child1" matches "/parent/*" -// - "/parent/child1?status=1" matches "/parent/*" +// - "/parent/child1?status=1" matches "/parent/*". func KeyMatch5(key1 string, key2 string) bool { i := strings.Index(key1, "?") @@ -305,13 +305,13 @@ func KeyMatch5(key1 string, key2 string) bool { // KeyMatch5Func is the wrapper for KeyMatch5. func KeyMatch5Func(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "keyMatch5", err) + return false, fmt.Errorf("%s: %w", "keyMatch5", err) } name1 := args[0].(string) name2 := args[1].(string) - return bool(KeyMatch5(name1, name2)), nil + return KeyMatch5(name1, name2), nil } // RegexMatch determines whether key1 matches the pattern of key2 in regular expression. @@ -326,17 +326,17 @@ func RegexMatch(key1 string, key2 string) bool { // RegexMatchFunc is the wrapper for RegexMatch. func RegexMatchFunc(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "regexMatch", err) + return false, fmt.Errorf("%s: %w", "regexMatch", err) } name1 := args[0].(string) name2 := args[1].(string) - return bool(RegexMatch(name1, name2)), nil + return RegexMatch(name1, name2), nil } // IPMatch determines whether IP address ip1 matches the pattern of IP address ip2, ip2 can be an IP address or a CIDR pattern. -// For example, "192.168.2.123" matches "192.168.2.0/24" +// For example, "192.168.2.123" matches "192.168.2.0/24". func IPMatch(ip1 string, ip2 string) bool { objIP1 := net.ParseIP(ip1) if objIP1 == nil { @@ -359,16 +359,16 @@ func IPMatch(ip1 string, ip2 string) bool { // IPMatchFunc is the wrapper for IPMatch. func IPMatchFunc(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "ipMatch", err) + return false, fmt.Errorf("%s: %w", "ipMatch", err) } ip1 := args[0].(string) ip2 := args[1].(string) - return bool(IPMatch(ip1, ip2)), nil + return IPMatch(ip1, ip2), nil } -// GlobMatch determines whether key1 matches the pattern of key2 using glob pattern +// GlobMatch determines whether key1 matches the pattern of key2 using glob pattern. func GlobMatch(key1 string, key2 string) (bool, error) { return path.Match(key2, key1) } @@ -376,7 +376,7 @@ func GlobMatch(key1 string, key2 string) (bool, error) { // GlobMatchFunc is the wrapper for GlobMatch. func GlobMatchFunc(args ...interface{}) (interface{}, error) { if err := validateVariadicArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "globMatch", err) + return false, fmt.Errorf("%s: %w", "globMatch", err) } name1 := args[0].(string) @@ -453,13 +453,13 @@ func GenerateConditionalGFunction(crm rbac.ConditionalRoleManager) govaluate.Exp // TimeMatchFunc is the wrapper for TimeMatch. func TimeMatchFunc(args ...string) (bool, error) { if err := validateVariadicStringArgs(2, args...); err != nil { - return false, fmt.Errorf("%s: %s", "TimeMatch", err) + return false, fmt.Errorf("%s: %w", "TimeMatch", err) } return TimeMatch(args[0], args[1]) } // TimeMatch determines whether the current time is between startTime and endTime. -// You can use "_" to indicate that the parameter is ignored +// You can use "_" to indicate that the parameter is ignored. func TimeMatch(startTime, endTime string) (bool, error) { now := time.Now() if startTime != "_" { diff --git a/vendor/github.com/casbin/casbin/v2/util/util.go b/vendor/github.com/casbin/casbin/v2/util/util.go index e89e5eba..f247b27b 100644 --- a/vendor/github.com/casbin/casbin/v2/util/util.go +++ b/vendor/github.com/casbin/casbin/v2/util/util.go @@ -15,6 +15,7 @@ package util import ( + "encoding/json" "regexp" "sort" "strings" @@ -25,10 +26,13 @@ var evalReg = regexp.MustCompile(`\beval\((?P[^)]*)\)`) var escapeAssertionRegex = regexp.MustCompile(`\b((r|p)[0-9]*)\.`) -var numericRegex = regexp.MustCompile(`^-?\d+(?:\.\d+)?$`) - -func IsNumeric(s string) bool { - return numericRegex.MatchString(s) +func JsonToMap(jsonStr string) (map[string]interface{}, error) { + result := make(map[string]interface{}) + err := json.Unmarshal([]byte(jsonStr), &result) + if err != nil { + return result, err + } + return result, nil } // EscapeAssertion escapes the dots in the assertion, because the expression evaluation doesn't support such variable names. @@ -76,7 +80,7 @@ func Array2DEquals(a [][]string, b [][]string) bool { return true } -// SortArray2D Sorts the two-dimensional string array +// SortArray2D Sorts the two-dimensional string array. func SortArray2D(arr [][]string) { if len(arr) != 0 { sort.Slice(arr, func(i, j int) bool { @@ -155,7 +159,7 @@ func SetEquals(a []string, b []string) bool { return true } -// SetEquals determines whether two string sets are identical. +// SetEquals determines whether two int sets are identical. func SetEqualsInt(a []int, b []int) bool { if len(a) != len(b) { return false @@ -172,7 +176,7 @@ func SetEqualsInt(a []int, b []int) bool { return true } -// SetEquals determines whether two string sets are identical. +// Set2DEquals determines whether two string slice sets are identical. func Set2DEquals(a [][]string, b [][]string) bool { if len(a) != len(b) { return false @@ -229,12 +233,12 @@ func SetSubtract(a []string, b []string) []string { return diff } -// HasEval determine whether matcher contains function eval +// HasEval determine whether matcher contains function eval. func HasEval(s string) bool { return evalReg.MatchString(s) } -// ReplaceEval replace function eval with the value of its parameters +// ReplaceEval replace function eval with the value of its parameters. func ReplaceEval(s string, rule string) string { return evalReg.ReplaceAllString(s, "("+rule+")") } @@ -255,7 +259,7 @@ func ReplaceEvalWithMap(src string, sets map[string]string) string { }) } -// GetEvalValue returns the parameters of function eval +// GetEvalValue returns the parameters of function eval. func GetEvalValue(s string) []string { subMatch := evalReg.FindAllStringSubmatch(s, -1) var rules []string diff --git a/vendor/github.com/Knetic/govaluate/.gitignore b/vendor/github.com/casbin/govaluate/.gitignore similarity index 100% rename from vendor/github.com/Knetic/govaluate/.gitignore rename to vendor/github.com/casbin/govaluate/.gitignore diff --git a/vendor/github.com/casbin/govaluate/.releaserc.json b/vendor/github.com/casbin/govaluate/.releaserc.json new file mode 100644 index 00000000..58cb0bb4 --- /dev/null +++ b/vendor/github.com/casbin/govaluate/.releaserc.json @@ -0,0 +1,16 @@ +{ + "debug": true, + "branches": [ + "+([0-9])?(.{+([0-9]),x}).x", + "master", + { + "name": "beta", + "prerelease": true + } + ], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/github" + ] +} diff --git a/vendor/github.com/Knetic/govaluate/CONTRIBUTORS b/vendor/github.com/casbin/govaluate/CONTRIBUTORS similarity index 100% rename from vendor/github.com/Knetic/govaluate/CONTRIBUTORS rename to vendor/github.com/casbin/govaluate/CONTRIBUTORS diff --git a/vendor/github.com/Knetic/govaluate/EvaluableExpression.go b/vendor/github.com/casbin/govaluate/EvaluableExpression.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/EvaluableExpression.go rename to vendor/github.com/casbin/govaluate/EvaluableExpression.go diff --git a/vendor/github.com/Knetic/govaluate/EvaluableExpression_sql.go b/vendor/github.com/casbin/govaluate/EvaluableExpression_sql.go similarity index 82% rename from vendor/github.com/Knetic/govaluate/EvaluableExpression_sql.go rename to vendor/github.com/casbin/govaluate/EvaluableExpression_sql.go index 7e0ad1c8..52409fa2 100644 --- a/vendor/github.com/Knetic/govaluate/EvaluableExpression_sql.go +++ b/vendor/github.com/casbin/govaluate/EvaluableExpression_sql.go @@ -8,15 +8,15 @@ import ( ) /* - Returns a string representing this expression as if it were written in SQL. - This function assumes that all parameters exist within the same table, and that the table essentially represents - a serialized object of some sort (e.g., hibernate). - If your data model is more normalized, you may need to consider iterating through each actual token given by `Tokens()` - to create your query. +Returns a string representing this expression as if it were written in SQL. +This function assumes that all parameters exist within the same table, and that the table essentially represents +a serialized object of some sort (e.g., hibernate). +If your data model is more normalized, you may need to consider iterating through each actual token given by `Tokens()` +to create your query. - Boolean values are considered to be "1" for true, "0" for false. +Boolean values are considered to be "1" for true, "0" for false. - Times are formatted according to this.QueryDateFormat. +Times are formatted according to this.QueryDateFormat. */ func (this EvaluableExpression) ToSQLQuery() (string, error) { @@ -91,7 +91,7 @@ func (this EvaluableExpression) findNextSQLString(stream *tokenStream, transacti case NREQ: ret = "NOT RLIKE" default: - ret = fmt.Sprintf("%s", token.Value.(string)) + ret = fmt.Sprintf("%s", token.Value) } case TERNARY: @@ -116,7 +116,7 @@ func (this EvaluableExpression) findNextSQLString(stream *tokenStream, transacti switch prefixSymbols[token.Value.(string)] { case INVERT: - ret = fmt.Sprintf("NOT") + ret = "NOT" default: right, err := this.findNextSQLString(stream, transactions) @@ -149,7 +149,7 @@ func (this EvaluableExpression) findNextSQLString(stream *tokenStream, transacti ret = fmt.Sprintf("MOD(%s, %s)", left, right) default: - ret = fmt.Sprintf("%s", token.Value.(string)) + ret = fmt.Sprintf("%s", token.Value) } case CLAUSE: ret = "(" diff --git a/vendor/github.com/Knetic/govaluate/ExpressionToken.go b/vendor/github.com/casbin/govaluate/ExpressionToken.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/ExpressionToken.go rename to vendor/github.com/casbin/govaluate/ExpressionToken.go diff --git a/vendor/github.com/Knetic/govaluate/LICENSE b/vendor/github.com/casbin/govaluate/LICENSE similarity index 100% rename from vendor/github.com/Knetic/govaluate/LICENSE rename to vendor/github.com/casbin/govaluate/LICENSE diff --git a/vendor/github.com/Knetic/govaluate/MANUAL.md b/vendor/github.com/casbin/govaluate/MANUAL.md similarity index 100% rename from vendor/github.com/Knetic/govaluate/MANUAL.md rename to vendor/github.com/casbin/govaluate/MANUAL.md diff --git a/vendor/github.com/Knetic/govaluate/OperatorSymbol.go b/vendor/github.com/casbin/govaluate/OperatorSymbol.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/OperatorSymbol.go rename to vendor/github.com/casbin/govaluate/OperatorSymbol.go diff --git a/vendor/github.com/Knetic/govaluate/README.md b/vendor/github.com/casbin/govaluate/README.md similarity index 89% rename from vendor/github.com/Knetic/govaluate/README.md rename to vendor/github.com/casbin/govaluate/README.md index 2e5716d4..576a9df1 100644 --- a/vendor/github.com/Knetic/govaluate/README.md +++ b/vendor/github.com/casbin/govaluate/README.md @@ -1,10 +1,9 @@ govaluate ==== -[![Build Status](https://travis-ci.org/Knetic/govaluate.svg?branch=master)](https://travis-ci.org/Knetic/govaluate) -[![Godoc](https://img.shields.io/badge/godoc-reference-5272B4.svg)](https://godoc.org/github.com/Knetic/govaluate) -[![Go Report Card](https://goreportcard.com/badge/github.com/Knetic/govaluate)](https://goreportcard.com/report/github.com/Knetic/govaluate) -[![Gocover](https://gocover.io/_badge/github.com/Knetic/govaluate)](https://gocover.io/github.com/Knetic/govaluate) +[![Build Status](https://github.com/casbin/govaluate/actions/workflows/build.yml/badge.svg)](https://github.com/casbin/govaluate/actions/workflows/build.yml) +[![Godoc](https://godoc.org/github.com/casbin/govaluate?status.svg)](https://pkg.go.dev/github.com/casbin/govaluate) +[![Go Report Card](https://goreportcard.com/badge/github.com/casbin/govaluate)](https://goreportcard.com/report/github.com/casbin/govaluate) Provides support for evaluating arbitrary C-like artithmetic/string expressions. @@ -77,7 +76,7 @@ These examples have all returned boolean values, but it's equally possible to re // result is now set to "50.0", the float64 value. ``` -You can also do date parsing, though the formats are somewhat limited. Stick to RF3339, ISO8061, unix date, or ruby date formats. If you're having trouble getting a date string to parse, check the list of formats actually used: [parsing.go:248](https://github.com/Knetic/govaluate/blob/0580e9b47a69125afa0e4ebd1cf93c49eb5a43ec/parsing.go#L258). +You can also do date parsing, though the formats are somewhat limited. Stick to RF3339, ISO8061, unix date, or ruby date formats. If you're having trouble getting a date string to parse, check the list of formats actually used: [parsing.go:248](https://github.com/casbin/govaluate/blob/0580e9b47a69125afa0e4ebd1cf93c49eb5a43ec/parsing.go#L258). ```go expression, err := govaluate.NewEvaluableExpression("'2014-01-02' > '2014-01-01 23:59:59'"); @@ -162,14 +161,14 @@ Fields are accessed in a similar way. Assuming `foo` has a field called "Length" "foo.Length > 9000" +The values of a `map` are accessed in the same way. Assuming the parameter `foo` is `map[string]int{ "bar": 1 }` + + "foo.bar == 1" + Accessors can be nested to any depth, like the following "foo.Bar.Baz.SomeFunction()" -However it is not _currently_ supported to access values in `map`s. So the following will not work - - "foo.SomeMap['key']" - This may be convenient, but note that using accessors involves a _lot_ of reflection. This makes the expression about four times slower than just using a parameter (consult the benchmarks for more precise measurements on your system). If at all reasonable, the author recommends extracting the values you care about into a parameter map beforehand, or defining a struct that implements the `Parameters` interface, and which grabs fields as required. If there are functions you want to use, it's better to pass them as expression functions (see the above section). These approaches use no reflection, and are designed to be fast and clean. @@ -189,14 +188,14 @@ What operators and types does this support? * Ternary conditional: `?` `:` * Null coalescence: `??` -See [MANUAL.md](https://github.com/Knetic/govaluate/blob/master/MANUAL.md) for exacting details on what types each operator supports. +See [MANUAL.md](https://github.com/casbin/govaluate/blob/master/MANUAL.md) for exacting details on what types each operator supports. Types -- Some operators don't make sense when used with some types. For instance, what does it mean to get the modulo of a string? What happens if you check to see if two numbers are logically AND'ed together? -Everyone has a different intuition about the answers to these questions. To prevent confusion, this library will _refuse to operate_ upon types for which there is not an unambiguous meaning for the operation. See [MANUAL.md](https://github.com/Knetic/govaluate/blob/master/MANUAL.md) for details about what operators are valid for which types. +Everyone has a different intuition about the answers to these questions. To prevent confusion, this library will _refuse to operate_ upon types for which there is not an unambiguous meaning for the operation. See [MANUAL.md](https://github.com/casbin/govaluate/blob/master/MANUAL.md) for details about what operators are valid for which types. Benchmarks -- @@ -223,7 +222,7 @@ ok API Breaks -- -While this library has very few cases which will ever result in an API break, it can (and [has](https://github.com/Knetic/govaluate/releases/tag/v2.0.0)) happened. If you are using this in production, vendor the commit you've tested against, or use gopkg.in to redirect your import (e.g., `import "gopkg.in/Knetic/govaluate.v2"`). Master branch (while infrequent) _may_ at some point contain API breaking changes, and the author will have no way to communicate these to downstreams, other than creating a new major release. +While this library has very few cases which will ever result in an API break, it can happen. If you are using this in production, vendor the commit you've tested against, or use gopkg.in to redirect your import (e.g., `import "gopkg.in/casbin/govaluate.v1"`). Master branch (while infrequent) _may_ at some point contain API breaking changes, and the author will have no way to communicate these to downstreams, other than creating a new major release. Releases will explicitly state when an API break happens, and if they do not specify an API break it should be safe to upgrade. diff --git a/vendor/github.com/Knetic/govaluate/TokenKind.go b/vendor/github.com/casbin/govaluate/TokenKind.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/TokenKind.go rename to vendor/github.com/casbin/govaluate/TokenKind.go diff --git a/vendor/github.com/Knetic/govaluate/evaluationStage.go b/vendor/github.com/casbin/govaluate/evaluationStage.go similarity index 86% rename from vendor/github.com/Knetic/govaluate/evaluationStage.go rename to vendor/github.com/casbin/govaluate/evaluationStage.go index 11ea5872..27add4a7 100644 --- a/vendor/github.com/Knetic/govaluate/evaluationStage.go +++ b/vendor/github.com/casbin/govaluate/evaluationStage.go @@ -7,6 +7,7 @@ import ( "reflect" "regexp" "strings" + "unicode" ) const ( @@ -173,14 +174,14 @@ func regexStage(left interface{}, right interface{}, parameters Parameters) (int var pattern *regexp.Regexp var err error - switch right.(type) { + switch right := right.(type) { case string: - pattern, err = regexp.Compile(right.(string)) + pattern, err = regexp.Compile(right) if err != nil { - return nil, errors.New(fmt.Sprintf("Unable to compile regexp pattern '%v': %v", right, err)) + return nil, fmt.Errorf("Unable to compile regexp pattern '%v': %v", right, err) } case *regexp.Regexp: - pattern = right.(*regexp.Regexp) + pattern = right } return pattern.Match([]byte(left.(string))), nil @@ -238,9 +239,9 @@ func makeFunctionStage(function ExpressionFunction) evaluationOperator { return function() } - switch right.(type) { + switch right := right.(type) { case []interface{}: - return function(right.([]interface{})...) + return function(right...) default: return function(right) } @@ -313,6 +314,7 @@ func makeAccessorStage(pair []string) evaluationOperator { } }() + LOOP: for i := 1; i < len(pair); i++ { coreValue := reflect.ValueOf(value) @@ -325,32 +327,55 @@ func makeAccessorStage(pair []string) evaluationOperator { coreValue = coreValue.Elem() } - if coreValue.Kind() != reflect.Struct { - return nil, errors.New("Unable to access '" + pair[i] + "', '" + pair[i-1] + "' is not a struct") - } + var field reflect.Value + var method reflect.Value - field := coreValue.FieldByName(pair[i]) - if field != (reflect.Value{}) { - value = field.Interface() - continue - } - - method := coreValue.MethodByName(pair[i]) - if method == (reflect.Value{}) { - if corePtrVal.IsValid() { - method = corePtrVal.MethodByName(pair[i]) + switch coreValue.Kind() { + case reflect.Struct: + // check if field is exported + firstCharacter := getFirstRune(pair[i]) + if unicode.ToUpper(firstCharacter) != firstCharacter { + errorMsg := fmt.Sprintf("Unable to access unexported field '%s' in '%s'", pair[i], pair[i-1]) + return nil, errors.New(errorMsg) } + + field = coreValue.FieldByName(pair[i]) + if field != (reflect.Value{}) { + value = field.Interface() + continue LOOP + } + + method = coreValue.MethodByName(pair[i]) if method == (reflect.Value{}) { - return nil, errors.New("No method or field '" + pair[i] + "' present on parameter '" + pair[i-1] + "'") + if corePtrVal.IsValid() { + method = corePtrVal.MethodByName(pair[i]) + } } + case reflect.Map: + field = coreValue.MapIndex(reflect.ValueOf(pair[i])) + if field != (reflect.Value{}) { + inter := field.Interface() + if reflect.TypeOf(inter).Kind() == reflect.Func { + method = reflect.ValueOf(inter) + } else { + value = inter + continue LOOP + } + } + default: + return nil, errors.New("Unable to access '" + pair[i] + "', '" + pair[i-1] + "' is not a struct or map") } - switch right.(type) { + if method == (reflect.Value{}) { + return nil, errors.New("No method or field '" + pair[i] + "' present on parameter '" + pair[i-1] + "'") + } + + switch right := right.(type) { case []interface{}: - givenParams := right.([]interface{}) + givenParams := right params = make([]reflect.Value, len(givenParams)) - for idx, _ := range givenParams { + for idx := range givenParams { params[idx] = reflect.ValueOf(givenParams[idx]) } @@ -361,7 +386,7 @@ func makeAccessorStage(pair []string) evaluationOperator { break } - params = []reflect.Value{reflect.ValueOf(right.(interface{}))} + params = []reflect.Value{reflect.ValueOf(right)} } params, err = typeConvertParams(method, params) @@ -408,9 +433,9 @@ func separatorStage(left interface{}, right interface{}, parameters Parameters) var ret []interface{} - switch left.(type) { + switch left := left.(type) { case []interface{}: - ret = append(left.([]interface{}), right) + ret = append(left, right) default: ret = []interface{}{left, right} } @@ -421,6 +446,7 @@ func separatorStage(left interface{}, right interface{}, parameters Parameters) func inStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) { for _, value := range right.([]interface{}) { + value = castToFloat64(value) if left == value { return true, nil } @@ -467,8 +493,8 @@ func isFloat64(value interface{}) bool { } /* - Addition usually means between numbers, but can also mean string concat. - String concat needs one (or both) of the sides to be a string. +Addition usually means between numbers, but can also mean string concat. +String concat needs one (or both) of the sides to be a string. */ func additionTypeCheck(left interface{}, right interface{}) bool { @@ -482,8 +508,8 @@ func additionTypeCheck(left interface{}, right interface{}) bool { } /* - Comparison can either be between numbers, or lexicographic between two strings, - but never between the two. +Comparison can either be between numbers, or lexicographic between two strings, +but never between the two. */ func comparatorTypeCheck(left interface{}, right interface{}) bool { @@ -505,8 +531,8 @@ func isArray(value interface{}) bool { } /* - Converting a boolean to an interface{} requires an allocation. - We can use interned bools to avoid this cost. +Converting a boolean to an interface{} requires an allocation. +We can use interned bools to avoid this cost. */ func boolIface(b bool) interface{} { if b { diff --git a/vendor/github.com/Knetic/govaluate/expressionFunctions.go b/vendor/github.com/casbin/govaluate/expressionFunctions.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/expressionFunctions.go rename to vendor/github.com/casbin/govaluate/expressionFunctions.go diff --git a/vendor/github.com/Knetic/govaluate/expressionOutputStream.go b/vendor/github.com/casbin/govaluate/expressionOutputStream.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/expressionOutputStream.go rename to vendor/github.com/casbin/govaluate/expressionOutputStream.go diff --git a/vendor/github.com/Knetic/govaluate/lexerState.go b/vendor/github.com/casbin/govaluate/lexerState.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/lexerState.go rename to vendor/github.com/casbin/govaluate/lexerState.go diff --git a/vendor/github.com/Knetic/govaluate/lexerStream.go b/vendor/github.com/casbin/govaluate/lexerStream.go similarity index 90% rename from vendor/github.com/Knetic/govaluate/lexerStream.go rename to vendor/github.com/casbin/govaluate/lexerStream.go index b72e6bdb..c6ed76ec 100644 --- a/vendor/github.com/Knetic/govaluate/lexerStream.go +++ b/vendor/github.com/casbin/govaluate/lexerStream.go @@ -23,9 +23,7 @@ func newLexerStream(source string) *lexerStream { func (this *lexerStream) readCharacter() rune { - var character rune - - character = this.source[this.position] + character := this.source[this.position] this.position += 1 return character } diff --git a/vendor/github.com/Knetic/govaluate/parameters.go b/vendor/github.com/casbin/govaluate/parameters.go similarity index 100% rename from vendor/github.com/Knetic/govaluate/parameters.go rename to vendor/github.com/casbin/govaluate/parameters.go diff --git a/vendor/github.com/Knetic/govaluate/parsing.go b/vendor/github.com/casbin/govaluate/parsing.go similarity index 90% rename from vendor/github.com/Knetic/govaluate/parsing.go rename to vendor/github.com/casbin/govaluate/parsing.go index 40c7ed2c..dae78f7d 100644 --- a/vendor/github.com/Knetic/govaluate/parsing.go +++ b/vendor/github.com/casbin/govaluate/parsing.go @@ -79,8 +79,6 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre continue } - kind = UNKNOWN - // numeric constant if isNumeric(character) { @@ -188,17 +186,6 @@ func readToken(stream *lexerStream, state lexerState, functions map[string]Expre kind = ACCESSOR splits := strings.Split(tokenString, ".") tokenValue = splits - - // check that none of them are unexported - for i := 1; i < len(splits); i++ { - - firstCharacter := getFirstRune(splits[i]) - - if unicode.ToUpper(firstCharacter) != firstCharacter { - errorMsg := fmt.Sprintf("Unable to access unexported field '%s' in token '%s'", splits[i], tokenString) - return ExpressionToken{}, errors.New(errorMsg), false - } - } } break } @@ -298,8 +285,8 @@ func readTokenUntilFalse(stream *lexerStream, condition func(rune) bool) string } /* - Returns the string that was read until the given [condition] was false, or whitespace was broken. - Returns false if the stream ended before whitespace was broken or condition was met. +Returns the string that was read until the given [condition] was false, or whitespace was broken. +Returns false if the stream ended before whitespace was broken or condition was met. */ func readUntilFalse(stream *lexerStream, includeWhitespace bool, breakWhitespace bool, allowEscaping bool, condition func(rune) bool) (string, bool) { @@ -345,8 +332,8 @@ func readUntilFalse(stream *lexerStream, includeWhitespace bool, breakWhitespace } /* - Checks to see if any optimizations can be performed on the given [tokens], which form a complete, valid expression. - The returns slice will represent the optimized (or unmodified) list of tokens to use. +Checks to see if any optimizations can be performed on the given [tokens], which form a complete, valid expression. +The returns slice will represent the optimized (or unmodified) list of tokens to use. */ func optimizeTokens(tokens []ExpressionToken) ([]ExpressionToken, error) { @@ -385,7 +372,7 @@ func optimizeTokens(tokens []ExpressionToken) ([]ExpressionToken, error) { } /* - Checks the balance of tokens which have multiple parts, such as parenthesis. +Checks the balance of tokens which have multiple parts, such as parenthesis. */ func checkBalance(tokens []ExpressionToken) error { @@ -414,10 +401,6 @@ func checkBalance(tokens []ExpressionToken) error { return nil } -func isDigit(character rune) bool { - return unicode.IsDigit(character) -} - func isHexDigit(character rune) bool { character = unicode.ToLower(character) @@ -466,9 +449,9 @@ func isNotClosingBracket(character rune) bool { } /* - Attempts to parse the [candidate] as a Time. - Tries a series of standardized date formats, returns the Time if one applies, - otherwise returns false through the second return. +Attempts to parse the [candidate] as a Time. +Tries a series of standardized date formats, returns the Time if one applies, +otherwise returns false through the second return. */ func tryParseTime(candidate string) (time.Time, bool) { diff --git a/vendor/github.com/Knetic/govaluate/sanitizedParameters.go b/vendor/github.com/casbin/govaluate/sanitizedParameters.go similarity index 61% rename from vendor/github.com/Knetic/govaluate/sanitizedParameters.go rename to vendor/github.com/casbin/govaluate/sanitizedParameters.go index 28bd795d..b254bff6 100644 --- a/vendor/github.com/Knetic/govaluate/sanitizedParameters.go +++ b/vendor/github.com/casbin/govaluate/sanitizedParameters.go @@ -16,27 +16,27 @@ func (p sanitizedParameters) Get(key string) (interface{}, error) { } func castToFloat64(value interface{}) interface{} { - switch value.(type) { + switch value := value.(type) { case uint8: - return float64(value.(uint8)) + return float64(value) case uint16: - return float64(value.(uint16)) + return float64(value) case uint32: - return float64(value.(uint32)) + return float64(value) case uint64: - return float64(value.(uint64)) + return float64(value) case int8: - return float64(value.(int8)) + return float64(value) case int16: - return float64(value.(int16)) + return float64(value) case int32: - return float64(value.(int32)) + return float64(value) case int64: - return float64(value.(int64)) + return float64(value) case int: - return float64(value.(int)) + return float64(value) case float32: - return float64(value.(float32)) + return float64(value) } return value diff --git a/vendor/github.com/Knetic/govaluate/stagePlanner.go b/vendor/github.com/casbin/govaluate/stagePlanner.go similarity index 85% rename from vendor/github.com/Knetic/govaluate/stagePlanner.go rename to vendor/github.com/casbin/govaluate/stagePlanner.go index d71ed129..400a2879 100644 --- a/vendor/github.com/Knetic/govaluate/stagePlanner.go +++ b/vendor/github.com/casbin/govaluate/stagePlanner.go @@ -39,16 +39,16 @@ var stageSymbolMap = map[OperatorSymbol]evaluationOperator{ } /* - A "precedent" is a function which will recursively parse new evaluateionStages from a given stream of tokens. - It's called a `precedent` because it is expected to handle exactly what precedence of operator, - and defer to other `precedent`s for other operators. +A "precedent" is a function which will recursively parse new evaluateionStages from a given stream of tokens. +It's called a `precedent` because it is expected to handle exactly what precedence of operator, +and defer to other `precedent`s for other operators. */ type precedent func(stream *tokenStream) (*evaluationStage, error) /* - A convenience function for specifying the behavior of a `precedent`. - Most `precedent` functions can be described by the same function, just with different type checks, symbols, and error formats. - This struct is passed to `makePrecedentFromPlanner` to create a `precedent` function. +A convenience function for specifying the behavior of a `precedent`. +Most `precedent` functions can be described by the same function, just with different type checks, symbols, and error formats. +This struct is passed to `makePrecedentFromPlanner` to create a `precedent` function. */ type precedencePlanner struct { validSymbols map[string]OperatorSymbol @@ -145,8 +145,8 @@ func init() { } /* - Given a planner, creates a function which will evaluate a specific precedence level of operators, - and link it to other `precedent`s which recurse to parse other precedence levels. +Given a planner, creates a function which will evaluate a specific precedence level of operators, +and link it to other `precedent`s which recurse to parse other precedence levels. */ func makePrecedentFromPlanner(planner *precedencePlanner) precedent { @@ -174,9 +174,9 @@ func makePrecedentFromPlanner(planner *precedencePlanner) precedent { } /* - Creates a `evaluationStageList` object which represents an execution plan (or tree) - which is used to completely evaluate a set of tokens at evaluation-time. - The three stages of evaluation can be thought of as parsing strings to tokens, then tokens to a stage list, then evaluation with parameters. +Creates a `evaluationStageList` object which represents an execution plan (or tree) +which is used to completely evaluate a set of tokens at evaluation-time. +The three stages of evaluation can be thought of as parsing strings to tokens, then tokens to a stage list, then evaluation with parameters. */ func planStages(tokens []ExpressionToken) (*evaluationStage, error) { @@ -205,8 +205,8 @@ func planTokens(stream *tokenStream) (*evaluationStage, error) { } /* - The most usual method of parsing an evaluation stage for a given precedence. - Most stages use the same logic +The most usual method of parsing an evaluation stage for a given precedence. +Most stages use the same logic */ func planPrecedenceLevel( stream *tokenStream, @@ -231,7 +231,12 @@ func planPrecedenceLevel( } } - for stream.hasNext() { + rewind := func() (*evaluationStage, error) { + stream.rewind() + return leftStage, nil + } + + if stream.hasNext() { token = stream.next() @@ -246,19 +251,19 @@ func planPrecedenceLevel( } if !keyFound { - break + return rewind() } } if validSymbols != nil { if !isString(token.Value) { - break + return rewind() } symbol, keyFound = validSymbols[token.Value.(string)] if !keyFound { - break + return rewind() } } @@ -285,12 +290,11 @@ func planPrecedenceLevel( }, nil } - stream.rewind() - return leftStage, nil + return rewind() } /* - A special case where functions need to be of higher precedence than values, and need a special wrapped execution stage operator. +A special case where functions need to be of higher precedence than values, and need a special wrapped execution stage operator. */ func planFunction(stream *tokenStream) (*evaluationStage, error) { @@ -365,8 +369,8 @@ func planAccessor(stream *tokenStream) (*evaluationStage, error) { } /* - A truly special precedence function, this handles all the "lowest-case" errata of the process, including literals, parmeters, - clauses, and prefixes. +A truly special precedence function, this handles all the "lowest-case" errata of the process, including literals, parmeters, +clauses, and prefixes. */ func planValue(stream *tokenStream) (*evaluationStage, error) { @@ -445,8 +449,8 @@ func planValue(stream *tokenStream) (*evaluationStage, error) { } /* - Convenience function to pass a triplet of typechecks between `findTypeChecks` and `planPrecedenceLevel`. - Each of these members may be nil, which indicates that type does not matter for that value. +Convenience function to pass a triplet of typechecks between `findTypeChecks` and `planPrecedenceLevel`. +Each of these members may be nil, which indicates that type does not matter for that value. */ type typeChecks struct { left stageTypeCheck @@ -455,7 +459,7 @@ type typeChecks struct { } /* - Maps a given [symbol] to a set of typechecks to be used during runtime. +Maps a given [symbol] to a set of typechecks to be used during runtime. */ func findTypeChecks(symbol OperatorSymbol) typeChecks { @@ -550,8 +554,8 @@ func findTypeChecks(symbol OperatorSymbol) typeChecks { } /* - During stage planning, stages of equal precedence are parsed such that they'll be evaluated in reverse order. - For commutative operators like "+" or "-", it's no big deal. But for order-specific operators, it ruins the expected result. +During stage planning, stages of equal precedence are parsed such that they'll be evaluated in reverse order. +For commutative operators like "+" or "-", it's no big deal. But for order-specific operators, it ruins the expected result. */ func reorderStages(rootStage *evaluationStage) { @@ -596,9 +600,9 @@ func reorderStages(rootStage *evaluationStage) { } /* - Performs a "mirror" on a subtree of stages. - This mirror functionally inverts the order of execution for all members of the [stages] list. - That list is assumed to be a root-to-leaf (ordered) list of evaluation stages, where each is a right-hand stage of the last. +Performs a "mirror" on a subtree of stages. +This mirror functionally inverts the order of execution for all members of the [stages] list. +That list is assumed to be a root-to-leaf (ordered) list of evaluation stages, where each is a right-hand stage of the last. */ func mirrorStageSubtree(stages []*evaluationStage) { @@ -643,7 +647,7 @@ func mirrorStageSubtree(stages []*evaluationStage) { } /* - Recurses through all operators in the entire tree, eliding operators where both sides are literals. +Recurses through all operators in the entire tree, eliding operators where both sides are literals. */ func elideLiterals(root *evaluationStage) *evaluationStage { @@ -659,9 +663,9 @@ func elideLiterals(root *evaluationStage) *evaluationStage { } /* - Elides a specific stage, if possible. - Returns the unmodified [root] stage if it cannot or should not be elided. - Otherwise, returns a new stage representing the condensed value from the elided stages. +Elides a specific stage, if possible. +Returns the unmodified [root] stage if it cannot or should not be elided. +Otherwise, returns a new stage representing the condensed value from the elided stages. */ func elideStage(root *evaluationStage) *evaluationStage { diff --git a/vendor/github.com/Knetic/govaluate/test.sh b/vendor/github.com/casbin/govaluate/test.sh similarity index 100% rename from vendor/github.com/Knetic/govaluate/test.sh rename to vendor/github.com/casbin/govaluate/test.sh diff --git a/vendor/github.com/Knetic/govaluate/tokenStream.go b/vendor/github.com/casbin/govaluate/tokenStream.go similarity index 80% rename from vendor/github.com/Knetic/govaluate/tokenStream.go rename to vendor/github.com/casbin/govaluate/tokenStream.go index d0029209..7c7c40ab 100644 --- a/vendor/github.com/Knetic/govaluate/tokenStream.go +++ b/vendor/github.com/casbin/govaluate/tokenStream.go @@ -7,10 +7,7 @@ type tokenStream struct { } func newTokenStream(tokens []ExpressionToken) *tokenStream { - - var ret *tokenStream - - ret = new(tokenStream) + ret := new(tokenStream) ret.tokens = tokens ret.tokenLength = len(tokens) return ret @@ -21,10 +18,7 @@ func (this *tokenStream) rewind() { } func (this *tokenStream) next() ExpressionToken { - - var token ExpressionToken - - token = this.tokens[this.index] + token := this.tokens[this.index] this.index += 1 return token diff --git a/vendor/github.com/cespare/xxhash/v2/README.md b/vendor/github.com/cespare/xxhash/v2/README.md index 8bf0e5b7..33c88305 100644 --- a/vendor/github.com/cespare/xxhash/v2/README.md +++ b/vendor/github.com/cespare/xxhash/v2/README.md @@ -70,3 +70,5 @@ benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$') - [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) - [FreeCache](https://github.com/coocood/freecache) - [FastCache](https://github.com/VictoriaMetrics/fastcache) +- [Ristretto](https://github.com/dgraph-io/ristretto) +- [Badger](https://github.com/dgraph-io/badger) diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash.go b/vendor/github.com/cespare/xxhash/v2/xxhash.go index a9e0d45c..78bddf1c 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash.go @@ -19,10 +19,13 @@ const ( // Store the primes in an array as well. // // The consts are used when possible in Go code to avoid MOVs but we need a -// contiguous array of the assembly code. +// contiguous array for the assembly code. var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} // Digest implements hash.Hash64. +// +// Note that a zero-valued Digest is not ready to receive writes. +// Call Reset or create a Digest using New before calling other methods. type Digest struct { v1 uint64 v2 uint64 @@ -33,19 +36,31 @@ type Digest struct { n int // how much of mem is used } -// New creates a new Digest that computes the 64-bit xxHash algorithm. +// New creates a new Digest with a zero seed. func New() *Digest { + return NewWithSeed(0) +} + +// NewWithSeed creates a new Digest with the given seed. +func NewWithSeed(seed uint64) *Digest { var d Digest - d.Reset() + d.ResetWithSeed(seed) return &d } // Reset clears the Digest's state so that it can be reused. +// It uses a seed value of zero. func (d *Digest) Reset() { - d.v1 = primes[0] + prime2 - d.v2 = prime2 - d.v3 = 0 - d.v4 = -primes[0] + d.ResetWithSeed(0) +} + +// ResetWithSeed clears the Digest's state so that it can be reused. +// It uses the given seed to initialize the state. +func (d *Digest) ResetWithSeed(seed uint64) { + d.v1 = seed + prime1 + prime2 + d.v2 = seed + prime2 + d.v3 = seed + d.v4 = seed - prime1 d.total = 0 d.n = 0 } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go index 9216e0a4..78f95f25 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go @@ -6,7 +6,7 @@ package xxhash -// Sum64 computes the 64-bit xxHash digest of b. +// Sum64 computes the 64-bit xxHash digest of b with a zero seed. // //go:noescape func Sum64(b []byte) uint64 diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go index 26df13bb..118e49e8 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go @@ -3,7 +3,7 @@ package xxhash -// Sum64 computes the 64-bit xxHash digest of b. +// Sum64 computes the 64-bit xxHash digest of b with a zero seed. func Sum64(b []byte) uint64 { // A simpler version would be // d := New() diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go index e86f1b5f..05f5e7df 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go @@ -5,7 +5,7 @@ package xxhash -// Sum64String computes the 64-bit xxHash digest of s. +// Sum64String computes the 64-bit xxHash digest of s with a zero seed. func Sum64String(s string) uint64 { return Sum64([]byte(s)) } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go index 1c1638fd..cf9d42ae 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go @@ -33,7 +33,7 @@ import ( // // See https://github.com/golang/go/issues/42739 for discussion. -// Sum64String computes the 64-bit xxHash digest of s. +// Sum64String computes the 64-bit xxHash digest of s with a zero seed. // It may be faster than Sum64([]byte(s)) by avoiding a copy. func Sum64String(s string) uint64 { b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})) diff --git a/vendor/github.com/datarhei/gosrt/Makefile b/vendor/github.com/datarhei/gosrt/Makefile index d4452e64..ba3817f3 100644 --- a/vendor/github.com/datarhei/gosrt/Makefile +++ b/vendor/github.com/datarhei/gosrt/Makefile @@ -9,7 +9,7 @@ test: ## fuzz: Run fuzz tests fuzz: - go test -fuzz=Fuzz -run=^Fuzz ./internal/packet -fuzztime 30s + go test -fuzz=Fuzz -run=^Fuzz ./packet -fuzztime 30s ## vet: Analyze code for potential errors vet: diff --git a/vendor/github.com/datarhei/gosrt/README.md b/vendor/github.com/datarhei/gosrt/README.md index 2c39d900..25681a47 100644 --- a/vendor/github.com/datarhei/gosrt/README.md +++ b/vendor/github.com/datarhei/gosrt/README.md @@ -46,13 +46,13 @@ A Go version of 1.18+ is required. ## Installation -``` +```shell go get github.com/datarhei/gosrt ``` ## Caller example -``` +```go import "github.com/datarhei/gosrt" conn, err := srt.Dial("srt", "golang.org:6000", srt.Config{ @@ -80,7 +80,7 @@ In the `contrib/client` directory you'll find a complete example of a SRT client ## Listener example -``` +```go import "github.com/datarhei/gosrt" ln, err := srt.Listen("srt", ":6000", srt.Config{...}) @@ -128,7 +128,7 @@ In the `contrib/client` directory you'll find an example implementation of a SRT Build the client application with -``` +```shell cd contrib/client && go build ``` @@ -187,31 +187,45 @@ known options (similar to [srt-live-transmit](https://github.com/Haivision/srt/b Reading from a SRT sender and play with `ffplay`: -``` +```shell ./client -from "srt://127.0.0.1:6001/?mode=listener&streamid=..." -to - | ffplay -f mpegts -i - ``` Reading from UDP and sending to a SRT server: -``` +```shell ./client -from udp://:6000 -to "srt://127.0.0.1:6001/?mode=caller&streamid=..." ``` Simulate point-to-point transfer on localhost. Open one console and start `ffmpeg` (you need at least version 4.3.2, built with SRT enabled) to send to an UDP address: -``` -ffmpeg -f lavfi -re -i testsrc2=rate=25:size=640x360 -codec:v libx264 -b:v 1024k -maxrate:v 1024k -bufsize:v 1024k -preset ultrafast -r 25 -g 50 -pix_fmt yuv420p -vsync 1 -flags2 local_header -f mpegts "udp://127.0.0.1:6000?pkt_size=1316" +```shell +ffmpeg \ + -f lavfi \ + -re \ + -i testsrc2=rate=25:size=640x360 \ + -codec:v libx264 \ + -b:v 1024k \ + -maxrate:v 1024k \ + -bufsize:v 1024k \ + -preset ultrafast \ + -r 25 \ + -g 50 \ + -pix_fmt yuv420p \ + -flags2 local_header \ + -f mpegts \ + "udp://127.0.0.1:6000?pkt_size=1316" ``` In another console read from the UDP and start a SRT listenr: -``` +```shell ./client -from udp://:6000 -to "srt://127.0.0.1:6001/?mode=listener&streamid=foobar" ``` In the third console connect to that stream and play the video with `ffplay`: -``` +```shell ./client -from "srt://127.0.0.1:6001/?mode=caller&streamid=foobar" -to - | ffplay -f mpegts -i - ``` @@ -222,7 +236,7 @@ a stream that can be read by many clients. Build the client application with -``` +```shell cd contrib/server && go build ``` @@ -264,27 +278,42 @@ If you implement your own server you are free to interpret the streamID as you w Running a server listening on port 6001 with defaults: -``` +```shell ./server -addr ":6001" ``` Now you can use the contributed client to publish a stream: -``` +```shell ./client -from ... -to "srt://127.0.0.1:6001/?mode=caller&streamid=publish:/live/stream" ``` or directly from `ffmpeg`: -``` -ffmpeg -f lavfi -re -i testsrc2=rate=25:size=640x360 -codec:v libx264 -b:v 1024k -maxrate:v 1024k -bufsize:v 1024k -preset ultrafast -r 25 -g 50 -pix_fmt yuv420p -vsync 1 -flags2 local_header -f mpegts -transtype live "srt://127.0.0.1:6001?streamid=publish:/live/stream" +```shell +ffmpeg \ + -f lavfi \ + -re \ + -i testsrc2=rate=25:size=640x360 \ + -codec:v libx264 \ + -b:v 1024k \ + -maxrate:v 1024k \ + -bufsize:v 1024k \ + -preset ultrafast \ + -r 25 \ + -g 50 \ + -pix_fmt yuv420p \ + -flags2 local_header \ + -f mpegts \ + -transtype live \ + "srt://127.0.0.1:6001?streamid=publish:/live/stream" ``` If the server is not on localhost, you might adjust the `peerlatency` in order to avoid packet loss: `-peerlatency 1000000`. Now you can play the stream: -``` +```shell ffplay -f mpegts -transtype live -i "srt://127.0.0.1:6001?streamid=/live/stream" ``` @@ -295,19 +324,34 @@ get more errors during playback, you might increase the receive buffer by adding The stream can be encrypted with a passphrase. First start the server with a passphrase. If you are using `srt-live-transmit`, the passphrase has to be at least 10 characters long otherwise it will not be accepted. -``` +```shell ./server -addr :6001 -passphrase foobarfoobar ``` Send an encrpyted stream to the server: -``` -ffmpeg -f lavfi -re -i testsrc2=rate=25:size=640x360 -codec:v libx264 -b:v 1024k -maxrate:v 1024k -bufsize:v 1024k -preset ultrafast -r 25 -g 50 -pix_fmt yuv420p -vsync 1 -flags2 local_header -f mpegts -transtype live "srt://127.0.0.1:6001?streamid=publish:/live/stream&passphrase=foobarfoobar" +```shell +ffmpeg \ + -f lavfi \ + -re \ + -i testsrc2=rate=25:size=640x360 \ + -codec:v libx264 \ + -b:v 1024k \ + -maxrate:v 1024k \ + -bufsize:v 1024k \ + -preset ultrafast \ + -r 25 \ + -g 50 \ + -pix_fmt yuv420p \ + -flags2 local_header \ + -f mpegts \ + -transtype live \ + "srt://127.0.0.1:6001?streamid=publish:/live/stream&passphrase=foobarfoobar" ``` Receive an encrypted stream from the server: -``` +```shell ffplay -f mpegts -transtype live -i "srt://127.0.0.1:6001?streamid=/live/stream&passphrase=foobarfoobar" ``` @@ -320,7 +364,7 @@ This SRT module has a built-in logging facility for debugging purposes. Check th In the contributed server you see an example of how logging is used. Here's the essence: -``` +```go logger := srt.NewLogger([]string{"connection", "handshake"}) config := srt.DefaultConfig diff --git a/vendor/github.com/datarhei/gosrt/internal/circular/circular.go b/vendor/github.com/datarhei/gosrt/circular/circular.go similarity index 100% rename from vendor/github.com/datarhei/gosrt/internal/circular/circular.go rename to vendor/github.com/datarhei/gosrt/circular/circular.go diff --git a/vendor/github.com/datarhei/gosrt/congestion/congestion.go b/vendor/github.com/datarhei/gosrt/congestion/congestion.go new file mode 100644 index 00000000..10787ead --- /dev/null +++ b/vendor/github.com/datarhei/gosrt/congestion/congestion.go @@ -0,0 +1,124 @@ +// Package congestions provides interfaces and types congestion control implementations for SRT +package congestion + +import ( + "github.com/datarhei/gosrt/circular" + "github.com/datarhei/gosrt/packet" +) + +// Sender is the sending part of the congestion control +type Sender interface { + // Stats returns sender statistics. + Stats() SendStats + + // Flush flushes all queued packages. + Flush() + + // Push pushes a packet to be send on the sender queue. + Push(p packet.Packet) + + // Tick gets called from a connection in order to proceed with the queued packets. The provided value for + // now is corresponds to the timestamps in the queued packets. Those timestamps are the microseconds + // since the start of the connection. + Tick(now uint64) + + // ACK gets called when a sequence number has been confirmed from a receiver. + ACK(sequenceNumber circular.Number) + + // NAK get called when packets with the listed sequence number should be resend. + NAK(sequenceNumbers []circular.Number) + + // SetDropThreshold sets the threshold in microseconds for when to drop too late packages from the queue. + SetDropThreshold(threshold uint64) +} + +// Receiver is the receiving part of the congestion control +type Receiver interface { + // Stats returns receiver statistics. + Stats() ReceiveStats + + // PacketRate returns the current packets and bytes per second, and the capacity of the link. + PacketRate() (pps, bps, capacity float64) + + // Flush flushes all queued packages. + Flush() + + // Push pushed a recieved packet to the receiver queue. + Push(pkt packet.Packet) + + // Tick gets called from a connection in order to proceed with queued packets. The provided value for + // now is corresponds to the timestamps in the queued packets. Those timestamps are the microseconds + // since the start of the connection. + Tick(now uint64) + + // SetNAKInterval sets the interval between two periodic NAK messages to the sender in microseconds. + SetNAKInterval(nakInterval uint64) +} + +// SendStats are collected statistics from a sender +type SendStats struct { + Pkt uint64 // Sent packets in total + Byte uint64 // Sent bytes in total + + PktUnique uint64 + ByteUnique uint64 + + PktLoss uint64 + ByteLoss uint64 + + PktRetrans uint64 + ByteRetrans uint64 + + UsSndDuration uint64 // microseconds + + PktDrop uint64 + ByteDrop uint64 + + // instantaneous + PktBuf uint64 + ByteBuf uint64 + MsBuf uint64 + + PktFlightSize uint64 + + UsPktSndPeriod float64 // microseconds + BytePayload uint64 + + MbpsEstimatedInputBandwidth float64 + MbpsEstimatedSentBandwidth float64 + + PktLossRate float64 +} + +// ReceiveStats are collected statistics from a reciever +type ReceiveStats struct { + Pkt uint64 + Byte uint64 + + PktUnique uint64 + ByteUnique uint64 + + PktLoss uint64 + ByteLoss uint64 + + PktRetrans uint64 + ByteRetrans uint64 + + PktBelated uint64 + ByteBelated uint64 + + PktDrop uint64 + ByteDrop uint64 + + // instantaneous + PktBuf uint64 + ByteBuf uint64 + MsBuf uint64 + + BytePayload uint64 + + MbpsEstimatedRecvBandwidth float64 + MbpsEstimatedLinkCapacity float64 + + PktLossRate float64 +} diff --git a/vendor/github.com/datarhei/gosrt/congestion/live/doc.go b/vendor/github.com/datarhei/gosrt/congestion/live/doc.go new file mode 100644 index 00000000..7eedf546 --- /dev/null +++ b/vendor/github.com/datarhei/gosrt/congestion/live/doc.go @@ -0,0 +1,2 @@ +// Package live provides implementations of the Sender and Receiver interfaces for live congestion control +package live diff --git a/vendor/github.com/datarhei/gosrt/congestion/live/fake.go b/vendor/github.com/datarhei/gosrt/congestion/live/fake.go new file mode 100644 index 00000000..c1bc1f7f --- /dev/null +++ b/vendor/github.com/datarhei/gosrt/congestion/live/fake.go @@ -0,0 +1,182 @@ +package live + +import ( + "sync" + "time" + + "github.com/datarhei/gosrt/circular" + "github.com/datarhei/gosrt/congestion" + "github.com/datarhei/gosrt/packet" +) + +type fakeLiveReceive struct { + maxSeenSequenceNumber circular.Number + lastACKSequenceNumber circular.Number + lastDeliveredSequenceNumber circular.Number + + nPackets uint + + periodicACKInterval uint64 // config + periodicNAKInterval uint64 // config + + lastPeriodicACK uint64 + + avgPayloadSize float64 // bytes + + rate struct { + last time.Time + period time.Duration + + packets uint64 + bytes uint64 + + pps float64 + bps float64 + } + + sendACK func(seq circular.Number, light bool) + sendNAK func(from, to circular.Number) + deliver func(p packet.Packet) + + lock sync.RWMutex +} + +func NewFakeLiveReceive(config ReceiveConfig) congestion.Receiver { + r := &fakeLiveReceive{ + maxSeenSequenceNumber: config.InitialSequenceNumber.Dec(), + lastACKSequenceNumber: config.InitialSequenceNumber.Dec(), + lastDeliveredSequenceNumber: config.InitialSequenceNumber.Dec(), + + periodicACKInterval: config.PeriodicACKInterval, + periodicNAKInterval: config.PeriodicNAKInterval, + + avgPayloadSize: 1456, // 5.1.2. SRT's Default LiveCC Algorithm + + sendACK: config.OnSendACK, + sendNAK: config.OnSendNAK, + deliver: config.OnDeliver, + } + + if r.sendACK == nil { + r.sendACK = func(seq circular.Number, light bool) {} + } + + if r.sendNAK == nil { + r.sendNAK = func(from, to circular.Number) {} + } + + if r.deliver == nil { + r.deliver = func(p packet.Packet) {} + } + + r.rate.last = time.Now() + r.rate.period = time.Second + + return r +} + +func (r *fakeLiveReceive) Stats() congestion.ReceiveStats { return congestion.ReceiveStats{} } +func (r *fakeLiveReceive) PacketRate() (pps, bps, capacity float64) { + r.lock.Lock() + defer r.lock.Unlock() + + tdiff := time.Since(r.rate.last) + + if tdiff < r.rate.period { + pps = r.rate.pps + bps = r.rate.bps + + return + } + + r.rate.pps = float64(r.rate.packets) / tdiff.Seconds() + r.rate.bps = float64(r.rate.bytes) / tdiff.Seconds() + + r.rate.packets, r.rate.bytes = 0, 0 + r.rate.last = time.Now() + + pps = r.rate.pps + bps = r.rate.bps + + return +} + +func (r *fakeLiveReceive) Flush() {} + +func (r *fakeLiveReceive) Push(pkt packet.Packet) { + r.lock.Lock() + defer r.lock.Unlock() + + if pkt == nil { + return + } + + r.nPackets++ + + pktLen := pkt.Len() + + r.rate.packets++ + r.rate.bytes += pktLen + + // 5.1.2. SRT's Default LiveCC Algorithm + r.avgPayloadSize = 0.875*r.avgPayloadSize + 0.125*float64(pktLen) + + if pkt.Header().PacketSequenceNumber.Lte(r.lastDeliveredSequenceNumber) { + // Too old, because up until r.lastDeliveredSequenceNumber, we already delivered + return + } + + if pkt.Header().PacketSequenceNumber.Lt(r.lastACKSequenceNumber) { + // Already acknowledged, ignoring + return + } + + if pkt.Header().PacketSequenceNumber.Lte(r.maxSeenSequenceNumber) { + return + } + + r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber +} + +func (r *fakeLiveReceive) periodicACK(now uint64) (ok bool, sequenceNumber circular.Number, lite bool) { + r.lock.RLock() + defer r.lock.RUnlock() + + // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) + if now-r.lastPeriodicACK < r.periodicACKInterval { + if r.nPackets >= 64 { + lite = true // Send light ACK + } else { + return + } + } + + ok = true + sequenceNumber = r.maxSeenSequenceNumber.Inc() + + r.lastACKSequenceNumber = r.maxSeenSequenceNumber + + r.lastPeriodicACK = now + r.nPackets = 0 + + return +} + +func (r *fakeLiveReceive) Tick(now uint64) { + if ok, sequenceNumber, lite := r.periodicACK(now); ok { + r.sendACK(sequenceNumber, lite) + } + + // Deliver packets whose PktTsbpdTime is ripe + r.lock.Lock() + defer r.lock.Unlock() + + r.lastDeliveredSequenceNumber = r.lastACKSequenceNumber +} + +func (r *fakeLiveReceive) SetNAKInterval(nakInterval uint64) { + r.lock.Lock() + defer r.lock.Unlock() + + r.periodicNAKInterval = nakInterval +} diff --git a/vendor/github.com/datarhei/gosrt/congestion/live/receive.go b/vendor/github.com/datarhei/gosrt/congestion/live/receive.go new file mode 100644 index 00000000..4999b757 --- /dev/null +++ b/vendor/github.com/datarhei/gosrt/congestion/live/receive.go @@ -0,0 +1,441 @@ +package live + +import ( + "container/list" + "fmt" + "strings" + "sync" + "time" + + "github.com/datarhei/gosrt/circular" + "github.com/datarhei/gosrt/congestion" + "github.com/datarhei/gosrt/packet" +) + +// ReceiveConfig is the configuration for the liveRecv congestion control +type ReceiveConfig struct { + InitialSequenceNumber circular.Number + PeriodicACKInterval uint64 // microseconds + PeriodicNAKInterval uint64 // microseconds + OnSendACK func(seq circular.Number, light bool) + OnSendNAK func(from, to circular.Number) + OnDeliver func(p packet.Packet) +} + +// receiver implements the Receiver interface +type receiver struct { + maxSeenSequenceNumber circular.Number + lastACKSequenceNumber circular.Number + lastDeliveredSequenceNumber circular.Number + packetList *list.List + lock sync.RWMutex + + nPackets uint + + periodicACKInterval uint64 // config + periodicNAKInterval uint64 // config + + lastPeriodicACK uint64 + lastPeriodicNAK uint64 + + avgPayloadSize float64 // bytes + avgLinkCapacity float64 // packets per second + + probeTime time.Time + probeNextSeq circular.Number + + statistics congestion.ReceiveStats + + rate struct { + last uint64 // microseconds + period uint64 + + packets uint64 + bytes uint64 + bytesRetrans uint64 + + packetsPerSecond float64 + bytesPerSecond float64 + + pktLossRate float64 + } + + sendACK func(seq circular.Number, light bool) + sendNAK func(from, to circular.Number) + deliver func(p packet.Packet) +} + +// NewReceiver takes a ReceiveConfig and returns a new Receiver +func NewReceiver(config ReceiveConfig) congestion.Receiver { + r := &receiver{ + maxSeenSequenceNumber: config.InitialSequenceNumber.Dec(), + lastACKSequenceNumber: config.InitialSequenceNumber.Dec(), + lastDeliveredSequenceNumber: config.InitialSequenceNumber.Dec(), + packetList: list.New(), + + periodicACKInterval: config.PeriodicACKInterval, + periodicNAKInterval: config.PeriodicNAKInterval, + + avgPayloadSize: 1456, // 5.1.2. SRT's Default LiveCC Algorithm + + sendACK: config.OnSendACK, + sendNAK: config.OnSendNAK, + deliver: config.OnDeliver, + } + + if r.sendACK == nil { + r.sendACK = func(seq circular.Number, light bool) {} + } + + if r.sendNAK == nil { + r.sendNAK = func(from, to circular.Number) {} + } + + if r.deliver == nil { + r.deliver = func(p packet.Packet) {} + } + + r.rate.last = 0 + r.rate.period = uint64(time.Second.Microseconds()) + + return r +} + +func (r *receiver) Stats() congestion.ReceiveStats { + r.lock.Lock() + defer r.lock.Unlock() + + r.statistics.BytePayload = uint64(r.avgPayloadSize) + r.statistics.MbpsEstimatedRecvBandwidth = r.rate.bytesPerSecond * 8 / 1024 / 1024 + r.statistics.MbpsEstimatedLinkCapacity = r.avgLinkCapacity * packet.MAX_PAYLOAD_SIZE * 8 / 1024 / 1024 + r.statistics.PktLossRate = r.rate.pktLossRate + + return r.statistics +} + +func (r *receiver) PacketRate() (pps, bps, capacity float64) { + r.lock.Lock() + defer r.lock.Unlock() + + pps = r.rate.packetsPerSecond + bps = r.rate.bytesPerSecond + capacity = r.avgLinkCapacity + + return +} + +func (r *receiver) Flush() { + r.lock.Lock() + defer r.lock.Unlock() + + r.packetList = r.packetList.Init() +} + +func (r *receiver) Push(pkt packet.Packet) { + r.lock.Lock() + defer r.lock.Unlock() + + if pkt == nil { + return + } + + // This is not really well (not at all) described in the specs. See core.cpp and window.h + // and search for PUMASK_SEQNO_PROBE (0xF). Every 16th and 17th packet are + // sent in pairs. This is used as a probe for the theoretical capacity of the link. + if !pkt.Header().RetransmittedPacketFlag { + probe := pkt.Header().PacketSequenceNumber.Val() & 0xF + if probe == 0 { + r.probeTime = time.Now() + r.probeNextSeq = pkt.Header().PacketSequenceNumber.Inc() + } else if probe == 1 && pkt.Header().PacketSequenceNumber.Equals(r.probeNextSeq) && !r.probeTime.IsZero() && pkt.Len() != 0 { + // The time between packets scaled to a fully loaded packet + diff := float64(time.Since(r.probeTime).Microseconds()) * (packet.MAX_PAYLOAD_SIZE / float64(pkt.Len())) + if diff != 0 { + // Here we're doing an average of the measurements. + r.avgLinkCapacity = 0.875*r.avgLinkCapacity + 0.125*1_000_000/diff + } + } else { + r.probeTime = time.Time{} + } + } else { + r.probeTime = time.Time{} + } + + r.nPackets++ + + pktLen := pkt.Len() + + r.rate.packets++ + r.rate.bytes += pktLen + + r.statistics.Pkt++ + r.statistics.Byte += pktLen + + //pkt.PktTsbpdTime = pkt.Timestamp + r.delay + if pkt.Header().RetransmittedPacketFlag { + r.statistics.PktRetrans++ + r.statistics.ByteRetrans += pktLen + + r.rate.bytesRetrans += pktLen + } + + // 5.1.2. SRT's Default LiveCC Algorithm + r.avgPayloadSize = 0.875*r.avgPayloadSize + 0.125*float64(pktLen) + + if pkt.Header().PacketSequenceNumber.Lte(r.lastDeliveredSequenceNumber) { + // Too old, because up until r.lastDeliveredSequenceNumber, we already delivered + r.statistics.PktBelated++ + r.statistics.ByteBelated += pktLen + + r.statistics.PktDrop++ + r.statistics.ByteDrop += pktLen + + return + } + + if pkt.Header().PacketSequenceNumber.Lt(r.lastACKSequenceNumber) { + // Already acknowledged, ignoring + r.statistics.PktDrop++ + r.statistics.ByteDrop += pktLen + + return + } + + if pkt.Header().PacketSequenceNumber.Equals(r.maxSeenSequenceNumber.Inc()) { + // In order, the packet we expected + r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber + } else if pkt.Header().PacketSequenceNumber.Lte(r.maxSeenSequenceNumber) { + // Out of order, is it a missing piece? put it in the correct position + for e := r.packetList.Front(); e != nil; e = e.Next() { + p := e.Value.(packet.Packet) + + if p.Header().PacketSequenceNumber == pkt.Header().PacketSequenceNumber { + // Already received (has been sent more than once), ignoring + r.statistics.PktDrop++ + r.statistics.ByteDrop += pktLen + + break + } else if p.Header().PacketSequenceNumber.Gt(pkt.Header().PacketSequenceNumber) { + // Late arrival, this fills a gap + r.statistics.PktBuf++ + r.statistics.PktUnique++ + + r.statistics.ByteBuf += pktLen + r.statistics.ByteUnique += pktLen + + r.packetList.InsertBefore(pkt, e) + + break + } + } + + return + } else { + // Too far ahead, there are some missing sequence numbers, immediate NAK report + // here we can prevent a possibly unnecessary NAK with SRTO_LOXXMAXTTL + r.sendNAK(r.maxSeenSequenceNumber.Inc(), pkt.Header().PacketSequenceNumber.Dec()) + + len := uint64(pkt.Header().PacketSequenceNumber.Distance(r.maxSeenSequenceNumber)) + r.statistics.PktLoss += len + r.statistics.ByteLoss += len * uint64(r.avgPayloadSize) + + r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber + } + + r.statistics.PktBuf++ + r.statistics.PktUnique++ + + r.statistics.ByteBuf += pktLen + r.statistics.ByteUnique += pktLen + + r.packetList.PushBack(pkt) +} + +func (r *receiver) periodicACK(now uint64) (ok bool, sequenceNumber circular.Number, lite bool) { + r.lock.Lock() + defer r.lock.Unlock() + + // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) + if now-r.lastPeriodicACK < r.periodicACKInterval { + if r.nPackets >= 64 { + lite = true // Send light ACK + } else { + return + } + } + + minPktTsbpdTime, maxPktTsbpdTime := uint64(0), uint64(0) + + ackSequenceNumber := r.lastDeliveredSequenceNumber + + // Find the sequence number up until we have all in a row. + // Where the first gap is (or at the end of the list) is where we can ACK to. + + e := r.packetList.Front() + if e != nil { + p := e.Value.(packet.Packet) + + minPktTsbpdTime = p.Header().PktTsbpdTime + maxPktTsbpdTime = p.Header().PktTsbpdTime + + // If there are packets that should be delivered by now, move foward. + if p.Header().PktTsbpdTime <= now { + for e = e.Next(); e != nil; e = e.Next() { + p = e.Value.(packet.Packet) + + if p.Header().PktTsbpdTime > now { + break + } + } + + ackSequenceNumber = p.Header().PacketSequenceNumber + maxPktTsbpdTime = p.Header().PktTsbpdTime + + if e != nil { + if e = e.Next(); e != nil { + p = e.Value.(packet.Packet) + } + } + } + + if p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { + ackSequenceNumber = p.Header().PacketSequenceNumber + + for e = e.Next(); e != nil; e = e.Next() { + p = e.Value.(packet.Packet) + if !p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { + break + } + + ackSequenceNumber = p.Header().PacketSequenceNumber + maxPktTsbpdTime = p.Header().PktTsbpdTime + } + } + + ok = true + sequenceNumber = ackSequenceNumber.Inc() + + // Keep track of the last ACK's sequence. with this we can faster ignore + // packets that come in that have a lower sequence number. + r.lastACKSequenceNumber = ackSequenceNumber + } + + r.lastPeriodicACK = now + r.nPackets = 0 + + r.statistics.MsBuf = (maxPktTsbpdTime - minPktTsbpdTime) / 1_000 + + return +} + +func (r *receiver) periodicNAK(now uint64) (ok bool, from, to circular.Number) { + r.lock.RLock() + defer r.lock.RUnlock() + + if now-r.lastPeriodicNAK < r.periodicNAKInterval { + return + } + + // Send a periodic NAK + + ackSequenceNumber := r.lastDeliveredSequenceNumber + + // Send a NAK only for the first gap. + // Alternatively send a NAK for max. X gaps because the size of the NAK packet is limited. + for e := r.packetList.Front(); e != nil; e = e.Next() { + p := e.Value.(packet.Packet) + + if !p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { + nackSequenceNumber := ackSequenceNumber.Inc() + + ok = true + from = nackSequenceNumber + to = p.Header().PacketSequenceNumber.Dec() + + break + } + + ackSequenceNumber = p.Header().PacketSequenceNumber + } + + r.lastPeriodicNAK = now + + return +} + +func (r *receiver) Tick(now uint64) { + if ok, sequenceNumber, lite := r.periodicACK(now); ok { + r.sendACK(sequenceNumber, lite) + } + + if ok, from, to := r.periodicNAK(now); ok { + r.sendNAK(from, to) + } + + // Deliver packets whose PktTsbpdTime is ripe + r.lock.Lock() + removeList := make([]*list.Element, 0, r.packetList.Len()) + for e := r.packetList.Front(); e != nil; e = e.Next() { + p := e.Value.(packet.Packet) + + if p.Header().PacketSequenceNumber.Lte(r.lastACKSequenceNumber) && p.Header().PktTsbpdTime <= now { + r.statistics.PktBuf-- + r.statistics.ByteBuf -= p.Len() + + r.lastDeliveredSequenceNumber = p.Header().PacketSequenceNumber + + r.deliver(p) + removeList = append(removeList, e) + } else { + break + } + } + + for _, e := range removeList { + r.packetList.Remove(e) + } + r.lock.Unlock() + + r.lock.Lock() + tdiff := now - r.rate.last // microseconds + + if tdiff > r.rate.period { + r.rate.packetsPerSecond = float64(r.rate.packets) / (float64(tdiff) / 1000 / 1000) + r.rate.bytesPerSecond = float64(r.rate.bytes) / (float64(tdiff) / 1000 / 1000) + if r.rate.bytes != 0 { + r.rate.pktLossRate = float64(r.rate.bytesRetrans) / float64(r.rate.bytes) * 100 + } else { + r.rate.bytes = 0 + } + + r.rate.packets = 0 + r.rate.bytes = 0 + r.rate.bytesRetrans = 0 + + r.rate.last = now + } + r.lock.Unlock() +} + +func (r *receiver) SetNAKInterval(nakInterval uint64) { + r.lock.Lock() + defer r.lock.Unlock() + + r.periodicNAKInterval = nakInterval +} + +func (r *receiver) String(t uint64) string { + var b strings.Builder + + b.WriteString(fmt.Sprintf("maxSeen=%d lastACK=%d lastDelivered=%d\n", r.maxSeenSequenceNumber.Val(), r.lastACKSequenceNumber.Val(), r.lastDeliveredSequenceNumber.Val())) + + r.lock.RLock() + for e := r.packetList.Front(); e != nil; e = e.Next() { + p := e.Value.(packet.Packet) + + b.WriteString(fmt.Sprintf(" %d @ %d (in %d)\n", p.Header().PacketSequenceNumber.Val(), p.Header().PktTsbpdTime, int64(p.Header().PktTsbpdTime)-int64(t))) + } + r.lock.RUnlock() + + return b.String() +} diff --git a/vendor/github.com/datarhei/gosrt/congestion/live/send.go b/vendor/github.com/datarhei/gosrt/congestion/live/send.go new file mode 100644 index 00000000..b296e949 --- /dev/null +++ b/vendor/github.com/datarhei/gosrt/congestion/live/send.go @@ -0,0 +1,320 @@ +package live + +import ( + "container/list" + "sync" + "time" + + "github.com/datarhei/gosrt/circular" + "github.com/datarhei/gosrt/congestion" + "github.com/datarhei/gosrt/packet" +) + +// SendConfig is the configuration for the liveSend congestion control +type SendConfig struct { + InitialSequenceNumber circular.Number + DropThreshold uint64 + MaxBW int64 + InputBW int64 + MinInputBW int64 + OverheadBW int64 + OnDeliver func(p packet.Packet) +} + +// sender implements the Sender interface +type sender struct { + nextSequenceNumber circular.Number + dropThreshold uint64 + + packetList *list.List + lossList *list.List + lock sync.RWMutex + + avgPayloadSize float64 // bytes + pktSndPeriod float64 // microseconds + maxBW float64 // bytes/s + inputBW float64 // bytes/s + overheadBW float64 // percent + + statistics congestion.SendStats + + probeTime uint64 + + rate struct { + period uint64 // microseconds + last uint64 + + bytes uint64 + bytesSent uint64 + bytesRetrans uint64 + + estimatedInputBW float64 // bytes/s + estimatedSentBW float64 // bytes/s + + pktLossRate float64 + } + + deliver func(p packet.Packet) +} + +// NewSender takes a SendConfig and returns a new Sender +func NewSender(config SendConfig) congestion.Sender { + s := &sender{ + nextSequenceNumber: config.InitialSequenceNumber, + dropThreshold: config.DropThreshold, + packetList: list.New(), + lossList: list.New(), + + avgPayloadSize: packet.MAX_PAYLOAD_SIZE, // 5.1.2. SRT's Default LiveCC Algorithm + maxBW: float64(config.MaxBW), + inputBW: float64(config.InputBW), + overheadBW: float64(config.OverheadBW), + + deliver: config.OnDeliver, + } + + if s.deliver == nil { + s.deliver = func(p packet.Packet) {} + } + + s.maxBW = 128 * 1024 * 1024 // 1 Gbit/s + s.pktSndPeriod = (s.avgPayloadSize + 16) * 1_000_000 / s.maxBW + + s.rate.period = uint64(time.Second.Microseconds()) + s.rate.last = 0 + + return s +} + +func (s *sender) Stats() congestion.SendStats { + s.lock.Lock() + defer s.lock.Unlock() + + s.statistics.UsPktSndPeriod = s.pktSndPeriod + s.statistics.BytePayload = uint64(s.avgPayloadSize) + s.statistics.MsBuf = 0 + + max := s.lossList.Back() + min := s.lossList.Front() + + if max != nil && min != nil { + s.statistics.MsBuf = (max.Value.(packet.Packet).Header().PktTsbpdTime - min.Value.(packet.Packet).Header().PktTsbpdTime) / 1_000 + } + + s.statistics.MbpsEstimatedInputBandwidth = s.rate.estimatedInputBW * 8 / 1024 / 1024 + s.statistics.MbpsEstimatedSentBandwidth = s.rate.estimatedSentBW * 8 / 1024 / 1024 + + s.statistics.PktLossRate = s.rate.pktLossRate + + return s.statistics +} + +func (s *sender) Flush() { + s.lock.Lock() + defer s.lock.Unlock() + + s.packetList = s.packetList.Init() + s.lossList = s.lossList.Init() +} + +func (s *sender) Push(p packet.Packet) { + s.lock.Lock() + defer s.lock.Unlock() + + if p == nil { + return + } + + // Give to the packet a sequence number + p.Header().PacketSequenceNumber = s.nextSequenceNumber + p.Header().PacketPositionFlag = packet.SinglePacket + p.Header().OrderFlag = false + p.Header().MessageNumber = 1 + + s.nextSequenceNumber = s.nextSequenceNumber.Inc() + + pktLen := p.Len() + + s.statistics.PktBuf++ + s.statistics.ByteBuf += pktLen + + // Input bandwidth calculation + s.rate.bytes += pktLen + + p.Header().Timestamp = uint32(p.Header().PktTsbpdTime & uint64(packet.MAX_TIMESTAMP)) + + // Every 16th and 17th packet should be sent at the same time in order + // for the receiver to determine the link capacity. Not really well + // documented in the specs. + // PktTsbpdTime is used for the timing of sending the packets. Here we + // can modify it because it has already been used to set the packet's + // timestamp. + probe := p.Header().PacketSequenceNumber.Val() & 0xF + if probe == 0 { + s.probeTime = p.Header().PktTsbpdTime + } else if probe == 1 { + p.Header().PktTsbpdTime = s.probeTime + } + + s.packetList.PushBack(p) + + s.statistics.PktFlightSize = uint64(s.packetList.Len()) +} + +func (s *sender) Tick(now uint64) { + // Deliver packets whose PktTsbpdTime is ripe + s.lock.Lock() + removeList := make([]*list.Element, 0, s.packetList.Len()) + for e := s.packetList.Front(); e != nil; e = e.Next() { + p := e.Value.(packet.Packet) + if p.Header().PktTsbpdTime <= now { + s.statistics.Pkt++ + s.statistics.PktUnique++ + + pktLen := p.Len() + + s.statistics.Byte += pktLen + s.statistics.ByteUnique += pktLen + + s.statistics.UsSndDuration += uint64(s.pktSndPeriod) + + // 5.1.2. SRT's Default LiveCC Algorithm + s.avgPayloadSize = 0.875*s.avgPayloadSize + 0.125*float64(pktLen) + + s.rate.bytesSent += pktLen + + s.deliver(p) + removeList = append(removeList, e) + } else { + break + } + } + + for _, e := range removeList { + s.lossList.PushBack(e.Value) + s.packetList.Remove(e) + } + s.lock.Unlock() + + s.lock.Lock() + removeList = make([]*list.Element, 0, s.lossList.Len()) + for e := s.lossList.Front(); e != nil; e = e.Next() { + p := e.Value.(packet.Packet) + + if p.Header().PktTsbpdTime+s.dropThreshold <= now { + // Dropped packet because too old + s.statistics.PktDrop++ + s.statistics.PktLoss++ + s.statistics.ByteDrop += p.Len() + s.statistics.ByteLoss += p.Len() + + removeList = append(removeList, e) + } + } + + // These packets are not needed anymore (too late) + for _, e := range removeList { + p := e.Value.(packet.Packet) + + s.statistics.PktBuf-- + s.statistics.ByteBuf -= p.Len() + + s.lossList.Remove(e) + + // This packet has been ACK'd and we don't need it anymore + p.Decommission() + } + s.lock.Unlock() + + s.lock.Lock() + tdiff := now - s.rate.last + + if tdiff > s.rate.period { + s.rate.estimatedInputBW = float64(s.rate.bytes) / (float64(tdiff) / 1000 / 1000) + s.rate.estimatedSentBW = float64(s.rate.bytesSent) / (float64(tdiff) / 1000 / 1000) + if s.rate.bytesSent != 0 { + s.rate.pktLossRate = float64(s.rate.bytesRetrans) / float64(s.rate.bytesSent) * 100 + } else { + s.rate.pktLossRate = 0 + } + + s.rate.bytes = 0 + s.rate.bytesSent = 0 + s.rate.bytesRetrans = 0 + + s.rate.last = now + } + s.lock.Unlock() +} + +func (s *sender) ACK(sequenceNumber circular.Number) { + s.lock.Lock() + defer s.lock.Unlock() + + removeList := make([]*list.Element, 0, s.lossList.Len()) + for e := s.lossList.Front(); e != nil; e = e.Next() { + p := e.Value.(packet.Packet) + if p.Header().PacketSequenceNumber.Lt(sequenceNumber) { + // Remove packet from buffer because it has been successfully transmitted + removeList = append(removeList, e) + } else { + break + } + } + + // These packets are not needed anymore (ACK'd) + for _, e := range removeList { + p := e.Value.(packet.Packet) + + s.statistics.PktBuf-- + s.statistics.ByteBuf -= p.Len() + + s.lossList.Remove(e) + + // This packet has been ACK'd and we don't need it anymore + p.Decommission() + } + + s.pktSndPeriod = (s.avgPayloadSize + 16) * 1000000 / s.maxBW +} + +func (s *sender) NAK(sequenceNumbers []circular.Number) { + if len(sequenceNumbers) == 0 { + return + } + + s.lock.Lock() + defer s.lock.Unlock() + + for e := s.lossList.Back(); e != nil; e = e.Prev() { + p := e.Value.(packet.Packet) + + for i := 0; i < len(sequenceNumbers); i += 2 { + if p.Header().PacketSequenceNumber.Gte(sequenceNumbers[i]) && p.Header().PacketSequenceNumber.Lte(sequenceNumbers[i+1]) { + s.statistics.PktRetrans++ + s.statistics.Pkt++ + s.statistics.PktLoss++ + + s.statistics.ByteRetrans += p.Len() + s.statistics.Byte += p.Len() + s.statistics.ByteLoss += p.Len() + + // 5.1.2. SRT's Default LiveCC Algorithm + s.avgPayloadSize = 0.875*s.avgPayloadSize + 0.125*float64(p.Len()) + + s.rate.bytesSent += p.Len() + s.rate.bytesRetrans += p.Len() + + p.Header().RetransmittedPacketFlag = true + s.deliver(p) + } + } + } +} + +func (s *sender) SetDropThreshold(threshold uint64) { + s.lock.Lock() + defer s.lock.Unlock() + + s.dropThreshold = threshold +} diff --git a/vendor/github.com/datarhei/gosrt/connection.go b/vendor/github.com/datarhei/gosrt/connection.go index a14cf125..ea83ca79 100644 --- a/vendor/github.com/datarhei/gosrt/connection.go +++ b/vendor/github.com/datarhei/gosrt/connection.go @@ -11,10 +11,11 @@ import ( "sync" "time" - "github.com/datarhei/gosrt/internal/circular" - "github.com/datarhei/gosrt/internal/congestion" - "github.com/datarhei/gosrt/internal/crypto" - "github.com/datarhei/gosrt/internal/packet" + "github.com/datarhei/gosrt/circular" + "github.com/datarhei/gosrt/congestion" + "github.com/datarhei/gosrt/congestion/live" + "github.com/datarhei/gosrt/crypto" + "github.com/datarhei/gosrt/packet" ) // Conn is a SRT network connection. @@ -24,11 +25,20 @@ type Conn interface { // time limit; see SetDeadline and SetReadDeadline. Read(p []byte) (int, error) + // ReadPacket reads a packet from the queue of received packets. It blocks + // if the queue is empty. Only data packets are returned. Using ReadPacket + // and Read at the same time may lead to data loss. + ReadPacket() (packet.Packet, error) + // Write writes data to the connection. // Write can be made to time out and return an error after a fixed // time limit; see SetDeadline and SetWriteDeadline. Write(p []byte) (int, error) + // WritePacket writes a packet to the write queue. Packets on the write queue + // will be sent to the peer of the connection. Only data packets will be sent. + WritePacket(p packet.Packet) error + // Close closes the connection. // Any blocked Read or Write operations will be unblocked and return errors. Close() error @@ -252,7 +262,7 @@ func newSRTConn(config srtConnConfig) *srtConn { // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) -> periodicACK = 10 milliseconds // 4.8.2. Packet Retransmission (NAKs) -> periodicNAK at least 20 milliseconds - c.recv = congestion.NewLiveReceive(congestion.ReceiveConfig{ + c.recv = live.NewReceiver(live.ReceiveConfig{ InitialSequenceNumber: c.initialPacketSequenceNumber, PeriodicACKInterval: 10_000, PeriodicNAKInterval: 20_000, @@ -269,7 +279,7 @@ func newSRTConn(config srtConnConfig) *srtConn { } c.dropThreshold += 20_000 - c.snd = congestion.NewLiveSend(congestion.SendConfig{ + c.snd = live.NewSender(live.SendConfig{ InitialSequenceNumber: c.initialPacketSequenceNumber, DropThreshold: c.dropThreshold, MaxBW: c.config.MaxBW, @@ -281,9 +291,9 @@ func newSRTConn(config srtConnConfig) *srtConn { c.ctx, c.cancelCtx = context.WithCancel(context.Background()) - go c.networkQueueReader() - go c.writeQueueReader() - go c.ticker() + go c.networkQueueReader(c.ctx) + go c.writeQueueReader(c.ctx) + go c.ticker(c.ctx) c.debug.expectedRcvPacketSequenceNumber = c.initialPacketSequenceNumber c.debug.expectedReadPacketSequenceNumber = c.initialPacketSequenceNumber @@ -311,11 +321,19 @@ func newSRTConn(config srtConnConfig) *srtConn { } func (c *srtConn) LocalAddr() net.Addr { + if c.localAddr == nil { + return nil + } + addr, _ := net.ResolveUDPAddr("udp", c.localAddr.String()) return addr } func (c *srtConn) RemoteAddr() net.Addr { + if c.remoteAddr == nil { + return nil + } + addr, _ := net.ResolveUDPAddr("udp", c.remoteAddr.String()) return addr } @@ -338,7 +356,7 @@ func (c *srtConn) Version() uint32 { // ticker invokes the congestion control in regular intervals with // the current connection time. -func (c *srtConn) ticker() { +func (c *srtConn) ticker(ctx context.Context) { ticker := time.NewTicker(c.tick) defer ticker.Stop() defer func() { @@ -347,7 +365,7 @@ func (c *srtConn) ticker() { for { select { - case <-c.ctx.Done(): + case <-ctx.Done(): return case t := <-ticker.C: tickTime := uint64(t.Sub(c.start).Microseconds()) @@ -358,9 +376,7 @@ func (c *srtConn) ticker() { } } -// readPacket reads a packet from the queue of received packets. It blocks -// if the queue is empty. Only data packets are returned. -func (c *srtConn) readPacket() (packet.Packet, error) { +func (c *srtConn) ReadPacket() (packet.Packet, error) { var p packet.Packet select { case <-c.ctx.Done(): @@ -391,7 +407,7 @@ func (c *srtConn) Read(b []byte) (int, error) { c.readBuffer.Reset() - p, err := c.readPacket() + p, err := c.ReadPacket() if err != nil { return 0, err } @@ -404,9 +420,9 @@ func (c *srtConn) Read(b []byte) (int, error) { return c.readBuffer.Read(b) } -// writePacket writes a packet to the write queue. Packets on the write queue +// WritePacket writes a packet to the write queue. Packets on the write queue // will be sent to the peer of the connection. Only data packets will be sent. -func (c *srtConn) writePacket(p packet.Packet) error { +func (c *srtConn) WritePacket(p packet.Packet) error { if p.Header().IsControlPacket { // Ignore control packets return nil @@ -429,7 +445,7 @@ func (c *srtConn) Write(b []byte) (int, error) { return 0, err } - p := packet.NewPacket(nil, nil) + p := packet.NewPacket(nil) p.SetData(c.writeData[:n]) @@ -526,14 +542,14 @@ func (c *srtConn) pop(p packet.Packet) { } // networkQueueReader reads the packets from the network queue in order to process them. -func (c *srtConn) networkQueueReader() { +func (c *srtConn) networkQueueReader(ctx context.Context) { defer func() { c.log("connection:close", func() string { return "left network queue reader loop" }) }() for { select { - case <-c.ctx.Done(): + case <-ctx.Done(): return case p := <-c.networkQueue: c.handlePacket(p) @@ -543,14 +559,14 @@ func (c *srtConn) networkQueueReader() { // writeQueueReader reads the packets from the write queue and puts them into congestion // control for sending. -func (c *srtConn) writeQueueReader() { +func (c *srtConn) writeQueueReader(ctx context.Context) { defer func() { c.log("connection:close", func() string { return "left write queue reader loop" }) }() for { select { - case <-c.ctx.Done(): + case <-ctx.Done(): return case p := <-c.writeQueue: // Put the packet into the send congestion control @@ -1133,7 +1149,7 @@ func (c *srtConn) handleKMResponse(p packet.Packet) { // sendShutdown sends a shutdown packet to the peer. func (c *srtConn) sendShutdown() { - p := packet.NewPacket(c.remoteAddr, nil) + p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true @@ -1156,7 +1172,7 @@ func (c *srtConn) sendShutdown() { // sendNAK sends a NAK to the peer with the given range of sequence numbers. func (c *srtConn) sendNAK(from, to circular.Number) { - p := packet.NewPacket(c.remoteAddr, nil) + p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true @@ -1182,7 +1198,7 @@ func (c *srtConn) sendNAK(from, to circular.Number) { // sendACK sends an ACK to the peer with the given sequence number. func (c *srtConn) sendACK(seq circular.Number, lite bool) { - p := packet.NewPacket(c.remoteAddr, nil) + p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true @@ -1233,7 +1249,7 @@ func (c *srtConn) sendACK(seq circular.Number, lite bool) { // sendACKACK sends an ACKACK to the peer with the given ACK sequence. func (c *srtConn) sendACKACK(ackSequence uint32) { - p := packet.NewPacket(c.remoteAddr, nil) + p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true @@ -1280,7 +1296,7 @@ func (c *srtConn) sendHSRequest() { SendTSBPDDelay: uint16(c.config.ReceiverLatency.Milliseconds()), } - p := packet.NewPacket(c.remoteAddr, nil) + p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true @@ -1319,7 +1335,7 @@ func (c *srtConn) sendKMRequest(key packet.PacketEncryption) { c.crypto.MarshalKM(cif, c.config.Passphrase, key) - p := packet.NewPacket(c.remoteAddr, nil) + p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true diff --git a/vendor/github.com/datarhei/gosrt/internal/crypto/crypto.go b/vendor/github.com/datarhei/gosrt/crypto/crypto.go similarity index 94% rename from vendor/github.com/datarhei/gosrt/internal/crypto/crypto.go rename to vendor/github.com/datarhei/gosrt/crypto/crypto.go index a4c14474..245c5f13 100644 --- a/vendor/github.com/datarhei/gosrt/internal/crypto/crypto.go +++ b/vendor/github.com/datarhei/gosrt/crypto/crypto.go @@ -4,13 +4,13 @@ package crypto import ( "crypto/aes" "crypto/cipher" - "crypto/rand" "crypto/sha1" "encoding/binary" "errors" "fmt" - "github.com/datarhei/gosrt/internal/packet" + "github.com/datarhei/gosrt/packet" + "github.com/datarhei/gosrt/rand" "github.com/benburkert/openpgp/aes/keywrap" "golang.org/x/crypto/pbkdf2" @@ -113,13 +113,24 @@ func (c *crypto) generateSEK(keyLength int) ([]byte, error) { var ErrInvalidKey = errors.New("crypto: invalid key for encryption. Must be even, odd, or both") // ErrInvalidWrap is returned when the packet encryption indicates a different length of the wrapped key -var ErrInvalidWrap = errors.New("crypto: the unwrapped key has the wrong length") +var ErrInvalidWrap = errors.New("crypto: the un/wrapped key has the wrong length") func (c *crypto) UnmarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string) error { if km.KeyBasedEncryption == packet.UnencryptedPacket || !km.KeyBasedEncryption.IsValid() { return ErrInvalidKey } + n := 1 + if km.KeyBasedEncryption == packet.EvenAndOddKey { + n = 2 + } + + wrapLength := n * c.keyLength + + if len(km.Wrap)-8 != wrapLength { + return ErrInvalidWrap + } + if len(km.Salt) != 0 { copy(c.salt, km.Salt) } @@ -131,12 +142,7 @@ func (c *crypto) UnmarshalKM(km *packet.CIFKeyMaterialExtension, passphrase stri return err } - n := 1 - if km.KeyBasedEncryption == packet.EvenAndOddKey { - n = 2 - } - - if len(unwrap) != n*c.keyLength { + if len(unwrap) != wrapLength { return ErrInvalidWrap } @@ -223,6 +229,10 @@ func (c *crypto) EncryptOrDecryptPayload(data []byte, key packet.PacketEncryptio // // CTR = (MSB(112, Salt) XOR psn) << 16 + if len(c.salt) != 16 { + return fmt.Errorf("crypto: invalid salt. Must be of length 16 bytes") + } + ctr := make([]byte, 16) binary.BigEndian.PutUint32(ctr[10:], packetSequenceNumber) diff --git a/vendor/github.com/datarhei/gosrt/dial.go b/vendor/github.com/datarhei/gosrt/dial.go index ff4d5c78..115ac869 100644 --- a/vendor/github.com/datarhei/gosrt/dial.go +++ b/vendor/github.com/datarhei/gosrt/dial.go @@ -11,10 +11,10 @@ import ( "sync" "time" - "github.com/datarhei/gosrt/internal/circular" - "github.com/datarhei/gosrt/internal/crypto" - "github.com/datarhei/gosrt/internal/packet" - "github.com/datarhei/gosrt/internal/rand" + "github.com/datarhei/gosrt/circular" + "github.com/datarhei/gosrt/crypto" + "github.com/datarhei/gosrt/packet" + "github.com/datarhei/gosrt/rand" ) // ErrClientClosed is returned when the client connection has @@ -44,14 +44,15 @@ type dialer struct { start time.Time rcvQueue chan packet.Packet // for packets that come from the wire - sndQueue chan packet.Packet // for packets that go to the wire + + sndMutex sync.Mutex + sndData bytes.Buffer // for packets that go to the wire shutdown bool shutdownLock sync.RWMutex shutdownOnce sync.Once stopReader context.CancelFunc - stopWriter context.CancelFunc doneChan chan error } @@ -112,7 +113,6 @@ func Dial(network, address string, config Config) (Conn, error) { dl.connChan = make(chan connResponse) dl.rcvQueue = make(chan packet.Packet, 2048) - dl.sndQueue = make(chan packet.Packet, 2048) dl.doneChan = make(chan error) @@ -157,8 +157,8 @@ func Dial(network, address string, config Config) (Conn, error) { return } - p := packet.NewPacket(dl.remoteAddr, buffer[:n]) - if p == nil { + p, err := packet.NewPacketFromData(dl.remoteAddr, buffer[:n]) + if err != nil { continue } @@ -175,10 +175,6 @@ func Dial(network, address string, config Config) (Conn, error) { readerCtx, dl.stopReader = context.WithCancel(context.Background()) go dl.reader(readerCtx) - var writerCtx context.Context - writerCtx, dl.stopWriter = context.WithCancel(context.Background()) - go dl.writer(writerCtx) - // Send the initial handshake request dl.sendInduction() @@ -258,51 +254,29 @@ func (dl *dialer) reader(ctx context.Context) { } } -// send adds a packet to the send queue +// Send a packet to the wire. This function must be synchronous in order to allow to safely call Packet.Decommission() afterward. func (dl *dialer) send(p packet.Packet) { - // non-blocking - select { - case dl.sndQueue <- p: - default: - dl.log("dial", func() string { return "send queue is full" }) + dl.sndMutex.Lock() + defer dl.sndMutex.Unlock() + + dl.sndData.Reset() + + if err := p.Marshal(&dl.sndData); err != nil { + p.Decommission() + dl.log("packet:send:error", func() string { return "marshalling packet failed" }) + return } -} -// writer reads packets from the send queue and writes them to the wire -func (dl *dialer) writer(ctx context.Context) { - defer func() { - dl.log("dial", func() string { return "left writer loop" }) - }() + buffer := dl.sndData.Bytes() - dl.log("dial", func() string { return "writer loop started" }) + dl.log("packet:send:dump", func() string { return p.Dump() }) - var data bytes.Buffer + // Write the packet's contents to the wire + dl.pc.Write(buffer) - for { - select { - case <-ctx.Done(): - return - case p := <-dl.sndQueue: - data.Reset() - - if err := p.Marshal(&data); err != nil { - p.Decommission() - dl.log("packet:send:error", func() string { return "marshalling packet failed" }) - continue - } - - buffer := data.Bytes() - - dl.log("packet:send:dump", func() string { return p.Dump() }) - - // Write the packet's contents to the wire. - dl.pc.Write(buffer) - - if p.Header().IsControlPacket { - // Control packets can be decommissioned because they will not be sent again - p.Decommission() - } - } + if p.Header().IsControlPacket { + // Control packets can be decommissioned because they will not be sent again (data packets might be retransferred) + p.Decommission() } } @@ -558,7 +532,7 @@ func (dl *dialer) handleHandshake(p packet.Packet) { } func (dl *dialer) sendInduction() { - p := packet.NewPacket(dl.remoteAddr, nil) + p := packet.NewPacket(dl.remoteAddr) p.Header().IsControlPacket = true @@ -593,7 +567,7 @@ func (dl *dialer) sendInduction() { } func (dl *dialer) sendShutdown(peerSocketId uint32) { - p := packet.NewPacket(dl.remoteAddr, nil) + p := packet.NewPacket(dl.remoteAddr) data := [4]byte{} binary.BigEndian.PutUint32(data[0:], 0) @@ -614,26 +588,68 @@ func (dl *dialer) sendShutdown(peerSocketId uint32) { } func (dl *dialer) LocalAddr() net.Addr { + dl.connLock.RLock() + defer dl.connLock.RUnlock() + + if dl.conn == nil { + return nil + } + return dl.conn.LocalAddr() } func (dl *dialer) RemoteAddr() net.Addr { + dl.connLock.RLock() + defer dl.connLock.RUnlock() + + if dl.conn == nil { + return nil + } + return dl.conn.RemoteAddr() } func (dl *dialer) SocketId() uint32 { + dl.connLock.RLock() + defer dl.connLock.RUnlock() + + if dl.conn == nil { + return 0 + } + return dl.conn.SocketId() } func (dl *dialer) PeerSocketId() uint32 { + dl.connLock.RLock() + defer dl.connLock.RUnlock() + + if dl.conn == nil { + return 0 + } + return dl.conn.PeerSocketId() } func (dl *dialer) StreamId() string { + dl.connLock.RLock() + defer dl.connLock.RUnlock() + + if dl.conn == nil { + return "" + } + return dl.conn.StreamId() } func (dl *dialer) Version() uint32 { + dl.connLock.RLock() + defer dl.connLock.RUnlock() + + if dl.conn == nil { + return 0 + } + return dl.conn.Version() } @@ -657,7 +673,6 @@ func (dl *dialer) Close() error { dl.connLock.RUnlock() dl.stopReader() - dl.stopWriter() dl.log("dial", func() string { return "closing socket" }) dl.pc.Close() @@ -679,10 +694,14 @@ func (dl *dialer) Read(p []byte) (n int, err error) { dl.connLock.RLock() defer dl.connLock.RUnlock() + if dl.conn == nil { + return 0, fmt.Errorf("no connection") + } + return dl.conn.Read(p) } -func (dl *dialer) readPacket() (packet.Packet, error) { +func (dl *dialer) ReadPacket() (packet.Packet, error) { if err := dl.checkConnection(); err != nil { return nil, err } @@ -690,7 +709,11 @@ func (dl *dialer) readPacket() (packet.Packet, error) { dl.connLock.RLock() defer dl.connLock.RUnlock() - return dl.conn.readPacket() + if dl.conn == nil { + return nil, fmt.Errorf("no connection") + } + + return dl.conn.ReadPacket() } func (dl *dialer) Write(p []byte) (n int, err error) { @@ -701,10 +724,14 @@ func (dl *dialer) Write(p []byte) (n int, err error) { dl.connLock.RLock() defer dl.connLock.RUnlock() + if dl.conn == nil { + return 0, fmt.Errorf("no connection") + } + return dl.conn.Write(p) } -func (dl *dialer) writePacket(p packet.Packet) error { +func (dl *dialer) WritePacket(p packet.Packet) error { if err := dl.checkConnection(); err != nil { return err } @@ -712,14 +739,32 @@ func (dl *dialer) writePacket(p packet.Packet) error { dl.connLock.RLock() defer dl.connLock.RUnlock() - return dl.conn.writePacket(p) + if dl.conn == nil { + return fmt.Errorf("no connection") + } + + return dl.conn.WritePacket(p) } func (dl *dialer) SetDeadline(t time.Time) error { return dl.conn.SetDeadline(t) } func (dl *dialer) SetReadDeadline(t time.Time) error { return dl.conn.SetReadDeadline(t) } func (dl *dialer) SetWriteDeadline(t time.Time) error { return dl.conn.SetWriteDeadline(t) } -func (dl *dialer) Stats(s *Statistics) { dl.conn.Stats(s) } + +func (dl *dialer) Stats(s *Statistics) { + dl.connLock.RLock() + defer dl.connLock.RUnlock() + + if dl.conn == nil { + return + } + + dl.conn.Stats(s) +} func (dl *dialer) log(topic string, message func() string) { + if dl.config.Logger == nil { + return + } + dl.config.Logger.Print(topic, dl.socketId, 2, message) } diff --git a/vendor/github.com/datarhei/gosrt/internal/congestion/congestion.go b/vendor/github.com/datarhei/gosrt/internal/congestion/congestion.go deleted file mode 100644 index 62efa985..00000000 --- a/vendor/github.com/datarhei/gosrt/internal/congestion/congestion.go +++ /dev/null @@ -1,117 +0,0 @@ -// Package congestions provides congestion control implementations for SRT -package congestion - -import ( - "github.com/datarhei/gosrt/internal/circular" - "github.com/datarhei/gosrt/internal/packet" -) - -// SendConfig is the configuration for the liveSend congestion control -type SendConfig struct { - InitialSequenceNumber circular.Number - DropThreshold uint64 - MaxBW int64 - InputBW int64 - MinInputBW int64 - OverheadBW int64 - OnDeliver func(p packet.Packet) -} - -// Sender is the sending part of the congestion control -type Sender interface { - Stats() SendStats - Flush() - Push(p packet.Packet) - Tick(now uint64) - ACK(sequenceNumber circular.Number) - NAK(sequenceNumbers []circular.Number) - SetDropThreshold(threshold uint64) -} - -// ReceiveConfig is the configuration for the liveResv congestion control -type ReceiveConfig struct { - InitialSequenceNumber circular.Number - PeriodicACKInterval uint64 // microseconds - PeriodicNAKInterval uint64 // microseconds - OnSendACK func(seq circular.Number, light bool) - OnSendNAK func(from, to circular.Number) - OnDeliver func(p packet.Packet) -} - -// Receiver is the receiving part of the congestion control -type Receiver interface { - Stats() ReceiveStats - PacketRate() (pps, bps, capacity float64) - Flush() - Push(pkt packet.Packet) - Tick(now uint64) - SetNAKInterval(nakInterval uint64) -} - -// SendStats are collected statistics from liveSend -type SendStats struct { - Pkt uint64 // Sent packets in total - Byte uint64 // Sent bytes in total - - PktUnique uint64 - ByteUnique uint64 - - PktLoss uint64 - ByteLoss uint64 - - PktRetrans uint64 - ByteRetrans uint64 - - UsSndDuration uint64 // microseconds - - PktDrop uint64 - ByteDrop uint64 - - // instantaneous - PktBuf uint64 - ByteBuf uint64 - MsBuf uint64 - - PktFlightSize uint64 - - UsPktSndPeriod float64 // microseconds - BytePayload uint64 - - MbpsEstimatedInputBandwidth float64 - MbpsEstimatedSentBandwidth float64 - - PktLossRate float64 -} - -// ReceiveStats are collected statistics from liveRecv -type ReceiveStats struct { - Pkt uint64 - Byte uint64 - - PktUnique uint64 - ByteUnique uint64 - - PktLoss uint64 - ByteLoss uint64 - - PktRetrans uint64 - ByteRetrans uint64 - - PktBelated uint64 - ByteBelated uint64 - - PktDrop uint64 - ByteDrop uint64 - - // instantaneous - PktBuf uint64 - ByteBuf uint64 - MsBuf uint64 - - BytePayload uint64 - - MbpsEstimatedRecvBandwidth float64 - MbpsEstimatedLinkCapacity float64 - - PktLossRate float64 -} diff --git a/vendor/github.com/datarhei/gosrt/internal/congestion/live.go b/vendor/github.com/datarhei/gosrt/internal/congestion/live.go deleted file mode 100644 index 6012fac9..00000000 --- a/vendor/github.com/datarhei/gosrt/internal/congestion/live.go +++ /dev/null @@ -1,900 +0,0 @@ -package congestion - -import ( - "container/list" - "fmt" - "strings" - "sync" - "time" - - "github.com/datarhei/gosrt/internal/circular" - "github.com/datarhei/gosrt/internal/packet" -) - -// liveSend implements the Sender interface -type liveSend struct { - nextSequenceNumber circular.Number - dropThreshold uint64 - - packetList *list.List - lossList *list.List - lock sync.RWMutex - - avgPayloadSize float64 // bytes - pktSndPeriod float64 // microseconds - maxBW float64 // bytes/s - inputBW float64 // bytes/s - overheadBW float64 // percent - - statistics SendStats - - probeTime uint64 - - rate struct { - period uint64 // microseconds - last uint64 - - bytes uint64 - bytesSent uint64 - bytesRetrans uint64 - - estimatedInputBW float64 // bytes/s - estimatedSentBW float64 // bytes/s - - pktLossRate float64 - } - - deliver func(p packet.Packet) -} - -// NewLiveSend takes a SendConfig and returns a new Sender -func NewLiveSend(config SendConfig) Sender { - s := &liveSend{ - nextSequenceNumber: config.InitialSequenceNumber, - dropThreshold: config.DropThreshold, - packetList: list.New(), - lossList: list.New(), - - avgPayloadSize: packet.MAX_PAYLOAD_SIZE, // 5.1.2. SRT's Default LiveCC Algorithm - maxBW: float64(config.MaxBW), - inputBW: float64(config.InputBW), - overheadBW: float64(config.OverheadBW), - - deliver: config.OnDeliver, - } - - if s.deliver == nil { - s.deliver = func(p packet.Packet) {} - } - - s.maxBW = 128 * 1024 * 1024 // 1 Gbit/s - s.pktSndPeriod = (s.avgPayloadSize + 16) * 1_000_000 / s.maxBW - - s.rate.period = uint64(time.Second.Microseconds()) - s.rate.last = 0 - - return s -} - -func (s *liveSend) Stats() SendStats { - s.lock.Lock() - defer s.lock.Unlock() - - s.statistics.UsPktSndPeriod = s.pktSndPeriod - s.statistics.BytePayload = uint64(s.avgPayloadSize) - s.statistics.MsBuf = 0 - - max := s.lossList.Back() - min := s.lossList.Front() - - if max != nil && min != nil { - s.statistics.MsBuf = (max.Value.(packet.Packet).Header().PktTsbpdTime - min.Value.(packet.Packet).Header().PktTsbpdTime) / 1_000 - } - - s.statistics.MbpsEstimatedInputBandwidth = s.rate.estimatedInputBW * 8 / 1024 / 1024 - s.statistics.MbpsEstimatedSentBandwidth = s.rate.estimatedSentBW * 8 / 1024 / 1024 - - s.statistics.PktLossRate = s.rate.pktLossRate - - return s.statistics -} - -func (s *liveSend) Flush() { - s.lock.Lock() - defer s.lock.Unlock() - - s.packetList = s.packetList.Init() - s.lossList = s.lossList.Init() -} - -func (s *liveSend) Push(p packet.Packet) { - s.lock.Lock() - defer s.lock.Unlock() - - if p == nil { - return - } - - // Give to the packet a sequence number - p.Header().PacketSequenceNumber = s.nextSequenceNumber - p.Header().PacketPositionFlag = packet.SinglePacket - p.Header().OrderFlag = false - p.Header().MessageNumber = 1 - - s.nextSequenceNumber = s.nextSequenceNumber.Inc() - - pktLen := p.Len() - - s.statistics.PktBuf++ - s.statistics.ByteBuf += pktLen - - // Input bandwidth calculation - s.rate.bytes += pktLen - - p.Header().Timestamp = uint32(p.Header().PktTsbpdTime & uint64(packet.MAX_TIMESTAMP)) - - // Every 16th and 17th packet should be sent at the same time in order - // for the receiver to determine the link capacity. Not really well - // documented in the specs. - // PktTsbpdTime is used for the timing of sending the packets. Here we - // can modify it because it has already been used to set the packet's - // timestamp. - probe := p.Header().PacketSequenceNumber.Val() & 0xF - if probe == 0 { - s.probeTime = p.Header().PktTsbpdTime - } else if probe == 1 { - p.Header().PktTsbpdTime = s.probeTime - } - - s.packetList.PushBack(p) - - s.statistics.PktFlightSize = uint64(s.packetList.Len()) -} - -func (s *liveSend) Tick(now uint64) { - // Deliver packets whose PktTsbpdTime is ripe - s.lock.Lock() - removeList := make([]*list.Element, 0, s.packetList.Len()) - for e := s.packetList.Front(); e != nil; e = e.Next() { - p := e.Value.(packet.Packet) - if p.Header().PktTsbpdTime <= now { - s.statistics.Pkt++ - s.statistics.PktUnique++ - - pktLen := p.Len() - - s.statistics.Byte += pktLen - s.statistics.ByteUnique += pktLen - - s.statistics.UsSndDuration += uint64(s.pktSndPeriod) - - // 5.1.2. SRT's Default LiveCC Algorithm - s.avgPayloadSize = 0.875*s.avgPayloadSize + 0.125*float64(pktLen) - - s.rate.bytesSent += pktLen - - s.deliver(p) - removeList = append(removeList, e) - } else { - break - } - } - - for _, e := range removeList { - s.lossList.PushBack(e.Value) - s.packetList.Remove(e) - } - s.lock.Unlock() - - s.lock.Lock() - removeList = make([]*list.Element, 0, s.lossList.Len()) - for e := s.lossList.Front(); e != nil; e = e.Next() { - p := e.Value.(packet.Packet) - - if p.Header().PktTsbpdTime+s.dropThreshold <= now { - // Dropped packet because too old - s.statistics.PktDrop++ - s.statistics.PktLoss++ - s.statistics.ByteDrop += p.Len() - s.statistics.ByteLoss += p.Len() - - removeList = append(removeList, e) - } - } - - // These packets are not needed anymore (too late) - for _, e := range removeList { - p := e.Value.(packet.Packet) - - s.statistics.PktBuf-- - s.statistics.ByteBuf -= p.Len() - - s.lossList.Remove(e) - - // This packet has been ACK'd and we don't need it anymore - p.Decommission() - } - s.lock.Unlock() - - s.lock.Lock() - tdiff := now - s.rate.last - - if tdiff > s.rate.period { - s.rate.estimatedInputBW = float64(s.rate.bytes) / (float64(tdiff) / 1000 / 1000) - s.rate.estimatedSentBW = float64(s.rate.bytesSent) / (float64(tdiff) / 1000 / 1000) - if s.rate.bytesSent != 0 { - s.rate.pktLossRate = float64(s.rate.bytesRetrans) / float64(s.rate.bytesSent) * 100 - } else { - s.rate.pktLossRate = 0 - } - - s.rate.bytes = 0 - s.rate.bytesSent = 0 - s.rate.bytesRetrans = 0 - - s.rate.last = now - } - s.lock.Unlock() -} - -func (s *liveSend) ACK(sequenceNumber circular.Number) { - s.lock.Lock() - defer s.lock.Unlock() - - removeList := make([]*list.Element, 0, s.lossList.Len()) - for e := s.lossList.Front(); e != nil; e = e.Next() { - p := e.Value.(packet.Packet) - if p.Header().PacketSequenceNumber.Lt(sequenceNumber) { - // Remove packet from buffer because it has been successfully transmitted - removeList = append(removeList, e) - } else { - break - } - } - - // These packets are not needed anymore (ACK'd) - for _, e := range removeList { - p := e.Value.(packet.Packet) - - s.statistics.PktBuf-- - s.statistics.ByteBuf -= p.Len() - - s.lossList.Remove(e) - - // This packet has been ACK'd and we don't need it anymore - p.Decommission() - } - - s.pktSndPeriod = (s.avgPayloadSize + 16) * 1000000 / s.maxBW -} - -func (s *liveSend) NAK(sequenceNumbers []circular.Number) { - if len(sequenceNumbers) == 0 { - return - } - - s.lock.Lock() - defer s.lock.Unlock() - - for e := s.lossList.Back(); e != nil; e = e.Prev() { - p := e.Value.(packet.Packet) - - for i := 0; i < len(sequenceNumbers); i += 2 { - if p.Header().PacketSequenceNumber.Gte(sequenceNumbers[i]) && p.Header().PacketSequenceNumber.Lte(sequenceNumbers[i+1]) { - s.statistics.PktRetrans++ - s.statistics.Pkt++ - s.statistics.PktLoss++ - - s.statistics.ByteRetrans += p.Len() - s.statistics.Byte += p.Len() - s.statistics.ByteLoss += p.Len() - - // 5.1.2. SRT's Default LiveCC Algorithm - s.avgPayloadSize = 0.875*s.avgPayloadSize + 0.125*float64(p.Len()) - - s.rate.bytesSent += p.Len() - s.rate.bytesRetrans += p.Len() - - p.Header().RetransmittedPacketFlag = true - s.deliver(p) - } - } - } -} - -func (s *liveSend) SetDropThreshold(threshold uint64) { - s.lock.Lock() - defer s.lock.Unlock() - - s.dropThreshold = threshold -} - -// liveReceive implements the Receiver interface -type liveReceive struct { - maxSeenSequenceNumber circular.Number - lastACKSequenceNumber circular.Number - lastDeliveredSequenceNumber circular.Number - packetList *list.List - lock sync.RWMutex - - nPackets uint - - periodicACKInterval uint64 // config - periodicNAKInterval uint64 // config - - lastPeriodicACK uint64 - lastPeriodicNAK uint64 - - avgPayloadSize float64 // bytes - avgLinkCapacity float64 // packets per second - - probeTime time.Time - probeNextSeq circular.Number - - statistics ReceiveStats - - rate struct { - last uint64 // microseconds - period uint64 - - packets uint64 - bytes uint64 - bytesRetrans uint64 - - packetsPerSecond float64 - bytesPerSecond float64 - - pktLossRate float64 - } - - sendACK func(seq circular.Number, light bool) - sendNAK func(from, to circular.Number) - deliver func(p packet.Packet) -} - -// NewLiveReceive takes a ReceiveConfig and returns a new Receiver -func NewLiveReceive(config ReceiveConfig) Receiver { - r := &liveReceive{ - maxSeenSequenceNumber: config.InitialSequenceNumber.Dec(), - lastACKSequenceNumber: config.InitialSequenceNumber.Dec(), - lastDeliveredSequenceNumber: config.InitialSequenceNumber.Dec(), - packetList: list.New(), - - periodicACKInterval: config.PeriodicACKInterval, - periodicNAKInterval: config.PeriodicNAKInterval, - - avgPayloadSize: 1456, // 5.1.2. SRT's Default LiveCC Algorithm - - sendACK: config.OnSendACK, - sendNAK: config.OnSendNAK, - deliver: config.OnDeliver, - } - - if r.sendACK == nil { - r.sendACK = func(seq circular.Number, light bool) {} - } - - if r.sendNAK == nil { - r.sendNAK = func(from, to circular.Number) {} - } - - if r.deliver == nil { - r.deliver = func(p packet.Packet) {} - } - - r.rate.last = 0 - r.rate.period = uint64(time.Second.Microseconds()) - - return r -} - -func (r *liveReceive) Stats() ReceiveStats { - r.lock.Lock() - defer r.lock.Unlock() - - r.statistics.BytePayload = uint64(r.avgPayloadSize) - r.statistics.MbpsEstimatedRecvBandwidth = r.rate.bytesPerSecond * 8 / 1024 / 1024 - r.statistics.MbpsEstimatedLinkCapacity = r.avgLinkCapacity * packet.MAX_PAYLOAD_SIZE * 8 / 1024 / 1024 - r.statistics.PktLossRate = r.rate.pktLossRate - - return r.statistics -} - -func (r *liveReceive) PacketRate() (pps, bps, capacity float64) { - r.lock.Lock() - defer r.lock.Unlock() - - pps = r.rate.packetsPerSecond - bps = r.rate.bytesPerSecond - capacity = r.avgLinkCapacity - - return -} - -func (r *liveReceive) Flush() { - r.lock.Lock() - defer r.lock.Unlock() - - r.packetList = r.packetList.Init() -} - -func (r *liveReceive) Push(pkt packet.Packet) { - r.lock.Lock() - defer r.lock.Unlock() - - if pkt == nil { - return - } - - // This is not really well (not at all) described in the specs. See core.cpp and window.h - // and search for PUMASK_SEQNO_PROBE (0xF). Every 16th and 17th packet are - // sent in pairs. This is used as a probe for the theoretical capacity of the link. - if !pkt.Header().RetransmittedPacketFlag { - probe := pkt.Header().PacketSequenceNumber.Val() & 0xF - if probe == 0 { - r.probeTime = time.Now() - r.probeNextSeq = pkt.Header().PacketSequenceNumber.Inc() - } else if probe == 1 && pkt.Header().PacketSequenceNumber.Equals(r.probeNextSeq) && !r.probeTime.IsZero() && pkt.Len() != 0 { - // The time between packets scaled to a fully loaded packet - diff := float64(time.Since(r.probeTime).Microseconds()) * (packet.MAX_PAYLOAD_SIZE / float64(pkt.Len())) - if diff != 0 { - // Here we're doing an average of the measurements. - r.avgLinkCapacity = 0.875*r.avgLinkCapacity + 0.125*1_000_000/diff - } - } else { - r.probeTime = time.Time{} - } - } else { - r.probeTime = time.Time{} - } - - r.nPackets++ - - pktLen := pkt.Len() - - r.rate.packets++ - r.rate.bytes += pktLen - - r.statistics.Pkt++ - r.statistics.Byte += pktLen - - //pkt.PktTsbpdTime = pkt.Timestamp + r.delay - if pkt.Header().RetransmittedPacketFlag { - r.statistics.PktRetrans++ - r.statistics.ByteRetrans += pktLen - - r.rate.bytesRetrans += pktLen - } - - // 5.1.2. SRT's Default LiveCC Algorithm - r.avgPayloadSize = 0.875*r.avgPayloadSize + 0.125*float64(pktLen) - - if pkt.Header().PacketSequenceNumber.Lte(r.lastDeliveredSequenceNumber) { - // Too old, because up until r.lastDeliveredSequenceNumber, we already delivered - r.statistics.PktBelated++ - r.statistics.ByteBelated += pktLen - - r.statistics.PktDrop++ - r.statistics.ByteDrop += pktLen - - return - } - - if pkt.Header().PacketSequenceNumber.Lt(r.lastACKSequenceNumber) { - // Already acknowledged, ignoring - r.statistics.PktDrop++ - r.statistics.ByteDrop += pktLen - - return - } - - if pkt.Header().PacketSequenceNumber.Equals(r.maxSeenSequenceNumber.Inc()) { - // In order, the packet we expected - r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber - } else if pkt.Header().PacketSequenceNumber.Lte(r.maxSeenSequenceNumber) { - // Out of order, is it a missing piece? put it in the correct position - for e := r.packetList.Front(); e != nil; e = e.Next() { - p := e.Value.(packet.Packet) - - if p.Header().PacketSequenceNumber == pkt.Header().PacketSequenceNumber { - // Already received (has been sent more than once), ignoring - r.statistics.PktDrop++ - r.statistics.ByteDrop += pktLen - - break - } else if p.Header().PacketSequenceNumber.Gt(pkt.Header().PacketSequenceNumber) { - // Late arrival, this fills a gap - r.statistics.PktBuf++ - r.statistics.PktUnique++ - - r.statistics.ByteBuf += pktLen - r.statistics.ByteUnique += pktLen - - r.packetList.InsertBefore(pkt, e) - - break - } - } - - return - } else { - // Too far ahead, there are some missing sequence numbers, immediate NAK report - // here we can prevent a possibly unnecessary NAK with SRTO_LOXXMAXTTL - r.sendNAK(r.maxSeenSequenceNumber.Inc(), pkt.Header().PacketSequenceNumber.Dec()) - - len := uint64(pkt.Header().PacketSequenceNumber.Distance(r.maxSeenSequenceNumber)) - r.statistics.PktLoss += len - r.statistics.ByteLoss += len * uint64(r.avgPayloadSize) - - r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber - } - - r.statistics.PktBuf++ - r.statistics.PktUnique++ - - r.statistics.ByteBuf += pktLen - r.statistics.ByteUnique += pktLen - - r.packetList.PushBack(pkt) -} - -func (r *liveReceive) periodicACK(now uint64) (ok bool, sequenceNumber circular.Number, lite bool) { - r.lock.Lock() - defer r.lock.Unlock() - - // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) - if now-r.lastPeriodicACK < r.periodicACKInterval { - if r.nPackets >= 64 { - lite = true // Send light ACK - } else { - return - } - } - - minPktTsbpdTime, maxPktTsbpdTime := uint64(0), uint64(0) - - ackSequenceNumber := r.lastDeliveredSequenceNumber - - // Find the sequence number up until we have all in a row. - // Where the first gap is (or at the end of the list) is where we can ACK to. - - e := r.packetList.Front() - if e != nil { - p := e.Value.(packet.Packet) - - minPktTsbpdTime = p.Header().PktTsbpdTime - maxPktTsbpdTime = p.Header().PktTsbpdTime - - // If there are packets that should be delivered by now, move foward. - if p.Header().PktTsbpdTime <= now { - for e = e.Next(); e != nil; e = e.Next() { - p = e.Value.(packet.Packet) - - if p.Header().PktTsbpdTime > now { - break - } - } - - ackSequenceNumber = p.Header().PacketSequenceNumber - maxPktTsbpdTime = p.Header().PktTsbpdTime - - if e != nil { - if e = e.Next(); e != nil { - p = e.Value.(packet.Packet) - } - } - } - - if p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { - ackSequenceNumber = p.Header().PacketSequenceNumber - - for e = e.Next(); e != nil; e = e.Next() { - p = e.Value.(packet.Packet) - if !p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { - break - } - - ackSequenceNumber = p.Header().PacketSequenceNumber - maxPktTsbpdTime = p.Header().PktTsbpdTime - } - } - - ok = true - sequenceNumber = ackSequenceNumber.Inc() - - // Keep track of the last ACK's sequence. with this we can faster ignore - // packets that come in that have a lower sequence number. - r.lastACKSequenceNumber = ackSequenceNumber - } - - r.lastPeriodicACK = now - r.nPackets = 0 - - r.statistics.MsBuf = (maxPktTsbpdTime - minPktTsbpdTime) / 1_000 - - return -} - -func (r *liveReceive) periodicNAK(now uint64) (ok bool, from, to circular.Number) { - r.lock.RLock() - defer r.lock.RUnlock() - - if now-r.lastPeriodicNAK < r.periodicNAKInterval { - return - } - - // Send a periodic NAK - - ackSequenceNumber := r.lastDeliveredSequenceNumber - - // Send a NAK only for the first gap. - // Alternatively send a NAK for max. X gaps because the size of the NAK packet is limited. - for e := r.packetList.Front(); e != nil; e = e.Next() { - p := e.Value.(packet.Packet) - - if !p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { - nackSequenceNumber := ackSequenceNumber.Inc() - - ok = true - from = nackSequenceNumber - to = p.Header().PacketSequenceNumber.Dec() - - break - } - - ackSequenceNumber = p.Header().PacketSequenceNumber - } - - r.lastPeriodicNAK = now - - return -} - -func (r *liveReceive) Tick(now uint64) { - if ok, sequenceNumber, lite := r.periodicACK(now); ok { - r.sendACK(sequenceNumber, lite) - } - - if ok, from, to := r.periodicNAK(now); ok { - r.sendNAK(from, to) - } - - // Deliver packets whose PktTsbpdTime is ripe - r.lock.Lock() - removeList := make([]*list.Element, 0, r.packetList.Len()) - for e := r.packetList.Front(); e != nil; e = e.Next() { - p := e.Value.(packet.Packet) - - if p.Header().PacketSequenceNumber.Lte(r.lastACKSequenceNumber) && p.Header().PktTsbpdTime <= now { - r.statistics.PktBuf-- - r.statistics.ByteBuf -= p.Len() - - r.lastDeliveredSequenceNumber = p.Header().PacketSequenceNumber - - r.deliver(p) - removeList = append(removeList, e) - } else { - break - } - } - - for _, e := range removeList { - r.packetList.Remove(e) - } - r.lock.Unlock() - - r.lock.Lock() - tdiff := now - r.rate.last // microseconds - - if tdiff > r.rate.period { - r.rate.packetsPerSecond = float64(r.rate.packets) / (float64(tdiff) / 1000 / 1000) - r.rate.bytesPerSecond = float64(r.rate.bytes) / (float64(tdiff) / 1000 / 1000) - if r.rate.bytes != 0 { - r.rate.pktLossRate = float64(r.rate.bytesRetrans) / float64(r.rate.bytes) * 100 - } else { - r.rate.bytes = 0 - } - - r.rate.packets = 0 - r.rate.bytes = 0 - r.rate.bytesRetrans = 0 - - r.rate.last = now - } - r.lock.Unlock() -} - -func (r *liveReceive) SetNAKInterval(nakInterval uint64) { - r.lock.Lock() - defer r.lock.Unlock() - - r.periodicNAKInterval = nakInterval -} - -func (r *liveReceive) String(t uint64) string { - var b strings.Builder - - b.WriteString(fmt.Sprintf("maxSeen=%d lastACK=%d lastDelivered=%d\n", r.maxSeenSequenceNumber.Val(), r.lastACKSequenceNumber.Val(), r.lastDeliveredSequenceNumber.Val())) - - r.lock.RLock() - for e := r.packetList.Front(); e != nil; e = e.Next() { - p := e.Value.(packet.Packet) - - b.WriteString(fmt.Sprintf(" %d @ %d (in %d)\n", p.Header().PacketSequenceNumber.Val(), p.Header().PktTsbpdTime, int64(p.Header().PktTsbpdTime)-int64(t))) - } - r.lock.RUnlock() - - return b.String() -} - -type fakeLiveReceive struct { - maxSeenSequenceNumber circular.Number - lastACKSequenceNumber circular.Number - lastDeliveredSequenceNumber circular.Number - - nPackets uint - - periodicACKInterval uint64 // config - periodicNAKInterval uint64 // config - - lastPeriodicACK uint64 - - avgPayloadSize float64 // bytes - - rate struct { - last time.Time - period time.Duration - - packets uint64 - bytes uint64 - - pps float64 - bps float64 - } - - sendACK func(seq circular.Number, light bool) - sendNAK func(from, to circular.Number) - deliver func(p packet.Packet) - - lock sync.RWMutex -} - -func NewFakeLiveReceive(config ReceiveConfig) Receiver { - r := &fakeLiveReceive{ - maxSeenSequenceNumber: config.InitialSequenceNumber.Dec(), - lastACKSequenceNumber: config.InitialSequenceNumber.Dec(), - lastDeliveredSequenceNumber: config.InitialSequenceNumber.Dec(), - - periodicACKInterval: config.PeriodicACKInterval, - periodicNAKInterval: config.PeriodicNAKInterval, - - avgPayloadSize: 1456, // 5.1.2. SRT's Default LiveCC Algorithm - - sendACK: config.OnSendACK, - sendNAK: config.OnSendNAK, - deliver: config.OnDeliver, - } - - if r.sendACK == nil { - r.sendACK = func(seq circular.Number, light bool) {} - } - - if r.sendNAK == nil { - r.sendNAK = func(from, to circular.Number) {} - } - - if r.deliver == nil { - r.deliver = func(p packet.Packet) {} - } - - r.rate.last = time.Now() - r.rate.period = time.Second - - return r -} - -func (r *fakeLiveReceive) Stats() ReceiveStats { return ReceiveStats{} } -func (r *fakeLiveReceive) PacketRate() (pps, bps, capacity float64) { - r.lock.Lock() - defer r.lock.Unlock() - - tdiff := time.Since(r.rate.last) - - if tdiff < r.rate.period { - pps = r.rate.pps - bps = r.rate.bps - - return - } - - r.rate.pps = float64(r.rate.packets) / tdiff.Seconds() - r.rate.bps = float64(r.rate.bytes) / tdiff.Seconds() - - r.rate.packets, r.rate.bytes = 0, 0 - r.rate.last = time.Now() - - pps = r.rate.pps - bps = r.rate.bps - - return -} - -func (r *fakeLiveReceive) Flush() {} - -func (r *fakeLiveReceive) Push(pkt packet.Packet) { - r.lock.Lock() - defer r.lock.Unlock() - - if pkt == nil { - return - } - - r.nPackets++ - - pktLen := pkt.Len() - - r.rate.packets++ - r.rate.bytes += pktLen - - // 5.1.2. SRT's Default LiveCC Algorithm - r.avgPayloadSize = 0.875*r.avgPayloadSize + 0.125*float64(pktLen) - - if pkt.Header().PacketSequenceNumber.Lte(r.lastDeliveredSequenceNumber) { - // Too old, because up until r.lastDeliveredSequenceNumber, we already delivered - return - } - - if pkt.Header().PacketSequenceNumber.Lt(r.lastACKSequenceNumber) { - // Already acknowledged, ignoring - return - } - - if pkt.Header().PacketSequenceNumber.Lte(r.maxSeenSequenceNumber) { - return - } - - r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber -} - -func (r *fakeLiveReceive) periodicACK(now uint64) (ok bool, sequenceNumber circular.Number, lite bool) { - r.lock.RLock() - defer r.lock.RUnlock() - - // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) - if now-r.lastPeriodicACK < r.periodicACKInterval { - if r.nPackets >= 64 { - lite = true // Send light ACK - } else { - return - } - } - - ok = true - sequenceNumber = r.maxSeenSequenceNumber.Inc() - - r.lastACKSequenceNumber = r.maxSeenSequenceNumber - - r.lastPeriodicACK = now - r.nPackets = 0 - - return -} - -func (r *fakeLiveReceive) Tick(now uint64) { - if ok, sequenceNumber, lite := r.periodicACK(now); ok { - r.sendACK(sequenceNumber, lite) - } - - // Deliver packets whose PktTsbpdTime is ripe - r.lock.Lock() - defer r.lock.Unlock() - - r.lastDeliveredSequenceNumber = r.lastACKSequenceNumber -} - -func (r *fakeLiveReceive) SetNAKInterval(nakInterval uint64) { - r.lock.Lock() - defer r.lock.Unlock() - - r.periodicNAKInterval = nakInterval -} diff --git a/vendor/github.com/datarhei/gosrt/listen.go b/vendor/github.com/datarhei/gosrt/listen.go index c2ad21ff..1385f4ef 100644 --- a/vendor/github.com/datarhei/gosrt/listen.go +++ b/vendor/github.com/datarhei/gosrt/listen.go @@ -10,9 +10,9 @@ import ( "sync" "time" - "github.com/datarhei/gosrt/internal/crypto" - srtnet "github.com/datarhei/gosrt/internal/net" - "github.com/datarhei/gosrt/internal/packet" + "github.com/datarhei/gosrt/crypto" + srtnet "github.com/datarhei/gosrt/net" + "github.com/datarhei/gosrt/packet" ) // ConnType represents the kind of connection as returned @@ -39,6 +39,52 @@ const ( SUBSCRIBE // This connection is meant to read data from a PUBLISHed stream ) +// RejectionReason are the rejection reasons that can be returned from the AcceptFunc in order to send +// another reason than the default one (REJ_PEER) to the client. +type RejectionReason uint32 + +// Table 7: Handshake Rejection Reason Codes +const ( + REJ_UNKNOWN RejectionReason = 1000 // unknown reason + REJ_SYSTEM RejectionReason = 1001 // system function error + REJ_PEER RejectionReason = 1002 // rejected by peer + REJ_RESOURCE RejectionReason = 1003 // resource allocation problem + REJ_ROGUE RejectionReason = 1004 // incorrect data in handshake + REJ_BACKLOG RejectionReason = 1005 // listener's backlog exceeded + REJ_IPE RejectionReason = 1006 // internal program error + REJ_CLOSE RejectionReason = 1007 // socket is closing + REJ_VERSION RejectionReason = 1008 // peer is older version than agent's min + REJ_RDVCOOKIE RejectionReason = 1009 // rendezvous cookie collision + REJ_BADSECRET RejectionReason = 1010 // wrong password + REJ_UNSECURE RejectionReason = 1011 // password required or unexpected + REJ_MESSAGEAPI RejectionReason = 1012 // stream flag collision + REJ_CONGESTION RejectionReason = 1013 // incompatible congestion-controller type + REJ_FILTER RejectionReason = 1014 // incompatible packet filter + REJ_GROUP RejectionReason = 1015 // incompatible group +) + +// These are the extended rejection reasons that may be less well supported +// Codes & their meanings taken from https://github.com/Haivision/srt/blob/f477af533562505abf5295f059cf2156b17be740/srtcore/access_control.h +const ( + REJX_BAD_REQUEST RejectionReason = 1400 // General syntax error in the SocketID specification (also a fallback code for undefined cases) + REJX_UNAUTHORIZED RejectionReason = 1401 // Authentication failed, provided that the user was correctly identified and access to the required resource would be granted + REJX_OVERLOAD RejectionReason = 1402 // The server is too heavily loaded, or you have exceeded credits for accessing the service and the resource. + REJX_FORBIDDEN RejectionReason = 1403 // Access denied to the resource by any kind of reason. + REJX_NOTFOUND RejectionReason = 1404 // Resource not found at this time. + REJX_BAD_MODE RejectionReason = 1405 // The mode specified in `m` key in StreamID is not supported for this request. + REJX_UNACCEPTABLE RejectionReason = 1406 // The requested parameters specified in SocketID cannot be satisfied for the requested resource. Also when m=publish and the data format is not acceptable. + REJX_CONFLICT RejectionReason = 1407 // The resource being accessed is already locked for modification. This is in case of m=publish and the specified resource is currently read-only. + REJX_NOTSUP_MEDIA RejectionReason = 1415 // The media type is not supported by the application. This is the `t` key that specifies the media type as stream, file and auth, possibly extended by the application. + REJX_LOCKED RejectionReason = 1423 // The resource being accessed is locked for any access. + REJX_FAILED_DEPEND RejectionReason = 1424 // The request failed because it specified a dependent session ID that has been disconnected. + REJX_ISE RejectionReason = 1500 // Unexpected internal server error + REJX_UNIMPLEMENTED RejectionReason = 1501 // The request was recognized, but the current version doesn't support it. + REJX_GW RejectionReason = 1502 // The server acts as a gateway and the target endpoint rejected the connection. + REJX_DOWN RejectionReason = 1503 // The service has been temporarily taken over by a stub reporting this error. The real service can be down for maintenance or crashed. + REJX_VERSION RejectionReason = 1505 // SRT version not supported. This might be either unsupported backward compatibility, or an upper value of a version. + REJX_NOROOM RejectionReason = 1507 // The data stream cannot be archived due to lacking storage space. This is in case when the request type was to send a file or the live stream to be archived. +) + // ConnRequest is an incoming connection request type ConnRequest interface { // RemoteAddr returns the address of the peer. The returned net.Addr @@ -63,6 +109,10 @@ type ConnRequest interface { // data. Returns an error if the passphrase did not work or the connection // is not encrypted. SetPassphrase(p string) error + + // SetRejectionReason sets the rejection reason for the connection. If + // no set, REJ_PEER will be used. + SetRejectionReason(r RejectionReason) } // connRequest implements the ConnRequest interface @@ -72,9 +122,11 @@ type connRequest struct { socketId uint32 timestamp uint32 - handshake *packet.CIFHandshake - crypto crypto.Crypto - passphrase string + config Config + handshake *packet.CIFHandshake + crypto crypto.Crypto + passphrase string + rejectionReason RejectionReason } func (req *connRequest) RemoteAddr() net.Addr { @@ -110,6 +162,10 @@ func (req *connRequest) SetPassphrase(passphrase string) error { return nil } +func (req *connRequest) SetRejectionReason(reason RejectionReason) { + req.rejectionReason = reason +} + // ErrListenerClosed is returned when the listener is about to shutdown. var ErrListenerClosed = errors.New("srt: listener closed") @@ -148,7 +204,9 @@ type listener struct { start time.Time rcvQueue chan packet.Packet - sndQueue chan packet.Packet + + sndMutex sync.Mutex + sndData bytes.Buffer syncookie *srtnet.SYNCookie @@ -157,9 +215,10 @@ type listener struct { shutdownOnce sync.Once stopReader context.CancelFunc - stopWriter context.CancelFunc - doneChan chan error + doneChan chan struct{} + doneErr error + doneOnce sync.Once } // Listen returns a new listener on the SRT protocol on the address with @@ -202,21 +261,24 @@ func Listen(network, address string, config Config) (Listener, error) { ln.pc = pc ln.addr = pc.LocalAddr() + if ln.addr == nil { + return nil, fmt.Errorf("listen: no local address") + } ln.conns = make(map[uint32]*srtConn) ln.backlog = make(chan connRequest, 128) ln.rcvQueue = make(chan packet.Packet, 2048) - ln.sndQueue = make(chan packet.Packet, 2048) - ln.syncookie, err = srtnet.NewSYNCookie(ln.addr.String(), nil) + syncookie, err := srtnet.NewSYNCookie(ln.addr.String(), nil) if err != nil { ln.Close() return nil, err } + ln.syncookie = syncookie - ln.doneChan = make(chan error) + ln.doneChan = make(chan struct{}) ln.start = time.Now() @@ -224,16 +286,12 @@ func Listen(network, address string, config Config) (Listener, error) { readerCtx, ln.stopReader = context.WithCancel(context.Background()) go ln.reader(readerCtx) - var writerCtx context.Context - writerCtx, ln.stopWriter = context.WithCancel(context.Background()) - go ln.writer(writerCtx) - go func() { buffer := make([]byte, config.MSS) // MTU size for { if ln.isShutdown() { - ln.doneChan <- ErrListenerClosed + ln.markDone(ErrListenerClosed) return } @@ -245,16 +303,16 @@ func Listen(network, address string, config Config) (Listener, error) { } if ln.isShutdown() { - ln.doneChan <- ErrListenerClosed + ln.markDone(ErrListenerClosed) return } - ln.doneChan <- err + ln.markDone(err) return } - p := packet.NewPacket(addr, buffer[:n]) - if p == nil { + p, err := packet.NewPacketFromData(addr, buffer[:n]) + if err != nil { continue } @@ -276,22 +334,27 @@ func (ln *listener) Accept(acceptFn AcceptFunc) (Conn, ConnType, error) { } select { - case err := <-ln.doneChan: - return nil, REJECT, err + case <-ln.doneChan: + return nil, REJECT, ln.error() case request := <-ln.backlog: if acceptFn == nil { - ln.reject(request, packet.REJ_PEER) + ln.reject(request, REJ_PEER) break } mode := acceptFn(&request) if mode != PUBLISH && mode != SUBSCRIBE { - ln.reject(request, packet.REJ_PEER) + // Figure out the reason + reason := REJ_PEER + if request.rejectionReason > 0 { + reason = request.rejectionReason + } + ln.reject(request, reason) break } if request.crypto != nil && len(request.passphrase) == 0 { - ln.reject(request, packet.REJ_BADSECRET) + ln.reject(request, REJ_BADSECRET) break } @@ -299,8 +362,8 @@ func (ln *listener) Accept(acceptFn AcceptFunc) (Conn, ConnType, error) { socketId := uint32(time.Since(ln.start).Microseconds()) // Select the largest TSBPD delay advertised by the caller, but at least 120ms - recvTsbpdDelay := uint16(ln.config.ReceiverLatency.Milliseconds()) - sendTsbpdDelay := uint16(ln.config.PeerLatency.Milliseconds()) + recvTsbpdDelay := uint16(request.config.ReceiverLatency.Milliseconds()) + sendTsbpdDelay := uint16(request.config.PeerLatency.Milliseconds()) if request.handshake.Version == 5 { if request.handshake.SRTHS.SendTSBPDDelay > recvTsbpdDelay { @@ -311,17 +374,17 @@ func (ln *listener) Accept(acceptFn AcceptFunc) (Conn, ConnType, error) { sendTsbpdDelay = request.handshake.SRTHS.RecvTSBPDDelay } - ln.config.StreamId = request.handshake.StreamId + request.config.StreamId = request.handshake.StreamId } - ln.config.Passphrase = request.passphrase + request.config.Passphrase = request.passphrase // Create a new connection conn := newSRTConn(srtConnConfig{ version: request.handshake.Version, localAddr: ln.addr, remoteAddr: request.addr, - config: ln.config, + config: request.config, start: request.start, socketId: socketId, peerSocketId: request.handshake.SRTSocketId, @@ -333,7 +396,7 @@ func (ln *listener) Accept(acceptFn AcceptFunc) (Conn, ConnType, error) { keyBaseEncryption: packet.EvenKeyEncrypted, onSend: ln.send, onShutdown: ln.handleShutdown, - logger: ln.config.Logger, + logger: request.config.Logger, }) ln.log("connection:new", func() string { return fmt.Sprintf("%#08x (%s) %s", conn.SocketId(), conn.StreamId(), mode) }) @@ -369,14 +432,33 @@ func (ln *listener) Accept(acceptFn AcceptFunc) (Conn, ConnType, error) { return nil, REJECT, nil } +// markDone marks the listener as done by closing +// the done channel & sets the error +func (ln *listener) markDone(err error) { + ln.doneOnce.Do(func() { + ln.lock.Lock() + defer ln.lock.Unlock() + ln.doneErr = err + close(ln.doneChan) + }) +} + +// error returns the error that caused the listener to be done +// if it's nil then the listener is not done +func (ln *listener) error() error { + ln.lock.Lock() + defer ln.lock.Unlock() + return ln.doneErr +} + func (ln *listener) handleShutdown(socketId uint32) { ln.lock.Lock() delete(ln.conns, socketId) ln.lock.Unlock() } -func (ln *listener) reject(request connRequest, reason packet.HandshakeType) { - p := packet.NewPacket(request.addr, nil) +func (ln *listener) reject(request connRequest, reason RejectionReason) { + p := packet.NewPacket(request.addr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE @@ -386,7 +468,7 @@ func (ln *listener) reject(request connRequest, reason packet.HandshakeType) { p.Header().Timestamp = uint32(time.Since(ln.start).Microseconds()) p.Header().DestinationSocketId = request.socketId - request.handshake.HandshakeType = reason + request.handshake.HandshakeType = packet.HandshakeType(reason) p.MarshalCIF(request.handshake) @@ -397,7 +479,7 @@ func (ln *listener) reject(request connRequest, reason packet.HandshakeType) { } func (ln *listener) accept(request connRequest) { - p := packet.NewPacket(request.addr, nil) + p := packet.NewPacket(request.addr) p.Header().IsControlPacket = true @@ -436,7 +518,6 @@ func (ln *listener) Close() { ln.lock.RUnlock() ln.stopReader() - ln.stopWriter() ln.log("listen", func() string { return "closing socket" }) @@ -445,7 +526,12 @@ func (ln *listener) Close() { } func (ln *listener) Addr() net.Addr { - addr, _ := net.ResolveUDPAddr("udp", ln.addr.String()) + addrString := "0.0.0.0:0" + if ln.addr != nil { + addrString = ln.addr.String() + } + + addr, _ := net.ResolveUDPAddr("udp", addrString) return addr } @@ -489,49 +575,29 @@ func (ln *listener) reader(ctx context.Context) { } } +// Send a packet to the wire. This function must be synchronous in order to allow to safely call Packet.Decommission() afterward. func (ln *listener) send(p packet.Packet) { - // non-blocking - select { - case ln.sndQueue <- p: - default: - ln.log("listen", func() string { return "send queue is full" }) + ln.sndMutex.Lock() + defer ln.sndMutex.Unlock() + + ln.sndData.Reset() + + if err := p.Marshal(&ln.sndData); err != nil { + p.Decommission() + ln.log("packet:send:error", func() string { return "marshalling packet failed" }) + return } -} -func (ln *listener) writer(ctx context.Context) { - defer func() { - ln.log("listen", func() string { return "left writer loop" }) - }() + buffer := ln.sndData.Bytes() - ln.log("listen", func() string { return "writer loop started" }) + ln.log("packet:send:dump", func() string { return p.Dump() }) - var data bytes.Buffer + // Write the packet's contents to the wire + ln.pc.WriteTo(buffer, p.Header().Addr) - for { - select { - case <-ctx.Done(): - return - case p := <-ln.sndQueue: - data.Reset() - - if err := p.Marshal(&data); err != nil { - p.Decommission() - ln.log("packet:send:error", func() string { return "marshalling packet failed" }) - continue - } - - buffer := data.Bytes() - - ln.log("packet:send:dump", func() string { return p.Dump() }) - - // Write the packet's contents to the wire - ln.pc.WriteTo(buffer, p.Header().Addr) - - if p.Header().IsControlPacket { - // Control packets can be decommissioned because they will not be sent again (data packets might be retransferred) - p.Decommission() - } - } + if p.Header().IsControlPacket { + // Control packets can be decommissioned because they will not be sent again (data packets might be retransferred) + p.Decommission() } } @@ -558,6 +624,9 @@ func (ln *listener) handleHandshake(p packet.Packet) { cif.PeerIP.FromNetAddr(ln.addr) + // Create a copy of the configuration for the connection + config := ln.config + if cif.HandshakeType == packet.HSTYPE_INDUCTION { // cif cif.Version = 5 @@ -578,7 +647,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { } else if cif.HandshakeType == packet.HSTYPE_CONCLUSION { // Verify the SYN cookie if !ln.syncookie.Verify(cif.SynCookie, p.Header().Addr.String()) { - cif.HandshakeType = packet.REJ_ROGUE + cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return "invalid SYN cookie" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -590,7 +659,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { // Peer is advertising a too big MSS if cif.MaxTransmissionUnitSize > MAX_MSS_SIZE { - cif.HandshakeType = packet.REJ_ROGUE + cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("MTU is too big (%d bytes)", cif.MaxTransmissionUnitSize) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -601,13 +670,13 @@ func (ln *listener) handleHandshake(p packet.Packet) { } // If the peer has a smaller MTU size, adjust to it - if cif.MaxTransmissionUnitSize < ln.config.MSS { - ln.config.MSS = cif.MaxTransmissionUnitSize - ln.config.PayloadSize = ln.config.MSS - SRT_HEADER_SIZE - UDP_HEADER_SIZE + if cif.MaxTransmissionUnitSize < config.MSS { + config.MSS = cif.MaxTransmissionUnitSize + config.PayloadSize = config.MSS - SRT_HEADER_SIZE - UDP_HEADER_SIZE - if ln.config.PayloadSize < MIN_PAYLOAD_SIZE { - cif.HandshakeType = packet.REJ_ROGUE - ln.log("handshake:recv:error", func() string { return fmt.Sprintf("payload size is too small (%d bytes)", ln.config.PayloadSize) }) + if config.PayloadSize < MIN_PAYLOAD_SIZE { + cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) + ln.log("handshake:recv:error", func() string { return fmt.Sprintf("payload size is too small (%d bytes)", config.PayloadSize) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) @@ -619,7 +688,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { if cif.Version == 4 { // Check if the type (encryption field + extension field) has the value 2 if cif.EncryptionField != 0 || cif.ExtensionField != 2 { - cif.HandshakeType = packet.REJ_ROGUE + cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return "invalid type, expecting a value of 2 (UDT_DGRAM)" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -630,10 +699,10 @@ func (ln *listener) handleHandshake(p packet.Packet) { } } else if cif.Version == 5 { // Check if the peer version is sufficient - if cif.SRTHS.SRTVersion < ln.config.MinVersion { - cif.HandshakeType = packet.REJ_VERSION + if cif.SRTHS.SRTVersion < config.MinVersion { + cif.HandshakeType = packet.HandshakeType(REJ_VERSION) ln.log("handshake:recv:error", func() string { - return fmt.Sprintf("peer version insufficient (%#06x), expecting at least %#06x", cif.SRTHS.SRTVersion, ln.config.MinVersion) + return fmt.Sprintf("peer version insufficient (%#06x), expecting at least %#06x", cif.SRTHS.SRTVersion, config.MinVersion) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -645,7 +714,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { // Check the required SRT flags if !cif.SRTHS.SRTFlags.TSBPDSND || !cif.SRTHS.SRTFlags.TSBPDRCV || !cif.SRTHS.SRTFlags.TLPKTDROP || !cif.SRTHS.SRTFlags.PERIODICNAK || !cif.SRTHS.SRTFlags.REXMITFLG { - cif.HandshakeType = packet.REJ_ROGUE + cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return "not all required flags are set" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -657,7 +726,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { // We only support live streaming if cif.SRTHS.SRTFlags.STREAM { - cif.HandshakeType = packet.REJ_MESSAGEAPI + cif.HandshakeType = packet.HandshakeType(REJ_MESSAGEAPI) ln.log("handshake:recv:error", func() string { return "only live streaming is supported" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -667,7 +736,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { return } } else { - cif.HandshakeType = packet.REJ_ROGUE + cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("only HSv4 and HSv5 are supported (got HSv%d)", cif.Version) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -684,6 +753,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { start: time.Now(), socketId: cif.SRTSocketId, timestamp: p.Header().Timestamp, + config: config, handshake: cif, } @@ -691,7 +761,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { if cif.SRTKM != nil { cr, err := crypto.New(int(cif.SRTKM.KLen)) if err != nil { - cif.HandshakeType = packet.REJ_ROGUE + cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("crypto: %s", err) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -708,7 +778,7 @@ func (ln *listener) handleHandshake(p packet.Packet) { select { case ln.backlog <- c: default: - cif.HandshakeType = packet.REJ_BACKLOG + cif.HandshakeType = packet.HandshakeType(REJ_BACKLOG) ln.log("handshake:recv:error", func() string { return "backlog is full" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) @@ -725,5 +795,9 @@ func (ln *listener) handleHandshake(p packet.Packet) { } func (ln *listener) log(topic string, message func() string) { + if ln.config.Logger == nil { + return + } + ln.config.Logger.Print(topic, 0, 2, message) } diff --git a/vendor/github.com/datarhei/gosrt/internal/net/ip.go b/vendor/github.com/datarhei/gosrt/net/ip.go similarity index 77% rename from vendor/github.com/datarhei/gosrt/internal/net/ip.go rename to vendor/github.com/datarhei/gosrt/net/ip.go index 32dd5faa..c5303c4e 100644 --- a/vendor/github.com/datarhei/gosrt/internal/net/ip.go +++ b/vendor/github.com/datarhei/gosrt/net/ip.go @@ -12,11 +12,11 @@ type IP struct { } func (i *IP) setDefault() { - i.ip = net.ParseIP("127.0.0.1") + i.ip = net.IPv4(127, 0, 0, 1) } func (i *IP) isValid() bool { - if i.ip.String() == "" || i.ip.IsUnspecified() { + if i.ip == nil || i.ip.String() == "" || i.ip.IsUnspecified() { return false } @@ -24,11 +24,22 @@ func (i *IP) isValid() bool { } func (i IP) String() string { + if i.ip == nil { + return "" + } + return i.ip.String() } func (i *IP) Parse(ip string) { - i.ip = net.ParseIP(ip) + i.setDefault() + + iip := net.ParseIP(ip) + if iip == nil { + return + } + + i.ip = iip if !i.isValid() { i.setDefault() @@ -36,7 +47,16 @@ func (i *IP) Parse(ip string) { } func (i *IP) FromNetIP(ip net.IP) { - i.ip = net.ParseIP(ip.String()) + if ip == nil { + return + } + + iip := net.ParseIP(ip.String()) + if iip == nil { + return + } + + i.ip = iip if !i.isValid() { i.setDefault() @@ -44,12 +64,22 @@ func (i *IP) FromNetIP(ip net.IP) { } func (i *IP) FromNetAddr(addr net.Addr) { + if addr == nil { + i.setDefault() + return + } + if addr.Network() != "udp" { i.setDefault() + return } if a, err := net.ResolveUDPAddr("udp", addr.String()); err == nil { - i.ip = a.IP + if a == nil || a.IP == nil { + i.setDefault() + } else { + i.ip = a.IP + } } else { i.setDefault() } @@ -85,7 +115,12 @@ func (i *IP) Unmarshal(data []byte) error { fmt.Fprintf(&b, "%04x:", (ip3&0xffff0000)>>16) fmt.Fprintf(&b, "%04x", ip3&0x0000ffff) - i.ip = net.ParseIP(b.String()) + iip := net.ParseIP(b.String()) + if iip == nil { + return fmt.Errorf("invalid ip") + } + + i.ip = iip } } @@ -98,6 +133,14 @@ func (i *IP) Unmarshal(data []byte) error { // Marshal converts an IP to 16 byte host byte order func (i *IP) Marshal(data []byte) { + if i.ip == nil || !i.isValid() { + i.setDefault() + } + + if len([]byte(i.ip)) == 4 { + i.ip = net.IPv4(i.ip[0], i.ip[1], i.ip[2], i.ip[3]) + } + if len(data) < 16 { return } diff --git a/vendor/github.com/datarhei/gosrt/internal/net/syncookie.go b/vendor/github.com/datarhei/gosrt/net/syncookie.go similarity index 82% rename from vendor/github.com/datarhei/gosrt/internal/net/syncookie.go rename to vendor/github.com/datarhei/gosrt/net/syncookie.go index 3b2cad01..cc746857 100644 --- a/vendor/github.com/datarhei/gosrt/internal/net/syncookie.go +++ b/vendor/github.com/datarhei/gosrt/net/syncookie.go @@ -6,9 +6,10 @@ import ( "strconv" "time" - "github.com/datarhei/gosrt/internal/rand" + "github.com/datarhei/gosrt/rand" ) +// SYNCookie implements a syn cookie for the SRT handshake. type SYNCookie struct { secret1 string secret2 string @@ -20,6 +21,7 @@ func defaultCounter() int64 { return time.Now().Unix() >> 6 } +// NewSYNCookie returns a SYNCookie for a destination address. func NewSYNCookie(daddr string, counter func() int64) (*SYNCookie, error) { s := &SYNCookie{ daddr: daddr, @@ -44,10 +46,12 @@ func NewSYNCookie(daddr string, counter func() int64) (*SYNCookie, error) { return s, nil } +// Get returns the current syn cookie with a sender address. func (s *SYNCookie) Get(saddr string) uint32 { return s.calculate(s.counter(), saddr) } +// Verify verfies that two syn cookies relate. func (s *SYNCookie) Verify(cookie uint32, saddr string) bool { counter := s.counter() diff --git a/vendor/github.com/datarhei/gosrt/internal/packet/packet.go b/vendor/github.com/datarhei/gosrt/packet/packet.go similarity index 94% rename from vendor/github.com/datarhei/gosrt/internal/packet/packet.go rename to vendor/github.com/datarhei/gosrt/packet/packet.go index 940759f6..a03018bd 100644 --- a/vendor/github.com/datarhei/gosrt/internal/packet/packet.go +++ b/vendor/github.com/datarhei/gosrt/packet/packet.go @@ -9,11 +9,12 @@ import ( "io" "net" "sort" + "strconv" "strings" "sync" - "github.com/datarhei/gosrt/internal/circular" - srtnet "github.com/datarhei/gosrt/internal/net" + "github.com/datarhei/gosrt/circular" + srtnet "github.com/datarhei/gosrt/net" ) const MAX_SEQUENCENUMBER uint32 = 0b01111111_11111111_11111111_11111111 @@ -78,26 +79,6 @@ const ( HSTYPE_INDUCTION HandshakeType = 0x00000001 ) -// Table 7: Handshake Rejection Reason Codes -const ( - REJ_UNKNOWN HandshakeType = 1000 - REJ_SYSTEM HandshakeType = 1001 - REJ_PEER HandshakeType = 1002 - REJ_RESOURCE HandshakeType = 1003 - REJ_ROGUE HandshakeType = 1004 - REJ_BACKLOG HandshakeType = 1005 - REJ_IPE HandshakeType = 1006 - REJ_CLOSE HandshakeType = 1007 - REJ_VERSION HandshakeType = 1008 - REJ_RDVCOOKIE HandshakeType = 1009 - REJ_BADSECRET HandshakeType = 1010 - REJ_UNSECURE HandshakeType = 1011 - REJ_MESSAGEAPI HandshakeType = 1012 - REJ_CONGESTION HandshakeType = 1013 - REJ_FILTER HandshakeType = 1014 - REJ_GROUP HandshakeType = 1015 -) - func (h HandshakeType) String() string { switch h { case HSTYPE_DONE: @@ -110,45 +91,9 @@ func (h HandshakeType) String() string { return "WAVEHAND" case HSTYPE_INDUCTION: return "INDUCTION" - case REJ_UNKNOWN: - return "REJ_UNKNOWN (unknown reason)" - case REJ_SYSTEM: - return "REJ_SYSTEM (system function error)" - case REJ_PEER: - return "REJ_PEER (rejected by peer)" - case REJ_RESOURCE: - return "REJ_RESOURCE (resource allocation problem)" - case REJ_ROGUE: - return "REJ_ROGUE (incorrect data in handshake)" - case REJ_BACKLOG: - return "REJ_BACKLOG (listener's backlog exceeded)" - case REJ_IPE: - return "REJ_IPE (internal program error)" - case REJ_CLOSE: - return "REJ_CLOSE (socket is closing)" - case REJ_VERSION: - return "REJ_VERSION (peer is older version than agent's min)" - case REJ_RDVCOOKIE: - return "REJ_RDVCOOKIE (rendezvous cookie collision)" - case REJ_BADSECRET: - return "REJ_BADSECRET (wrong password)" - case REJ_UNSECURE: - return "REJ_UNSECURE (password required or unexpected)" - case REJ_MESSAGEAPI: - return "REJ_MESSAGEAPI (stream flag collision)" - case REJ_CONGESTION: - return "REJ_CONGESTION (incompatible congestion-controller type)" - case REJ_FILTER: - return "REJ_FILTER (incompatible packet filter)" - case REJ_GROUP: - return "REJ_GROUP (incompatible group)" } - return "unknown" -} - -func (h HandshakeType) IsUnknown() bool { - return h.String() == "unknown" + return "REJECT (" + strconv.FormatUint(uint64(h), 32) + ")" } func (h HandshakeType) IsHandshake() bool { @@ -166,13 +111,7 @@ func (h HandshakeType) IsHandshake() bool { } func (h HandshakeType) IsRejection() bool { - if h.IsUnknown() { - return false - } else if h.IsHandshake() { - return false - } - - return true + return !h.IsHandshake() } func (h HandshakeType) Val() uint32 { @@ -236,17 +175,44 @@ func (h CtrlSubType) Value() uint16 { } type Packet interface { + // String returns a string representation of the packet. String() string + + // Clone clones a packet. Clone() Packet + + // Header returns a pointer to the packet header. Header() *PacketHeader + + // Data returns the payload the packets holds. The packets stays the + // owner of the data, i.e. modifying the returned data will also + // modify the payload. Data() []byte + + // SetData replaces the payload of the packet with the provided one. SetData([]byte) + + // Len return the length of the payload in the packet. Len() uint64 - Unmarshal(data []byte) error + + // Marshal writes the bytes representation of the packet to the provided writer. Marshal(w io.Writer) error + + // Unmarshal parses the given data into the packet header and its payload. Returns an error on failure. + Unmarshal(data []byte) error + + // Dump returns the same as String with an additional hex-dump of the marshalled packet. Dump() string + + // MarshalCIF writes the byte representation of a control information field as payload + // of the packet. Only for control packets. MarshalCIF(c CIF) + + // UnmarshalCIF parses the payload into a control information field struct. Returns an error + // on failure. UnmarshalCIF(c CIF) error + + // Decommission frees the payload. The packet shouldn't be uses afterwards. Decommission() } @@ -311,7 +277,20 @@ func (p *pool) Put(b *bytes.Buffer) { var payloadPool *pool = newPool() -func NewPacket(addr net.Addr, rawdata []byte) Packet { +func NewPacketFromData(addr net.Addr, rawdata []byte) (Packet, error) { + p := NewPacket(addr) + + if len(rawdata) != 0 { + if err := p.Unmarshal(rawdata); err != nil { + p.Decommission() + return nil, fmt.Errorf("invalid data: %w", err) + } + } + + return p, nil +} + +func NewPacket(addr net.Addr) Packet { p := &pkt{ header: PacketHeader{ Addr: addr, @@ -324,13 +303,6 @@ func NewPacket(addr net.Addr, rawdata []byte) Packet { payload: payloadPool.Get(), } - if len(rawdata) != 0 { - if err := p.Unmarshal(rawdata); err != nil { - p.Decommission() - return nil - } - } - return p } @@ -424,6 +396,10 @@ func (p *pkt) Unmarshal(data []byte) error { } func (p *pkt) Marshal(w io.Writer) error { + if w == nil { + return fmt.Errorf("invalid writer") + } + var buffer [16]byte if p.payload == nil { @@ -488,14 +464,21 @@ func (p *pkt) UnmarshalCIF(c CIF) error { return c.Unmarshal(p.payload.Bytes()) } +// CIF reepresents a control information field type CIF interface { + // Marshal writes a byte representation of the CIF to the provided writer. Marshal(w io.Writer) + + // Unmarshal parses the provided bytes into the CIF. Returns a non nil error of failure. Unmarshal(data []byte) error + + // String returns a string representation of the CIF. String() string } // 3.2.1. Handshake +// CIFHandshake represents the SRT handshake messages. type CIFHandshake struct { IsRequest bool @@ -685,6 +668,10 @@ func (c *CIFHandshake) Unmarshal(data []byte) error { } func (c *CIFHandshake) Marshal(w io.Writer) { + if w == nil { + return + } + var buffer [128]byte if len(c.StreamId) == 0 { @@ -789,6 +776,8 @@ func (c *CIFHandshake) Marshal(w io.Writer) { } // 3.2.1.1.1. Handshake Extension Message Flags + +// CIFHandshakeExtensionFlags represents the Handshake Extension Message Flags type CIFHandshakeExtensionFlags struct { TSBPDSND bool // Defines if the TSBPD mechanism (Section 4.5) will be used for sending. TSBPDRCV bool // Defines if the TSBPD mechanism (Section 4.5) will be used for receiving. @@ -802,6 +791,7 @@ type CIFHandshakeExtensionFlags struct { // 3.2.1.1. Handshake Extension Message +// CIFHandshakeExtension represents the Handshake Extension Message type CIFHandshakeExtension struct { SRTVersion uint32 SRTFlags CIFHandshakeExtensionFlags @@ -856,6 +846,10 @@ func (c *CIFHandshakeExtension) Unmarshal(data []byte) error { } func (c *CIFHandshakeExtension) Marshal(w io.Writer) { + if w == nil { + return + } + var buffer [12]byte binary.BigEndian.PutUint32(buffer[0:], c.SRTVersion) @@ -907,6 +901,8 @@ const ( KM_BADSECRET uint32 = 4 ) +// CIFKeyMaterialExtension represents the Key Material message. It is used as part of +// the v5 handshake or on its own after a v4 handshake. type CIFKeyMaterialExtension struct { Error uint32 S uint8 // This is a fixed-width field that is reserved for future usage. value = {0} @@ -1050,6 +1046,10 @@ func (c *CIFKeyMaterialExtension) Unmarshal(data []byte) error { } func (c *CIFKeyMaterialExtension) Marshal(w io.Writer) { + if w == nil { + return + } + var buffer [128]byte b := byte(0) @@ -1093,6 +1093,7 @@ func (c *CIFKeyMaterialExtension) Marshal(w io.Writer) { // 3.2.4. ACK (Acknowledgment) +// CIFACK represents an ACK message. type CIFACK struct { IsLite bool IsSmall bool @@ -1170,6 +1171,10 @@ func (c *CIFACK) Unmarshal(data []byte) error { } func (c *CIFACK) Marshal(w io.Writer) { + if w == nil { + return + } + var buffer [28]byte binary.BigEndian.PutUint32(buffer[0:], c.LastACKPacketSequenceNumber.Val()) @@ -1191,6 +1196,7 @@ func (c *CIFACK) Marshal(w io.Writer) { // 3.2.5. NAK (Loss Report) +// CIFNAK represents a NAK message type CIFNAK struct { LostPacketSequenceNumber []circular.Number } @@ -1257,6 +1263,10 @@ func (c *CIFNAK) Unmarshal(data []byte) error { } func (c *CIFNAK) Marshal(w io.Writer) { + if w == nil { + return + } + if len(c.LostPacketSequenceNumber)%2 != 0 { return } @@ -1279,6 +1289,7 @@ func (c *CIFNAK) Marshal(w io.Writer) { // 3.2.7. Shutdown +// CIFShutdown represents a shutdown message. type CIFShutdown struct{} func (c CIFShutdown) String() string { @@ -1294,6 +1305,10 @@ func (c *CIFShutdown) Unmarshal(data []byte) error { } func (c *CIFShutdown) Marshal(w io.Writer) { + if w == nil { + return + } + var buffer [4]byte binary.BigEndian.PutUint32(buffer[0:], 0) diff --git a/vendor/github.com/datarhei/gosrt/pubsub.go b/vendor/github.com/datarhei/gosrt/pubsub.go index 2e37a6f0..6cccd672 100644 --- a/vendor/github.com/datarhei/gosrt/pubsub.go +++ b/vendor/github.com/datarhei/gosrt/pubsub.go @@ -6,7 +6,7 @@ import ( "io" "sync" - "github.com/datarhei/gosrt/internal/packet" + "github.com/datarhei/gosrt/packet" ) // PubSub is a publish/subscriber service for SRT connections. @@ -23,11 +23,6 @@ type PubSub interface { Subscribe(c Conn) error } -type packetReadWriter interface { - readPacket() (packet.Packet, error) - writePacket(p packet.Packet) error -} - // pubSub is an implementation of the PubSub interface type pubSub struct { incoming chan packet.Packet @@ -107,12 +102,6 @@ func (pb *pubSub) Publish(c Conn) error { var p packet.Packet var err error - conn, ok := c.(packetReadWriter) - if !ok { - err := fmt.Errorf("the provided connection is not a SRT connection") - pb.logger.Print("pubsub:error", 0, 1, func() string { return err.Error() }) - return err - } socketId := c.SocketId() @@ -121,7 +110,7 @@ func (pb *pubSub) Publish(c Conn) error { pb.publish = true for { - p, err = conn.readPacket() + p, err = c.ReadPacket() if err != nil { pb.logger.Print("pubsub:error", socketId, 1, func() string { return err.Error() }) break @@ -142,12 +131,6 @@ func (pb *pubSub) Publish(c Conn) error { func (pb *pubSub) Subscribe(c Conn) error { l := make(chan packet.Packet, 1024) socketId := c.SocketId() - conn, ok := c.(packetReadWriter) - if !ok { - err := fmt.Errorf("the provided connection is not a SRT connection") - pb.logger.Print("pubsub:error", 0, 1, func() string { return err.Error() }) - return err - } pb.logger.Print("pubsub:subscribe", socketId, 1, func() string { return "new subscriber" }) @@ -166,7 +149,7 @@ func (pb *pubSub) Subscribe(c Conn) error { case <-pb.ctx.Done(): return io.EOF case p := <-l: - err := conn.writePacket(p) + err := c.WritePacket(p) p.Decommission() if err != nil { pb.logger.Print("pubsub:error", socketId, 1, func() string { return err.Error() }) diff --git a/vendor/github.com/datarhei/gosrt/internal/rand/rand.go b/vendor/github.com/datarhei/gosrt/rand/rand.go similarity index 95% rename from vendor/github.com/datarhei/gosrt/internal/rand/rand.go rename to vendor/github.com/datarhei/gosrt/rand/rand.go index e7504589..0f354943 100644 --- a/vendor/github.com/datarhei/gosrt/internal/rand/rand.go +++ b/vendor/github.com/datarhei/gosrt/rand/rand.go @@ -18,6 +18,10 @@ func RandomString(length int, charset string) (string, error) { return string(b), nil } +func Read(b []byte) (int, error) { + return rand.Read(b) +} + func Uint32() (uint32, error) { var b [4]byte _, err := rand.Read(b[:]) diff --git a/vendor/github.com/datarhei/joy4/av/av.go b/vendor/github.com/datarhei/joy4/av/av.go index df997262..5c038230 100644 --- a/vendor/github.com/datarhei/joy4/av/av.go +++ b/vendor/github.com/datarhei/joy4/av/av.go @@ -116,6 +116,9 @@ type CodecType uint32 var ( H264 = MakeVideoCodecType(avCodecTypeMagic + 1) + HEVC = MakeVideoCodecType(avCodecTypeMagic + 2) + VP9 = MakeVideoCodecType(avCodecTypeMagic + 3) + AV1 = MakeVideoCodecType(avCodecTypeMagic + 4) AAC = MakeAudioCodecType(avCodecTypeMagic + 1) PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2) PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3) @@ -126,10 +129,16 @@ var ( const codecTypeAudioBit = 0x1 const codecTypeOtherBits = 1 -func (self CodecType) String() string { - switch self { +func (c CodecType) String() string { + switch c { case H264: return "H264" + case HEVC: + return "HEVC" + case VP9: + return "VP9" + case AV1: + return "AV1" case AAC: return "AAC" case PCM_MULAW: @@ -144,12 +153,12 @@ func (self CodecType) String() string { return "" } -func (self CodecType) IsAudio() bool { - return self&codecTypeAudioBit != 0 +func (c CodecType) IsAudio() bool { + return c&codecTypeAudioBit != 0 } -func (self CodecType) IsVideo() bool { - return self&codecTypeAudioBit == 0 +func (c CodecType) IsVideo() bool { + return c&codecTypeAudioBit == 0 } // Make a new audio codec type. @@ -169,7 +178,7 @@ const avCodecTypeMagic = 233333 // CodecData is some important bytes for initializing audio/video decoder, // can be converted to VideoCodecData or AudioCodecData using: // -// codecdata.(AudioCodecData) or codecdata.(VideoCodecData) +// codecdata.(AudioCodecData) or codecdata.(VideoCodecData) // // for H264, CodecData is AVCDecoderConfigure bytes, includes SPS/PPS. type CodecData interface { diff --git a/vendor/github.com/datarhei/joy4/av/pktque/filters.go b/vendor/github.com/datarhei/joy4/av/pktque/filters.go index ff54d3f0..4d10e422 100644 --- a/vendor/github.com/datarhei/joy4/av/pktque/filters.go +++ b/vendor/github.com/datarhei/joy4/av/pktque/filters.go @@ -2,8 +2,9 @@ package pktque import ( - "github.com/datarhei/joy4/av" "time" + + "github.com/datarhei/joy4/av" ) type Filter interface { diff --git a/vendor/github.com/datarhei/joy4/codec/aacparser/parser.go b/vendor/github.com/datarhei/joy4/codec/aacparser/parser.go index a2209935..a94c086c 100644 --- a/vendor/github.com/datarhei/joy4/codec/aacparser/parser.go +++ b/vendor/github.com/datarhei/joy4/codec/aacparser/parser.go @@ -3,10 +3,11 @@ package aacparser import ( "bytes" "fmt" - "github.com/datarhei/joy4/av" - "github.com/datarhei/joy4/utils/bits" "io" "time" + + "github.com/datarhei/joy4/av" + "github.com/datarhei/joy4/utils/bits" ) // copied from libavcodec/mpeg4audio.h diff --git a/vendor/github.com/datarhei/joy4/codec/av1parser/parser.go b/vendor/github.com/datarhei/joy4/codec/av1parser/parser.go new file mode 100644 index 00000000..50ec01a1 --- /dev/null +++ b/vendor/github.com/datarhei/joy4/codec/av1parser/parser.go @@ -0,0 +1,44 @@ +package av1parser + +import ( + "github.com/datarhei/joy4/av" +) + +type CodecData struct { + Record []byte + IsMpeg2TS bool +} + +func (codec CodecData) Type() av.CodecType { + return av.AV1 +} + +func (codec CodecData) AV1DecoderConfRecordBytes() []byte { + return codec.Record +} + +func (codec CodecData) AV1VideoDescriptorBytes() []byte { + return codec.Record +} + +func (codec CodecData) Width() int { + return 0 +} + +func (codec CodecData) Height() int { + return 0 +} + +func NewCodecDataFromAV1DecoderConfRecord(record []byte) (data CodecData, err error) { + data.Record = record + data.IsMpeg2TS = false + + return +} + +func NewCodecDataFromAV1VideoDescriptor(record []byte) (data CodecData, err error) { + data.Record = record + data.IsMpeg2TS = true + + return +} diff --git a/vendor/github.com/datarhei/joy4/codec/h264parser/parser.go b/vendor/github.com/datarhei/joy4/codec/h264parser/parser.go index 61a33399..e38364f0 100644 --- a/vendor/github.com/datarhei/joy4/codec/h264parser/parser.go +++ b/vendor/github.com/datarhei/joy4/codec/h264parser/parser.go @@ -3,6 +3,7 @@ package h264parser import ( "bytes" "fmt" + "github.com/datarhei/joy4/av" "github.com/datarhei/joy4/utils/bits" "github.com/datarhei/joy4/utils/bits/pio" diff --git a/vendor/github.com/datarhei/joy4/codec/hevcparser/parser.go b/vendor/github.com/datarhei/joy4/codec/hevcparser/parser.go new file mode 100644 index 00000000..8ec02382 --- /dev/null +++ b/vendor/github.com/datarhei/joy4/codec/hevcparser/parser.go @@ -0,0 +1,695 @@ +package hevcparser + +// based on https://github.com/deepch/vdk/blob/v0.0.21/codec/h265parser/parser.go + +import ( + "bytes" + "errors" + "fmt" + + "github.com/datarhei/joy4/av" + "github.com/datarhei/joy4/utils/bits" + "github.com/datarhei/joy4/utils/bits/pio" +) + +type SPSInfo struct { + ProfileIdc uint + LevelIdc uint + CropLeft uint + CropRight uint + CropTop uint + CropBottom uint + Width uint + Height uint + PicWidthInLumaSamples uint + PicHeightInLumaSamples uint + generalProfileSpace uint + generalTierFlag uint + generalProfileIDC uint + generalProfileCompatibilityFlags uint32 + generalConstraintIndicatorFlags uint64 + generalLevelIDC uint +} + +const ( + NAL_UNIT_CODED_SLICE_TRAIL_N = 0 + NAL_UNIT_CODED_SLICE_TRAIL_R = 1 + NAL_UNIT_CODED_SLICE_TSA_N = 2 + NAL_UNIT_CODED_SLICE_TSA_R = 3 + NAL_UNIT_CODED_SLICE_STSA_N = 4 + NAL_UNIT_CODED_SLICE_STSA_R = 5 + NAL_UNIT_CODED_SLICE_RADL_N = 6 + NAL_UNIT_CODED_SLICE_RADL_R = 7 + NAL_UNIT_CODED_SLICE_RASL_N = 8 + NAL_UNIT_CODED_SLICE_RASL_R = 9 + NAL_UNIT_RESERVED_VCL_N10 = 10 + NAL_UNIT_RESERVED_VCL_R11 = 11 + NAL_UNIT_RESERVED_VCL_N12 = 12 + NAL_UNIT_RESERVED_VCL_R13 = 13 + NAL_UNIT_RESERVED_VCL_N14 = 14 + NAL_UNIT_RESERVED_VCL_R15 = 15 + NAL_UNIT_CODED_SLICE_BLA_W_LP = 16 + NAL_UNIT_CODED_SLICE_BLA_W_RADL = 17 + NAL_UNIT_CODED_SLICE_BLA_N_LP = 18 + NAL_UNIT_CODED_SLICE_IDR_W_RADL = 19 + NAL_UNIT_CODED_SLICE_IDR_N_LP = 20 + NAL_UNIT_CODED_SLICE_CRA = 21 + NAL_UNIT_RESERVED_IRAP_VCL22 = 22 + NAL_UNIT_RESERVED_IRAP_VCL23 = 23 + NAL_UNIT_RESERVED_VCL24 = 24 + NAL_UNIT_RESERVED_VCL25 = 25 + NAL_UNIT_RESERVED_VCL26 = 26 + NAL_UNIT_RESERVED_VCL27 = 27 + NAL_UNIT_RESERVED_VCL28 = 28 + NAL_UNIT_RESERVED_VCL29 = 29 + NAL_UNIT_RESERVED_VCL30 = 30 + NAL_UNIT_RESERVED_VCL31 = 31 + NAL_UNIT_VPS = 32 + NAL_UNIT_SPS = 33 + NAL_UNIT_PPS = 34 + NAL_UNIT_ACCESS_UNIT_DELIMITER = 35 + NAL_UNIT_EOS = 36 + NAL_UNIT_EOB = 37 + NAL_UNIT_FILLER_DATA = 38 + NAL_UNIT_PREFIX_SEI = 39 + NAL_UNIT_SUFFIX_SEI = 40 + NAL_UNIT_RESERVED_NVCL41 = 41 + NAL_UNIT_RESERVED_NVCL42 = 42 + NAL_UNIT_RESERVED_NVCL43 = 43 + NAL_UNIT_RESERVED_NVCL44 = 44 + NAL_UNIT_RESERVED_NVCL45 = 45 + NAL_UNIT_RESERVED_NVCL46 = 46 + NAL_UNIT_RESERVED_NVCL47 = 47 + NAL_UNIT_UNSPECIFIED_48 = 48 + NAL_UNIT_UNSPECIFIED_49 = 49 + NAL_UNIT_UNSPECIFIED_50 = 50 + NAL_UNIT_UNSPECIFIED_51 = 51 + NAL_UNIT_UNSPECIFIED_52 = 52 + NAL_UNIT_UNSPECIFIED_53 = 53 + NAL_UNIT_UNSPECIFIED_54 = 54 + NAL_UNIT_UNSPECIFIED_55 = 55 + NAL_UNIT_UNSPECIFIED_56 = 56 + NAL_UNIT_UNSPECIFIED_57 = 57 + NAL_UNIT_UNSPECIFIED_58 = 58 + NAL_UNIT_UNSPECIFIED_59 = 59 + NAL_UNIT_UNSPECIFIED_60 = 60 + NAL_UNIT_UNSPECIFIED_61 = 61 + NAL_UNIT_UNSPECIFIED_62 = 62 + NAL_UNIT_UNSPECIFIED_63 = 63 + NAL_UNIT_INVALID = 64 +) + +const ( + MAX_VPS_COUNT = 16 + MAX_SUB_LAYERS = 7 + MAX_SPS_COUNT = 32 +) + +var ( + ErrorHEVCIncorectUnitSize = errors.New("incorrect unit size") + ErrorHECVIncorectUnitType = errors.New("incorrect unit type") +) + +var StartCodeBytes = []byte{0, 0, 1} +var AUDBytes = []byte{0, 0, 0, 1, 0x9, 0xf0, 0, 0, 0, 1} // AUD + +const ( + NALU_RAW = iota + NALU_AVCC + NALU_ANNEXB +) + +func SplitNALUs(b []byte) (nalus [][]byte, typ int) { + if len(b) < 4 { + return [][]byte{b}, NALU_RAW + } + val3 := pio.U24BE(b) + val4 := pio.U32BE(b) + if val4 <= uint32(len(b)) { + _val4 := val4 + _b := b[4:] + nalus := [][]byte{} + for { + nalus = append(nalus, _b[:_val4]) + _b = _b[_val4:] + if len(_b) < 4 { + break + } + _val4 = pio.U32BE(_b) + _b = _b[4:] + if _val4 > uint32(len(_b)) { + break + } + } + if len(_b) == 0 { + return nalus, NALU_AVCC + } + } + if val3 == 1 || val4 == 1 { + _val3 := val3 + _val4 := val4 + start := 0 + pos := 0 + for { + if start != pos { + nalus = append(nalus, b[start:pos]) + } + if _val3 == 1 { + pos += 3 + } else if _val4 == 1 { + pos += 4 + } + start = pos + if start == len(b) { + break + } + _val3 = 0 + _val4 = 0 + for pos < len(b) { + if pos+2 < len(b) && b[pos] == 0 { + _val3 = pio.U24BE(b[pos:]) + if _val3 == 0 { + if pos+3 < len(b) { + _val4 = uint32(b[pos+3]) + if _val4 == 1 { + break + } + } + } else if _val3 == 1 { + break + } + pos++ + } else { + pos++ + } + } + } + typ = NALU_ANNEXB + return + } + + return [][]byte{b}, NALU_RAW +} + +func ParseSPS(sps []byte) (ctx SPSInfo, err error) { + if len(sps) < 2 { + err = ErrorHEVCIncorectUnitSize + return + } + rbsp := nal2rbsp(sps[2:]) + br := &bits.GolombBitReader{R: bytes.NewReader(rbsp)} + + // sps_video_parameter_set_id + if _, err = br.ReadBits(4); err != nil { + return + } + + // sps_max_sub_layers_minus1 + spsMaxSubLayersMinus1, err := br.ReadBits(3) + if err != nil { + return + } + + // sps_temporal_id_nesting_flag + if _, err = br.ReadBit(); err != nil { + return + } + + // profile_tier_level( 1, sps_max_sub_layers_minus1 ) + if err = parsePTL(br, &ctx, spsMaxSubLayersMinus1); err != nil { + return + } + + // sps_seq_parameter_set_id + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + + // chroma_format_idc + var chroma_format_idc uint + if chroma_format_idc, err = br.ReadExponentialGolombCode(); err != nil { + return + } + if chroma_format_idc == 3 { + // separate_colour_plane_flag + if _, err = br.ReadBit(); err != nil { + return + } + } + + // Table 6-1, Section 6.2 + var subWidthC uint + var subHeightC uint + + switch chroma_format_idc { + case 0: + subWidthC, subHeightC = 1, 1 + case 1: + subWidthC, subHeightC = 2, 2 + case 2: + subWidthC, subHeightC = 2, 1 + case 3: + subWidthC, subHeightC = 1, 1 + } + + // pic_width_in_luma_samples + if ctx.PicWidthInLumaSamples, err = br.ReadExponentialGolombCode(); err != nil { + return + } + + // pic_height_in_luma_samples + if ctx.PicHeightInLumaSamples, err = br.ReadExponentialGolombCode(); err != nil { + return + } + + // conformance_window_flag + conformanceWindowFlag, err := br.ReadBit() + if err != nil { + return + } + + var conf_win_left_offset uint + var conf_win_right_offset uint + var conf_win_top_offset uint + var conf_win_bottom_offset uint + + if conformanceWindowFlag != 0 { + // conf_win_left_offset + conf_win_left_offset, err = br.ReadExponentialGolombCode() + if err != nil { + return + } + ctx.CropLeft = subWidthC * conf_win_left_offset + + // conf_win_right_offset + conf_win_right_offset, err = br.ReadExponentialGolombCode() + if err != nil { + return + } + ctx.CropRight = subWidthC * conf_win_right_offset + + // conf_win_top_offset + conf_win_top_offset, err = br.ReadExponentialGolombCode() + if err != nil { + return + } + ctx.CropTop = subHeightC * conf_win_top_offset + + // conf_win_bottom_offset + conf_win_bottom_offset, err = br.ReadExponentialGolombCode() + if err != nil { + return + } + ctx.CropBottom = subHeightC * conf_win_bottom_offset + } + + ctx.Width = ctx.PicWidthInLumaSamples - ctx.CropLeft - ctx.CropRight + ctx.Height = ctx.PicHeightInLumaSamples - ctx.CropTop - ctx.CropBottom + + // bit_depth_luma_minus8 + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + + // bit_depth_chroma_minus8 + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + + // log2_max_pic_order_cnt_lsb_minus4 + _, err = br.ReadExponentialGolombCode() + if err != nil { + return + } + + // sps_sub_layer_ordering_info_present_flag + spsSubLayerOrderingInfoPresentFlag, err := br.ReadBit() + if err != nil { + return + } + var i uint + if spsSubLayerOrderingInfoPresentFlag != 0 { + i = 0 + } else { + i = spsMaxSubLayersMinus1 + } + for ; i <= spsMaxSubLayersMinus1; i++ { + // sps_max_dec_pic_buffering_minus1[ i ] + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + // sps_max_num_reorder_pics[ i ] + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + // sps_max_latency_increase_plus1[ i ] + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + } + + // log2_min_luma_coding_block_size_minus3 + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + // log2_diff_max_min_luma_coding_block_size + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + // log2_min_luma_transform_block_size_minus2 + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + // log2_diff_max_min_luma_transform_block_size + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + // max_transform_hierarchy_depth_inter + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + // max_transform_hierarchy_depth_intra + if _, err = br.ReadExponentialGolombCode(); err != nil { + return + } + return +} + +func parsePTL(br *bits.GolombBitReader, ctx *SPSInfo, maxSubLayersMinus1 uint) error { + var err error + var ptl SPSInfo + if ptl.generalProfileSpace, err = br.ReadBits(2); err != nil { + return err + } + if ptl.generalTierFlag, err = br.ReadBit(); err != nil { + return err + } + if ptl.generalProfileIDC, err = br.ReadBits(5); err != nil { + return err + } + if ptl.generalProfileCompatibilityFlags, err = br.ReadBits32(32); err != nil { + return err + } + if ptl.generalConstraintIndicatorFlags, err = br.ReadBits64(48); err != nil { + return err + } + if ptl.generalLevelIDC, err = br.ReadBits(8); err != nil { + return err + } + updatePTL(ctx, &ptl) + if maxSubLayersMinus1 == 0 { + return nil + } + subLayerProfilePresentFlag := make([]uint, maxSubLayersMinus1) + subLayerLevelPresentFlag := make([]uint, maxSubLayersMinus1) + for i := uint(0); i < maxSubLayersMinus1; i++ { + if subLayerProfilePresentFlag[i], err = br.ReadBit(); err != nil { + return err + } + if subLayerLevelPresentFlag[i], err = br.ReadBit(); err != nil { + return err + } + } + if maxSubLayersMinus1 > 0 { + for i := maxSubLayersMinus1; i < 8; i++ { + if _, err = br.ReadBits(2); err != nil { + return err + } + } + } + for i := uint(0); i < maxSubLayersMinus1; i++ { + if subLayerProfilePresentFlag[i] != 0 { + if _, err = br.ReadBits32(32); err != nil { + return err + } + if _, err = br.ReadBits32(32); err != nil { + return err + } + if _, err = br.ReadBits32(24); err != nil { + return err + } + } + + if subLayerLevelPresentFlag[i] != 0 { + if _, err = br.ReadBits(8); err != nil { + return err + } + } + } + return nil +} + +func updatePTL(ctx, ptl *SPSInfo) { + ctx.generalProfileSpace = ptl.generalProfileSpace + + if ptl.generalTierFlag > ctx.generalTierFlag { + ctx.generalLevelIDC = ptl.generalLevelIDC + + ctx.generalTierFlag = ptl.generalTierFlag + } else { + if ptl.generalLevelIDC > ctx.generalLevelIDC { + ctx.generalLevelIDC = ptl.generalLevelIDC + } + } + + if ptl.generalProfileIDC > ctx.generalProfileIDC { + ctx.generalProfileIDC = ptl.generalProfileIDC + } + + ctx.generalProfileCompatibilityFlags &= ptl.generalProfileCompatibilityFlags + + ctx.generalConstraintIndicatorFlags &= ptl.generalConstraintIndicatorFlags +} + +func nal2rbsp(nal []byte) []byte { + return bytes.Replace(nal, []byte{0x0, 0x0, 0x3}, []byte{0x0, 0x0}, -1) +} + +type CodecData struct { + Record []byte + RecordInfo HEVCDecoderConfRecord + SPSInfo SPSInfo +} + +func (codec CodecData) Type() av.CodecType { + return av.HEVC +} + +func (codec CodecData) HEVCDecoderConfRecordBytes() []byte { + return codec.Record +} + +func (codec CodecData) SPS() []byte { + return codec.RecordInfo.SPS[0] +} + +func (codec CodecData) PPS() []byte { + return codec.RecordInfo.PPS[0] +} + +func (codec CodecData) VPS() []byte { + return codec.RecordInfo.VPS[0] +} + +func (codec CodecData) Width() int { + return int(codec.SPSInfo.Width) +} + +func (codec CodecData) Height() int { + return int(codec.SPSInfo.Height) +} + +func NewCodecDataFromHEVCDecoderConfRecord(record []byte) (self CodecData, err error) { + self.Record = record + if _, err = (&self.RecordInfo).Unmarshal(record); err != nil { + return + } + if len(self.RecordInfo.SPS) == 0 { + err = fmt.Errorf("hevcparser: no SPS found in HEVCDecoderConfRecord") + return + } + if len(self.RecordInfo.PPS) == 0 { + err = fmt.Errorf("hevcparser: no PPS found in HEVCDecoderConfRecord") + return + } + if len(self.RecordInfo.VPS) == 0 { + err = fmt.Errorf("hevcparser: no VPS found in HEVCDecoderConfRecord") + return + } + if self.SPSInfo, err = ParseSPS(self.RecordInfo.SPS[0]); err != nil { + err = fmt.Errorf("hevcparser: parse SPS failed(%s)", err) + return + } + return +} + +func NewCodecDataFromVPSAndSPSAndPPS(vps, sps, pps []byte) (self CodecData, err error) { + recordinfo := HEVCDecoderConfRecord{} + recordinfo.HEVCProfileIndication = sps[3] + recordinfo.ProfileCompatibility = sps[4] + recordinfo.HEVCLevelIndication = sps[5] + recordinfo.SPS = [][]byte{sps} + recordinfo.PPS = [][]byte{pps} + recordinfo.VPS = [][]byte{vps} + recordinfo.LengthSizeMinusOne = 3 + if self.SPSInfo, err = ParseSPS(sps); err != nil { + return + } + buf := make([]byte, recordinfo.Len()) + recordinfo.Marshal(buf, self.SPSInfo) + self.RecordInfo = recordinfo + self.Record = buf + return +} + +type HEVCDecoderConfRecord struct { + HEVCProfileIndication uint8 + ProfileCompatibility uint8 + HEVCLevelIndication uint8 + LengthSizeMinusOne uint8 + VPS [][]byte + SPS [][]byte + PPS [][]byte +} + +var ErrDecconfInvalid = fmt.Errorf("hevcparser: HEVCDecoderConfRecord invalid") + +func (record *HEVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { + if len(b) < 30 { + err = ErrDecconfInvalid + return + } + record.HEVCProfileIndication = b[1] + record.ProfileCompatibility = b[2] + record.HEVCLevelIndication = b[3] + record.LengthSizeMinusOne = b[4] & 0x03 + + vpscount := int(b[25] & 0x1f) + n += 26 + for i := 0; i < vpscount; i++ { + if len(b) < n+2 { + err = ErrDecconfInvalid + return + } + vpslen := int(pio.U16BE(b[n:])) + n += 2 + + if len(b) < n+vpslen { + err = ErrDecconfInvalid + return + } + record.VPS = append(record.VPS, b[n:n+vpslen]) + n += vpslen + } + + if len(b) < n+1 { + err = ErrDecconfInvalid + return + } + + n++ + n++ + + spscount := int(b[n]) + n++ + + for i := 0; i < spscount; i++ { + if len(b) < n+2 { + err = ErrDecconfInvalid + return + } + spslen := int(pio.U16BE(b[n:])) + n += 2 + + if len(b) < n+spslen { + err = ErrDecconfInvalid + return + } + record.SPS = append(record.SPS, b[n:n+spslen]) + n += spslen + } + + n++ + n++ + + ppscount := int(b[n]) + n++ + + for i := 0; i < ppscount; i++ { + if len(b) < n+2 { + err = ErrDecconfInvalid + return + } + ppslen := int(pio.U16BE(b[n:])) + n += 2 + + if len(b) < n+ppslen { + err = ErrDecconfInvalid + return + } + record.PPS = append(record.PPS, b[n:n+ppslen]) + n += ppslen + } + return +} + +func (record HEVCDecoderConfRecord) Len() (n int) { + n = 23 + for _, sps := range record.SPS { + n += 5 + len(sps) + } + for _, pps := range record.PPS { + n += 5 + len(pps) + } + for _, vps := range record.VPS { + n += 5 + len(vps) + } + return +} + +func (record HEVCDecoderConfRecord) Marshal(b []byte, si SPSInfo) (n int) { + b[0] = 1 + b[1] = record.HEVCProfileIndication + b[2] = record.ProfileCompatibility + b[3] = record.HEVCLevelIndication + b[21] = 3 + b[22] = 3 + n += 23 + b[n] = (record.VPS[0][0] >> 1) & 0x3f + n++ + b[n] = byte(len(record.VPS) >> 8) + n++ + b[n] = byte(len(record.VPS)) + n++ + for _, vps := range record.VPS { + pio.PutU16BE(b[n:], uint16(len(vps))) + n += 2 + copy(b[n:], vps) + n += len(vps) + } + b[n] = (record.SPS[0][0] >> 1) & 0x3f + n++ + b[n] = byte(len(record.SPS) >> 8) + n++ + b[n] = byte(len(record.SPS)) + n++ + for _, sps := range record.SPS { + pio.PutU16BE(b[n:], uint16(len(sps))) + n += 2 + copy(b[n:], sps) + n += len(sps) + } + b[n] = (record.PPS[0][0] >> 1) & 0x3f + n++ + b[n] = byte(len(record.PPS) >> 8) + n++ + b[n] = byte(len(record.PPS)) + n++ + for _, pps := range record.PPS { + pio.PutU16BE(b[n:], uint16(len(pps))) + n += 2 + copy(b[n:], pps) + n += len(pps) + } + return +} diff --git a/vendor/github.com/datarhei/joy4/codec/vp9parser/parser.go b/vendor/github.com/datarhei/joy4/codec/vp9parser/parser.go new file mode 100644 index 00000000..d5bbaa61 --- /dev/null +++ b/vendor/github.com/datarhei/joy4/codec/vp9parser/parser.go @@ -0,0 +1,31 @@ +package vp9parser + +import ( + "github.com/datarhei/joy4/av" +) + +type CodecData struct { + Record []byte +} + +func (codec CodecData) Type() av.CodecType { + return av.VP9 +} + +func (codec CodecData) VPDecoderConfRecordBytes() []byte { + return codec.Record +} + +func (codec CodecData) Width() int { + return 0 +} + +func (codec CodecData) Height() int { + return 0 +} + +func NewCodecDataFromVPDecoderConfRecord(record []byte) (self CodecData, err error) { + self.Record = record + + return +} diff --git a/vendor/github.com/datarhei/joy4/format/flv/flv.go b/vendor/github.com/datarhei/joy4/format/flv/flv.go index 742811d5..3289fb53 100644 --- a/vendor/github.com/datarhei/joy4/format/flv/flv.go +++ b/vendor/github.com/datarhei/joy4/format/flv/flv.go @@ -3,15 +3,19 @@ package flv import ( "bufio" "fmt" + "io" + "github.com/datarhei/joy4/av" "github.com/datarhei/joy4/av/avutil" "github.com/datarhei/joy4/codec" "github.com/datarhei/joy4/codec/aacparser" + "github.com/datarhei/joy4/codec/av1parser" "github.com/datarhei/joy4/codec/fake" "github.com/datarhei/joy4/codec/h264parser" + "github.com/datarhei/joy4/codec/hevcparser" + "github.com/datarhei/joy4/codec/vp9parser" "github.com/datarhei/joy4/format/flv/flvio" "github.com/datarhei/joy4/utils/bits/pio" - "io" ) var MaxProbePacketCount = 20 @@ -27,16 +31,29 @@ func NewMetadataByStreams(streams []av.CodecData) (metadata flvio.AMFMap, err er switch typ { case av.H264: metadata["videocodecid"] = flvio.VIDEO_H264 + case av.HEVC: + metadata["videocodecid"] = flvio.FourCCToFloat(flvio.FOURCC_HEVC) + case av.VP9: + metadata["videocodecid"] = flvio.FourCCToFloat(flvio.FOURCC_VP9) + case av.AV1: + metadata["videocodecid"] = flvio.FourCCToFloat(flvio.FOURCC_AV1) default: err = fmt.Errorf("flv: metadata: unsupported video codecType=%v", stream.Type()) return } - metadata["width"] = stream.Width() - metadata["height"] = stream.Height() - metadata["displayWidth"] = stream.Width() - metadata["displayHeight"] = stream.Height() + width, height := stream.Width(), stream.Height() + + if width != 0 { + metadata["width"] = width + metadata["displayWidth"] = width + } + + if height != 0 { + metadata["height"] = height + metadata["displayHeight"] = height + } case typ.IsAudio(): stream := _stream.(av.AudioCodecData) @@ -68,36 +85,98 @@ type Prober struct { CachedPkts []av.Packet } -func (self *Prober) CacheTag(_tag flvio.Tag, timestamp int32) { - pkt, _ := self.TagToPacket(_tag, timestamp) - self.CachedPkts = append(self.CachedPkts, pkt) +func (prober *Prober) CacheTag(_tag flvio.Tag, timestamp int32) { + pkt, _ := prober.TagToPacket(_tag, timestamp) + prober.CachedPkts = append(prober.CachedPkts, pkt) } -func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) { - self.PushedCount++ +func (prober *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) { + prober.PushedCount++ - if self.PushedCount > MaxProbePacketCount { + if prober.PushedCount > MaxProbePacketCount { err = fmt.Errorf("flv: max probe packet count reached") return } switch tag.Type { case flvio.TAG_VIDEO: - switch tag.AVCPacketType { - case flvio.AVC_SEQHDR: - if !self.GotVideo { - var stream h264parser.CodecData - if stream, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil { - err = fmt.Errorf("flv: h264 seqhdr invalid: %s", err.Error()) - return + if tag.IsExHeader { + if tag.FourCC == flvio.FOURCC_HEVC { + if tag.PacketType == flvio.PKTTYPE_SEQUENCE_START { + if !prober.GotVideo { + var stream hevcparser.CodecData + //fmt.Printf("got HEVC sequence start:\n%s\n", hex.Dump(tag.Data)) + if stream, err = hevcparser.NewCodecDataFromHEVCDecoderConfRecord(tag.Data); err != nil { + err = fmt.Errorf("flv: hevc seqhdr invalid: %s", err.Error()) + return + } + prober.VideoStreamIdx = len(prober.Streams) + prober.Streams = append(prober.Streams, stream) + prober.GotVideo = true + } + } else if tag.PacketType == flvio.PKTTYPE_CODED_FRAMES || tag.PacketType == flvio.PKTTYPE_CODED_FRAMESX { + prober.CacheTag(tag, timestamp) } - self.VideoStreamIdx = len(self.Streams) - self.Streams = append(self.Streams, stream) - self.GotVideo = true - } + } else if tag.FourCC == flvio.FOURCC_VP9 { + if tag.PacketType == flvio.PKTTYPE_SEQUENCE_START { + if !prober.GotVideo { + var stream vp9parser.CodecData + //fmt.Printf("got VP9 sequence start:\n%s\n", hex.Dump(tag.Data)) + if stream, err = vp9parser.NewCodecDataFromVPDecoderConfRecord(tag.Data); err != nil { + err = fmt.Errorf("flv: vp9 seqhdr invalid: %s", err.Error()) + return + } + prober.VideoStreamIdx = len(prober.Streams) + prober.Streams = append(prober.Streams, stream) + prober.GotVideo = true + } + } else if tag.PacketType == flvio.PKTTYPE_CODED_FRAMES || tag.PacketType == flvio.PKTTYPE_CODED_FRAMESX { + prober.CacheTag(tag, timestamp) + } + } else if tag.FourCC == flvio.FOURCC_AV1 { + if tag.PacketType == flvio.PKTTYPE_SEQUENCE_START || tag.PacketType == flvio.PKTTYPE_MPEG2TS_SEQUENCE_START { + if !prober.GotVideo { + var stream av1parser.CodecData - case flvio.AVC_NALU: - self.CacheTag(tag, timestamp) + if tag.PacketType == flvio.PKTTYPE_SEQUENCE_START { + //fmt.Printf("got AV1 sequence start:\n%s\n", hex.Dump(tag.Data)) + if stream, err = av1parser.NewCodecDataFromAV1DecoderConfRecord(tag.Data); err != nil { + err = fmt.Errorf("flv: av1 seqhdr invalid: %s", err.Error()) + return + } + } else { + //fmt.Printf("got AV1 video descriptor:\n%s\n", hex.Dump(tag.Data)) + if stream, err = av1parser.NewCodecDataFromAV1VideoDescriptor(tag.Data); err != nil { + err = fmt.Errorf("flv: av1 video descriptor invalid: %s", err.Error()) + return + } + } + prober.VideoStreamIdx = len(prober.Streams) + prober.Streams = append(prober.Streams, stream) + prober.GotVideo = true + } + } else if tag.PacketType == flvio.PKTTYPE_CODED_FRAMES || tag.PacketType == flvio.PKTTYPE_CODED_FRAMESX { + prober.CacheTag(tag, timestamp) + } + } + } else { + switch tag.AVCPacketType { + case flvio.AVC_SEQHDR: + if !prober.GotVideo { + var stream h264parser.CodecData + //fmt.Printf("got H264 sequence start:\n%s\n", hex.Dump(tag.Data)) + if stream, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil { + err = fmt.Errorf("flv: h264 seqhdr invalid: %s", err.Error()) + return + } + prober.VideoStreamIdx = len(prober.Streams) + prober.Streams = append(prober.Streams, stream) + prober.GotVideo = true + } + + case flvio.AVC_NALU: + prober.CacheTag(tag, timestamp) + } } case flvio.TAG_AUDIO: @@ -105,42 +184,42 @@ func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) { case flvio.SOUND_AAC: switch tag.AACPacketType { case flvio.AAC_SEQHDR: - if !self.GotAudio { + if !prober.GotAudio { var stream aacparser.CodecData if stream, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(tag.Data); err != nil { err = fmt.Errorf("flv: aac seqhdr invalid") return } - self.AudioStreamIdx = len(self.Streams) - self.Streams = append(self.Streams, stream) - self.GotAudio = true + prober.AudioStreamIdx = len(prober.Streams) + prober.Streams = append(prober.Streams, stream) + prober.GotAudio = true } case flvio.AAC_RAW: - self.CacheTag(tag, timestamp) + prober.CacheTag(tag, timestamp) } case flvio.SOUND_SPEEX: - if !self.GotAudio { + if !prober.GotAudio { stream := codec.NewSpeexCodecData(16000, tag.ChannelLayout()) - self.AudioStreamIdx = len(self.Streams) - self.Streams = append(self.Streams, stream) - self.GotAudio = true - self.CacheTag(tag, timestamp) + prober.AudioStreamIdx = len(prober.Streams) + prober.Streams = append(prober.Streams, stream) + prober.GotAudio = true + prober.CacheTag(tag, timestamp) } case flvio.SOUND_NELLYMOSER: - if !self.GotAudio { + if !prober.GotAudio { stream := fake.CodecData{ CodecType_: av.NELLYMOSER, SampleRate_: 16000, SampleFormat_: av.S16, ChannelLayout_: tag.ChannelLayout(), } - self.AudioStreamIdx = len(self.Streams) - self.Streams = append(self.Streams, stream) - self.GotAudio = true - self.CacheTag(tag, timestamp) + prober.AudioStreamIdx = len(prober.Streams) + prober.Streams = append(prober.Streams, stream) + prober.GotAudio = true + prober.CacheTag(tag, timestamp) } } @@ -149,25 +228,25 @@ func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) { return } -func (self *Prober) Probed() (ok bool) { - if self.HasAudio || self.HasVideo { - if self.HasAudio == self.GotAudio && self.HasVideo == self.GotVideo { +func (prober *Prober) Probed() (ok bool) { + if prober.HasAudio || prober.HasVideo { + if prober.HasAudio == prober.GotAudio && prober.HasVideo == prober.GotVideo { return true } } else { - if self.PushedCount == MaxProbePacketCount { + if prober.PushedCount == MaxProbePacketCount { return true } } return } -func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet, ok bool) { +func (prober *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet, ok bool) { switch tag.Type { case flvio.TAG_VIDEO: - pkt.Idx = int8(self.VideoStreamIdx) - switch tag.AVCPacketType { - case flvio.AVC_NALU: + pkt.Idx = int8(prober.VideoStreamIdx) + switch tag.PacketType { + case flvio.PKTTYPE_CODED_FRAMES, flvio.PKTTYPE_CODED_FRAMESX: ok = true pkt.Data = tag.Data pkt.CompositionTime = flvio.TsToTime(tag.CompositionTime) @@ -175,7 +254,7 @@ func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet, } case flvio.TAG_AUDIO: - pkt.Idx = int8(self.AudioStreamIdx) + pkt.Idx = int8(prober.AudioStreamIdx) switch tag.SoundFormat { case flvio.SOUND_AAC: switch tag.AACPacketType { @@ -198,13 +277,13 @@ func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet, return } -func (self *Prober) Empty() bool { - return len(self.CachedPkts) == 0 +func (prober *Prober) Empty() bool { + return len(prober.CachedPkts) == 0 } -func (self *Prober) PopPacket() av.Packet { - pkt := self.CachedPkts[0] - self.CachedPkts = self.CachedPkts[1:] +func (prober *Prober) PopPacket() av.Packet { + pkt := prober.CachedPkts[0] + prober.CachedPkts = prober.CachedPkts[1:] return pkt } @@ -219,6 +298,55 @@ func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err error) { Data: h264.AVCDecoderConfRecordBytes(), FrameType: flvio.FRAME_KEY, } + //fmt.Printf("set H264 sequence start:\n%v\n", hex.Dump(tag.Data)) + ok = true + _tag = tag + + case av.HEVC: + hevc := stream.(hevcparser.CodecData) + tag := flvio.Tag{ + Type: flvio.TAG_VIDEO, + IsExHeader: true, + PacketType: flvio.PKTTYPE_SEQUENCE_START, + FourCC: flvio.FOURCC_HEVC, + Data: hevc.HEVCDecoderConfRecordBytes(), + FrameType: flvio.FRAME_KEY, + } + //fmt.Printf("set HEVC sequence start:\n%v\n", hex.Dump(tag.Data)) + ok = true + _tag = tag + + case av.VP9: + vp9 := stream.(vp9parser.CodecData) + tag := flvio.Tag{ + Type: flvio.TAG_VIDEO, + IsExHeader: true, + PacketType: flvio.PKTTYPE_SEQUENCE_START, + FourCC: flvio.FOURCC_VP9, + Data: vp9.VPDecoderConfRecordBytes(), + FrameType: flvio.FRAME_KEY, + } + //fmt.Printf("set VP9 sequence start:\n%v\n", hex.Dump(tag.Data)) + ok = true + _tag = tag + + case av.AV1: + av1 := stream.(av1parser.CodecData) + tag := flvio.Tag{ + Type: flvio.TAG_VIDEO, + IsExHeader: true, + PacketType: flvio.PKTTYPE_SEQUENCE_START, + FourCC: flvio.FOURCC_AV1, + Data: av1.AV1DecoderConfRecordBytes(), + FrameType: flvio.FRAME_KEY, + } + + if av1.IsMpeg2TS { + tag.PacketType = flvio.PKTTYPE_MPEG2TS_SEQUENCE_START + tag.Data = av1.AV1VideoDescriptorBytes() + } + + //fmt.Printf("set AV1 sequence start:\n%v\n", hex.Dump(tag.Data)) ok = true _tag = tag @@ -272,6 +400,58 @@ func PacketToTag(pkt av.Packet, stream av.CodecData) (tag flvio.Tag, timestamp i tag.FrameType = flvio.FRAME_INTER } + case av.HEVC: + tag = flvio.Tag{ + Type: flvio.TAG_VIDEO, + IsExHeader: true, + PacketType: flvio.PKTTYPE_CODED_FRAMES, + CompositionTime: flvio.TimeToTs(pkt.CompositionTime), + FourCC: flvio.FOURCC_HEVC, + Data: pkt.Data, + } + + if pkt.CompositionTime == 0 { + tag.PacketType = flvio.PKTTYPE_CODED_FRAMESX + } + + if pkt.IsKeyFrame { + tag.FrameType = flvio.FRAME_KEY + } else { + tag.FrameType = flvio.FRAME_INTER + } + + case av.VP9: + tag = flvio.Tag{ + Type: flvio.TAG_VIDEO, + IsExHeader: true, + PacketType: flvio.PKTTYPE_CODED_FRAMES, + CompositionTime: flvio.TimeToTs(pkt.CompositionTime), + FourCC: flvio.FOURCC_VP9, + Data: pkt.Data, + } + + if pkt.IsKeyFrame { + tag.FrameType = flvio.FRAME_KEY + } else { + tag.FrameType = flvio.FRAME_INTER + } + + case av.AV1: + tag = flvio.Tag{ + Type: flvio.TAG_VIDEO, + IsExHeader: true, + PacketType: flvio.PKTTYPE_CODED_FRAMES, + CompositionTime: flvio.TimeToTs(pkt.CompositionTime), + FourCC: flvio.FOURCC_AV1, + Data: pkt.Data, + } + + if pkt.IsKeyFrame { + tag.FrameType = flvio.FRAME_KEY + } else { + tag.FrameType = flvio.FRAME_INTER + } + case av.AAC: tag = flvio.Tag{ Type: flvio.TAG_AUDIO, @@ -335,9 +515,9 @@ func NewMuxer(w io.Writer) *Muxer { return NewMuxerWriteFlusher(bufio.NewWriterSize(w, pio.RecommendBufioSize)) } -var CodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX} +var CodecTypes = []av.CodecType{av.H264, av.HEVC, av.VP9, av.AV1, av.AAC, av.SPEEX} -func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { +func (muxer *Muxer) WriteHeader(streams []av.CodecData) (err error) { var flags uint8 for _, stream := range streams { if stream.Type().IsVideo() { @@ -347,8 +527,8 @@ func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { } } - n := flvio.FillFileHeader(self.b, flags) - if _, err = self.bufw.Write(self.b[:n]); err != nil { + n := flvio.FillFileHeader(muxer.b, flags) + if _, err = muxer.bufw.Write(muxer.b[:n]); err != nil { return } @@ -359,28 +539,28 @@ func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { return } if ok { - if err = flvio.WriteTag(self.bufw, tag, 0, self.b); err != nil { + if err = flvio.WriteTag(muxer.bufw, tag, 0, muxer.b); err != nil { return } } } - self.streams = streams + muxer.streams = streams return } -func (self *Muxer) WritePacket(pkt av.Packet) (err error) { - stream := self.streams[pkt.Idx] +func (muxer *Muxer) WritePacket(pkt av.Packet) (err error) { + stream := muxer.streams[pkt.Idx] tag, timestamp := PacketToTag(pkt, stream) - if err = flvio.WriteTag(self.bufw, tag, timestamp, self.b); err != nil { + if err = flvio.WriteTag(muxer.bufw, tag, timestamp, muxer.b); err != nil { return } return } -func (self *Muxer) WriteTrailer() (err error) { - if err = self.bufw.Flush(); err != nil { +func (muxer *Muxer) WriteTrailer() (err error) { + if err = muxer.bufw.Flush(); err != nil { return } return @@ -401,78 +581,76 @@ func NewDemuxer(r io.Reader) *Demuxer { } } -func (self *Demuxer) prepare() (err error) { - for self.stage < 2 { - switch self.stage { +func (demuxer *Demuxer) prepare() (err error) { + for demuxer.stage < 2 { + switch demuxer.stage { case 0: - if _, err = io.ReadFull(self.bufr, self.b[:flvio.FileHeaderLength]); err != nil { + if _, err = io.ReadFull(demuxer.bufr, demuxer.b[:flvio.FileHeaderLength]); err != nil { return } var flags uint8 var skip int - if flags, skip, err = flvio.ParseFileHeader(self.b); err != nil { + if flags, skip, err = flvio.ParseFileHeader(demuxer.b); err != nil { return } - if _, err = self.bufr.Discard(skip); err != nil { + if _, err = demuxer.bufr.Discard(skip); err != nil { return } if flags&flvio.FILE_HAS_AUDIO != 0 { - self.prober.HasAudio = true + demuxer.prober.HasAudio = true } if flags&flvio.FILE_HAS_VIDEO != 0 { - self.prober.HasVideo = true + demuxer.prober.HasVideo = true } - self.stage++ + demuxer.stage++ case 1: - for !self.prober.Probed() { + for !demuxer.prober.Probed() { var tag flvio.Tag var timestamp int32 - if tag, timestamp, err = flvio.ReadTag(self.bufr, self.b); err != nil { + if tag, timestamp, err = flvio.ReadTag(demuxer.bufr, demuxer.b); err != nil { return } - if err = self.prober.PushTag(tag, timestamp); err != nil { + if err = demuxer.prober.PushTag(tag, timestamp); err != nil { return } } - self.stage++ + demuxer.stage++ } } return } -func (self *Demuxer) Streams() (streams []av.CodecData, err error) { - if err = self.prepare(); err != nil { +func (demuxer *Demuxer) Streams() (streams []av.CodecData, err error) { + if err = demuxer.prepare(); err != nil { return } - streams = self.prober.Streams + streams = demuxer.prober.Streams return } -func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) { - if err = self.prepare(); err != nil { +func (demuxer *Demuxer) ReadPacket() (pkt av.Packet, err error) { + if err = demuxer.prepare(); err != nil { return } - if !self.prober.Empty() { - pkt = self.prober.PopPacket() + if !demuxer.prober.Empty() { + pkt = demuxer.prober.PopPacket() return } for { var tag flvio.Tag var timestamp int32 - if tag, timestamp, err = flvio.ReadTag(self.bufr, self.b); err != nil { + if tag, timestamp, err = flvio.ReadTag(demuxer.bufr, demuxer.b); err != nil { return } var ok bool - if pkt, ok = self.prober.TagToPacket(tag, timestamp); ok { + if pkt, ok = demuxer.prober.TagToPacket(tag, timestamp); ok { return } } - - return } func Handler(h *avutil.RegisterHandler) { diff --git a/vendor/github.com/datarhei/joy4/format/flv/flvio/flvio.go b/vendor/github.com/datarhei/joy4/format/flv/flvio/flvio.go index a69bdb51..8c0a57ea 100644 --- a/vendor/github.com/datarhei/joy4/format/flv/flvio/flvio.go +++ b/vendor/github.com/datarhei/joy4/format/flv/flvio/flvio.go @@ -2,10 +2,11 @@ package flvio import ( "fmt" - "github.com/datarhei/joy4/av" - "github.com/datarhei/joy4/utils/bits/pio" "io" "time" + + "github.com/datarhei/joy4/av" + "github.com/datarhei/joy4/utils/bits/pio" ) func TsToTime(ts int32) time.Duration { @@ -60,6 +61,27 @@ const ( VIDEO_H264 = 7 ) +const ( + PKTTYPE_SEQUENCE_START = 0 + PKTTYPE_CODED_FRAMES = 1 + PKTTYPE_SEQUENCE_END = 2 + PKTTYPE_CODED_FRAMESX = 3 + PKTTYPE_METADATA = 4 + PKTTYPE_MPEG2TS_SEQUENCE_START = 5 +) + +var ( + FOURCC_AV1 = [4]byte{'a', 'v', '0', '1'} + FOURCC_VP9 = [4]byte{'v', 'p', '0', '9'} + FOURCC_HEVC = [4]byte{'h', 'v', 'c', '1'} +) + +func FourCCToFloat(fourcc [4]byte) float64 { + i := int(fourcc[0])<<24 | int(fourcc[1])<<16 | int(fourcc[2])<<8 | int(fourcc[3]) + + return float64(i) +} + type Tag struct { /* 8 = Audio @@ -126,14 +148,22 @@ type Tag struct { AACPacketType uint8 /* + 0: reserved 1: keyframe (for AVC, a seekable frame) 2: inter frame (for AVC, a non- seekable frame) 3: disposable inter frame (H.263 only) 4: generated keyframe (reserved for server use only) 5: video info/command frame + 6: reserved + 7: reserved */ FrameType uint8 + /* + FrameType & 0b1000 != 0 + */ + IsExHeader bool + /* 1: JPEG (currently unused) 2: Sorenson H.263 @@ -145,6 +175,16 @@ type Tag struct { */ CodecID uint8 + /* + 0: PacketTypeSequenceStart + 1: PacketTypeCodedFrames + 2: PacketTypeSequenceEnd + 3: PacketTypeCodedFramesX + 4: PacketTypeMetadata + 5: PacketTypeMPEG2TSSequenceStart + */ + PacketType uint8 + /* 0: AVC sequence header 1: AVC NALU @@ -154,18 +194,20 @@ type Tag struct { CompositionTime int32 + FourCC [4]byte + Data []byte } -func (self Tag) ChannelLayout() av.ChannelLayout { - if self.SoundType == SOUND_MONO { +func (t Tag) ChannelLayout() av.ChannelLayout { + if t.SoundType == SOUND_MONO { return av.CH_MONO } else { return av.CH_STEREO } } -func (self *Tag) audioParseHeader(b []byte) (n int, err error) { +func (t *Tag) audioParseHeader(b []byte) (n int, err error) { if len(b) < n+1 { err = fmt.Errorf("audiodata: parse invalid") return @@ -173,97 +215,163 @@ func (self *Tag) audioParseHeader(b []byte) (n int, err error) { flags := b[n] n++ - self.SoundFormat = flags >> 4 - self.SoundRate = (flags >> 2) & 0x3 - self.SoundSize = (flags >> 1) & 0x1 - self.SoundType = flags & 0x1 + t.SoundFormat = flags >> 4 + t.SoundRate = (flags >> 2) & 0x3 + t.SoundSize = (flags >> 1) & 0x1 + t.SoundType = flags & 0x1 - switch self.SoundFormat { + switch t.SoundFormat { case SOUND_AAC: if len(b) < n+1 { err = fmt.Errorf("audiodata: parse invalid") return } - self.AACPacketType = b[n] + t.AACPacketType = b[n] n++ } return } -func (self Tag) audioFillHeader(b []byte) (n int) { +func (t Tag) audioFillHeader(b []byte) (n int) { var flags uint8 - flags |= self.SoundFormat << 4 - flags |= self.SoundRate << 2 - flags |= self.SoundSize << 1 - flags |= self.SoundType + flags |= t.SoundFormat << 4 + flags |= t.SoundRate << 2 + flags |= t.SoundSize << 1 + flags |= t.SoundType b[n] = flags n++ - switch self.SoundFormat { + switch t.SoundFormat { case SOUND_AAC: - b[n] = self.AACPacketType + b[n] = t.AACPacketType n++ } return } -func (self *Tag) videoParseHeader(b []byte) (n int, err error) { +func (t *Tag) videoParseHeader(b []byte) (n int, err error) { if len(b) < n+1 { err = fmt.Errorf("videodata: parse invalid") return } flags := b[n] - self.FrameType = flags >> 4 - self.CodecID = flags & 0xf + t.FrameType = flags >> 4 + t.CodecID = flags & 0b1111 + + //fmt.Printf("%#8b\n", flags) n++ - if self.FrameType == FRAME_INTER || self.FrameType == FRAME_KEY { + if (t.FrameType & 0b1000) != 0 { + t.IsExHeader = true + t.PacketType = t.CodecID + t.CodecID = 0 + + if t.PacketType != PKTTYPE_METADATA { + t.FrameType = t.FrameType & 0b0111 + } + } + + if !t.IsExHeader { + if t.FrameType == FRAME_INTER || t.FrameType == FRAME_KEY { + if len(b) < n+4 { + err = fmt.Errorf("videodata: parse invalid: neither interframe nor keyframe") + return + } + t.AVCPacketType = b[n] + switch t.AVCPacketType { + case AVC_SEQHDR: + t.PacketType = PKTTYPE_SEQUENCE_START + case AVC_NALU: + t.PacketType = PKTTYPE_CODED_FRAMES + case AVC_EOS: + t.PacketType = PKTTYPE_SEQUENCE_END + } + n++ + + t.CompositionTime = pio.I24BE(b[n:]) + n += 3 + } + } else { if len(b) < n+4 { - err = fmt.Errorf("videodata: parse invalid") + err = fmt.Errorf("videodata: parse invalid: not enough bytes for the fourCC value") return } - self.AVCPacketType = b[n] - n++ - self.CompositionTime = pio.I24BE(b[n:]) + t.FourCC[0] = b[n] + t.FourCC[1] = b[n+1] + t.FourCC[2] = b[n+2] + t.FourCC[3] = b[n+3] + + n += 4 + + t.CompositionTime = 0 + + if t.FourCC == FOURCC_HEVC { + if t.PacketType == PKTTYPE_CODED_FRAMES { + t.CompositionTime = pio.I24BE(b[n:]) + n += 3 + } + } + } + + //fmt.Printf("parseVideoHeader: PacketType: %d\n", t.PacketType) + + return +} + +func (t Tag) videoFillHeader(b []byte) (n int) { + if t.IsExHeader { + flags := t.FrameType<<4 | t.PacketType | 0b10000000 + b[n] = flags + n++ + b[n] = t.FourCC[0] + b[n+1] = t.FourCC[1] + b[n+2] = t.FourCC[2] + b[n+3] = t.FourCC[3] + n += 4 + + if t.FourCC == FOURCC_HEVC { + if t.PacketType == PKTTYPE_CODED_FRAMES { + pio.PutI24BE(b[n:], t.CompositionTime) + n += 3 + } + } + } else { + flags := t.FrameType<<4 | t.CodecID + b[n] = flags + n++ + b[n] = t.AVCPacketType + n++ + pio.PutI24BE(b[n:], t.CompositionTime) n += 3 } + //fmt.Printf("videoFillHeader: PacketType: %d\n%s\n", t.PacketType, hex.Dump(b[:n])) + return } -func (self Tag) videoFillHeader(b []byte) (n int) { - flags := self.FrameType<<4 | self.CodecID - b[n] = flags - n++ - b[n] = self.AVCPacketType - n++ - pio.PutI24BE(b[n:], self.CompositionTime) - n += 3 - return -} - -func (self Tag) FillHeader(b []byte) (n int) { - switch self.Type { +func (t Tag) FillHeader(b []byte) (n int) { + switch t.Type { case TAG_AUDIO: - return self.audioFillHeader(b) + return t.audioFillHeader(b) case TAG_VIDEO: - return self.videoFillHeader(b) + return t.videoFillHeader(b) } return } -func (self *Tag) ParseHeader(b []byte) (n int, err error) { - switch self.Type { +func (t *Tag) ParseHeader(b []byte) (n int, err error) { + switch t.Type { case TAG_AUDIO: - return self.audioParseHeader(b) + return t.audioParseHeader(b) case TAG_VIDEO: - return self.videoParseHeader(b) + return t.videoParseHeader(b) } return diff --git a/vendor/github.com/datarhei/joy4/format/rtmp/rtmp.go b/vendor/github.com/datarhei/joy4/format/rtmp/rtmp.go index 8d9dc745..ebaedaf9 100644 --- a/vendor/github.com/datarhei/joy4/format/rtmp/rtmp.go +++ b/vendor/github.com/datarhei/joy4/format/rtmp/rtmp.go @@ -69,21 +69,21 @@ type Server struct { doneChan chan struct{} } -func (self *Server) handleConn(conn *Conn) (err error) { - if self.HandleConn != nil { - self.HandleConn(conn) +func (s *Server) handleConn(conn *Conn) (err error) { + if s.HandleConn != nil { + s.HandleConn(conn) } else { if err = conn.prepare(stageCommandDone, 0); err != nil { return } if conn.playing { - if self.HandlePlay != nil { - self.HandlePlay(conn) + if s.HandlePlay != nil { + s.HandlePlay(conn) } } else if conn.publishing { - if self.HandlePublish != nil { - self.HandlePublish(conn) + if s.HandlePublish != nil { + s.HandlePublish(conn) } } } @@ -91,8 +91,8 @@ func (self *Server) handleConn(conn *Conn) (err error) { return } -func (self *Server) ListenAndServe() error { - addr := self.Addr +func (s *Server) ListenAndServe() error { + addr := s.Addr if addr == "" { addr = ":1935" } @@ -102,11 +102,11 @@ func (self *Server) ListenAndServe() error { return err } - return self.Serve(listener) + return s.Serve(listener) } -func (self *Server) ListenAndServeTLS(certFile, keyFile string) error { - addr := self.Addr +func (s *Server) ListenAndServeTLS(certFile, keyFile string) error { + addr := s.Addr if addr == "" { addr = ":1935" } @@ -116,14 +116,14 @@ func (self *Server) ListenAndServeTLS(certFile, keyFile string) error { return err } - return self.ServeTLS(listener, certFile, keyFile) + return s.ServeTLS(listener, certFile, keyFile) } -func (self *Server) ServeTLS(listener net.Listener, certFile, keyFile string) error { +func (s *Server) ServeTLS(listener net.Listener, certFile, keyFile string) error { var config *tls.Config - if self.TLSConfig != nil { - config = self.TLSConfig.Clone() + if s.TLSConfig != nil { + config = s.TLSConfig.Clone() } else { config = &tls.Config{} } @@ -142,24 +142,24 @@ func (self *Server) ServeTLS(listener net.Listener, certFile, keyFile string) er listener = tls.NewListener(listener, config) - return self.Serve(listener) + return s.Serve(listener) } -func (self *Server) Serve(listener net.Listener) error { - self.doneChan = make(chan struct{}) +func (s *Server) Serve(listener net.Listener) error { + s.doneChan = make(chan struct{}) - self.listener = listener - defer self.listener.Close() + s.listener = listener + defer s.listener.Close() if Debug { - fmt.Println("rtmp: server: listening on", self.listener.Addr().String()) + fmt.Println("rtmp: server: listening on", s.listener.Addr().String()) } for { - netconn, err := self.listener.Accept() + netconn, err := s.listener.Accept() if err != nil { select { - case <-self.doneChan: + case <-s.doneChan: return ErrServerClosed default: } @@ -174,7 +174,7 @@ func (self *Server) Serve(listener net.Listener) error { conn := NewConn(netconn) conn.isserver = true go func() { - err := self.handleConn(conn) + err := s.handleConn(conn) if Debug { fmt.Println("rtmp: server: client closed err:", err) } @@ -183,15 +183,15 @@ func (self *Server) Serve(listener net.Listener) error { } } -func (self *Server) Close() { - if self.listener == nil { +func (s *Server) Close() { + if s.listener == nil { return } - close(self.doneChan) + close(s.doneChan) - self.listener.Close() - self.listener = nil + s.listener.Close() + s.listener = nil } const ( @@ -212,9 +212,6 @@ type Conn struct { prober *flv.Prober streams []av.CodecData - txbytes uint64 - rxbytes uint64 - bufr *bufio.Reader bufw *bufio.Writer ackn uint32 @@ -253,6 +250,8 @@ type Conn struct { metadata flvio.AMFMap eventtype uint16 + + start time.Time } type txrxcount struct { @@ -261,15 +260,15 @@ type txrxcount struct { rxbytes uint64 } -func (self *txrxcount) Read(p []byte) (int, error) { - n, err := self.ReadWriter.Read(p) - self.rxbytes += uint64(n) +func (t *txrxcount) Read(p []byte) (int, error) { + n, err := t.ReadWriter.Read(p) + t.rxbytes += uint64(n) return n, err } -func (self *txrxcount) Write(p []byte) (int, error) { - n, err := self.ReadWriter.Write(p) - self.txbytes += uint64(n) +func (t *txrxcount) Write(p []byte) (int, error) { + n, err := t.ReadWriter.Write(p) + t.txbytes += uint64(n) return n, err } @@ -285,11 +284,15 @@ func NewConn(netconn net.Conn) *Conn { conn.bufw = bufio.NewWriterSize(conn.txrxcount, pio.RecommendBufioSize) conn.writebuf = make([]byte, 4096) conn.readbuf = make([]byte, 4096) + conn.start = time.Now() return conn } type chunkStream struct { timenow uint32 + prevtimenow uint32 + tscount int + gentimenow bool timedelta uint32 hastimeext bool msgsid uint32 @@ -300,9 +303,9 @@ type chunkStream struct { msgdata []byte } -func (self *chunkStream) Start() { - self.msgdataleft = self.msgdatalen - self.msgdata = make([]byte, self.msgdatalen) +func (cs *chunkStream) Start() { + cs.msgdataleft = cs.msgdatalen + cs.msgdata = make([]byte, cs.msgdatalen) } const ( @@ -327,56 +330,56 @@ const ( eventtypePingResponse = 7 ) -func (self *Conn) NetConn() net.Conn { - return self.netconn +func (conn *Conn) NetConn() net.Conn { + return conn.netconn } -func (self *Conn) TxBytes() uint64 { - return self.txrxcount.txbytes +func (conn *Conn) TxBytes() uint64 { + return conn.txrxcount.txbytes } -func (self *Conn) RxBytes() uint64 { - return self.txrxcount.rxbytes +func (conn *Conn) RxBytes() uint64 { + return conn.txrxcount.rxbytes } -func (self *Conn) Close() (err error) { - return self.netconn.Close() +func (conn *Conn) Close() (err error) { + return conn.netconn.Close() } -func (self *Conn) pollCommand() (err error) { +func (conn *Conn) pollCommand() (err error) { for { - if err = self.pollMsg(); err != nil { + if err = conn.pollMsg(); err != nil { return } - if self.gotcommand { + if conn.gotcommand { return } } } -func (self *Conn) pollAVTag() (tag flvio.Tag, err error) { +func (conn *Conn) pollAVTag() (tag flvio.Tag, err error) { for { - if err = self.pollMsg(); err != nil { + if err = conn.pollMsg(); err != nil { return } - switch self.msgtypeid { + switch conn.msgtypeid { case msgtypeidVideoMsg, msgtypeidAudioMsg: - tag = self.avtag + tag = conn.avtag return } } } -func (self *Conn) pollMsg() (err error) { - self.gotmsg = false - self.gotcommand = false - self.datamsgvals = nil - self.avtag = flvio.Tag{} +func (conn *Conn) pollMsg() (err error) { + conn.gotmsg = false + conn.gotcommand = false + conn.datamsgvals = nil + conn.avtag = flvio.Tag{} for { - if err = self.readChunk(); err != nil { + if err = conn.readChunk(); err != nil { return } - if self.gotmsg { + if conn.gotmsg { return } } @@ -431,95 +434,113 @@ func createURL(tcurl, app, play string) (*url.URL, error) { var CodecTypes = flv.CodecTypes -func (self *Conn) writeBasicConf() (err error) { - // > SetChunkSize - if err = self.writeSetChunkSize(1024 * 1024 * 1); err != nil { - return - } +func (conn *Conn) writeBasicConf() (err error) { // > WindowAckSize - if err = self.writeWindowAckSize(1024 * 1024 * 3); err != nil { + if err = conn.writeWindowAckSize(2500000, false); err != nil { return } // > SetPeerBandwidth - if err = self.writeSetPeerBandwidth(1024*1024*3, 0); err != nil { + if err = conn.writeSetPeerBandwidth(2500000, 2, true); err != nil { + return + } + if conn.isserver { + // > StreamBegin + if err = conn.writeStreamBegin(0, true); err != nil { + return + } + } + // > SetChunkSize + if err = conn.writeSetChunkSize(1024*64, true); err != nil { return } return } -func (self *Conn) readConnect() (err error) { +func (conn *Conn) readConnect() (err error) { var connectpath string // < connect("app") - if err = self.pollCommand(); err != nil { + if err = conn.pollCommand(); err != nil { return } - if self.commandname != "connect" { + if conn.commandname != "connect" { err = fmt.Errorf("first command is not connect") return } - if self.commandobj == nil { + if conn.commandobj == nil { err = fmt.Errorf("connect command params invalid") return } + //fmt.Printf("readConnect: %+v\n", conn.commandobj) + var ok bool var _app, _tcurl interface{} - if _app, ok = self.commandobj["app"]; !ok { + if _app, ok = conn.commandobj["app"]; !ok { err = fmt.Errorf("the `connect` params missing `app`") return } connectpath, _ = _app.(string) var tcurl string - if _tcurl, ok = self.commandobj["tcUrl"]; !ok { - _tcurl, ok = self.commandobj["tcurl"] + if _tcurl, ok = conn.commandobj["tcUrl"]; !ok { + _tcurl, ok = conn.commandobj["tcurl"] } if ok { tcurl, _ = _tcurl.(string) } - connectparams := self.commandobj + connectparams := conn.commandobj - if err = self.writeBasicConf(); err != nil { + if err = conn.writeBasicConf(); err != nil { return } + objectEncoding, ok := connectparams["objectEncoding"] + if !ok { + objectEncoding = 3 + } + // > _result("NetConnection.Connect.Success") - if err = self.writeCommandMsg(3, 0, "_result", self.commandtransid, + if err = conn.writeCommandMsg(false, 3, 0, "_result", conn.commandtransid, flvio.AMFMap{ - "fmtVer": "FMS/3,0,1,123", + "fmsVer": "FMS/3,0,1,123", "capabilities": 31, }, flvio.AMFMap{ "level": "status", "code": "NetConnection.Connect.Success", "description": "Connection succeeded.", - "objectEncoding": 3, + "objectEncoding": objectEncoding, }, ); err != nil { return } - if err = self.flushWrite(); err != nil { + // > onBWDone() + if err = conn.writeCommandMsg(true, 3, 0, "onBWDone", 0, nil, 8192); err != nil { + return + } + + if err = conn.flushWrite(); err != nil { return } for { - if err = self.pollMsg(); err != nil { + if err = conn.pollMsg(); err != nil { return } - if self.gotcommand { - switch self.commandname { + if conn.gotcommand { + switch conn.commandname { // < createStream case "createStream": - self.avmsgsid = uint32(1) + conn.avmsgsid = uint32(1) // > _result(streamid) - if err = self.writeCommandMsg(3, 0, "_result", self.commandtransid, nil, self.avmsgsid); err != nil { + if err = conn.writeCommandMsg(false, 3, 0, "_result", conn.commandtransid, nil, conn.avmsgsid); err != nil { return } - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } @@ -529,20 +550,20 @@ func (self *Conn) readConnect() (err error) { fmt.Println("rtmp: < publish") } - if len(self.commandparams) < 1 { + if len(conn.commandparams) < 1 { err = fmt.Errorf("publish params invalid") return } - publishpath, _ := self.commandparams[0].(string) + publishpath, _ := conn.commandparams[0].(string) var cberr error - if self.OnPlayOrPublish != nil { - cberr = self.OnPlayOrPublish(self.commandname, connectparams) + if conn.OnPlayOrPublish != nil { + cberr = conn.OnPlayOrPublish(conn.commandname, connectparams) } // > onStatus() - if err = self.writeCommandMsg(5, self.avmsgsid, - "onStatus", self.commandtransid, nil, + if err = conn.writeCommandMsg(false, 5, conn.avmsgsid, + "onStatus", conn.commandtransid, nil, flvio.AMFMap{ "level": "status", "code": "NetStream.Publish.Start", @@ -551,7 +572,7 @@ func (self *Conn) readConnect() (err error) { ); err != nil { return } - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } @@ -566,10 +587,10 @@ func (self *Conn) readConnect() (err error) { return } - self.URL = u - self.publishing = true - self.reading = true - self.stage++ + conn.URL = u + conn.publishing = true + conn.reading = true + conn.stage++ return // < play("path") @@ -578,20 +599,20 @@ func (self *Conn) readConnect() (err error) { fmt.Println("rtmp: < play") } - if len(self.commandparams) < 1 { + if len(conn.commandparams) < 1 { err = fmt.Errorf("command play params invalid") return } - playpath, _ := self.commandparams[0].(string) + playpath, _ := conn.commandparams[0].(string) // > streamBegin(streamid) - if err = self.writeStreamBegin(self.avmsgsid); err != nil { + if err = conn.writeStreamBegin(conn.avmsgsid, false); err != nil { return } // > onStatus() - if err = self.writeCommandMsg(5, self.avmsgsid, - "onStatus", self.commandtransid, nil, + if err = conn.writeCommandMsg(false, 5, conn.avmsgsid, + "onStatus", conn.commandtransid, nil, flvio.AMFMap{ "level": "status", "code": "NetStream.Play.Start", @@ -608,7 +629,7 @@ func (self *Conn) readConnect() (err error) { // return //} - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } @@ -618,10 +639,10 @@ func (self *Conn) readConnect() (err error) { return } - self.URL = u - self.playing = true - self.writing = true - self.stage++ + conn.URL = u + conn.playing = true + conn.writing = true + conn.stage++ return } @@ -629,19 +650,19 @@ func (self *Conn) readConnect() (err error) { } } -func (self *Conn) checkConnectResult() (ok bool, errmsg string) { - if len(self.commandparams) < 1 { +func (conn *Conn) checkConnectResult() (ok bool, errmsg string) { + if len(conn.commandparams) < 1 { errmsg = "params length < 1" return } - obj, _ := self.commandparams[0].(flvio.AMFMap) + obj, _ := conn.commandparams[0].(flvio.AMFMap) if obj == nil { errmsg = "params[0] not object" return } - _code, _ := obj["code"] + _code := obj["code"] if _code == nil { errmsg = "code invalid" return @@ -657,73 +678,74 @@ func (self *Conn) checkConnectResult() (ok bool, errmsg string) { return } -func (self *Conn) checkCreateStreamResult() (ok bool, avmsgsid uint32) { - if len(self.commandparams) < 1 { +func (conn *Conn) checkCreateStreamResult() (ok bool, avmsgsid uint32) { + if len(conn.commandparams) < 1 { return } ok = true - _avmsgsid, _ := self.commandparams[0].(float64) + _avmsgsid, _ := conn.commandparams[0].(float64) avmsgsid = uint32(_avmsgsid) return } -func (self *Conn) probe() (err error) { - for !self.prober.Probed() { +func (conn *Conn) probe() (err error) { + for !conn.prober.Probed() { var tag flvio.Tag - if tag, err = self.pollAVTag(); err != nil { + if tag, err = conn.pollAVTag(); err != nil { return } - if err = self.prober.PushTag(tag, int32(self.timestamp)); err != nil { + if err = conn.prober.PushTag(tag, int32(conn.timestamp)); err != nil { if Debug { fmt.Printf("rtmp: error probing tag: %s\n", err.Error()) } } } - self.streams = self.prober.Streams - self.stage++ + conn.streams = conn.prober.Streams + conn.stage++ return } -func (self *Conn) writeConnect(path string) (err error) { - if err = self.writeBasicConf(); err != nil { +func (conn *Conn) writeConnect(path string) (err error) { + if err = conn.writeBasicConf(); err != nil { return } // > connect("app") if Debug { - fmt.Printf("rtmp: > connect('%s') host=%s\n", path, self.URL.Host) + fmt.Printf("rtmp: > connect('%s') host=%s\n", path, conn.URL.Host) } - if err = self.writeCommandMsg(3, 0, "connect", 1, + if err = conn.writeCommandMsg(false, 3, 0, "connect", 1, flvio.AMFMap{ "app": path, "flashVer": "MAC 22,0,0,192", - "tcUrl": getTcUrl(self.URL), + "tcUrl": getTcUrl(conn.URL), "fpad": false, "capabilities": 15, "audioCodecs": 4071, "videoCodecs": 252, "videoFunction": 1, + "fourCcList": flvio.AMFArray{"av01", "vp09", "hvc1"}, }, ); err != nil { return } - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } for { - if err = self.pollMsg(); err != nil { + if err = conn.pollMsg(); err != nil { return } - if self.gotcommand { + if conn.gotcommand { // < _result("NetConnection.Connect.Success") - if self.commandname == "_result" { + if conn.commandname == "_result" { var ok bool var errmsg string - if ok, errmsg = self.checkConnectResult(); !ok { + if ok, errmsg = conn.checkConnectResult(); !ok { err = fmt.Errorf("command connect failed: %s", errmsg) return } @@ -733,9 +755,9 @@ func (self *Conn) writeConnect(path string) (err error) { break } } else { - if self.msgtypeid == msgtypeidWindowAckSize { - if len(self.msgdata) == 4 { - self.readAckSize = pio.U32BE(self.msgdata) + if conn.msgtypeid == msgtypeidWindowAckSize { + if len(conn.msgdata) == 4 { + conn.readAckSize = pio.U32BE(conn.msgdata) } //if err = self.writeWindowAckSize(0xffffffff); err != nil { // return @@ -747,10 +769,10 @@ func (self *Conn) writeConnect(path string) (err error) { return } -func (self *Conn) connectPublish() (err error) { - connectpath, publishpath := SplitPath(self.URL) +func (conn *Conn) connectPublish() (err error) { + connectpath, publishpath := SplitPath(conn.URL) - if err = self.writeConnect(connectpath); err != nil { + if err = conn.writeConnect(connectpath); err != nil { return } @@ -760,24 +782,24 @@ func (self *Conn) connectPublish() (err error) { if Debug { fmt.Printf("rtmp: > createStream()\n") } - if err = self.writeCommandMsg(3, 0, "createStream", transid, nil); err != nil { + if err = conn.writeCommandMsg(false, 3, 0, "createStream", transid, nil); err != nil { return } transid++ - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } for { - if err = self.pollMsg(); err != nil { + if err = conn.pollMsg(); err != nil { return } - if self.gotcommand { + if conn.gotcommand { // < _result(avmsgsid) of createStream - if self.commandname == "_result" { + if conn.commandname == "_result" { var ok bool - if ok, self.avmsgsid = self.checkCreateStreamResult(); !ok { + if ok, conn.avmsgsid = conn.checkCreateStreamResult(); !ok { err = fmt.Errorf("createStream command failed") return } @@ -790,25 +812,25 @@ func (self *Conn) connectPublish() (err error) { if Debug { fmt.Printf("rtmp: > publish('%s')\n", publishpath) } - if err = self.writeCommandMsg(8, self.avmsgsid, "publish", transid, nil, publishpath); err != nil { + if err = conn.writeCommandMsg(false, 8, conn.avmsgsid, "publish", transid, nil, publishpath); err != nil { return } transid++ - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } - self.writing = true - self.publishing = true - self.stage++ + conn.writing = true + conn.publishing = true + conn.stage++ return } -func (self *Conn) connectPlay() (err error) { - connectpath, playpath := SplitPath(self.URL) +func (conn *Conn) connectPlay() (err error) { + connectpath, playpath := SplitPath(conn.URL) - if err = self.writeConnect(connectpath); err != nil { + if err = conn.writeConnect(connectpath); err != nil { return } @@ -816,28 +838,28 @@ func (self *Conn) connectPlay() (err error) { if Debug { fmt.Printf("rtmp: > createStream()\n") } - if err = self.writeCommandMsg(3, 0, "createStream", 2, nil); err != nil { + if err = conn.writeCommandMsg(false, 3, 0, "createStream", 2, nil); err != nil { return } // > SetBufferLength 0,100ms - if err = self.writeSetBufferLength(0, 100); err != nil { + if err = conn.writeSetBufferLength(0, 100, false); err != nil { return } - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } for { - if err = self.pollMsg(); err != nil { + if err = conn.pollMsg(); err != nil { return } - if self.gotcommand { + if conn.gotcommand { // < _result(avmsgsid) of createStream - if self.commandname == "_result" { + if conn.commandname == "_result" { var ok bool - if ok, self.avmsgsid = self.checkCreateStreamResult(); !ok { + if ok, conn.avmsgsid = conn.checkCreateStreamResult(); !ok { err = fmt.Errorf("createStream command failed") return } @@ -850,72 +872,72 @@ func (self *Conn) connectPlay() (err error) { if Debug { fmt.Printf("rtmp: > play('%s')\n", playpath) } - if err = self.writeCommandMsg(8, self.avmsgsid, "play", 0, nil, playpath); err != nil { + if err = conn.writeCommandMsg(false, 8, conn.avmsgsid, "play", 0, nil, playpath); err != nil { return } - if err = self.flushWrite(); err != nil { + if err = conn.flushWrite(); err != nil { return } - self.reading = true - self.playing = true - self.stage++ + conn.reading = true + conn.playing = true + conn.stage++ return } -func (self *Conn) ReadPacket() (pkt av.Packet, err error) { - if err = self.prepare(stageCodecDataDone, prepareReading); err != nil { +func (conn *Conn) ReadPacket() (pkt av.Packet, err error) { + if err = conn.prepare(stageCodecDataDone, prepareReading); err != nil { return } - if !self.prober.Empty() { - pkt = self.prober.PopPacket() + if !conn.prober.Empty() { + pkt = conn.prober.PopPacket() return } for { var tag flvio.Tag - if tag, err = self.pollAVTag(); err != nil { + if tag, err = conn.pollAVTag(); err != nil { return } var ok bool - if pkt, ok = self.prober.TagToPacket(tag, int32(self.timestamp)); ok { + if pkt, ok = conn.prober.TagToPacket(tag, int32(conn.timestamp)); ok { return pkt, nil } } } -func (self *Conn) Prepare() (err error) { - return self.prepare(stageCommandDone, 0) +func (conn *Conn) Prepare() (err error) { + return conn.prepare(stageCommandDone, 0) } -func (self *Conn) prepare(stage int, flags int) (err error) { - for self.stage < stage { - switch self.stage { +func (conn *Conn) prepare(stage int, flags int) (err error) { + for conn.stage < stage { + switch conn.stage { case 0: - if self.isserver { - if err = self.handshakeServer(); err != nil { + if conn.isserver { + if err = conn.handshakeServer(); err != nil { return } } else { - if err = self.handshakeClient(); err != nil { + if err = conn.handshakeClient(); err != nil { return } } case stageHandshakeDone: - if self.isserver { - if err = self.readConnect(); err != nil { + if conn.isserver { + if err = conn.readConnect(); err != nil { return } } else { if flags == prepareReading { - if err = self.connectPlay(); err != nil { + if err = conn.connectPlay(); err != nil { return } } else { - if err = self.connectPublish(); err != nil { + if err = conn.connectPublish(); err != nil { return } } @@ -923,7 +945,7 @@ func (self *Conn) prepare(stage int, flags int) (err error) { case stageCommandDone: if flags == prepareReading { - if err = self.probe(); err != nil { + if err = conn.probe(); err != nil { return } } else { @@ -935,56 +957,56 @@ func (self *Conn) prepare(stage int, flags int) (err error) { return } -func (self *Conn) Streams() (streams []av.CodecData, err error) { - if err = self.prepare(stageCodecDataDone, prepareReading); err != nil { +func (conn *Conn) Streams() (streams []av.CodecData, err error) { + if err = conn.prepare(stageCodecDataDone, prepareReading); err != nil { return } - streams = self.streams + streams = conn.streams return } -func (self *Conn) WritePacket(pkt av.Packet) (err error) { - if err = self.prepare(stageCodecDataDone, prepareWriting); err != nil { +func (conn *Conn) WritePacket(pkt av.Packet) (err error) { + if err = conn.prepare(stageCodecDataDone, prepareWriting); err != nil { return } - stream := self.streams[pkt.Idx] + stream := conn.streams[pkt.Idx] tag, timestamp := flv.PacketToTag(pkt, stream) if Debug { fmt.Println("rtmp: WritePacket", pkt.Idx, pkt.Time, pkt.CompositionTime) } - if err = self.writeAVTag(tag, int32(timestamp)); err != nil { + if err = conn.writeAVTag(tag, int32(timestamp)); err != nil { return } return } -func (self *Conn) WriteTrailer() (err error) { - if err = self.flushWrite(); err != nil { +func (conn *Conn) WriteTrailer() (err error) { + if err = conn.flushWrite(); err != nil { return } return } -func (self *Conn) SetMetaData(data flvio.AMFMap) { - self.metadata = data +func (conn *Conn) SetMetaData(data flvio.AMFMap) { + conn.metadata = data } -func (self *Conn) GetMetaData() flvio.AMFMap { - return self.metadata +func (conn *Conn) GetMetaData() flvio.AMFMap { + return conn.metadata } -func (self *Conn) WriteHeader(streams []av.CodecData) (err error) { - if err = self.prepare(stageCommandDone, prepareWriting); err != nil { +func (conn *Conn) WriteHeader(streams []av.CodecData) (err error) { + if err = conn.prepare(stageCommandDone, prepareWriting); err != nil { return } var metadata flvio.AMFMap = nil - metadata = self.GetMetaData() + //metadata = self.GetMetaData() if metadata == nil { if metadata, err = flv.NewMetadataByStreams(streams); err != nil { @@ -993,7 +1015,7 @@ func (self *Conn) WriteHeader(streams []av.CodecData) (err error) { } // > onMetaData() - if err = self.writeDataMsg(5, self.avmsgsid, "onMetaData", metadata); err != nil { + if err = conn.writeDataMsg(5, conn.avmsgsid, "onMetaData", metadata); err != nil { return } @@ -1006,88 +1028,100 @@ func (self *Conn) WriteHeader(streams []av.CodecData) (err error) { return } if ok { - if err = self.writeAVTag(tag, 0); err != nil { + if err = conn.writeAVTag(tag, 0); err != nil { return } } } - self.streams = streams - self.stage++ + conn.streams = streams + conn.stage++ return } -func (self *Conn) tmpwbuf(n int) []byte { - if len(self.writebuf) < n { - self.writebuf = make([]byte, n) +func (conn *Conn) tmpwbuf(n int) []byte { + if len(conn.writebuf) < n { + conn.writebuf = make([]byte, n) } - return self.writebuf + return conn.writebuf } -func (self *Conn) writeSetChunkSize(size int) (err error) { - self.writeMaxChunkSize = size - b := self.tmpwbuf(chunkHeaderLength + 4) - n := self.fillChunkHeader(b, 2, 0, msgtypeidSetChunkSize, 0, 4) +func (conn *Conn) writeSetChunkSize(size int, append bool) (err error) { + conn.writeMaxChunkSize = size + var b []byte + var n int + + b = conn.tmpwbuf(chunkHeaderLength + 4) + n = conn.fillChunkHeader(append, b, 2, 0, msgtypeidSetChunkSize, 0, 4) pio.PutU32BE(b[n:], uint32(size)) n += 4 - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } -func (self *Conn) writeAck(seqnum uint32) (err error) { - b := self.tmpwbuf(chunkHeaderLength + 4) - n := self.fillChunkHeader(b, 2, 0, msgtypeidAck, 0, 4) +func (conn *Conn) writeAck(seqnum uint32, append bool) (err error) { + var b []byte + var n int + + b = conn.tmpwbuf(chunkHeaderLength + 4) + n = conn.fillChunkHeader(append, b, 2, 0, msgtypeidAck, 0, 4) pio.PutU32BE(b[n:], seqnum) n += 4 - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } -func (self *Conn) writeWindowAckSize(size uint32) (err error) { - b := self.tmpwbuf(chunkHeaderLength + 4) - n := self.fillChunkHeader(b, 2, 0, msgtypeidWindowAckSize, 0, 4) +func (conn *Conn) writeWindowAckSize(size uint32, append bool) (err error) { + var b []byte + var n int + + b = conn.tmpwbuf(chunkHeaderLength + 4) + n = conn.fillChunkHeader(append, b, 2, 0, msgtypeidWindowAckSize, 0, 4) pio.PutU32BE(b[n:], size) n += 4 - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } -func (self *Conn) writeSetPeerBandwidth(acksize uint32, limittype uint8) (err error) { - b := self.tmpwbuf(chunkHeaderLength + 5) - n := self.fillChunkHeader(b, 2, 0, msgtypeidSetPeerBandwidth, 0, 5) +func (conn *Conn) writeSetPeerBandwidth(acksize uint32, limittype uint8, append bool) (err error) { + var b []byte + var n int + + b = conn.tmpwbuf(chunkHeaderLength + 5) + n = conn.fillChunkHeader(append, b, 2, 0, msgtypeidSetPeerBandwidth, 0, 5) pio.PutU32BE(b[n:], acksize) n += 4 b[n] = limittype n++ - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } -func (self *Conn) writeCommandMsg(csid, msgsid uint32, args ...interface{}) (err error) { - return self.writeAMF0Msg(msgtypeidCommandMsgAMF0, csid, msgsid, args...) +func (conn *Conn) writeCommandMsg(append bool, csid, msgsid uint32, args ...interface{}) (err error) { + return conn.writeAMF0Msg(append, msgtypeidCommandMsgAMF0, csid, msgsid, args...) } -func (self *Conn) writeDataMsg(csid, msgsid uint32, args ...interface{}) (err error) { - return self.writeAMF0Msg(msgtypeidDataMsgAMF0, csid, msgsid, args...) +func (conn *Conn) writeDataMsg(csid, msgsid uint32, args ...interface{}) (err error) { + return conn.writeAMF0Msg(false, msgtypeidDataMsgAMF0, csid, msgsid, args...) } -func (self *Conn) writeAMF0Msg(msgtypeid uint8, csid, msgsid uint32, args ...interface{}) (err error) { +func (conn *Conn) writeAMF0Msg(append bool, msgtypeid uint8, csid, msgsid uint32, args ...interface{}) (err error) { size := 0 for _, arg := range args { size += flvio.LenAMF0Val(arg) } - b := self.tmpwbuf(chunkHeaderLength + size) - n := self.fillChunkHeader(b, csid, 0, msgtypeid, msgsid, size) + b := conn.tmpwbuf(chunkHeaderLength + size) + n := conn.fillChunkHeader(append, b, csid, 0, msgtypeid, msgsid, size) for _, arg := range args { n += flvio.FillAMF0Val(b[n:], arg) } - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } -func (self *Conn) writeAVTag(tag flvio.Tag, ts int32) (err error) { +func (conn *Conn) writeAVTag(tag flvio.Tag, ts int32) (err error) { var msgtypeid uint8 var csid uint32 var data []byte @@ -1109,114 +1143,181 @@ func (self *Conn) writeAVTag(tag flvio.Tag, ts int32) (err error) { actualChunkHeaderLength += 4 } - b := self.tmpwbuf(actualChunkHeaderLength + flvio.MaxTagSubHeaderLength) + b := conn.tmpwbuf(actualChunkHeaderLength + flvio.MaxTagSubHeaderLength) hdrlen := tag.FillHeader(b[actualChunkHeaderLength:]) - self.fillChunkHeader(b, csid, ts, msgtypeid, self.avmsgsid, hdrlen+len(data)) - n := hdrlen + actualChunkHeaderLength + conn.fillChunkHeader(false, b, csid, ts, msgtypeid, conn.avmsgsid, hdrlen+len(data)) + n := actualChunkHeaderLength + hdrlen - if n+len(data) > self.writeMaxChunkSize { - if err = self.writeSetChunkSize(n + len(data)); err != nil { - return - } - } - - if _, err = self.bufw.Write(b[:n]); err != nil { + if _, err = conn.bufw.Write(b[:n]); err != nil { return } - _, err = self.bufw.Write(data) - err = self.bufw.Flush() + + chunksize := conn.writeMaxChunkSize + msgdataleft := len(data) + + n = msgdataleft + if msgdataleft > chunksize-hdrlen { + n = chunksize - hdrlen + } + + if _, err = conn.bufw.Write(data[:n]); err != nil { + return + } + + data = data[n:] + msgdataleft -= n + + for { + if msgdataleft == 0 { + break + } + + n = conn.fillChunkHeader3(b, csid, ts) + + if _, err = conn.bufw.Write(b[:n]); err != nil { + return + } + + n = msgdataleft + if msgdataleft > chunksize { + n = chunksize + } + + if _, err = conn.bufw.Write(data[:n]); err != nil { + return + } + + data = data[n:] + msgdataleft -= n + } + + err = conn.bufw.Flush() + return } -func (self *Conn) writeStreamBegin(msgsid uint32) (err error) { - b := self.tmpwbuf(chunkHeaderLength + 6) - n := self.fillChunkHeader(b, 2, 0, msgtypeidUserControl, 0, 6) +func (conn *Conn) writeStreamBegin(msgsid uint32, append bool) (err error) { + b := conn.tmpwbuf(chunkHeaderLength + 6) + n := conn.fillChunkHeader(append, b, 2, 0, msgtypeidUserControl, 0, 6) pio.PutU16BE(b[n:], eventtypeStreamBegin) n += 2 pio.PutU32BE(b[n:], msgsid) n += 4 - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } -func (self *Conn) writeSetBufferLength(msgsid uint32, timestamp uint32) (err error) { - b := self.tmpwbuf(chunkHeaderLength + 10) - n := self.fillChunkHeader(b, 2, 0, msgtypeidUserControl, 0, 10) +func (conn *Conn) writeSetBufferLength(msgsid uint32, timestamp uint32, append bool) (err error) { + b := conn.tmpwbuf(chunkHeaderLength + 10) + n := conn.fillChunkHeader(append, b, 2, 0, msgtypeidUserControl, 0, 10) pio.PutU16BE(b[n:], eventtypeSetBufferLength) n += 2 pio.PutU32BE(b[n:], msgsid) n += 4 pio.PutU32BE(b[n:], timestamp) n += 4 - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } -func (self *Conn) writePingResponse(timestamp uint32) (err error) { - b := self.tmpwbuf(chunkHeaderLength + 10) - n := self.fillChunkHeader(b, 2, 0, msgtypeidUserControl, 0, 6) +func (conn *Conn) writePingResponse(timestamp uint32, append bool) (err error) { + b := conn.tmpwbuf(chunkHeaderLength + 10) + n := conn.fillChunkHeader(append, b, 2, 0, msgtypeidUserControl, 0, 6) pio.PutU16BE(b[n:], eventtypePingResponse) n += 2 pio.PutU32BE(b[n:], timestamp) n += 4 - _, err = self.bufw.Write(b[:n]) + _, err = conn.bufw.Write(b[:n]) return } const chunkHeaderLength = 12 const FlvTimestampMax = 0xFFFFFF -func (self *Conn) fillChunkHeader(b []byte, csid uint32, timestamp int32, msgtypeid uint8, msgsid uint32, msgdatalen int) (n int) { - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | timestamp |message length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | message length (cont) |message type id| msg stream id | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | message stream id (cont) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // - // Figure 9 Chunk Message Header – Type 0 +func (conn *Conn) fillChunkHeader(append bool, b []byte, csid uint32, timestamp int32, msgtypeid uint8, msgsid uint32, msgdatalen int) (n int) { + if !append { + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | timestamp |message length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | message length (cont) |message type id| msg stream id | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | message stream id (cont) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // Figure 9 Chunk Message Header – Type 0 - b[n] = byte(csid) & 0x3f - n++ - if uint32(timestamp) <= FlvTimestampMax { - pio.PutU24BE(b[n:], uint32(timestamp)) - } else { - pio.PutU24BE(b[n:], FlvTimestampMax) - } - n += 3 - pio.PutU24BE(b[n:], uint32(msgdatalen)) - n += 3 - b[n] = msgtypeid - n++ - pio.PutU32LE(b[n:], msgsid) - n += 4 - if uint32(timestamp) > FlvTimestampMax { - pio.PutU32BE(b[n:], uint32(timestamp)) + b[n] = byte(csid) & 0x3f + n++ + if uint32(timestamp) <= FlvTimestampMax { + pio.PutU24BE(b[n:], uint32(timestamp)) + } else { + pio.PutU24BE(b[n:], FlvTimestampMax) + } + n += 3 + pio.PutU24BE(b[n:], uint32(msgdatalen)) + n += 3 + b[n] = msgtypeid + n++ + pio.PutU32LE(b[n:], msgsid) n += 4 + if uint32(timestamp) > FlvTimestampMax { + pio.PutU32BE(b[n:], uint32(timestamp)) + n += 4 + } + } else { + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | timestamp delta |message length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | message length (cont) |message type id| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // Figure 10 Chunk Message Header – Type 1 + + b[n] = 1 << 6 + b[n] += byte(csid) & 0x3f + n++ + pio.PutU24BE(b[n:], 0) + n += 3 + pio.PutU24BE(b[n:], uint32(msgdatalen)) + n += 3 + b[n] = msgtypeid + n++ } if Debug { fmt.Printf("rtmp: write chunk msgdatalen=%d msgsid=%d\n", msgdatalen, msgsid) - fmt.Print(hex.Dump(b[:msgdatalen])) + fmt.Print(hex.Dump(b[:n])) } return } -func (self *Conn) flushWrite() (err error) { - if err = self.bufw.Flush(); err != nil { +func (c *Conn) fillChunkHeader3(b []byte, csid uint32, timestamp int32) (n int) { + pio.PutU8(b, (uint8(csid)&0x3f)|3<<6) + n++ + if uint32(timestamp) >= FlvTimestampMax { + pio.PutU32BE(b[n:], uint32(timestamp)) + n += 4 + } + + return +} + +func (conn *Conn) flushWrite() (err error) { + if err = conn.bufw.Flush(); err != nil { return } return } -func (self *Conn) readChunk() (err error) { - b := self.readbuf +func (conn *Conn) readChunk() (err error) { + b := conn.readbuf n := 0 - if _, err = io.ReadFull(self.bufr, b[:1]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:1]); err != nil { return } header := b[0] @@ -1231,23 +1332,23 @@ func (self *Conn) readChunk() (err error) { switch csid { default: // Chunk basic header 1 case 0: // Chunk basic header 2 - if _, err = io.ReadFull(self.bufr, b[:1]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:1]); err != nil { return fmt.Errorf("chunk basic header 2: %w", err) } n += 1 csid = uint32(b[0]) + 64 case 1: // Chunk basic header 3 - if _, err = io.ReadFull(self.bufr, b[:2]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:2]); err != nil { return fmt.Errorf("chunk basic header 3: %w", err) } n += 2 csid = uint32(pio.U16BE(b)) + 64 } - cs := self.readcsmap[csid] + cs := conn.readcsmap[csid] if cs == nil { cs = &chunkStream{} - self.readcsmap[csid] = cs + conn.readcsmap[csid] = cs } var timestamp uint32 @@ -1270,7 +1371,7 @@ func (self *Conn) readChunk() (err error) { return } h := b[:11] - if _, err = io.ReadFull(self.bufr, h); err != nil { + if _, err = io.ReadFull(conn.bufr, h); err != nil { return } n += len(h) @@ -1280,7 +1381,7 @@ func (self *Conn) readChunk() (err error) { cs.msgtypeid = h[6] cs.msgsid = pio.U32LE(h[7:11]) if timestamp == 0xffffff { - if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:4]); err != nil { return } n += 4 @@ -1307,7 +1408,7 @@ func (self *Conn) readChunk() (err error) { return } h := b[:7] - if _, err = io.ReadFull(self.bufr, h); err != nil { + if _, err = io.ReadFull(conn.bufr, h); err != nil { return } n += len(h) @@ -1316,7 +1417,7 @@ func (self *Conn) readChunk() (err error) { cs.msgdatalen = pio.U24BE(h[3:6]) cs.msgtypeid = h[6] if timestamp == 0xffffff { - if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:4]); err != nil { return } n += 4 @@ -1342,14 +1443,14 @@ func (self *Conn) readChunk() (err error) { return } h := b[:3] - if _, err = io.ReadFull(self.bufr, h); err != nil { + if _, err = io.ReadFull(conn.bufr, h); err != nil { return } n += len(h) cs.msghdrtype = msghdrtype timestamp = pio.U24BE(h[0:3]) if timestamp == 0xffffff { - if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:4]); err != nil { return } n += 4 @@ -1367,7 +1468,7 @@ func (self *Conn) readChunk() (err error) { switch cs.msghdrtype { case 0: if cs.hastimeext { - if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:4]); err != nil { return } n += 4 @@ -1376,7 +1477,7 @@ func (self *Conn) readChunk() (err error) { } case 1, 2: if cs.hastimeext { - if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { + if _, err = io.ReadFull(conn.bufr, b[:4]); err != nil { return } n += 4 @@ -1395,12 +1496,12 @@ func (self *Conn) readChunk() (err error) { } size := int(cs.msgdataleft) - if size > self.readMaxChunkSize { - size = self.readMaxChunkSize + if size > conn.readMaxChunkSize { + size = conn.readMaxChunkSize } off := cs.msgdatalen - cs.msgdataleft buf := cs.msgdata[off : int(off)+size] - if _, err = io.ReadFull(self.bufr, buf); err != nil { + if _, err = io.ReadFull(conn.bufr, buf); err != nil { return } n += len(buf) @@ -1417,25 +1518,47 @@ func (self *Conn) readChunk() (err error) { fmt.Print(hex.Dump(cs.msgdata)) } - if err = self.handleMsg(cs.timenow, cs.msgsid, cs.msgtypeid, cs.msgdata); err != nil { + timestamp = cs.timenow + + if cs.msgtypeid == msgtypeidVideoMsg || cs.msgtypeid == msgtypeidAudioMsg { + if !cs.gentimenow { + if cs.prevtimenow >= cs.timenow { + cs.tscount++ + } else { + cs.tscount = 0 + } + + if cs.tscount > 3 { + cs.gentimenow = true + } + } + + if cs.gentimenow { + timestamp = uint32((time.Since(conn.start).Milliseconds() % 0xFFFFFFFF) & 0xFFFFFFFF) + } + } + + if err = conn.handleMsg(timestamp, cs.msgsid, cs.msgtypeid, cs.msgdata); err != nil { return fmt.Errorf("handleMsg: %w", err) } + + cs.prevtimenow = cs.timenow } - self.ackn += uint32(n) + conn.ackn += uint32(n) - if self.readAckSize != 0 && self.ackn > self.readAckSize { - if err = self.writeAck(self.ackn); err != nil { + if conn.readAckSize != 0 && conn.ackn > conn.readAckSize { + if err = conn.writeAck(conn.ackn, false); err != nil { return fmt.Errorf("writeACK: %w", err) } - self.flushWrite() - self.ackn = 0 + conn.flushWrite() + conn.ackn = 0 } return } -func (self *Conn) handleCommandMsgAMF0(b []byte) (n int, err error) { +func (conn *Conn) handleCommandMsgAMF0(b []byte) (n int, err error) { var name, transid, obj interface{} var size int @@ -1453,38 +1576,38 @@ func (self *Conn) handleCommandMsgAMF0(b []byte) (n int, err error) { n += size var ok bool - if self.commandname, ok = name.(string); !ok { + if conn.commandname, ok = name.(string); !ok { err = fmt.Errorf("CommandMsgAMF0 command is not string") return } - self.commandtransid, _ = transid.(float64) - self.commandobj, _ = obj.(flvio.AMFMap) - self.commandparams = []interface{}{} + conn.commandtransid, _ = transid.(float64) + conn.commandobj, _ = obj.(flvio.AMFMap) + conn.commandparams = []interface{}{} for n < len(b) { if obj, size, err = flvio.ParseAMF0Val(b[n:]); err != nil { return } n += size - self.commandparams = append(self.commandparams, obj) + conn.commandparams = append(conn.commandparams, obj) } if n < len(b) { err = fmt.Errorf("CommandMsgAMF0 left bytes=%d", len(b)-n) return } - self.gotcommand = true + conn.gotcommand = true return } -func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, msgdata []byte) (err error) { - self.msgdata = msgdata - self.msgtypeid = msgtypeid - self.timestamp = timestamp +func (conn *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, msgdata []byte) (err error) { + conn.msgdata = msgdata + conn.msgtypeid = msgtypeid + conn.timestamp = timestamp switch msgtypeid { case msgtypeidCommandMsgAMF0: - if _, err = self.handleCommandMsgAMF0(msgdata); err != nil { + if _, err = conn.handleCommandMsgAMF0(msgdata); err != nil { return } @@ -1494,7 +1617,7 @@ func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, ms return } // skip first byte - if _, err = self.handleCommandMsgAMF0(msgdata[1:]); err != nil { + if _, err = conn.handleCommandMsgAMF0(msgdata[1:]); err != nil { return } @@ -1503,16 +1626,16 @@ func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, ms err = fmt.Errorf("short packet of UserControl") return } - self.eventtype = pio.U16BE(msgdata) + conn.eventtype = pio.U16BE(msgdata) - if self.eventtype == eventtypePingRequest { + if conn.eventtype == eventtypePingRequest { if len(msgdata) != 6 { err = fmt.Errorf("wrong length for UserControl.PingRequest") return } pingtimestamp := pio.U32BE(msgdata[2:]) - self.writePingResponse(pingtimestamp) - self.flushWrite() + conn.writePingResponse(pingtimestamp, false) + conn.flushWrite() } case msgtypeidDataMsgAMF0: @@ -1525,7 +1648,7 @@ func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, ms return } n += size - self.datamsgvals = append(self.datamsgvals, obj) + conn.datamsgvals = append(conn.datamsgvals, obj) } if n < len(b) { err = fmt.Errorf("DataMsgAMF0 left bytes=%d", len(b)-n) @@ -1536,33 +1659,37 @@ func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, ms metaindex := -1 - for i, x := range self.datamsgvals { - switch x.(type) { + for i, x := range conn.datamsgvals { + switch x := x.(type) { case string: - if x.(string) == "onMetaData" { + if x == "onMetaData" { metaindex = i + 1 } } } - if metaindex != -1 && metaindex < len(self.datamsgvals) { - self.metadata = self.datamsgvals[metaindex].(flvio.AMFMap) + if metaindex != -1 && metaindex < len(conn.datamsgvals) { + conn.metadata = conn.datamsgvals[metaindex].(flvio.AMFMap) + //fmt.Printf("onMetadata: %+v\n", self.metadata) + //fmt.Printf("videocodecid: %#08x (%f)\n", int64(self.metadata["videocodecid"].(float64)), self.metadata["videocodecid"].(float64)) } case msgtypeidVideoMsg: if len(msgdata) == 0 { return } + //fmt.Printf("msgdata: %#08x\n", msgdata[:5]) tag := flvio.Tag{Type: flvio.TAG_VIDEO} var n int if n, err = (&tag).ParseHeader(msgdata); err != nil { return } + //fmt.Printf("tag: %+v\n", tag) if !(tag.FrameType == flvio.FRAME_INTER || tag.FrameType == flvio.FRAME_KEY) { return } tag.Data = msgdata[n:] - self.avtag = tag + conn.avtag = tag case msgtypeidAudioMsg: if len(msgdata) == 0 { @@ -1574,28 +1701,26 @@ func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, ms return } tag.Data = msgdata[n:] - self.avtag = tag + conn.avtag = tag case msgtypeidSetChunkSize: if len(msgdata) < 4 { err = fmt.Errorf("short packet of SetChunkSize") return } - self.readMaxChunkSize = int(pio.U32BE(msgdata)) - return + conn.readMaxChunkSize = int(pio.U32BE(msgdata)) case msgtypeidWindowAckSize: - if len(self.msgdata) != 4 { + if len(conn.msgdata) != 4 { return fmt.Errorf("invalid packet of WindowAckSize") } - self.readAckSize = pio.U32BE(self.msgdata) - return + conn.readAckSize = pio.U32BE(conn.msgdata) default: if Debug { fmt.Printf("rtmp: unhandled msg: %d\n", msgtypeid) } } - self.gotmsg = true + conn.gotmsg = true return } @@ -1643,7 +1768,7 @@ func hsCalcDigestPos(p []byte, base int) (pos int) { func hsFindDigest(p []byte, key []byte, base int) int { gap := hsCalcDigestPos(p, base) digest := hsMakeDigest(key, p, gap) - if bytes.Compare(p[gap:gap+32], digest) != 0 { + if !bytes.Equal(p[gap:gap+32], digest) { return -1 } return gap @@ -1679,14 +1804,14 @@ func hsCreate2(p []byte, key []byte) { copy(p[gap:], digest) } -func (self *Conn) handshakeClient() (err error) { +func (conn *Conn) handshakeClient() (err error) { var random [(1 + 1536*2) * 2]byte C0C1C2 := random[:1536*2+1] C0 := C0C1C2[:1] //C1 := C0C1C2[1:1536+1] C0C1 := C0C1C2[:1536+1] - C2 := C0C1C2[1536+1:] + var C2 []byte S0S1S2 := random[1536*2+1:] //S0 := S0S1S2[:1] @@ -1698,15 +1823,15 @@ func (self *Conn) handshakeClient() (err error) { //hsCreate01(C0C1, hsClientFullKey) // > C0C1 - if _, err = self.bufw.Write(C0C1); err != nil { + if _, err = conn.bufw.Write(C0C1); err != nil { return } - if err = self.bufw.Flush(); err != nil { + if err = conn.bufw.Flush(); err != nil { return } // < S0S1S2 - if _, err = io.ReadFull(self.bufr, S0S1S2); err != nil { + if _, err = io.ReadFull(conn.bufr, S0S1S2); err != nil { return } @@ -1721,15 +1846,15 @@ func (self *Conn) handshakeClient() (err error) { } // > C2 - if _, err = self.bufw.Write(C2); err != nil { + if _, err = conn.bufw.Write(C2); err != nil { return } - self.stage++ + conn.stage++ return } -func (self *Conn) handshakeServer() (err error) { +func (conn *Conn) handshakeServer() (err error) { var random [(1 + 1536*2) * 2]byte C0C1C2 := random[:1536*2+1] @@ -1745,7 +1870,7 @@ func (self *Conn) handshakeServer() (err error) { S2 := S0S1S2[1536+1:] // < C0C1 - if _, err = io.ReadFull(self.bufr, C0C1); err != nil { + if _, err = io.ReadFull(conn.bufr, C0C1); err != nil { return } if C0[0] != 3 { @@ -1775,19 +1900,19 @@ func (self *Conn) handshakeServer() (err error) { } // > S0S1S2 - if _, err = self.bufw.Write(S0S1S2); err != nil { + if _, err = conn.bufw.Write(S0S1S2); err != nil { return } - if err = self.bufw.Flush(); err != nil { + if err = conn.bufw.Flush(); err != nil { return } // < C2 - if _, err = io.ReadFull(self.bufr, C2); err != nil { + if _, err = io.ReadFull(conn.bufr, C2); err != nil { return } - self.stage++ + conn.stage++ return } @@ -1796,8 +1921,8 @@ type closeConn struct { waitclose chan bool } -func (self closeConn) Close() error { - self.waitclose <- true +func (cc closeConn) Close() error { + cc.waitclose <- true return nil } diff --git a/vendor/github.com/datarhei/joy4/utils/bits/golomb_reader.go b/vendor/github.com/datarhei/joy4/utils/bits/golomb_reader.go index da57cb2f..b40978be 100644 --- a/vendor/github.com/datarhei/joy4/utils/bits/golomb_reader.go +++ b/vendor/github.com/datarhei/joy4/utils/bits/golomb_reader.go @@ -33,6 +33,30 @@ func (self *GolombBitReader) ReadBits(n int) (res uint, err error) { return } +func (self *GolombBitReader) ReadBits32(n uint) (r uint32, err error) { + var t uint + for i := uint(0); i < n; i++ { + t, err = self.ReadBit() + if err != nil { + return + } + r = (r << 1) | uint32(t) + } + return +} + +func (self *GolombBitReader) ReadBits64(n uint) (r uint64, err error) { + var t uint + for i := uint(0); i < n; i++ { + t, err = self.ReadBit() + if err != nil { + return + } + r = (r << 1) | uint64(t) + } + return +} + func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) { i := 0 for { diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index 889f9e77..c4234287 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -65,6 +65,29 @@ const ( CrossedOut ) +const ( + ResetBold Attribute = iota + 22 + ResetItalic + ResetUnderline + ResetBlinking + _ + ResetReversed + ResetConcealed + ResetCrossedOut +) + +var mapResetAttributes map[Attribute]Attribute = map[Attribute]Attribute{ + Bold: ResetBold, + Faint: ResetBold, + Italic: ResetItalic, + Underline: ResetUnderline, + BlinkSlow: ResetBlinking, + BlinkRapid: ResetBlinking, + ReverseVideo: ResetReversed, + Concealed: ResetConcealed, + CrossedOut: ResetCrossedOut, +} + // Foreground text colors const ( FgBlack Attribute = iota + 30 @@ -246,10 +269,7 @@ func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - c.SetWriter(w) - defer c.UnsetWriter(w) - - return fmt.Fprintln(w, a...) + return fmt.Fprintln(w, c.wrap(fmt.Sprint(a...))) } // Println formats using the default formats for its operands and writes to @@ -258,10 +278,7 @@ func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { // encountered. This is the standard fmt.Print() method wrapped with the given // color. func (c *Color) Println(a ...interface{}) (n int, err error) { - c.Set() - defer c.unset() - - return fmt.Fprintln(Output, a...) + return fmt.Fprintln(Output, c.wrap(fmt.Sprint(a...))) } // Sprint is just like Print, but returns a string instead of printing it. @@ -271,7 +288,7 @@ func (c *Color) Sprint(a ...interface{}) string { // Sprintln is just like Println, but returns a string instead of printing it. func (c *Color) Sprintln(a ...interface{}) string { - return c.wrap(fmt.Sprintln(a...)) + return fmt.Sprintln(c.Sprint(a...)) } // Sprintf is just like Printf, but returns a string instead of printing it. @@ -353,7 +370,7 @@ func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { // string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintlnFunc() func(a ...interface{}) string { return func(a ...interface{}) string { - return c.wrap(fmt.Sprintln(a...)) + return fmt.Sprintln(c.Sprint(a...)) } } @@ -383,7 +400,18 @@ func (c *Color) format() string { } func (c *Color) unformat() string { - return fmt.Sprintf("%s[%dm", escape, Reset) + //return fmt.Sprintf("%s[%dm", escape, Reset) + //for each element in sequence let's use the speficic reset escape, ou the generic one if not found + format := make([]string, len(c.params)) + for i, v := range c.params { + format[i] = strconv.Itoa(int(Reset)) + ra, ok := mapResetAttributes[v] + if ok { + format[i] = strconv.Itoa(int(ra)) + } + } + + return fmt.Sprintf("%s[%sm", escape, strings.Join(format, ";")) } // DisableColor disables the color output. Useful to not change any existing @@ -411,6 +439,12 @@ func (c *Color) isNoColorSet() bool { // Equals returns a boolean value indicating whether two colors are equal. func (c *Color) Equals(c2 *Color) bool { + if c == nil && c2 == nil { + return true + } + if c == nil || c2 == nil { + return false + } if len(c.params) != len(c2.params) { return false } diff --git a/vendor/github.com/gabriel-vasile/mimetype/README.md b/vendor/github.com/gabriel-vasile/mimetype/README.md index d310928d..231b2919 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/README.md +++ b/vendor/github.com/gabriel-vasile/mimetype/README.md @@ -10,9 +10,6 @@

- - Build Status - Go Reference diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/binary.go b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/binary.go index 29bdded3..f1e94498 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/binary.go +++ b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/binary.go @@ -150,32 +150,34 @@ func Marc(raw []byte, limit uint32) bool { } // Glb matches a glTF model format file. -// GLB is the binary file format representation of 3D models save in +// GLB is the binary file format representation of 3D models saved in // the GL transmission Format (glTF). -// see more: https://docs.fileformat.com/3d/glb/ -// https://www.iana.org/assignments/media-types/model/gltf-binary -// GLB file format is based on little endian and its header structure -// show below: +// GLB uses little endian and its header structure is as follows: // -// <-- 12-byte header --> -// | magic | version | length | -// | (uint32) | (uint32) | (uint32) | -// | \x67\x6C\x54\x46 | \x01\x00\x00\x00 | ... | -// | g l T F | 1 | ... | +// <-- 12-byte header --> +// | magic | version | length | +// | (uint32) | (uint32) | (uint32) | +// | \x67\x6C\x54\x46 | \x01\x00\x00\x00 | ... | +// | g l T F | 1 | ... | +// +// Visit [glTF specification] and [IANA glTF entry] for more details. +// +// [glTF specification]: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html +// [IANA glTF entry]: https://www.iana.org/assignments/media-types/model/gltf-binary var Glb = prefix([]byte("\x67\x6C\x54\x46\x02\x00\x00\x00"), []byte("\x67\x6C\x54\x46\x01\x00\x00\x00")) // TzIf matches a Time Zone Information Format (TZif) file. // See more: https://tools.ietf.org/id/draft-murchison-tzdist-tzif-00.html#rfc.section.3 // Its header structure is shown below: -// +---------------+---+ -// | magic (4) | <-+-- version (1) -// +---------------+---+---------------------------------------+ -// | [unused - reserved for future use] (15) | -// +---------------+---------------+---------------+-----------+ -// | isutccnt (4) | isstdcnt (4) | leapcnt (4) | -// +---------------+---------------+---------------+ -// | timecnt (4) | typecnt (4) | charcnt (4) | +// +---------------+---+ +// | magic (4) | <-+-- version (1) +// +---------------+---+---------------------------------------+ +// | [unused - reserved for future use] (15) | +// +---------------+---------------+---------------+-----------+ +// | isutccnt (4) | isstdcnt (4) | leapcnt (4) | +// +---------------+---------------+---------------+ +// | timecnt (4) | typecnt (4) | charcnt (4) | func TzIf(raw []byte, limit uint32) bool { // File is at least 44 bytes (header size). if len(raw) < 44 { diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go index 466058fb..34b84f40 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go +++ b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go @@ -177,7 +177,9 @@ func newXMLSig(localName, xmlns string) xmlSig { // and, optionally, followed by the arguments for the interpreter. // // Ex: -// #! /usr/bin/env php +// +// #! /usr/bin/env php +// // /usr/bin/env is the interpreter, php is the first and only argument. func shebang(sigs ...[]byte) Detector { return func(raw []byte, limit uint32) bool { diff --git a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go index 6a156192..84ed6492 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go +++ b/vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go @@ -3,6 +3,7 @@ package magic import ( "bytes" "encoding/csv" + "errors" "io" ) @@ -19,12 +20,23 @@ func Tsv(raw []byte, limit uint32) bool { func sv(in []byte, comma rune, limit uint32) bool { r := csv.NewReader(dropLastLine(in, limit)) r.Comma = comma - r.TrimLeadingSpace = true + r.ReuseRecord = true r.LazyQuotes = true r.Comment = '#' - lines, err := r.ReadAll() - return err == nil && r.FieldsPerRecord > 1 && len(lines) > 1 + lines := 0 + for { + _, err := r.Read() + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return false + } + lines++ + } + + return r.FieldsPerRecord > 1 && lines > 1 } // dropLastLine drops the last incomplete line from b. diff --git a/vendor/github.com/gabriel-vasile/mimetype/mimetype.go b/vendor/github.com/gabriel-vasile/mimetype/mimetype.go index 08e68e33..1b5909b7 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/mimetype.go +++ b/vendor/github.com/gabriel-vasile/mimetype/mimetype.go @@ -39,7 +39,8 @@ func Detect(in []byte) *MIME { // // DetectReader assumes the reader offset is at the start. If the input is an // io.ReadSeeker you previously read from, it should be rewinded before detection: -// reader.Seek(0, io.SeekStart) +// +// reader.Seek(0, io.SeekStart) func DetectReader(r io.Reader) (*MIME, error) { var in []byte var err error diff --git a/vendor/github.com/gabriel-vasile/mimetype/supported_mimes.md b/vendor/github.com/gabriel-vasile/mimetype/supported_mimes.md index cdec4e67..5ec6f6b6 100644 --- a/vendor/github.com/gabriel-vasile/mimetype/supported_mimes.md +++ b/vendor/github.com/gabriel-vasile/mimetype/supported_mimes.md @@ -1,4 +1,4 @@ -## 172 Supported MIME types +## 173 Supported MIME types This file is automatically generated when running tests. Do not edit manually. Extension | MIME type | Aliases diff --git a/vendor/github.com/go-openapi/jsonpointer/.golangci.yml b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml new file mode 100644 index 00000000..22f8d21c --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml @@ -0,0 +1,61 @@ +linters-settings: + govet: + check-shadowing: true + golint: + min-confidence: 0 + gocyclo: + min-complexity: 45 + maligned: + suggest-new: true + dupl: + threshold: 200 + goconst: + min-len: 2 + min-occurrences: 3 + +linters: + enable-all: true + disable: + - maligned + - unparam + - lll + - gochecknoinits + - gochecknoglobals + - funlen + - godox + - gocognit + - whitespace + - wsl + - wrapcheck + - testpackage + - nlreturn + - gomnd + - exhaustivestruct + - goerr113 + - errorlint + - nestif + - godot + - gofumpt + - paralleltest + - tparallel + - thelper + - ifshort + - exhaustruct + - varnamelen + - gci + - depguard + - errchkjson + - inamedparam + - nonamedreturns + - musttag + - ireturn + - forcetypeassert + - cyclop + # deprecated linters + - deadcode + - interfacer + - scopelint + - varcheck + - structcheck + - golint + - nosnakecase diff --git a/vendor/github.com/go-openapi/jsonpointer/README.md b/vendor/github.com/go-openapi/jsonpointer/README.md index 813788af..0108f1d5 100644 --- a/vendor/github.com/go-openapi/jsonpointer/README.md +++ b/vendor/github.com/go-openapi/jsonpointer/README.md @@ -1,6 +1,10 @@ -# gojsonpointer [![Build Status](https://travis-ci.org/go-openapi/jsonpointer.svg?branch=master)](https://travis-ci.org/go-openapi/jsonpointer) [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) +# gojsonpointer [![Build Status](https://github.com/go-openapi/jsonpointer/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/jsonpointer/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) + +[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) +[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/jsonpointer.svg)](https://pkg.go.dev/github.com/go-openapi/jsonpointer) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/jsonpointer)](https://goreportcard.com/report/github.com/go-openapi/jsonpointer) -[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer) An implementation of JSON Pointer - Go language ## Status diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer.go b/vendor/github.com/go-openapi/jsonpointer/pointer.go index de60dc7d..d970c7cf 100644 --- a/vendor/github.com/go-openapi/jsonpointer/pointer.go +++ b/vendor/github.com/go-openapi/jsonpointer/pointer.go @@ -110,19 +110,39 @@ func SetForToken(document any, decodedToken string, value any) (any, error) { return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider) } +func isNil(input any) bool { + if input == nil { + return true + } + + kind := reflect.TypeOf(input).Kind() + switch kind { //nolint:exhaustive + case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan: + return reflect.ValueOf(input).IsNil() + default: + return false + } +} + func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) { rValue := reflect.Indirect(reflect.ValueOf(node)) kind := rValue.Kind() + if isNil(node) { + return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken) + } - if rValue.Type().Implements(jsonPointableType) { - r, err := node.(JSONPointable).JSONLookup(decodedToken) + switch typed := node.(type) { + case JSONPointable: + r, err := typed.JSONLookup(decodedToken) if err != nil { return nil, kind, err } return r, kind, nil + case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect + return getSingleImpl(*typed, decodedToken, nameProvider) } - switch kind { + switch kind { //nolint:exhaustive case reflect.Struct: nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { @@ -170,7 +190,7 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameP return node.(JSONSetable).JSONSet(decodedToken, data) } - switch rValue.Kind() { + switch rValue.Kind() { //nolint:exhaustive case reflect.Struct: nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { @@ -231,8 +251,7 @@ func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.K if err != nil { return nil, knd, err } - node, kind = r, knd - + node = r } rValue := reflect.ValueOf(node) @@ -245,7 +264,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { knd := reflect.ValueOf(node).Kind() if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array { - return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values") + return errors.New("only structs, pointers, maps and slices are supported for setting values") } if nameProvider == nil { @@ -284,7 +303,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { continue } - switch kind { + switch kind { //nolint:exhaustive case reflect.Struct: nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { @@ -405,11 +424,11 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) { case json.Delim: switch tk { case '{': - if err := drainSingle(dec); err != nil { + if err = drainSingle(dec); err != nil { return 0, err } case '[': - if err := drainSingle(dec); err != nil { + if err = drainSingle(dec); err != nil { return 0, err } } @@ -435,20 +454,21 @@ func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) { if err != nil { return 0, err } - switch tk := tk.(type) { - case json.Delim: - switch tk { + + if delim, isDelim := tk.(json.Delim); isDelim { + switch delim { case '{': - if err := drainSingle(dec); err != nil { + if err = drainSingle(dec); err != nil { return 0, err } case '[': - if err := drainSingle(dec); err != nil { + if err = drainSingle(dec); err != nil { return 0, err } } } } + if !dec.More() { return 0, fmt.Errorf("token reference %q not found", decodedToken) } @@ -456,27 +476,27 @@ func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) { } // drainSingle drains a single level of object or array. -// The decoder has to guarantee the begining delim (i.e. '{' or '[') has been consumed. +// The decoder has to guarantee the beginning delim (i.e. '{' or '[') has been consumed. func drainSingle(dec *json.Decoder) error { for dec.More() { tk, err := dec.Token() if err != nil { return err } - switch tk := tk.(type) { - case json.Delim: - switch tk { + if delim, isDelim := tk.(json.Delim); isDelim { + switch delim { case '{': - if err := drainSingle(dec); err != nil { + if err = drainSingle(dec); err != nil { return err } case '[': - if err := drainSingle(dec); err != nil { + if err = drainSingle(dec); err != nil { return err } } } } + // Consumes the ending delim if _, err := dec.Token(); err != nil { return err @@ -498,14 +518,14 @@ const ( // Unescape unescapes a json pointer reference token string to the original representation func Unescape(token string) string { - step1 := strings.Replace(token, encRefTok1, decRefTok1, -1) - step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1) + step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1) + step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0) return step2 } // Escape escapes a pointer reference token string func Escape(token string) string { - step1 := strings.Replace(token, decRefTok0, encRefTok0, -1) - step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1) + step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0) + step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1) return step2 } diff --git a/vendor/github.com/go-openapi/jsonreference/.golangci.yml b/vendor/github.com/go-openapi/jsonreference/.golangci.yml index 013fc194..22f8d21c 100644 --- a/vendor/github.com/go-openapi/jsonreference/.golangci.yml +++ b/vendor/github.com/go-openapi/jsonreference/.golangci.yml @@ -1,50 +1,61 @@ linters-settings: govet: check-shadowing: true + golint: + min-confidence: 0 gocyclo: - min-complexity: 30 + min-complexity: 45 maligned: suggest-new: true dupl: - threshold: 100 + threshold: 200 goconst: min-len: 2 - min-occurrences: 4 - paralleltest: - ignore-missing: true + min-occurrences: 3 + linters: enable-all: true disable: - maligned + - unparam - lll + - gochecknoinits - gochecknoglobals + - funlen - godox - gocognit - whitespace - wsl - - funlen - - gochecknoglobals - - gochecknoinits - - scopelint - wrapcheck - - exhaustivestruct - - exhaustive - - nlreturn - testpackage - - gci - - gofumpt - - goerr113 + - nlreturn - gomnd - - tparallel + - exhaustivestruct + - goerr113 + - errorlint - nestif - godot - - errorlint - - varcheck - - interfacer - - deadcode - - golint + - gofumpt + - paralleltest + - tparallel + - thelper - ifshort - - structcheck - - nosnakecase - - varnamelen - exhaustruct + - varnamelen + - gci + - depguard + - errchkjson + - inamedparam + - nonamedreturns + - musttag + - ireturn + - forcetypeassert + - cyclop + # deprecated linters + - deadcode + - interfacer + - scopelint + - varcheck + - structcheck + - golint + - nosnakecase diff --git a/vendor/github.com/go-openapi/jsonreference/README.md b/vendor/github.com/go-openapi/jsonreference/README.md index b94753aa..c7fc2049 100644 --- a/vendor/github.com/go-openapi/jsonreference/README.md +++ b/vendor/github.com/go-openapi/jsonreference/README.md @@ -1,15 +1,19 @@ -# gojsonreference [![Build Status](https://travis-ci.org/go-openapi/jsonreference.svg?branch=master)](https://travis-ci.org/go-openapi/jsonreference) [![codecov](https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonreference) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) +# gojsonreference [![Build Status](https://github.com/go-openapi/jsonreference/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/jsonreference/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonreference) + +[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE) +[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/jsonreference.svg)](https://pkg.go.dev/github.com/go-openapi/jsonreference) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/jsonreference)](https://goreportcard.com/report/github.com/go-openapi/jsonreference) -[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonreference?status.svg)](http://godoc.org/github.com/go-openapi/jsonreference) An implementation of JSON Reference - Go language ## Status Feature complete. Stable API ## Dependencies -https://github.com/go-openapi/jsonpointer +* https://github.com/go-openapi/jsonpointer ## References -http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 -http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 +* http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 +* http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 diff --git a/vendor/github.com/go-openapi/spec/.gitignore b/vendor/github.com/go-openapi/spec/.gitignore index dd91ed6a..f47cb204 100644 --- a/vendor/github.com/go-openapi/spec/.gitignore +++ b/vendor/github.com/go-openapi/spec/.gitignore @@ -1,2 +1 @@ -secrets.yml -coverage.out +*.out diff --git a/vendor/github.com/go-openapi/spec/.golangci.yml b/vendor/github.com/go-openapi/spec/.golangci.yml index 835d55e7..22f8d21c 100644 --- a/vendor/github.com/go-openapi/spec/.golangci.yml +++ b/vendor/github.com/go-openapi/spec/.golangci.yml @@ -11,7 +11,7 @@ linters-settings: threshold: 200 goconst: min-len: 2 - min-occurrences: 2 + min-occurrences: 3 linters: enable-all: true @@ -40,3 +40,22 @@ linters: - tparallel - thelper - ifshort + - exhaustruct + - varnamelen + - gci + - depguard + - errchkjson + - inamedparam + - nonamedreturns + - musttag + - ireturn + - forcetypeassert + - cyclop + # deprecated linters + - deadcode + - interfacer + - scopelint + - varcheck + - structcheck + - golint + - nosnakecase diff --git a/vendor/github.com/go-openapi/spec/README.md b/vendor/github.com/go-openapi/spec/README.md index 18782c6d..7fd2810c 100644 --- a/vendor/github.com/go-openapi/spec/README.md +++ b/vendor/github.com/go-openapi/spec/README.md @@ -1,8 +1,5 @@ -# OAI object model +# OpenAPI v2 object model [![Build Status](https://github.com/go-openapi/spec/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/spec/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec) -[![Build Status](https://travis-ci.org/go-openapi/spec.svg?branch=master)](https://travis-ci.org/go-openapi/spec) - -[![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE) [![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/spec.svg)](https://pkg.go.dev/github.com/go-openapi/spec) @@ -32,3 +29,26 @@ The object model for OpenAPI specification documents. > This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story. > > An early attempt to support Swagger 3 may be found at: https://github.com/go-openapi/spec3 + +* Does the unmarshaling support YAML? + +> Not directly. The exposed types know only how to unmarshal from JSON. +> +> In order to load a YAML document as a Swagger spec, you need to use the loaders provided by +> github.com/go-openapi/loads +> +> Take a look at the example there: https://pkg.go.dev/github.com/go-openapi/loads#example-Spec +> +> See also https://github.com/go-openapi/spec/issues/164 + +* How can I validate a spec? + +> Validation is provided by [the validate package](http://github.com/go-openapi/validate) + +* Why do we have an `ID` field for `Schema` which is not part of the swagger spec? + +> We found jsonschema compatibility more important: since `id` in jsonschema influences +> how `$ref` are resolved. +> This `id` does not conflict with any property named `id`. +> +> See also https://github.com/go-openapi/spec/issues/23 diff --git a/vendor/github.com/go-openapi/spec/appveyor.yml b/vendor/github.com/go-openapi/spec/appveyor.yml deleted file mode 100644 index 09035939..00000000 --- a/vendor/github.com/go-openapi/spec/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: "0.1.{build}" - -clone_folder: C:\go-openapi\spec -shallow_clone: true # for startup speed -pull_requests: - do_not_increment_build_number: true - -#skip_tags: true -#skip_branch_with_pr: true - -# appveyor.yml -build: off - -environment: - GOPATH: c:\gopath - -stack: go 1.15 - -test_script: - - go test -v -timeout 20m ./... - -deploy: off - -notifications: - - provider: Slack - incoming_webhook: https://hooks.slack.com/services/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 - auth_token: - secure: Sf7kZf7ZGbnwWUMpffHwMu5A0cHkLK2MYY32LNTPj4+/3qC3Ghl7+9v4TSLOqOlCwdRNjOGblAq7s+GDJed6/xgRQl1JtCi1klzZNrYX4q01pgTPvvGcwbBkIYgeMaPeIRcK9OZnud7sRXdttozgTOpytps2U6Js32ip7uj5mHSg2ub0FwoSJwlS6dbezZ8+eDhoha0F/guY99BEwx8Bd+zROrT2TFGsSGOFGN6wFc7moCqTHO/YkWib13a2QNXqOxCCVBy/lt76Wp+JkeFppjHlzs/2lP3EAk13RIUAaesdEUHvIHrzCyNJEd3/+KO2DzsWOYfpktd+KBCvgaYOsoo7ubdT3IROeAegZdCgo/6xgCEsmFc9ZcqCfN5yNx2A+BZ2Vwmpws+bQ1E1+B5HDzzaiLcYfG4X2O210QVGVDLWsv1jqD+uPYeHY2WRfh5ZsIUFvaqgUEnwHwrK44/8REAhQavt1QAj5uJpsRd7CkRVPWRNK+yIky+wgbVUFEchRNmS55E7QWf+W4+4QZkQi7vUTMc9nbTUu2Es9NfvfudOpM2wZbn98fjpb/qq/nRv6Bk+ca+7XD5/IgNLMbWp2ouDdzbiHLCOfDUiHiDJhLfFZx9Bwo7ZwfzeOlbrQX66bx7xRKYmOe4DLrXhNcpbsMa8qbfxlZRCmYbubB/Y8h4= - channel: bots - on_build_success: false - on_build_failure: true - on_build_status_changed: true diff --git a/vendor/github.com/go-openapi/spec/bindata.go b/vendor/github.com/go-openapi/spec/bindata.go deleted file mode 100644 index afc83850..00000000 --- a/vendor/github.com/go-openapi/spec/bindata.go +++ /dev/null @@ -1,297 +0,0 @@ -// Code generated by go-bindata. DO NOT EDIT. -// sources: -// schemas/jsonschema-draft-04.json (4.357kB) -// schemas/v2/schema.json (40.248kB) - -package spec - -import ( - "bytes" - "compress/gzip" - "crypto/sha256" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo - digest [sha256.Size]byte -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -func (fi bindataFileInfo) Name() string { - return fi.name -} -func (fi bindataFileInfo) Size() int64 { - return fi.size -} -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} -func (fi bindataFileInfo) IsDir() bool { - return false -} -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _jsonschemaDraft04Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x57\x3d\x6f\xdb\x3c\x10\xde\xf3\x2b\x08\x26\x63\xf2\x2a\x2f\xd0\xc9\x5b\xd1\x2e\x01\x5a\x34\x43\x37\x23\x03\x6d\x9d\x6c\x06\x14\xa9\x50\x54\x60\xc3\xd0\x7f\x2f\x28\x4a\x14\x29\x91\x92\x2d\xa7\x8d\x97\x28\xbc\xaf\xe7\x8e\xf7\xc5\xd3\x0d\x42\x08\x61\x9a\xe2\x15\xc2\x7b\xa5\x8a\x55\x92\xbc\x96\x82\x3f\x94\xdb\x3d\xe4\xe4\x3f\x21\x77\x49\x2a\x49\xa6\x1e\x1e\xbf\x24\xe6\xec\x16\xdf\x1b\xa1\x3b\xf3\xff\x02\xc9\x14\xca\xad\xa4\x85\xa2\x82\x6b\xe9\x6f\x42\x02\x32\x2c\x28\x07\x45\x5a\x15\x3d\x77\x46\x39\xd5\xcc\x25\x5e\x21\x83\xb8\x21\x18\xb6\xaf\x52\x92\xa3\x47\x68\x88\xea\x58\x80\x56\x4e\x1a\xf2\xbd\x4f\xcc\x29\x7f\x52\x90\x6b\x7d\xff\x0f\x48\xb4\x3d\x3f\x21\x7c\x27\x21\xd3\x2a\x6e\x31\xaa\x2d\x53\xdd\xf3\xe3\x42\x94\x54\xd1\x77\x78\xe2\x0a\x76\x20\xe3\x20\x68\xcb\x30\x86\x41\xf3\x2a\xc7\x2b\xf4\x78\x8e\xfe\xef\x90\x91\x8a\xa9\xc7\xb1\x1d\xc2\xd8\x2f\x0d\x75\xed\xc1\x4e\x9c\xc8\x25\x43\xac\xa8\xbe\xd7\xcc\xa9\xd1\xa9\x21\xa0\x1a\xbd\x04\x61\x94\x34\x2f\x18\xfc\x3e\x16\x50\x8e\x4d\x03\x6f\x1c\x58\xdb\x48\x23\xbc\x11\x82\x01\xe1\xfa\xd3\x3a\x8e\x30\xaf\x18\x33\x7f\xf3\x8d\x39\x11\x9b\x57\xd8\x2a\xfd\x55\x2a\x49\xf9\x0e\xc7\xec\x37\xd4\x25\xf7\xec\x5c\x66\xc7\xd7\x99\xaa\xcf\x4f\x89\x8a\xd3\xb7\x0a\x3a\xaa\x92\x15\xf4\x30\x6f\x1c\xb0\xd6\x46\xe7\x98\x39\x2d\xa4\x28\x40\x2a\x3a\x88\x9e\x29\xba\x88\x37\x2d\xca\x60\x38\xfa\xba\x5b\x20\xac\xa8\x62\xb0\x4c\xd4\xaf\xda\x45\x0a\xba\x5c\x3b\xb9\xc7\x79\xc5\x14\x2d\x18\x34\x19\x1c\x51\xdb\x25\x4d\xb4\x7e\x06\x14\x38\x6c\x59\x55\xd2\x77\xf8\x69\x59\xfc\x7b\x73\xed\x93\x43\xcb\x32\x6d\x3c\x28\xdc\x1b\x9a\xd3\x62\xab\xc2\x27\xf7\x41\xc9\x08\x2b\x23\x08\xad\x13\x57\x21\x9c\xd3\x72\x0d\x42\x72\xf8\x01\x7c\xa7\xf6\x83\xce\x39\xd7\x82\x3c\x1f\x2f\xd6\x60\x1b\xa2\xdf\x35\x89\x52\x20\xe7\x73\x74\xe0\x66\x26\x64\x4e\xb4\x97\x58\xc2\x0e\x0e\xe1\x60\x92\x34\x6d\xa0\x10\xd6\xb5\x83\x61\x27\xe6\x47\xd3\x89\xbd\x63\xfd\x3b\x8d\x03\x3d\x6c\x42\x2d\x5b\x70\xee\xe8\xdf\x4b\xf4\x66\x4e\xe1\x01\x45\x17\x80\x74\xad\x4f\xc3\xf3\xae\xc6\x1d\xc6\xd7\xc2\xce\xc9\xe1\x29\x30\x86\x2f\x4a\xa6\x4b\x15\x84\x73\xc9\x6f\xfd\x7f\xa5\x6e\x9e\xbd\xf1\xb0\xd4\xdd\x45\x5a\xc2\x3e\x4b\x78\xab\xa8\x84\x74\x4a\x91\x3b\x92\x23\x05\xf2\x1c\x1e\x7b\xf3\x09\xf8\xcf\xab\x24\xb6\x60\xa2\xe8\x4c\x9f\x75\x77\xaa\x8c\xe6\x01\x45\x36\x86\xcf\xc3\x63\x3a\xea\xd4\x8d\x7e\x06\xac\x14\x0a\xe0\x29\xf0\xed\x07\x22\x1a\x65\xda\x44\xae\xa2\x73\x1a\xe6\x90\x69\xa2\x8c\x46\xb2\x2f\xde\x49\x38\x08\xed\xfe\xfd\x41\xaf\x9f\xa9\x55\xd7\xdd\x22\x8d\xfa\x45\x63\xc5\x0f\x80\xf3\xb4\x08\xd6\x79\x30\x9e\x93\xee\x59\xa6\xd0\x4b\xee\x22\xe3\x33\xc1\x3a\x27\x68\x36\x78\x7e\x87\x0a\x06\xd5\x2e\x20\xd3\xaf\x15\xfb\xd8\x3b\x73\x14\xbb\x92\xed\x05\x5d\x2e\x29\x38\x2c\x94\xe4\x42\x45\x5e\xd3\xb5\x7d\xdf\x47\xca\x38\xb4\x5c\xaf\xfb\x7d\xdd\x6d\xf4\xa1\x2d\x77\xdd\x2f\xce\x6d\xc4\x7b\x8b\x4e\x67\xa9\x6f\xfe\x04\x00\x00\xff\xff\xb1\xd1\x27\x78\x05\x11\x00\x00") - -func jsonschemaDraft04JsonBytes() ([]byte, error) { - return bindataRead( - _jsonschemaDraft04Json, - "jsonschema-draft-04.json", - ) -} - -func jsonschemaDraft04Json() (*asset, error) { - bytes, err := jsonschemaDraft04JsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "jsonschema-draft-04.json", size: 4357, mode: os.FileMode(0640), modTime: time.Unix(1568963823, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe1, 0x48, 0x9d, 0xb, 0x47, 0x55, 0xf0, 0x27, 0x93, 0x30, 0x25, 0x91, 0xd3, 0xfc, 0xb8, 0xf0, 0x7b, 0x68, 0x93, 0xa8, 0x2a, 0x94, 0xf2, 0x48, 0x95, 0xf8, 0xe4, 0xed, 0xf1, 0x1b, 0x82, 0xe2}} - return a, nil -} - -var _v2SchemaJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5d\x4f\x93\xdb\x36\xb2\xbf\xfb\x53\xa0\x14\x57\xd9\xae\xd8\x92\xe3\xf7\x2e\xcf\x97\xd4\xbc\xd8\x49\x66\x37\x5e\x4f\x79\x26\xbb\x87\x78\x5c\x05\x91\x2d\x09\x09\x09\x30\x00\x38\x33\x5a\xef\x7c\xf7\x2d\xf0\x9f\x08\x02\x20\x41\x8a\xd2\xc8\x0e\x0f\xa9\x78\x28\xa0\xd1\xdd\x68\x34\x7e\xdd\xf8\xf7\xf9\x11\x42\x33\x49\x64\x04\xb3\xd7\x68\x76\x86\xfe\x76\xf9\xfe\x1f\xe8\x32\xd8\x40\x8c\xd1\x8a\x71\x74\x79\x8b\xd7\x6b\xe0\xe8\xd5\xfc\x25\x3a\xbb\x38\x9f\xcf\x9e\xab\x0a\x24\x54\xa5\x37\x52\x26\xaf\x17\x0b\x91\x17\x99\x13\xb6\xb8\x79\xb5\x10\x59\xdd\xf9\xef\x82\xd1\x6f\xf2\xc2\x8f\xf3\x4f\xb5\x1a\xea\xc7\x17\x45\x41\xc6\xd7\x8b\x90\xe3\x95\x7c\xf1\xf2\x7f\x8b\xca\x45\x3d\xb9\x4d\x32\xa6\xd8\xf2\x77\x08\x64\xfe\x8d\xc3\x9f\x29\xe1\xa0\x9a\xff\xed\x11\x42\x08\xcd\x8a\xd6\xb3\x9f\x15\x67\x74\xc5\xca\x7f\x27\x58\x6e\xc4\xec\x11\x42\xd7\x59\x5d\x1c\x86\x44\x12\x46\x71\x74\xc1\x59\x02\x5c\x12\x10\xb3\xd7\x68\x85\x23\x01\x59\x81\x04\x4b\x09\x9c\x6a\xbf\x7e\xce\x49\x7d\xba\x7b\x51\xfd\xa1\x44\xe2\xb0\x52\xac\x7d\xb3\x08\x61\x45\x68\x46\x56\x2c\x6e\x80\x86\x8c\xbf\xbd\x93\x40\x05\x61\x74\x96\x95\xbe\x7f\x84\xd0\x7d\x4e\xde\x42\xb7\xe4\xbe\x46\xbb\x14\x5b\x48\x4e\xe8\xba\x90\x05\xa1\x19\xd0\x34\xae\xc4\xce\xbe\xbc\x9a\xbf\x9c\x15\x7f\x5d\x57\xc5\x42\x10\x01\x27\x89\xe2\x48\x51\xb9\xda\x40\xd5\x87\x37\xc0\x15\x5f\x88\xad\x90\xdc\x10\x81\x42\x16\xa4\x31\x50\x39\x2f\x38\xad\xab\xb0\x53\xd8\xac\x94\x56\x6f\xc3\x84\xf4\x11\xa4\x50\xb3\xfa\xe9\xd3\x6f\x9f\x3e\xdf\x2f\xd0\xeb\x8f\x1f\x3f\x7e\xbc\xfe\xf6\xe9\xf7\xaf\x5f\x7f\xfc\x18\x7e\xfb\xec\xfb\xc7\xb3\x36\x79\x54\x43\xe8\x29\xc5\x31\x20\xc6\x11\x49\x9e\xe5\x12\x41\x66\xa0\xe8\xed\x1d\x8e\x93\x08\x5e\xa3\x27\x3b\xc3\x7c\xa2\x73\xba\xc4\x02\x2e\xb0\xdc\xf4\xe5\x76\xd1\xca\x96\xa2\x8a\x94\xcd\x21\xc9\x6c\xec\x2c\x70\x42\x9e\x34\x74\x9d\x19\x7c\xcd\x20\x9c\xea\x2e\x0a\xfe\x42\x84\xd4\x29\x04\x8c\x8a\xb4\x41\xa2\xc1\xdc\x19\x8a\x88\x90\x4a\x49\xef\xce\xdf\xbd\x45\x4a\x52\x81\x70\x10\x40\x22\x21\x44\xcb\x6d\xc5\xec\x4e\x3c\x1c\x45\xef\x57\x9a\xb5\x7d\xae\xfe\xe5\xe4\x31\x86\x90\xe0\xab\x6d\x02\x3b\x2e\xcb\x11\x90\xd9\xa8\xc6\x77\xc2\x59\x98\x06\xfd\xf9\x2e\x78\x45\x01\xa6\xa8\xa0\x71\x5c\xbe\x33\xa7\xd2\xd9\x5f\x95\xef\xd9\xd5\xac\xfd\xdc\x5d\xbf\x5e\xb8\xd1\x3e\xc7\x31\x48\xe0\x5e\x4c\x14\x65\xdf\xb8\xa8\x71\x10\x09\xa3\xc2\xc7\x02\xcb\xa2\x4e\x5a\x02\x82\x94\x13\xb9\xf5\x30\xe6\xb2\xa4\xb5\xfe\x9b\x3e\x7a\xb2\x55\xd2\xa8\x4a\xbc\x16\xb6\x71\x8e\x39\xc7\xdb\x9d\xe1\x10\x09\x71\xbd\x9c\xb3\x41\x89\xd7\xa5\x89\xdc\x57\xb5\x53\x4a\xfe\x4c\xe1\xbc\xa0\x21\x79\x0a\x1a\x0f\x70\xa7\x5c\x08\x8e\xde\xb0\xc0\x43\x24\xad\x74\x63\x0e\xb1\xd9\x90\xe1\xb0\x2d\x13\xa7\x6d\x78\xfd\x04\x14\x38\x8e\x90\xaa\xce\x63\xac\x3e\x23\xbc\x64\xa9\xb4\xf8\x03\x63\xde\xcd\xbe\x16\x13\x4a\x55\xac\x82\x12\xc6\xac\xd4\x35\xf7\x22\xd4\x3a\xff\x22\x73\x0e\x6e\x51\xa0\x75\x1e\xae\x8f\xe8\x5d\xc7\x59\xe6\xe4\x9a\x18\x8d\xd6\x1c\x53\x84\x4d\xb7\x67\x28\x37\x09\x84\x69\x88\x12\x0e\x01\x11\x80\x32\xa2\xf5\xb9\xaa\xc6\xd9\x73\x53\xab\xfb\xb4\x2e\x20\xc6\x54\x92\xa0\x9a\xf3\x69\x1a\x2f\x81\x77\x37\xae\x53\x1a\xce\x40\xc4\xa8\x82\x1c\xb5\xef\xda\x24\x7d\xb9\x61\x69\x14\xa2\x25\xa0\x90\xac\x56\xc0\x81\x4a\xb4\xe2\x2c\xce\x4a\x64\x7a\x9a\x23\xf4\x13\x91\x3f\xa7\x4b\xf4\x63\x84\x6f\x18\x87\x10\xbd\xc3\xfc\x8f\x90\xdd\x52\x44\x04\xc2\x51\xc4\x6e\x21\x74\x48\x21\x81\xc7\xe2\xfd\xea\x12\xf8\x0d\x09\xf6\xe9\x47\x35\xaf\x67\xc4\x14\xf7\x22\x27\x97\xe1\xe2\x76\x2d\x06\x8c\x4a\x1c\x48\x3f\x73\x2d\x0b\x5b\x29\x45\x24\x00\x2a\x0c\x11\xec\x94\xca\xc2\xa6\xc1\x37\x21\x43\x83\x3b\x5f\x97\xf1\x43\x5e\x53\x73\x19\xa5\x36\xd8\x2d\x05\x2e\x34\x0b\xeb\x39\xfc\x1d\x63\x51\x01\xbd\x3d\xbb\x90\x84\x40\x25\x59\x6d\x09\x5d\xa3\x1c\x37\xe6\x5c\x16\x9a\x40\x09\x70\xc1\xe8\x82\xf1\x35\xa6\xe4\xdf\x99\x5c\x8e\x9e\x4d\x79\xb4\x27\x2f\xbf\x7e\xf8\x05\x25\x8c\x50\xa9\x98\x29\x90\x62\x60\xea\x75\xae\x13\xca\xbf\x2b\x1a\x29\x27\x76\xd6\x20\xc6\x64\x5f\xe6\x32\x1a\x08\x87\x21\x07\x21\xbc\xb4\xe4\xe0\x32\x67\xa6\xcd\xf3\x1e\xcd\xd9\x6b\xb6\x6f\x8e\x27\xa7\xed\xdb\xe7\xbc\xcc\x1a\x07\xce\x6f\x87\x33\xf0\xba\x51\x17\x22\x66\x78\x79\x8e\xce\xe5\x13\x81\x80\x06\x2c\xe5\x78\x0d\xa1\xb2\xb8\x54\xa8\x79\x09\xbd\xbf\x3c\x47\x01\x8b\x13\x2c\xc9\x32\xaa\xaa\x1d\xd5\xee\xab\x36\xbd\x6c\xfd\x54\x6c\xc8\x08\x01\x3c\xbd\xe7\x07\x88\xb0\x24\x37\x79\x90\x28\x4a\x1d\x10\x1a\x92\x1b\x12\xa6\x38\x42\x40\xc3\x4c\x43\x62\x8e\xae\x36\xb0\x45\x71\x2a\xa4\x9a\x23\x79\x59\xb1\xa8\xf2\xa4\x0c\x60\x9f\xcc\x8d\x40\xf5\x80\xca\xa8\x99\xc3\xa7\x85\x1f\x31\x25\xa9\x82\xc5\x6d\xbd\xd8\x36\x76\x7c\x02\x28\x97\xf6\x1d\x74\x3b\x11\x7e\x91\xae\x32\xf8\x6c\xf4\xe6\x7b\x9a\xa5\x1f\x62\xc6\x21\xcf\x9a\xe5\xed\x8b\x02\xf3\x2c\x33\x33\xdf\x00\xca\xc9\x09\xb4\x04\xf5\xa5\x08\xd7\xc3\x02\x18\x66\xf1\xab\x1e\x83\x37\x4c\xcd\x12\xc1\x1d\x50\xf6\xaa\xbd\xfe\xe2\x73\x48\x38\x08\xa0\x32\x9b\x18\x44\x86\x0b\x6a\xc1\xaa\x26\x96\x2d\x96\x3c\xa0\x54\x65\x73\xe3\x08\xb5\x8b\x99\xbd\x82\xbc\x9e\xc2\xe8\x53\x46\x83\x3f\x33\x54\x2b\x5b\xad\x92\x79\xd9\x8f\x5d\x93\x98\xf2\xe6\xc6\x1c\xe6\x9a\x9e\xfc\x43\x82\x31\x66\x8e\x53\x77\xfe\x90\xe7\xf3\xf6\xe9\x62\x23\x3f\x10\x93\x18\xae\x72\x1a\x9d\xf9\x48\xcb\xcc\x5a\x65\xc7\x4a\x04\xf0\xf3\xd5\xd5\x05\x8a\x41\x08\xbc\x86\x86\x43\x51\x6c\xe0\x46\x57\xf6\x44\x40\x0d\xfb\xff\xa2\xc3\x7c\x3d\x39\x84\xdc\x09\x22\x64\x4f\x12\xd9\xba\xaa\xf6\xe3\xbd\x56\xdd\x91\x25\x6a\x14\x9c\x89\x34\x8e\x31\xdf\xee\x15\x7e\x2f\x39\x81\x15\x2a\x28\x95\x66\x51\xf5\xfd\x83\xc5\xfe\x15\x07\xcf\xf7\x08\xee\x1d\x8e\xb6\xc5\x52\xcc\x8c\x5a\x93\x66\xc5\xd8\x79\x38\x46\xd6\xa7\x88\x37\xc9\x2e\xe3\xd2\xa5\x7b\x4b\x3a\xdc\xa1\xdc\x9e\x29\xf1\x8c\x8a\x99\x16\x47\x8d\xd4\x78\x8b\xf6\x1c\xe9\x71\x54\x1b\x69\xa8\x4a\x93\x37\xe5\xb2\x2c\x4f\x0c\x92\xab\xa0\x73\x32\x72\x59\xd3\xf0\x2d\x8d\xed\xca\x37\x16\x19\x9e\xdb\x1c\xab\x17\x49\xc3\x0f\x37\xdc\x88\xb1\xb4\xd4\x42\xcb\x58\x5e\x6a\x52\x0b\x15\x10\x0a\xb0\x04\xe7\xf8\x58\x32\x16\x01\xa6\xcd\x01\xb2\xc2\x69\x24\x35\x38\x6f\x30\x6a\xae\x1b\xb4\x71\xaa\xad\x1d\xa0\xd6\x20\x2d\x8b\x3c\xc6\x82\x62\x27\x34\x6d\x15\x84\x7b\x43\xb1\x35\x78\xa6\x24\x77\x28\xc1\x6e\xfc\xe9\x48\x74\xf4\x15\xe3\xe1\x84\x42\x88\x40\x7a\x26\x49\x3b\x48\xb1\xa4\x19\x8e\x0c\xa7\xb5\x01\x6c\x0c\x97\x61\x8a\xc2\x32\xd8\x8c\x44\x69\x24\xbf\x65\x1d\x74\xd6\xe5\x44\xef\xec\x48\x5e\xb7\x8a\xa3\x29\x8e\x41\x64\xce\x1f\x88\xdc\x00\x47\x4b\x40\x98\x6e\xd1\x0d\x8e\x48\x98\x63\x5c\x21\xb1\x4c\x05\x0a\x58\x98\xc5\x6d\x4f\x0a\x77\x53\x4f\x8b\xc4\x44\x1f\xb2\xdf\x8d\x3b\xea\x9f\xfe\xf6\xf2\xc5\xff\x5d\x7f\xfe\x9f\xfb\x67\x8f\xff\xf3\xe9\x69\xd1\xfe\xb3\xc7\xfd\x3c\xf8\x3f\x71\x94\x82\x23\xd1\x72\x00\xb7\x42\x99\x6c\xc0\x60\x7b\x0f\x79\xea\xa8\x53\x4b\x56\x31\xfa\x0b\x52\x9f\x96\xdb\xcd\x2f\xd7\x67\xcd\x04\x19\x85\xfe\xdb\x02\x9a\x59\x03\xad\x63\x3c\xea\xff\x2e\x18\xfd\x00\xd9\xe2\x56\x60\x59\x93\xb9\xb6\xb2\x3e\x3c\x2c\xab\x0f\xa7\xb2\x89\x43\xc7\xf6\xd5\xce\x2e\xad\xa6\xa9\xed\xa6\xc6\x5a\xb4\xa6\x67\xdf\x8c\x26\x7b\x50\x5a\x91\x08\x2e\x6d\xd4\x3a\xc1\x9d\xf2\xdb\xde\x1e\xb2\x2c\x6c\xa5\x64\xc9\x16\xb4\x90\xaa\x4a\xb7\x0c\xde\x13\xc3\x2a\x9a\x11\x9b\x7a\x1b\x3d\x95\x97\x37\x31\x6b\x69\x7e\x34\xc0\x67\x1f\x66\x19\x49\xef\xf1\x25\xf5\xac\x0e\xea\x0a\x28\x8d\x4d\x7e\xd9\x57\x4b\x49\xe5\xc6\xb3\x25\xfd\xe6\x57\x42\x25\xac\xcd\xcf\x36\x74\x8e\xca\x24\x47\xe7\x80\xa8\x92\x72\xbd\x3d\x84\x2d\x65\xe2\x82\x1a\x9c\xc4\x44\x92\x1b\x10\x79\x8a\xc4\x4a\x2f\x60\x51\x04\x81\xaa\xf0\xa3\x95\x27\xd7\x12\x7b\xa3\x96\x03\x45\x96\xc1\x8a\x07\xc9\xb2\xb0\x95\x52\x8c\xef\x48\x9c\xc6\x7e\x94\xca\xc2\x0e\x07\x12\x44\xa9\x20\x37\xf0\xae\x0f\x49\xa3\x96\x9d\x4b\x42\x7b\x70\x59\x14\xee\xe0\xb2\x0f\x49\xa3\x96\x4b\x97\xbf\x00\x5d\x4b\x4f\xfc\xbb\x2b\xee\x92\xb9\x17\xb5\xaa\xb8\x0b\x97\x17\x9b\x43\xfd\xd6\xc2\xb2\xc2\x2e\x29\xcf\xfd\x87\x4a\x55\xda\x25\x63\x1f\x5a\x65\x69\x2b\x2d\x3d\x67\xe9\x41\xae\x5e\xc1\x6e\x2b\xd4\xdb\x3e\xa8\xd3\x26\xd2\x48\x92\x24\xca\x61\x86\x8f\x8c\xbb\xf2\x8e\x91\xdf\x1f\x06\x19\x33\xf3\x03\x4d\xba\xcd\xe2\x2d\xfb\x69\xe9\x16\x15\x13\xd5\x56\x85\x4e\x3c\x5b\x8a\xbf\x25\x72\x83\xee\x5e\x20\x22\xf2\xc8\xaa\x7b\xdb\x8e\xe4\x29\x58\xca\x38\xb7\x3f\x2e\x59\xb8\xbd\xa8\x16\x16\xf7\xdb\x79\x51\x9f\x5a\xb4\x8d\x87\x3a\x6e\xbc\x3e\xc5\xb4\xcd\x58\xf9\xf5\x3c\xb9\x6f\x49\xaf\x57\xc1\xfa\x1c\x5d\x6d\x88\x8a\x8b\xd3\x28\xcc\xb7\xef\x10\x8a\x4a\x74\xa9\x4a\xa7\x62\xbf\x0d\x76\x23\x6f\x59\xd9\x31\xee\x40\x11\xfb\x28\xec\x8d\x22\x1c\x13\x5a\x64\x94\x23\x16\x60\xbb\xd2\x7c\xa0\x98\xb2\xe5\x6e\xbc\x54\x33\xe0\x3e\xb9\x52\x17\xdb\xb7\x1b\xc8\x12\x20\x8c\x23\xca\x64\x7e\x78\xa3\x62\x5b\x75\x56\xd9\x9e\x2a\x91\x27\xb0\x70\x34\x1f\x90\x89\xb5\x86\x73\x7e\x71\xda\x1e\xfb\x3a\x72\xdc\x5e\x79\x88\xcb\x74\x79\xd9\x64\xe4\xd4\xc2\x9e\xce\xb1\xfe\x85\x5a\xc0\xe9\x0c\x34\x3d\xd0\x43\xce\xa1\x36\x39\xd5\xa1\x4e\xf5\xf8\xb1\xa9\x23\x08\x75\x84\xac\x53\x6c\x3a\xc5\xa6\x53\x6c\x3a\xc5\xa6\x7f\xc5\xd8\xf4\x51\xfd\xff\x25\x4e\xfa\x33\x05\xbe\x9d\x60\xd2\x04\x93\x6a\x5f\x33\x9b\x98\x50\xd2\xe1\x50\x52\xc6\xcc\xdb\x38\x91\xdb\xe6\xaa\xa2\x8f\xa1\x6a\xa6\xd4\xc6\x56\xd6\x8c\x40\x02\x68\x48\xe8\x1a\xe1\x9a\xd9\x2e\xb7\x05\xc3\x34\xda\x2a\xbb\xcd\x12\x36\x98\x22\x50\x4c\xa1\x1b\xc5\xd5\x84\xf0\xbe\x24\x84\xf7\x2f\x22\x37\xef\x94\xd7\x9f\xa0\xde\x04\xf5\x26\xa8\x37\x41\x3d\x64\x40\x3d\xe5\xf2\xde\x60\x89\x27\xb4\x37\xa1\xbd\xda\xd7\xd2\x2c\x26\xc0\x37\x01\x3e\x1b\xef\x5f\x06\xe0\x6b\x7c\x5c\x91\x08\x26\x10\x38\x81\xc0\x09\x04\x76\x4a\x3d\x81\xc0\xbf\x12\x08\x4c\xb0\xdc\x7c\x99\x00\xd0\x75\x70\xb4\xf8\x5a\x7c\xea\xde\x3e\x39\x08\x30\x5a\x27\x35\xed\xb4\x65\xad\x69\x74\x10\x88\x79\xe2\x30\x52\x19\xd6\x04\x21\xa7\x95\xd5\x0e\x03\xf8\xda\x20\xd7\x84\xb4\x26\xa4\x35\x21\xad\x09\x69\x21\x03\x69\x51\x46\xff\xff\x18\x9b\x54\xed\x87\x47\x06\x9d\x4e\x73\x6e\x9a\xb3\xa9\xce\x83\x5e\x4b\xc6\x71\x20\x45\xd7\x72\xf5\x40\x72\x0e\x34\x6c\xf4\x6c\xf3\xba\x5e\x4b\x97\x0e\x52\xb8\xbe\x8b\x79\xa0\x10\x86\xa1\x75\xb0\x6f\xec\xc8\xf4\x3d\x4d\x7b\x86\xc2\x02\x31\x12\x51\xbf\x07\x94\xad\x10\xd6\x2e\x79\xcf\xe9\x1c\xf5\x1e\x31\x23\x5c\x18\xfb\x9c\xfb\x70\xe0\x62\xbd\xf7\xb5\x94\xcf\xf3\xf6\xfa\xc5\x4e\x9c\x85\x76\x1d\xae\x37\xbc\xde\xa3\x41\xcb\x29\xd0\x5e\x70\x67\x50\x93\x6d\x98\xa8\xd3\x67\x0f\x68\xb1\xeb\x38\x47\x07\x10\x1b\xd2\xe2\x18\x68\x6d\x40\xbb\xa3\x40\xba\x21\xf2\x8e\x81\xfb\xf6\x92\x77\x2f\x70\xe8\xdb\xb2\x36\xbf\x30\x91\xc5\x21\xe7\x45\xcc\x34\x0c\x48\x8e\xd0\xf2\x9b\x7c\x3c\xbd\x1c\x04\x3e\x07\xe8\x7c\x2f\x84\x7a\x48\x4d\x1f\xba\xe1\x76\x45\x7b\x60\xe0\x01\xca\xee\x04\xca\x31\xbe\x73\x5f\xa3\x70\x0c\xad\x1f\xa5\xf5\x76\xd5\xbb\xd2\x7e\xfb\x30\x90\xcf\xfa\x67\x7a\xe6\xc3\x37\x42\x19\xe2\xc9\x9c\x61\x4c\xe7\xd1\x77\x55\x86\x6e\x8f\x7b\x85\x42\x33\xa3\xaa\x57\xae\xfd\xd5\xcc\x9c\x56\x68\xe2\xde\x0e\xa8\x2c\xa9\xb0\x7d\xf0\x54\x2d\x80\xf2\x48\x39\x3d\x98\x1a\x6d\x0b\x9d\xba\x53\xfb\xce\xf8\xd1\x7e\xbb\x60\x4f\x06\xf5\xce\xda\xab\xeb\xca\xcb\xd5\xac\x20\xda\x72\x3b\xa2\x4b\x38\xd7\xb5\x89\xbe\x42\xd9\xb9\x73\xc4\x0c\x6d\xb7\xd9\xf8\x8d\xbd\x3e\x9c\xf5\x53\x68\x48\x14\x36\x8f\x09\xc5\x92\xf1\x21\xd1\x09\x07\x1c\xbe\xa7\x91\xf3\x6a\xc8\xc1\x57\xb0\xdd\xc5\xc6\x1d\xad\x76\x1d\xa8\x82\x0e\x4c\x38\xfe\xa5\x8c\xc5\x0a\x40\x5d\xa1\xbb\x98\xd1\xfb\x74\x61\xed\x1a\x98\xaf\x3c\x8c\x1e\xe3\xc2\x92\x29\x74\x3e\x99\xd0\xf9\x41\x50\xd0\x38\x4b\x57\x7e\x5b\x7a\x0e\xe6\xce\x4e\xd7\x19\x35\x57\xbb\x3c\x3c\xd2\x5e\x4f\x4b\x4c\xf7\x0f\x4d\x2b\x91\x5d\x94\xa6\x95\xc8\x69\x25\x72\x5a\x89\x7c\xb8\x95\xc8\x07\x80\x8c\xda\x9c\x64\x7b\xb7\x71\xdf\x57\x12\x4b\x9a\x1f\x72\x0c\x13\x03\xad\x3c\xd5\x4e\xde\x8e\x57\x13\x6d\x34\x86\xcf\x97\xe6\xa4\x68\xc4\xb0\xf6\xc9\xc2\xeb\x8d\x0b\xd7\xcd\xfe\xba\xa6\xf5\x30\xeb\x30\x33\xbe\xc7\x56\x27\xab\x08\xd9\x6d\xbb\x09\xee\x7c\x2d\xcf\xee\x87\x38\xac\xc8\xdd\x90\x9a\x58\x4a\x4e\x96\xa9\x79\x79\xf3\xde\x20\xf0\x96\xe3\x24\x19\xeb\xba\xf2\x53\x19\xab\x12\xaf\x47\xb3\xa0\x3e\xef\x9b\x8d\x6d\x6d\x7b\xde\x3b\x3b\x1a\xc0\x3f\x95\x7e\xed\x78\xfb\x76\xb8\xaf\xb3\xdd\xc5\xeb\x95\xed\x5a\x62\x41\x82\xb3\x54\x6e\x80\x4a\x92\x6f\x36\xbd\x34\xae\xde\x6f\xa4\xc0\xbc\x08\xe3\x84\xfc\x1d\xb6\xe3\xd0\x62\x38\x95\x9b\x57\xe7\x71\x12\x91\x80\xc8\x31\x69\x5e\x60\x21\x6e\x19\x0f\xc7\xa4\x79\x96\x28\x3e\x47\x54\x65\x41\x36\x08\x40\x88\x1f\x58\x08\x56\xaa\xd5\xbf\xaf\xad\x96\xd7\xd6\xcf\x87\xf5\x34\x0f\x71\x93\x6e\x26\xed\x98\x5b\x9f\x4f\xcf\x95\x34\xc6\xd7\x11\xfa\xb0\x81\x22\x1a\xdb\xdf\x8e\xdc\xc3\xb9\xf8\xdd\x5d\x3c\x74\xe6\xea\xb7\x8b\xbf\xf5\x6e\xb3\x46\x2e\x64\xf4\xab\x3c\x4e\xcf\x36\x1d\xfe\xfa\xb8\x36\xba\x8a\xd8\xad\xf6\xc6\x41\x2a\x37\x8c\x17\x0f\xda\xfe\xda\xe7\x65\xbc\x71\x2c\x36\x57\x8a\x47\x12\x4c\xf1\xbd\x77\x6b\xa4\x50\x7e\x77\x7b\x22\x60\x89\xef\xcd\xf5\xb9\x0c\x97\x79\x0d\x2b\x35\x43\xcb\x3d\x24\xf1\x78\xfc\xf8\xcb\x1f\x15\x06\xe2\x78\xd8\x51\x21\xd9\x1f\xf0\xf5\x8f\x86\xa4\x50\xfa\xb1\x47\x43\xa5\xdd\x69\x14\xe8\xa3\xc0\x86\x91\xa7\x81\x50\xb4\x7c\xc0\x81\x80\x77\x7a\x9f\xc6\xc2\xa9\x8c\x05\x33\xb0\x3b\x31\xa4\xf4\xd7\x1b\x26\x55\x97\x7c\x65\xf8\x69\x1a\x84\x8e\x41\x78\xd9\xec\xc5\x11\x16\x1e\x74\x91\xf5\x56\xf5\x57\x49\x47\x5c\x92\xa9\x1e\x99\x36\xf4\xdb\xb1\x0e\xd3\x78\x02\xb0\x9b\x25\xcb\xe9\xe9\x1d\x0d\x44\x01\x42\x08\x91\x64\xd9\xdd\x37\x08\x17\xef\xf9\xe5\x0f\xbd\x46\x91\xf5\xf9\x89\x92\x37\xdd\x89\x59\x44\x1f\x9c\xee\x34\x1e\xbe\x47\x83\x32\x72\x8e\x37\xdf\xac\x69\x38\xef\x75\xb0\xda\xdb\xac\x83\x94\x2f\x39\xa6\x62\x05\x1c\x25\x9c\x49\x16\xb0\xa8\x3c\xc7\x7e\x76\x71\x3e\x6f\xb5\x24\xe7\xe8\xb7\xb9\xc7\x6c\x43\x92\xee\x21\xd4\x17\xa1\x7f\xba\x35\xfe\xae\x39\xbc\xde\xba\x69\xd9\x8e\xe1\x62\xde\x64\x7d\x16\x88\x1b\xed\x29\x11\xfd\x4f\xa9\xff\x99\x90\xc4\xf6\xf4\xf9\x6e\xe9\x28\x23\xd7\xca\xe5\xee\xee\x9f\x63\xb1\x5b\xfb\x10\xd7\x2f\x1d\xf2\xe3\xbf\xb9\xb5\x6f\xa4\x6d\x7d\x25\x79\xfb\x24\x31\xea\x56\xbe\x5d\x53\xcd\x2d\x36\xa3\x6d\xdf\xab\x1c\xb8\x6d\x6f\xc0\x98\xa7\xdd\xaa\x86\x8c\x1d\x39\xa3\x9d\x70\x2b\x9b\x68\xd9\xfd\x33\xfe\xa9\xb6\x4a\x2e\x63\x0f\xcf\x68\x27\xd9\x4c\xb9\x46\x6d\xcb\xbe\xa1\xa8\xd6\x5f\xc6\xd6\x9f\xf1\x4f\xf4\xd4\xb4\x78\xd0\xd6\xf4\x13\x3c\x3b\xac\xd0\xdc\x90\x34\xda\xc9\xb4\x9a\x1a\x8d\xbd\x93\x87\xd4\xe2\x21\x1b\xb3\x2b\xd1\xbe\xe7\x69\xd4\x53\x67\xd5\x40\xa0\xe3\x19\x3f\x6d\x1a\xbc\x0e\x86\x3c\x10\xb4\x3d\x2a\xcd\x78\x32\xe6\xab\xbd\x36\xc9\xf4\x3a\x58\xae\xc3\xf4\x47\xea\xbf\xfb\x47\xff\x0d\x00\x00\xff\xff\xd2\x32\x5a\x28\x38\x9d\x00\x00") - -func v2SchemaJsonBytes() ([]byte, error) { - return bindataRead( - _v2SchemaJson, - "v2/schema.json", - ) -} - -func v2SchemaJson() (*asset, error) { - bytes, err := v2SchemaJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "v2/schema.json", size: 40248, mode: os.FileMode(0640), modTime: time.Unix(1568964748, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xab, 0x88, 0x5e, 0xf, 0xbf, 0x17, 0x74, 0x0, 0xb2, 0x5a, 0x7f, 0xbc, 0x58, 0xcd, 0xc, 0x25, 0x73, 0xd5, 0x29, 0x1c, 0x7a, 0xd0, 0xce, 0x79, 0xd4, 0x89, 0x31, 0x27, 0x90, 0xf2, 0xff, 0xe6}} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - canonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[canonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// AssetString returns the asset contents as a string (instead of a []byte). -func AssetString(name string) (string, error) { - data, err := Asset(name) - return string(data), err -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// MustAssetString is like AssetString but panics when Asset would return an -// error. It simplifies safe initialization of global variables. -func MustAssetString(name string) string { - return string(MustAsset(name)) -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - canonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[canonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetDigest returns the digest of the file with the given name. It returns an -// error if the asset could not be found or the digest could not be loaded. -func AssetDigest(name string) ([sha256.Size]byte, error) { - canonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[canonicalName]; ok { - a, err := f() - if err != nil { - return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err) - } - return a.digest, nil - } - return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name) -} - -// Digests returns a map of all known files and their checksums. -func Digests() (map[string][sha256.Size]byte, error) { - mp := make(map[string][sha256.Size]byte, len(_bindata)) - for name := range _bindata { - a, err := _bindata[name]() - if err != nil { - return nil, err - } - mp[name] = a.digest - } - return mp, nil -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "jsonschema-draft-04.json": jsonschemaDraft04Json, - - "v2/schema.json": v2SchemaJson, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"}, -// AssetDir("data/img") would return []string{"a.png", "b.png"}, -// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - canonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(canonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "jsonschema-draft-04.json": {jsonschemaDraft04Json, map[string]*bintree{}}, - "v2": {nil, map[string]*bintree{ - "schema.json": {v2SchemaJson, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory. -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) -} - -// RestoreAssets restores an asset under the given directory recursively. -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - canonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) -} diff --git a/vendor/github.com/go-openapi/spec/embed.go b/vendor/github.com/go-openapi/spec/embed.go new file mode 100644 index 00000000..1f428475 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/embed.go @@ -0,0 +1,17 @@ +package spec + +import ( + "embed" + "path" +) + +//go:embed schemas/*.json schemas/*/*.json +var assets embed.FS + +func jsonschemaDraft04JSONBytes() ([]byte, error) { + return assets.ReadFile(path.Join("schemas", "jsonschema-draft-04.json")) +} + +func v2SchemaJSONBytes() ([]byte, error) { + return assets.ReadFile(path.Join("schemas", "v2", "schema.json")) +} diff --git a/vendor/github.com/go-openapi/spec/expander.go b/vendor/github.com/go-openapi/spec/expander.go index d4ea889d..b81a5699 100644 --- a/vendor/github.com/go-openapi/spec/expander.go +++ b/vendor/github.com/go-openapi/spec/expander.go @@ -27,7 +27,6 @@ import ( // all relative $ref's will be resolved from there. // // PathLoader injects a document loading method. By default, this resolves to the function provided by the SpecLoader package variable. -// type ExpandOptions struct { RelativeBase string // the path to the root document to expand. This is a file, not a directory SkipSchemas bool // do not expand schemas, just paths, parameters and responses @@ -58,7 +57,7 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error { if !options.SkipSchemas { for key, definition := range spec.Definitions { parentRefs := make([]string, 0, 10) - parentRefs = append(parentRefs, fmt.Sprintf("#/definitions/%s", key)) + parentRefs = append(parentRefs, "#/definitions/"+key) def, err := expandSchema(definition, parentRefs, resolver, specBasePath) if resolver.shouldStopOnError(err) { @@ -103,15 +102,21 @@ const rootBase = ".root" // baseForRoot loads in the cache the root document and produces a fake ".root" base path entry // for further $ref resolution -// -// Setting the cache is optional and this parameter may safely be left to nil. func baseForRoot(root interface{}, cache ResolutionCache) string { - if root == nil { - return "" - } - // cache the root document to resolve $ref's normalizedBase := normalizeBase(rootBase) + + if root == nil { + // ensure that we never leave a nil root: always cache the root base pseudo-document + cachedRoot, found := cache.Get(normalizedBase) + if found && cachedRoot != nil { + // the cache is already preloaded with a root + return normalizedBase + } + + root = map[string]interface{}{} + } + cache.Set(normalizedBase, root) return normalizedBase @@ -208,7 +213,19 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba } if target.Ref.String() != "" { - return expandSchemaRef(target, parentRefs, resolver, basePath) + if !resolver.options.SkipSchemas { + return expandSchemaRef(target, parentRefs, resolver, basePath) + } + + // when "expand" with SkipSchema, we just rebase the existing $ref without replacing + // the full schema. + rebasedRef, err := NewRef(normalizeURI(target.Ref.String(), basePath)) + if err != nil { + return nil, err + } + target.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID) + + return &target, nil } for k := range target.Definitions { @@ -520,21 +537,25 @@ func getRefAndSchema(input interface{}) (*Ref, *Schema, error) { } func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePath string) error { - ref, _, err := getRefAndSchema(input) + ref, sch, err := getRefAndSchema(input) if err != nil { return err } - if ref == nil { + if ref == nil && sch == nil { // nothing to do return nil } parentRefs := make([]string, 0, 10) - if err = resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) { - return err + if ref != nil { + // dereference this $ref + if err = resolver.deref(input, parentRefs, basePath); resolver.shouldStopOnError(err) { + return err + } + + ref, sch, _ = getRefAndSchema(input) } - ref, sch, _ := getRefAndSchema(input) if ref.String() != "" { transitiveResolver := resolver.transitiveResolver(basePath, *ref) basePath = resolver.updateBasePath(transitiveResolver, basePath) @@ -546,6 +567,7 @@ func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePa if ref != nil { *ref = Ref{} } + return nil } @@ -555,38 +577,29 @@ func expandParameterOrResponse(input interface{}, resolver *schemaLoader, basePa return ern } - switch { - case resolver.isCircular(&rebasedRef, basePath, parentRefs...): + if resolver.isCircular(&rebasedRef, basePath, parentRefs...) { // this is a circular $ref: stop expansion if !resolver.options.AbsoluteCircularRef { sch.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID) } else { sch.Ref = rebasedRef } - case !resolver.options.SkipSchemas: - // schema expanded to a $ref in another root - sch.Ref = rebasedRef - debugLog("rebased to: %s", sch.Ref.String()) - default: - // skip schema expansion but rebase $ref to schema - sch.Ref = denormalizeRef(&rebasedRef, resolver.context.basePath, resolver.context.rootID) } } + // $ref expansion or rebasing is performed by expandSchema below if ref != nil { *ref = Ref{} } // expand schema - if !resolver.options.SkipSchemas { - s, err := expandSchema(*sch, parentRefs, resolver, basePath) - if resolver.shouldStopOnError(err) { - return err - } - if s == nil { - // guard for when continuing on error - return nil - } + // yes, we do it even if options.SkipSchema is true: we have to go down that rabbit hole and rebase nested $ref) + s, err := expandSchema(*sch, parentRefs, resolver, basePath) + if resolver.shouldStopOnError(err) { + return err + } + + if s != nil { // guard for when continuing on error *sch = *s } diff --git a/vendor/github.com/go-openapi/spec/normalizer_nonwindows.go b/vendor/github.com/go-openapi/spec/normalizer_nonwindows.go index 2df07231..f19f1a8f 100644 --- a/vendor/github.com/go-openapi/spec/normalizer_nonwindows.go +++ b/vendor/github.com/go-openapi/spec/normalizer_nonwindows.go @@ -40,5 +40,5 @@ func repairURI(in string) (*url.URL, string) { return u, "" } -func fixWindowsURI(u *url.URL, in string) { +func fixWindowsURI(_ *url.URL, _ string) { } diff --git a/vendor/github.com/go-openapi/spec/operation.go b/vendor/github.com/go-openapi/spec/operation.go index 995ce6ac..a69cca88 100644 --- a/vendor/github.com/go-openapi/spec/operation.go +++ b/vendor/github.com/go-openapi/spec/operation.go @@ -217,9 +217,12 @@ func (o *Operation) AddParam(param *Parameter) *Operation { for i, p := range o.Parameters { if p.Name == param.Name && p.In == param.In { - params := append(o.Parameters[:i], *param) + params := make([]Parameter, 0, len(o.Parameters)+1) + params = append(params, o.Parameters[:i]...) + params = append(params, *param) params = append(params, o.Parameters[i+1:]...) o.Parameters = params + return o } } diff --git a/vendor/github.com/go-openapi/spec/parameter.go b/vendor/github.com/go-openapi/spec/parameter.go index 2b2b89b6..bd4f1cdb 100644 --- a/vendor/github.com/go-openapi/spec/parameter.go +++ b/vendor/github.com/go-openapi/spec/parameter.go @@ -84,27 +84,27 @@ type ParamProps struct { // Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn). // // There are five possible parameter types. -// * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part -// of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, -// the path parameter is `itemId`. -// * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`. -// * Header - Custom headers that are expected as part of the request. -// * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be -// _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for -// documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist -// together for the same operation. -// * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or -// `multipart/form-data` are used as the content type of the request (in Swagger's definition, -// the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used -// to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be -// declared together with a body parameter for the same operation. Form parameters have a different format based on -// the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4). -// * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload. -// For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple -// parameters that are being transferred. -// * `multipart/form-data` - each parameter takes a section in the payload with an internal header. -// For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is -// `submit-name`. This type of form parameters is more commonly used for file transfers. +// - Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part +// of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, +// the path parameter is `itemId`. +// - Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`. +// - Header - Custom headers that are expected as part of the request. +// - Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be +// _one_ body parameter. The name of the body parameter has no effect on the parameter itself and is used for +// documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist +// together for the same operation. +// - Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or +// `multipart/form-data` are used as the content type of the request (in Swagger's definition, +// the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used +// to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be +// declared together with a body parameter for the same operation. Form parameters have a different format based on +// the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4). +// - `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload. +// For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple +// parameters that are being transferred. +// - `multipart/form-data` - each parameter takes a section in the payload with an internal header. +// For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is +// `submit-name`. This type of form parameters is more commonly used for file transfers. // // For more information: http://goo.gl/8us55a#parameterObject type Parameter struct { diff --git a/vendor/github.com/go-openapi/spec/schema_loader.go b/vendor/github.com/go-openapi/spec/schema_loader.go index b81175af..0059b99a 100644 --- a/vendor/github.com/go-openapi/spec/schema_loader.go +++ b/vendor/github.com/go-openapi/spec/schema_loader.go @@ -168,14 +168,7 @@ func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) normalized := normalizeBase(pth) debugLog("loading doc from: %s", normalized) - unescaped, err := url.PathUnescape(normalized) - if err != nil { - return nil, url.URL{}, false, err - } - - u := url.URL{Path: unescaped} - - data, fromCache := r.cache.Get(u.RequestURI()) + data, fromCache := r.cache.Get(normalized) if fromCache { return data, toFetch, fromCache, nil } diff --git a/vendor/github.com/go-openapi/spec/schemas/jsonschema-draft-04.json b/vendor/github.com/go-openapi/spec/schemas/jsonschema-draft-04.json new file mode 100644 index 00000000..bcbb8474 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/schemas/jsonschema-draft-04.json @@ -0,0 +1,149 @@ +{ + "id": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] + }, + "simpleTypes": { + "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "$schema": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { "$ref": "#/definitions/positiveInteger" }, + "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/positiveInteger" }, + "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { "$ref": "#/definitions/positiveInteger" }, + "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} +} diff --git a/vendor/github.com/go-openapi/spec/schemas/v2/schema.json b/vendor/github.com/go-openapi/spec/schemas/v2/schema.json new file mode 100644 index 00000000..ebe10ed3 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/schemas/v2/schema.json @@ -0,0 +1,1607 @@ +{ + "title": "A JSON Schema for Swagger 2.0 API.", + "id": "http://swagger.io/v2/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "required": [ + "swagger", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "swagger": { + "type": "string", + "enum": [ + "2.0" + ], + "description": "The Swagger version of this document." + }, + "info": { + "$ref": "#/definitions/info" + }, + "host": { + "type": "string", + "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", + "description": "The host (name or ip) of the API. Example: 'swagger.io'" + }, + "basePath": { + "type": "string", + "pattern": "^/", + "description": "The base path to the API. Example: '/api'." + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "consumes": { + "description": "A list of MIME types accepted by the API.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "definitions": { + "$ref": "#/definitions/definitions" + }, + "parameters": { + "$ref": "#/definitions/parameterDefinitions" + }, + "responses": { + "$ref": "#/definitions/responseDefinitions" + }, + "security": { + "$ref": "#/definitions/security" + }, + "securityDefinitions": { + "$ref": "#/definitions/securityDefinitions" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "General information about the API.", + "required": [ + "version", + "title" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "title": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "version": { + "type": "string", + "description": "A semantic version number of the API." + }, + "description": { + "type": "string", + "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." + }, + "termsOfService": { + "type": "string", + "description": "The terms of service for the API." + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the owners of the API.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The identifying name of the contact person/organization." + }, + "url": { + "type": "string", + "description": "The URL pointing to the contact information.", + "format": "uri" + }, + "email": { + "type": "string", + "description": "The email address of the contact person/organization.", + "format": "email" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "license": { + "type": "object", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the license type. It's encouraged to use an OSI compatible license." + }, + "url": { + "type": "string", + "description": "The URL pointing to the license.", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "paths": { + "type": "object", + "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + }, + "^/": { + "$ref": "#/definitions/pathItem" + } + }, + "additionalProperties": false + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "description": "One or more JSON objects describing the schemas being consumed and produced by the API." + }, + "parameterDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameter" + }, + "description": "One or more JSON representations for parameters" + }, + "responseDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/response" + }, + "description": "One or more JSON representations for responses" + }, + "externalDocs": { + "type": "object", + "additionalProperties": false, + "description": "information about external documentation", + "required": [ + "url" + ], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "examples": { + "type": "object", + "additionalProperties": true + }, + "mimeType": { + "type": "string", + "description": "The MIME type of the HTTP message." + }, + "operation": { + "type": "object", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string", + "description": "A brief summary of the operation." + }, + "description": { + "type": "string", + "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string", + "description": "A unique identifier of the operation." + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "consumes": { + "description": "A list of MIME types the API can consume.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "parameters": { + "$ref": "#/definitions/parametersList" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "$ref": "#/definitions/security" + } + } + }, + "pathItem": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "parameters": { + "$ref": "#/definitions/parametersList" + } + } + }, + "responses": { + "type": "object", + "description": "Response objects names can either be any valid HTTP status code or 'default'.", + "minProperties": 1, + "additionalProperties": false, + "patternProperties": { + "^([0-9]{3})$|^(default)$": { + "$ref": "#/definitions/responseValue" + }, + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "not": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + } + }, + "responseValue": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "response": { + "type": "object", + "required": [ + "description" + ], + "properties": { + "description": { + "type": "string" + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/fileSchema" + } + ] + }, + "headers": { + "$ref": "#/definitions/headers" + }, + "examples": { + "$ref": "#/definitions/examples" + } + }, + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/header" + } + }, + "header": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "vendorExtension": { + "description": "Any property starting with x- is valid.", + "additionalProperties": true, + "additionalItems": true + }, + "bodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "schema" + ], + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "body" + ] + }, + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "schema": { + "$ref": "#/definitions/schema" + } + }, + "additionalProperties": false + }, + "headerParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "header" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "queryParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "query" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "formDataParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "formData" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array", + "file" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "pathParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "required" + ], + "properties": { + "required": { + "type": "boolean", + "enum": [ + true + ], + "description": "Determines whether or not this parameter is required or optional." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "path" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "nonBodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "type" + ], + "oneOf": [ + { + "$ref": "#/definitions/headerParameterSubSchema" + }, + { + "$ref": "#/definitions/formDataParameterSubSchema" + }, + { + "$ref": "#/definitions/queryParameterSubSchema" + }, + { + "$ref": "#/definitions/pathParameterSubSchema" + } + ] + }, + "parameter": { + "oneOf": [ + { + "$ref": "#/definitions/bodyParameter" + }, + { + "$ref": "#/definitions/nonBodyParameter" + } + ] + }, + "schema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "boolean" + } + ], + "default": {} + }, + "type": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/type" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + } + ], + "default": {} + }, + "allOf": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "default": {} + }, + "discriminator": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "fileSchema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "type" + ], + "properties": { + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "type": { + "type": "string", + "enum": [ + "file" + ] + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "primitivesItems": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "securityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "xml": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "tag": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "securityDefinitions": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/basicAuthenticationSecurity" + }, + { + "$ref": "#/definitions/apiKeySecurity" + }, + { + "$ref": "#/definitions/oauth2ImplicitSecurity" + }, + { + "$ref": "#/definitions/oauth2PasswordSecurity" + }, + { + "$ref": "#/definitions/oauth2ApplicationSecurity" + }, + { + "$ref": "#/definitions/oauth2AccessCodeSecurity" + } + ] + } + }, + "basicAuthenticationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "basic" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "apiKeySecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "name", + "in" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "apiKey" + ] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": [ + "header", + "query" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ImplicitSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "implicit" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2PasswordSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "password" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ApplicationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "application" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2AccessCodeSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "accessCode" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2Scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mediaTypeList": { + "type": "array", + "items": { + "$ref": "#/definitions/mimeType" + }, + "uniqueItems": true + }, + "parametersList": { + "type": "array", + "description": "The parameters needed to send a valid API call.", + "additionalItems": false, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "uniqueItems": true + }, + "schemesList": { + "type": "array", + "description": "The transfer protocol of the API.", + "items": { + "type": "string", + "enum": [ + "http", + "https", + "ws", + "wss" + ] + }, + "uniqueItems": true + }, + "collectionFormat": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes" + ], + "default": "csv" + }, + "collectionFormatWithMulti": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes", + "multi" + ], + "default": "csv" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "jsonReference": { + "type": "object", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + } + } + } + } +} diff --git a/vendor/github.com/go-openapi/spec/spec.go b/vendor/github.com/go-openapi/spec/spec.go index 7d38b6e6..876aa127 100644 --- a/vendor/github.com/go-openapi/spec/spec.go +++ b/vendor/github.com/go-openapi/spec/spec.go @@ -26,7 +26,7 @@ import ( const ( // SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs SwaggerSchemaURL = "http://swagger.io/v2/schema.json#" - // JSONSchemaURL the url for the json schema schema + // JSONSchemaURL the url for the json schema JSONSchemaURL = "http://json-schema.org/draft-04/schema#" ) @@ -41,7 +41,7 @@ func MustLoadJSONSchemaDraft04() *Schema { // JSONSchemaDraft04 loads the json schema document for json shema draft04 func JSONSchemaDraft04() (*Schema, error) { - b, err := Asset("jsonschema-draft-04.json") + b, err := jsonschemaDraft04JSONBytes() if err != nil { return nil, err } @@ -65,7 +65,7 @@ func MustLoadSwagger20Schema() *Schema { // Swagger20Schema loads the swagger 2.0 schema from the embedded assets func Swagger20Schema() (*Schema, error) { - b, err := Asset("v2/schema.json") + b, err := v2SchemaJSONBytes() if err != nil { return nil, err } diff --git a/vendor/github.com/go-openapi/spec/swagger.go b/vendor/github.com/go-openapi/spec/swagger.go index 44722ffd..1590fd17 100644 --- a/vendor/github.com/go-openapi/spec/swagger.go +++ b/vendor/github.com/go-openapi/spec/swagger.go @@ -253,7 +253,7 @@ func (s SchemaOrBool) MarshalJSON() ([]byte, error) { // UnmarshalJSON converts this bool or schema object from a JSON structure func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { var nw SchemaOrBool - if len(data) >= 4 { + if len(data) > 0 { if data[0] == '{' { var sch Schema if err := json.Unmarshal(data, &sch); err != nil { @@ -261,7 +261,7 @@ func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { } nw.Schema = &sch } - nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e') + nw.Allows = !bytes.Equal(data, []byte("false")) } *s = nw return nil diff --git a/vendor/github.com/go-openapi/spec/url_go18.go b/vendor/github.com/go-openapi/spec/url_go18.go deleted file mode 100644 index 60b78515..00000000 --- a/vendor/github.com/go-openapi/spec/url_go18.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !go1.19 -// +build !go1.19 - -package spec - -import "net/url" - -var parseURL = url.Parse diff --git a/vendor/github.com/go-openapi/spec/url_go19.go b/vendor/github.com/go-openapi/spec/url_go19.go index 392e3e63..5bdfe40b 100644 --- a/vendor/github.com/go-openapi/spec/url_go19.go +++ b/vendor/github.com/go-openapi/spec/url_go19.go @@ -1,6 +1,3 @@ -//go:build go1.19 -// +build go1.19 - package spec import "net/url" diff --git a/vendor/github.com/go-openapi/swag/.gitignore b/vendor/github.com/go-openapi/swag/.gitignore index d69b53ac..c4b1b64f 100644 --- a/vendor/github.com/go-openapi/swag/.gitignore +++ b/vendor/github.com/go-openapi/swag/.gitignore @@ -2,3 +2,4 @@ secrets.yml vendor Godeps .idea +*.out diff --git a/vendor/github.com/go-openapi/swag/.golangci.yml b/vendor/github.com/go-openapi/swag/.golangci.yml index bf503e40..80e2be00 100644 --- a/vendor/github.com/go-openapi/swag/.golangci.yml +++ b/vendor/github.com/go-openapi/swag/.golangci.yml @@ -4,14 +4,14 @@ linters-settings: golint: min-confidence: 0 gocyclo: - min-complexity: 25 + min-complexity: 45 maligned: suggest-new: true dupl: - threshold: 100 + threshold: 200 goconst: min-len: 3 - min-occurrences: 2 + min-occurrences: 3 linters: enable-all: true @@ -20,35 +20,41 @@ linters: - lll - gochecknoinits - gochecknoglobals - - nlreturn - - testpackage + - funlen + - godox + - gocognit + - whitespace + - wsl - wrapcheck + - testpackage + - nlreturn - gomnd - - exhaustive - exhaustivestruct - goerr113 - - wsl - - whitespace - - gofumpt - - godot + - errorlint - nestif - - godox - - funlen - - gci - - gocognit + - godot + - gofumpt - paralleltest + - tparallel - thelper - ifshort - - gomoddirectives - - cyclop - - forcetypeassert - - ireturn - - tagliatelle - - varnamelen - - goimports - - tenv - - golint - exhaustruct - - nilnil + - varnamelen + - gci + - depguard + - errchkjson + - inamedparam - nonamedreturns + - musttag + - ireturn + - forcetypeassert + - cyclop + # deprecated linters + - deadcode + - interfacer + - scopelint + - varcheck + - structcheck + - golint - nosnakecase diff --git a/vendor/github.com/go-openapi/swag/BENCHMARK.md b/vendor/github.com/go-openapi/swag/BENCHMARK.md new file mode 100644 index 00000000..e7f28ed6 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/BENCHMARK.md @@ -0,0 +1,52 @@ +# Benchmarks + +## Name mangling utilities + +```bash +go test -bench XXX -run XXX -benchtime 30s +``` + +### Benchmarks at b3e7a5386f996177e4808f11acb2aa93a0f660df + +``` +goos: linux +goarch: amd64 +pkg: github.com/go-openapi/swag +cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz +BenchmarkToXXXName/ToGoName-4 862623 44101 ns/op 10450 B/op 732 allocs/op +BenchmarkToXXXName/ToVarName-4 853656 40728 ns/op 10468 B/op 734 allocs/op +BenchmarkToXXXName/ToFileName-4 1268312 27813 ns/op 9785 B/op 617 allocs/op +BenchmarkToXXXName/ToCommandName-4 1276322 27903 ns/op 9785 B/op 617 allocs/op +BenchmarkToXXXName/ToHumanNameLower-4 895334 40354 ns/op 10472 B/op 731 allocs/op +BenchmarkToXXXName/ToHumanNameTitle-4 882441 40678 ns/op 10566 B/op 749 allocs/op +``` + +### Benchmarks after PR #79 + +~ x10 performance improvement and ~ /100 memory allocations. + +``` +goos: linux +goarch: amd64 +pkg: github.com/go-openapi/swag +cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz +BenchmarkToXXXName/ToGoName-4 9595830 3991 ns/op 42 B/op 5 allocs/op +BenchmarkToXXXName/ToVarName-4 9194276 3984 ns/op 62 B/op 7 allocs/op +BenchmarkToXXXName/ToFileName-4 17002711 2123 ns/op 147 B/op 7 allocs/op +BenchmarkToXXXName/ToCommandName-4 16772926 2111 ns/op 147 B/op 7 allocs/op +BenchmarkToXXXName/ToHumanNameLower-4 9788331 3749 ns/op 92 B/op 6 allocs/op +BenchmarkToXXXName/ToHumanNameTitle-4 9188260 3941 ns/op 104 B/op 6 allocs/op +``` + +``` +goos: linux +goarch: amd64 +pkg: github.com/go-openapi/swag +cpu: AMD Ryzen 7 5800X 8-Core Processor +BenchmarkToXXXName/ToGoName-16 18527378 1972 ns/op 42 B/op 5 allocs/op +BenchmarkToXXXName/ToVarName-16 15552692 2093 ns/op 62 B/op 7 allocs/op +BenchmarkToXXXName/ToFileName-16 32161176 1117 ns/op 147 B/op 7 allocs/op +BenchmarkToXXXName/ToCommandName-16 32256634 1137 ns/op 147 B/op 7 allocs/op +BenchmarkToXXXName/ToHumanNameLower-16 18599661 1946 ns/op 92 B/op 6 allocs/op +BenchmarkToXXXName/ToHumanNameTitle-16 17581353 2054 ns/op 105 B/op 6 allocs/op +``` diff --git a/vendor/github.com/go-openapi/swag/README.md b/vendor/github.com/go-openapi/swag/README.md index 217f6fa5..a7292229 100644 --- a/vendor/github.com/go-openapi/swag/README.md +++ b/vendor/github.com/go-openapi/swag/README.md @@ -1,7 +1,8 @@ -# Swag [![Build Status](https://travis-ci.org/go-openapi/swag.svg?branch=master)](https://travis-ci.org/go-openapi/swag) [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) +# Swag [![Build Status](https://github.com/go-openapi/swag/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/swag/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) +[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE) -[![GoDoc](https://godoc.org/github.com/go-openapi/swag?status.svg)](http://godoc.org/github.com/go-openapi/swag) +[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/swag.svg)](https://pkg.go.dev/github.com/go-openapi/swag) [![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/swag)](https://goreportcard.com/report/github.com/go-openapi/swag) Contains a bunch of helper functions for go-openapi and go-swagger projects. @@ -18,4 +19,5 @@ You may also use it standalone for your projects. This repo has only few dependencies outside of the standard library: -* YAML utilities depend on gopkg.in/yaml.v2 +* YAML utilities depend on `gopkg.in/yaml.v3` +* `github.com/mailru/easyjson v0.7.7` diff --git a/vendor/github.com/go-openapi/swag/initialism_index.go b/vendor/github.com/go-openapi/swag/initialism_index.go new file mode 100644 index 00000000..20a359bb --- /dev/null +++ b/vendor/github.com/go-openapi/swag/initialism_index.go @@ -0,0 +1,202 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "sort" + "strings" + "sync" +) + +var ( + // commonInitialisms are common acronyms that are kept as whole uppercased words. + commonInitialisms *indexOfInitialisms + + // initialisms is a slice of sorted initialisms + initialisms []string + + // a copy of initialisms pre-baked as []rune + initialismsRunes [][]rune + initialismsUpperCased [][]rune + + isInitialism func(string) bool + + maxAllocMatches int +) + +func init() { + // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769 + configuredInitialisms := map[string]bool{ + "ACL": true, + "API": true, + "ASCII": true, + "CPU": true, + "CSS": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTPS": true, + "HTTP": true, + "ID": true, + "IP": true, + "IPv4": true, + "IPv6": true, + "JSON": true, + "LHS": true, + "OAI": true, + "QPS": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SQL": true, + "SSH": true, + "TCP": true, + "TLS": true, + "TTL": true, + "UDP": true, + "UI": true, + "UID": true, + "UUID": true, + "URI": true, + "URL": true, + "UTF8": true, + "VM": true, + "XML": true, + "XMPP": true, + "XSRF": true, + "XSS": true, + } + + // a thread-safe index of initialisms + commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms) + initialisms = commonInitialisms.sorted() + initialismsRunes = asRunes(initialisms) + initialismsUpperCased = asUpperCased(initialisms) + maxAllocMatches = maxAllocHeuristic(initialismsRunes) + + // a test function + isInitialism = commonInitialisms.isInitialism +} + +func asRunes(in []string) [][]rune { + out := make([][]rune, len(in)) + for i, initialism := range in { + out[i] = []rune(initialism) + } + + return out +} + +func asUpperCased(in []string) [][]rune { + out := make([][]rune, len(in)) + + for i, initialism := range in { + out[i] = []rune(upper(trim(initialism))) + } + + return out +} + +func maxAllocHeuristic(in [][]rune) int { + heuristic := make(map[rune]int) + for _, initialism := range in { + heuristic[initialism[0]]++ + } + + var maxAlloc int + for _, val := range heuristic { + if val > maxAlloc { + maxAlloc = val + } + } + + return maxAlloc +} + +// AddInitialisms add additional initialisms +func AddInitialisms(words ...string) { + for _, word := range words { + // commonInitialisms[upper(word)] = true + commonInitialisms.add(upper(word)) + } + // sort again + initialisms = commonInitialisms.sorted() + initialismsRunes = asRunes(initialisms) + initialismsUpperCased = asUpperCased(initialisms) +} + +// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms. +// Since go1.9, this may be implemented with sync.Map. +type indexOfInitialisms struct { + sortMutex *sync.Mutex + index *sync.Map +} + +func newIndexOfInitialisms() *indexOfInitialisms { + return &indexOfInitialisms{ + sortMutex: new(sync.Mutex), + index: new(sync.Map), + } +} + +func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms { + m.sortMutex.Lock() + defer m.sortMutex.Unlock() + for k, v := range initial { + m.index.Store(k, v) + } + return m +} + +func (m *indexOfInitialisms) isInitialism(key string) bool { + _, ok := m.index.Load(key) + return ok +} + +func (m *indexOfInitialisms) add(key string) *indexOfInitialisms { + m.index.Store(key, true) + return m +} + +func (m *indexOfInitialisms) sorted() (result []string) { + m.sortMutex.Lock() + defer m.sortMutex.Unlock() + m.index.Range(func(key, _ interface{}) bool { + k := key.(string) + result = append(result, k) + return true + }) + sort.Sort(sort.Reverse(byInitialism(result))) + return +} + +type byInitialism []string + +func (s byInitialism) Len() int { + return len(s) +} +func (s byInitialism) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} +func (s byInitialism) Less(i, j int) bool { + if len(s[i]) != len(s[j]) { + return len(s[i]) < len(s[j]) + } + + return strings.Compare(s[i], s[j]) > 0 +} diff --git a/vendor/github.com/go-openapi/swag/loading.go b/vendor/github.com/go-openapi/swag/loading.go index 00038c37..783442fd 100644 --- a/vendor/github.com/go-openapi/swag/loading.go +++ b/vendor/github.com/go-openapi/swag/loading.go @@ -21,6 +21,7 @@ import ( "net/http" "net/url" "os" + "path" "path/filepath" "runtime" "strings" @@ -40,43 +41,97 @@ var LoadHTTPBasicAuthPassword = "" var LoadHTTPCustomHeaders = map[string]string{} // LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in -func LoadFromFileOrHTTP(path string) ([]byte, error) { - return LoadStrategy(path, os.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(path) +func LoadFromFileOrHTTP(pth string) ([]byte, error) { + return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(pth) } // LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in // timeout arg allows for per request overriding of the request timeout -func LoadFromFileOrHTTPWithTimeout(path string, timeout time.Duration) ([]byte, error) { - return LoadStrategy(path, os.ReadFile, loadHTTPBytes(timeout))(path) +func LoadFromFileOrHTTPWithTimeout(pth string, timeout time.Duration) ([]byte, error) { + return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(timeout))(pth) } -// LoadStrategy returns a loader function for a given path or uri -func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) { - if strings.HasPrefix(path, "http") { +// LoadStrategy returns a loader function for a given path or URI. +// +// The load strategy returns the remote load for any path starting with `http`. +// So this works for any URI with a scheme `http` or `https`. +// +// The fallback strategy is to call the local loader. +// +// The local loader takes a local file system path (absolute or relative) as argument, +// or alternatively a `file://...` URI, **without host** (see also below for windows). +// +// There are a few liberalities, initially intended to be tolerant regarding the URI syntax, +// especially on windows. +// +// Before the local loader is called, the given path is transformed: +// - percent-encoded characters are unescaped +// - simple paths (e.g. `./folder/file`) are passed as-is +// - on windows, occurrences of `/` are replaced by `\`, so providing a relative path such a `folder/file` works too. +// +// For paths provided as URIs with the "file" scheme, please note that: +// - `file://` is simply stripped. +// This means that the host part of the URI is not parsed at all. +// For example, `file:///folder/file" becomes "/folder/file`, +// but `file://localhost/folder/file` becomes `localhost/folder/file` on unix systems. +// Similarly, `file://./folder/file` yields `./folder/file`. +// - on windows, `file://...` can take a host so as to specify an UNC share location. +// +// Reminder about windows-specifics: +// - `file://host/folder/file` becomes an UNC path like `\\host\folder\file` (no port specification is supported) +// - `file:///c:/folder/file` becomes `C:\folder\file` +// - `file://c:/folder/file` is tolerated (without leading `/`) and becomes `c:\folder\file` +func LoadStrategy(pth string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) { + if strings.HasPrefix(pth, "http") { return remote } - return func(pth string) ([]byte, error) { - upth, err := pathUnescape(pth) + + return func(p string) ([]byte, error) { + upth, err := url.PathUnescape(p) if err != nil { return nil, err } - if strings.HasPrefix(pth, `file://`) { - if runtime.GOOS == "windows" { - // support for canonical file URIs on windows. - // Zero tolerance here for dodgy URIs. - u, _ := url.Parse(upth) - if u.Host != "" { - // assume UNC name (volume share) - // file://host/share/folder\... ==> \\host\share\path\folder - // NOTE: UNC port not yet supported - upth = strings.Join([]string{`\`, u.Host, u.Path}, `\`) - } else { - // file:///c:/folder/... ==> just remove the leading slash - upth = strings.TrimPrefix(upth, `file:///`) - } - } else { - upth = strings.TrimPrefix(upth, `file://`) + if !strings.HasPrefix(p, `file://`) { + // regular file path provided: just normalize slashes + return local(filepath.FromSlash(upth)) + } + + if runtime.GOOS != "windows" { + // crude processing: this leaves full URIs with a host with a (mostly) unexpected result + upth = strings.TrimPrefix(upth, `file://`) + + return local(filepath.FromSlash(upth)) + } + + // windows-only pre-processing of file://... URIs + + // support for canonical file URIs on windows. + u, err := url.Parse(filepath.ToSlash(upth)) + if err != nil { + return nil, err + } + + if u.Host != "" { + // assume UNC name (volume share) + // NOTE: UNC port not yet supported + + // when the "host" segment is a drive letter: + // file://C:/folder/... => C:\folder + upth = path.Clean(strings.Join([]string{u.Host, u.Path}, `/`)) + if !strings.HasSuffix(u.Host, ":") && u.Host[0] != '.' { + // tolerance: if we have a leading dot, this can't be a host + // file://host/share/folder\... ==> \\host\share\path\folder + upth = "//" + upth + } + } else { + // no host, let's figure out if this is a drive letter + upth = strings.TrimPrefix(upth, `file://`) + first, _, _ := strings.Cut(strings.TrimPrefix(u.Path, "/"), "/") + if strings.HasSuffix(first, ":") { + // drive letter in the first segment: + // file:///c:/folder/... ==> strip the leading slash + upth = strings.TrimPrefix(upth, `/`) } } diff --git a/vendor/github.com/go-openapi/swag/name_lexem.go b/vendor/github.com/go-openapi/swag/name_lexem.go index aa7f6a9b..8bb64ac3 100644 --- a/vendor/github.com/go-openapi/swag/name_lexem.go +++ b/vendor/github.com/go-openapi/swag/name_lexem.go @@ -14,74 +14,80 @@ package swag -import "unicode" +import ( + "unicode" + "unicode/utf8" +) type ( - nameLexem interface { - GetUnsafeGoName() string - GetOriginal() string - IsInitialism() bool - } + lexemKind uint8 - initialismNameLexem struct { + nameLexem struct { original string matchedInitialism string - } - - casualNameLexem struct { - original string + kind lexemKind } ) -func newInitialismNameLexem(original, matchedInitialism string) *initialismNameLexem { - return &initialismNameLexem{ +const ( + lexemKindCasualName lexemKind = iota + lexemKindInitialismName +) + +func newInitialismNameLexem(original, matchedInitialism string) nameLexem { + return nameLexem{ + kind: lexemKindInitialismName, original: original, matchedInitialism: matchedInitialism, } } -func newCasualNameLexem(original string) *casualNameLexem { - return &casualNameLexem{ +func newCasualNameLexem(original string) nameLexem { + return nameLexem{ + kind: lexemKindCasualName, original: original, } } -func (l *initialismNameLexem) GetUnsafeGoName() string { - return l.matchedInitialism -} +func (l nameLexem) GetUnsafeGoName() string { + if l.kind == lexemKindInitialismName { + return l.matchedInitialism + } + + var ( + first rune + rest string + ) -func (l *casualNameLexem) GetUnsafeGoName() string { - var first rune - var rest string for i, orig := range l.original { if i == 0 { first = orig continue } + if i > 0 { rest = l.original[i:] break } } + if len(l.original) > 1 { - return string(unicode.ToUpper(first)) + lower(rest) + b := poolOfBuffers.BorrowBuffer(utf8.UTFMax + len(rest)) + defer func() { + poolOfBuffers.RedeemBuffer(b) + }() + b.WriteRune(unicode.ToUpper(first)) + b.WriteString(lower(rest)) + return b.String() } return l.original } -func (l *initialismNameLexem) GetOriginal() string { +func (l nameLexem) GetOriginal() string { return l.original } -func (l *casualNameLexem) GetOriginal() string { - return l.original -} - -func (l *initialismNameLexem) IsInitialism() bool { - return true -} - -func (l *casualNameLexem) IsInitialism() bool { - return false +func (l nameLexem) IsInitialism() bool { + return l.kind == lexemKindInitialismName } diff --git a/vendor/github.com/go-openapi/swag/post_go19.go b/vendor/github.com/go-openapi/swag/post_go19.go deleted file mode 100644 index 7c7da9c0..00000000 --- a/vendor/github.com/go-openapi/swag/post_go19.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build go1.9 -// +build go1.9 - -package swag - -import ( - "sort" - "sync" -) - -// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms. -// Since go1.9, this may be implemented with sync.Map. -type indexOfInitialisms struct { - sortMutex *sync.Mutex - index *sync.Map -} - -func newIndexOfInitialisms() *indexOfInitialisms { - return &indexOfInitialisms{ - sortMutex: new(sync.Mutex), - index: new(sync.Map), - } -} - -func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms { - m.sortMutex.Lock() - defer m.sortMutex.Unlock() - for k, v := range initial { - m.index.Store(k, v) - } - return m -} - -func (m *indexOfInitialisms) isInitialism(key string) bool { - _, ok := m.index.Load(key) - return ok -} - -func (m *indexOfInitialisms) add(key string) *indexOfInitialisms { - m.index.Store(key, true) - return m -} - -func (m *indexOfInitialisms) sorted() (result []string) { - m.sortMutex.Lock() - defer m.sortMutex.Unlock() - m.index.Range(func(key, value interface{}) bool { - k := key.(string) - result = append(result, k) - return true - }) - sort.Sort(sort.Reverse(byInitialism(result))) - return -} diff --git a/vendor/github.com/go-openapi/swag/pre_go18.go b/vendor/github.com/go-openapi/swag/pre_go18.go deleted file mode 100644 index 2757d9b9..00000000 --- a/vendor/github.com/go-openapi/swag/pre_go18.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !go1.8 -// +build !go1.8 - -package swag - -import "net/url" - -func pathUnescape(path string) (string, error) { - return url.QueryUnescape(path) -} diff --git a/vendor/github.com/go-openapi/swag/pre_go19.go b/vendor/github.com/go-openapi/swag/pre_go19.go deleted file mode 100644 index 0565db37..00000000 --- a/vendor/github.com/go-openapi/swag/pre_go19.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !go1.9 -// +build !go1.9 - -package swag - -import ( - "sort" - "sync" -) - -// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms. -// Before go1.9, this may be implemented with a mutex on the map. -type indexOfInitialisms struct { - getMutex *sync.Mutex - index map[string]bool -} - -func newIndexOfInitialisms() *indexOfInitialisms { - return &indexOfInitialisms{ - getMutex: new(sync.Mutex), - index: make(map[string]bool, 50), - } -} - -func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms { - m.getMutex.Lock() - defer m.getMutex.Unlock() - for k, v := range initial { - m.index[k] = v - } - return m -} - -func (m *indexOfInitialisms) isInitialism(key string) bool { - m.getMutex.Lock() - defer m.getMutex.Unlock() - _, ok := m.index[key] - return ok -} - -func (m *indexOfInitialisms) add(key string) *indexOfInitialisms { - m.getMutex.Lock() - defer m.getMutex.Unlock() - m.index[key] = true - return m -} - -func (m *indexOfInitialisms) sorted() (result []string) { - m.getMutex.Lock() - defer m.getMutex.Unlock() - for k := range m.index { - result = append(result, k) - } - sort.Sort(sort.Reverse(byInitialism(result))) - return -} diff --git a/vendor/github.com/go-openapi/swag/split.go b/vendor/github.com/go-openapi/swag/split.go index a1825fb7..274727a8 100644 --- a/vendor/github.com/go-openapi/swag/split.go +++ b/vendor/github.com/go-openapi/swag/split.go @@ -15,124 +15,269 @@ package swag import ( + "bytes" + "sync" "unicode" + "unicode/utf8" ) -var nameReplaceTable = map[rune]string{ - '@': "At ", - '&': "And ", - '|': "Pipe ", - '$': "Dollar ", - '!': "Bang ", - '-': "", - '_': "", -} - type ( splitter struct { - postSplitInitialismCheck bool initialisms []string + initialismsRunes [][]rune + initialismsUpperCased [][]rune // initialisms cached in their trimmed, upper-cased version + postSplitInitialismCheck bool } - splitterOption func(*splitter) *splitter + splitterOption func(*splitter) + + initialismMatch struct { + body []rune + start, end int + complete bool + } + initialismMatches []initialismMatch ) -// split calls the splitter; splitter provides more control and post options -func split(str string) []string { - lexems := newSplitter().split(str) - result := make([]string, 0, len(lexems)) +type ( + // memory pools of temporary objects. + // + // These are used to recycle temporarily allocated objects + // and relieve the GC from undue pressure. - for _, lexem := range lexems { + matchesPool struct { + *sync.Pool + } + + buffersPool struct { + *sync.Pool + } + + lexemsPool struct { + *sync.Pool + } + + splittersPool struct { + *sync.Pool + } +) + +var ( + // poolOfMatches holds temporary slices for recycling during the initialism match process + poolOfMatches = matchesPool{ + Pool: &sync.Pool{ + New: func() any { + s := make(initialismMatches, 0, maxAllocMatches) + + return &s + }, + }, + } + + poolOfBuffers = buffersPool{ + Pool: &sync.Pool{ + New: func() any { + return new(bytes.Buffer) + }, + }, + } + + poolOfLexems = lexemsPool{ + Pool: &sync.Pool{ + New: func() any { + s := make([]nameLexem, 0, maxAllocMatches) + + return &s + }, + }, + } + + poolOfSplitters = splittersPool{ + Pool: &sync.Pool{ + New: func() any { + s := newSplitter() + + return &s + }, + }, + } +) + +// nameReplaceTable finds a word representation for special characters. +func nameReplaceTable(r rune) (string, bool) { + switch r { + case '@': + return "At ", true + case '&': + return "And ", true + case '|': + return "Pipe ", true + case '$': + return "Dollar ", true + case '!': + return "Bang ", true + case '-': + return "", true + case '_': + return "", true + default: + return "", false + } +} + +// split calls the splitter. +// +// Use newSplitter for more control and options +func split(str string) []string { + s := poolOfSplitters.BorrowSplitter() + lexems := s.split(str) + result := make([]string, 0, len(*lexems)) + + for _, lexem := range *lexems { result = append(result, lexem.GetOriginal()) } + poolOfLexems.RedeemLexems(lexems) + poolOfSplitters.RedeemSplitter(s) return result } -func (s *splitter) split(str string) []nameLexem { - return s.toNameLexems(str) -} - -func newSplitter(options ...splitterOption) *splitter { - splitter := &splitter{ +func newSplitter(options ...splitterOption) splitter { + s := splitter{ postSplitInitialismCheck: false, initialisms: initialisms, + initialismsRunes: initialismsRunes, + initialismsUpperCased: initialismsUpperCased, } for _, option := range options { - splitter = option(splitter) + option(&s) } - return splitter -} - -// withPostSplitInitialismCheck allows to catch initialisms after main split process -func withPostSplitInitialismCheck(s *splitter) *splitter { - s.postSplitInitialismCheck = true return s } -type ( - initialismMatch struct { - start, end int - body []rune - complete bool - } - initialismMatches []*initialismMatch -) +// withPostSplitInitialismCheck allows to catch initialisms after main split process +func withPostSplitInitialismCheck(s *splitter) { + s.postSplitInitialismCheck = true +} -func (s *splitter) toNameLexems(name string) []nameLexem { +func (p matchesPool) BorrowMatches() *initialismMatches { + s := p.Get().(*initialismMatches) + *s = (*s)[:0] // reset slice, keep allocated capacity + + return s +} + +func (p buffersPool) BorrowBuffer(size int) *bytes.Buffer { + s := p.Get().(*bytes.Buffer) + s.Reset() + + if s.Cap() < size { + s.Grow(size) + } + + return s +} + +func (p lexemsPool) BorrowLexems() *[]nameLexem { + s := p.Get().(*[]nameLexem) + *s = (*s)[:0] // reset slice, keep allocated capacity + + return s +} + +func (p splittersPool) BorrowSplitter(options ...splitterOption) *splitter { + s := p.Get().(*splitter) + s.postSplitInitialismCheck = false // reset options + for _, apply := range options { + apply(s) + } + + return s +} + +func (p matchesPool) RedeemMatches(s *initialismMatches) { + p.Put(s) +} + +func (p buffersPool) RedeemBuffer(s *bytes.Buffer) { + p.Put(s) +} + +func (p lexemsPool) RedeemLexems(s *[]nameLexem) { + p.Put(s) +} + +func (p splittersPool) RedeemSplitter(s *splitter) { + p.Put(s) +} + +func (m initialismMatch) isZero() bool { + return m.start == 0 && m.end == 0 +} + +func (s splitter) split(name string) *[]nameLexem { nameRunes := []rune(name) matches := s.gatherInitialismMatches(nameRunes) + if matches == nil { + return poolOfLexems.BorrowLexems() + } + return s.mapMatchesToNameLexems(nameRunes, matches) } -func (s *splitter) gatherInitialismMatches(nameRunes []rune) initialismMatches { - matches := make(initialismMatches, 0) +func (s splitter) gatherInitialismMatches(nameRunes []rune) *initialismMatches { + var matches *initialismMatches for currentRunePosition, currentRune := range nameRunes { - newMatches := make(initialismMatches, 0, len(matches)) + // recycle these allocations as we loop over runes + // with such recycling, only 2 slices should be allocated per call + // instead of o(n). + newMatches := poolOfMatches.BorrowMatches() // check current initialism matches - for _, match := range matches { - if keepCompleteMatch := match.complete; keepCompleteMatch { - newMatches = append(newMatches, match) - continue - } - - // drop failed match - currentMatchRune := match.body[currentRunePosition-match.start] - if !s.initialismRuneEqual(currentMatchRune, currentRune) { - continue - } - - // try to complete ongoing match - if currentRunePosition-match.start == len(match.body)-1 { - // we are close; the next step is to check the symbol ahead - // if it is a small letter, then it is not the end of match - // but beginning of the next word - - if currentRunePosition < len(nameRunes)-1 { - nextRune := nameRunes[currentRunePosition+1] - if newWord := unicode.IsLower(nextRune); newWord { - // oh ok, it was the start of a new word - continue - } + if matches != nil { // skip first iteration + for _, match := range *matches { + if keepCompleteMatch := match.complete; keepCompleteMatch { + *newMatches = append(*newMatches, match) + continue } - match.complete = true - match.end = currentRunePosition - } + // drop failed match + currentMatchRune := match.body[currentRunePosition-match.start] + if currentMatchRune != currentRune { + continue + } - newMatches = append(newMatches, match) + // try to complete ongoing match + if currentRunePosition-match.start == len(match.body)-1 { + // we are close; the next step is to check the symbol ahead + // if it is a small letter, then it is not the end of match + // but beginning of the next word + + if currentRunePosition < len(nameRunes)-1 { + nextRune := nameRunes[currentRunePosition+1] + if newWord := unicode.IsLower(nextRune); newWord { + // oh ok, it was the start of a new word + continue + } + } + + match.complete = true + match.end = currentRunePosition + } + + *newMatches = append(*newMatches, match) + } } // check for new initialism matches - for _, initialism := range s.initialisms { - initialismRunes := []rune(initialism) - if s.initialismRuneEqual(initialismRunes[0], currentRune) { - newMatches = append(newMatches, &initialismMatch{ + for i := range s.initialisms { + initialismRunes := s.initialismsRunes[i] + if initialismRunes[0] == currentRune { + *newMatches = append(*newMatches, initialismMatch{ start: currentRunePosition, body: initialismRunes, complete: false, @@ -140,24 +285,28 @@ func (s *splitter) gatherInitialismMatches(nameRunes []rune) initialismMatches { } } + if matches != nil { + poolOfMatches.RedeemMatches(matches) + } matches = newMatches } + // up to the caller to redeem this last slice return matches } -func (s *splitter) mapMatchesToNameLexems(nameRunes []rune, matches initialismMatches) []nameLexem { - nameLexems := make([]nameLexem, 0) +func (s splitter) mapMatchesToNameLexems(nameRunes []rune, matches *initialismMatches) *[]nameLexem { + nameLexems := poolOfLexems.BorrowLexems() - var lastAcceptedMatch *initialismMatch - for _, match := range matches { + var lastAcceptedMatch initialismMatch + for _, match := range *matches { if !match.complete { continue } - if firstMatch := lastAcceptedMatch == nil; firstMatch { - nameLexems = append(nameLexems, s.breakCasualString(nameRunes[:match.start])...) - nameLexems = append(nameLexems, s.breakInitialism(string(match.body))) + if firstMatch := lastAcceptedMatch.isZero(); firstMatch { + s.appendBrokenDownCasualString(nameLexems, nameRunes[:match.start]) + *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body))) lastAcceptedMatch = match @@ -169,63 +318,66 @@ func (s *splitter) mapMatchesToNameLexems(nameRunes []rune, matches initialismMa } middle := nameRunes[lastAcceptedMatch.end+1 : match.start] - nameLexems = append(nameLexems, s.breakCasualString(middle)...) - nameLexems = append(nameLexems, s.breakInitialism(string(match.body))) + s.appendBrokenDownCasualString(nameLexems, middle) + *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body))) lastAcceptedMatch = match } // we have not found any accepted matches - if lastAcceptedMatch == nil { - return s.breakCasualString(nameRunes) + if lastAcceptedMatch.isZero() { + *nameLexems = (*nameLexems)[:0] + s.appendBrokenDownCasualString(nameLexems, nameRunes) + } else if lastAcceptedMatch.end+1 != len(nameRunes) { + rest := nameRunes[lastAcceptedMatch.end+1:] + s.appendBrokenDownCasualString(nameLexems, rest) } - if lastAcceptedMatch.end+1 != len(nameRunes) { - rest := nameRunes[lastAcceptedMatch.end+1:] - nameLexems = append(nameLexems, s.breakCasualString(rest)...) - } + poolOfMatches.RedeemMatches(matches) return nameLexems } -func (s *splitter) initialismRuneEqual(a, b rune) bool { - return a == b -} - -func (s *splitter) breakInitialism(original string) nameLexem { +func (s splitter) breakInitialism(original string) nameLexem { return newInitialismNameLexem(original, original) } -func (s *splitter) breakCasualString(str []rune) []nameLexem { - segments := make([]nameLexem, 0) - currentSegment := "" +func (s splitter) appendBrokenDownCasualString(segments *[]nameLexem, str []rune) { + currentSegment := poolOfBuffers.BorrowBuffer(len(str)) // unlike strings.Builder, bytes.Buffer initial storage can reused + defer func() { + poolOfBuffers.RedeemBuffer(currentSegment) + }() addCasualNameLexem := func(original string) { - segments = append(segments, newCasualNameLexem(original)) + *segments = append(*segments, newCasualNameLexem(original)) } addInitialismNameLexem := func(original, match string) { - segments = append(segments, newInitialismNameLexem(original, match)) + *segments = append(*segments, newInitialismNameLexem(original, match)) } - addNameLexem := func(original string) { - if s.postSplitInitialismCheck { - for _, initialism := range s.initialisms { - if upper(initialism) == upper(original) { - addInitialismNameLexem(original, initialism) + var addNameLexem func(string) + if s.postSplitInitialismCheck { + addNameLexem = func(original string) { + for i := range s.initialisms { + if isEqualFoldIgnoreSpace(s.initialismsUpperCased[i], original) { + addInitialismNameLexem(original, s.initialisms[i]) + return } } - } - addCasualNameLexem(original) + addCasualNameLexem(original) + } + } else { + addNameLexem = addCasualNameLexem } - for _, rn := range string(str) { - if replace, found := nameReplaceTable[rn]; found { - if currentSegment != "" { - addNameLexem(currentSegment) - currentSegment = "" + for _, rn := range str { + if replace, found := nameReplaceTable(rn); found { + if currentSegment.Len() > 0 { + addNameLexem(currentSegment.String()) + currentSegment.Reset() } if replace != "" { @@ -236,27 +388,121 @@ func (s *splitter) breakCasualString(str []rune) []nameLexem { } if !unicode.In(rn, unicode.L, unicode.M, unicode.N, unicode.Pc) { - if currentSegment != "" { - addNameLexem(currentSegment) - currentSegment = "" + if currentSegment.Len() > 0 { + addNameLexem(currentSegment.String()) + currentSegment.Reset() } continue } if unicode.IsUpper(rn) { - if currentSegment != "" { - addNameLexem(currentSegment) + if currentSegment.Len() > 0 { + addNameLexem(currentSegment.String()) } - currentSegment = "" + currentSegment.Reset() } - currentSegment += string(rn) + currentSegment.WriteRune(rn) } - if currentSegment != "" { - addNameLexem(currentSegment) + if currentSegment.Len() > 0 { + addNameLexem(currentSegment.String()) } - - return segments +} + +// isEqualFoldIgnoreSpace is the same as strings.EqualFold, but +// it ignores leading and trailing blank spaces in the compared +// string. +// +// base is assumed to be composed of upper-cased runes, and be already +// trimmed. +// +// This code is heavily inspired from strings.EqualFold. +func isEqualFoldIgnoreSpace(base []rune, str string) bool { + var i, baseIndex int + // equivalent to b := []byte(str), but without data copy + b := hackStringBytes(str) + + for i < len(b) { + if c := b[i]; c < utf8.RuneSelf { + // fast path for ASCII + if c != ' ' && c != '\t' { + break + } + i++ + + continue + } + + // unicode case + r, size := utf8.DecodeRune(b[i:]) + if !unicode.IsSpace(r) { + break + } + i += size + } + + if i >= len(b) { + return len(base) == 0 + } + + for _, baseRune := range base { + if i >= len(b) { + break + } + + if c := b[i]; c < utf8.RuneSelf { + // single byte rune case (ASCII) + if baseRune >= utf8.RuneSelf { + return false + } + + baseChar := byte(baseRune) + if c != baseChar && + !('a' <= c && c <= 'z' && c-'a'+'A' == baseChar) { + return false + } + + baseIndex++ + i++ + + continue + } + + // unicode case + r, size := utf8.DecodeRune(b[i:]) + if unicode.ToUpper(r) != baseRune { + return false + } + baseIndex++ + i += size + } + + if baseIndex != len(base) { + return false + } + + // all passed: now we should only have blanks + for i < len(b) { + if c := b[i]; c < utf8.RuneSelf { + // fast path for ASCII + if c != ' ' && c != '\t' { + return false + } + i++ + + continue + } + + // unicode case + r, size := utf8.DecodeRune(b[i:]) + if !unicode.IsSpace(r) { + return false + } + + i += size + } + + return true } diff --git a/vendor/github.com/go-openapi/swag/string_bytes.go b/vendor/github.com/go-openapi/swag/string_bytes.go new file mode 100644 index 00000000..90745d5c --- /dev/null +++ b/vendor/github.com/go-openapi/swag/string_bytes.go @@ -0,0 +1,8 @@ +package swag + +import "unsafe" + +// hackStringBytes returns the (unsafe) underlying bytes slice of a string. +func hackStringBytes(str string) []byte { + return unsafe.Slice(unsafe.StringData(str), len(str)) +} diff --git a/vendor/github.com/go-openapi/swag/util.go b/vendor/github.com/go-openapi/swag/util.go index d971fbe3..5051401c 100644 --- a/vendor/github.com/go-openapi/swag/util.go +++ b/vendor/github.com/go-openapi/swag/util.go @@ -18,76 +18,25 @@ import ( "reflect" "strings" "unicode" + "unicode/utf8" ) -// commonInitialisms are common acronyms that are kept as whole uppercased words. -var commonInitialisms *indexOfInitialisms - -// initialisms is a slice of sorted initialisms -var initialisms []string - -var isInitialism func(string) bool - // GoNamePrefixFunc sets an optional rule to prefix go names // which do not start with a letter. // +// The prefix function is assumed to return a string that starts with an upper case letter. +// // e.g. to help convert "123" into "{prefix}123" // // The default is to prefix with "X" var GoNamePrefixFunc func(string) string -func init() { - // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769 - var configuredInitialisms = map[string]bool{ - "ACL": true, - "API": true, - "ASCII": true, - "CPU": true, - "CSS": true, - "DNS": true, - "EOF": true, - "GUID": true, - "HTML": true, - "HTTPS": true, - "HTTP": true, - "ID": true, - "IP": true, - "IPv4": true, - "IPv6": true, - "JSON": true, - "LHS": true, - "OAI": true, - "QPS": true, - "RAM": true, - "RHS": true, - "RPC": true, - "SLA": true, - "SMTP": true, - "SQL": true, - "SSH": true, - "TCP": true, - "TLS": true, - "TTL": true, - "UDP": true, - "UI": true, - "UID": true, - "UUID": true, - "URI": true, - "URL": true, - "UTF8": true, - "VM": true, - "XML": true, - "XMPP": true, - "XSRF": true, - "XSS": true, +func prefixFunc(name, in string) string { + if GoNamePrefixFunc == nil { + return "X" + in } - // a thread-safe index of initialisms - commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms) - initialisms = commonInitialisms.sorted() - - // a test function - isInitialism = commonInitialisms.isInitialism + return GoNamePrefixFunc(name) + in } const ( @@ -156,25 +105,9 @@ func SplitByFormat(data, format string) []string { return result } -type byInitialism []string - -func (s byInitialism) Len() int { - return len(s) -} -func (s byInitialism) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} -func (s byInitialism) Less(i, j int) bool { - if len(s[i]) != len(s[j]) { - return len(s[i]) < len(s[j]) - } - - return strings.Compare(s[i], s[j]) > 0 -} - // Removes leading whitespaces func trim(str string) string { - return strings.Trim(str, " ") + return strings.TrimSpace(str) } // Shortcut to strings.ToUpper() @@ -188,15 +121,20 @@ func lower(str string) string { } // Camelize an uppercased word -func Camelize(word string) (camelized string) { +func Camelize(word string) string { + camelized := poolOfBuffers.BorrowBuffer(len(word)) + defer func() { + poolOfBuffers.RedeemBuffer(camelized) + }() + for pos, ru := range []rune(word) { if pos > 0 { - camelized += string(unicode.ToLower(ru)) + camelized.WriteRune(unicode.ToLower(ru)) } else { - camelized += string(unicode.ToUpper(ru)) + camelized.WriteRune(unicode.ToUpper(ru)) } } - return + return camelized.String() } // ToFileName lowercases and underscores a go type name @@ -224,33 +162,40 @@ func ToCommandName(name string) string { // ToHumanNameLower represents a code name as a human series of words func ToHumanNameLower(name string) string { - in := newSplitter(withPostSplitInitialismCheck).split(name) - out := make([]string, 0, len(in)) + s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck) + in := s.split(name) + poolOfSplitters.RedeemSplitter(s) + out := make([]string, 0, len(*in)) - for _, w := range in { + for _, w := range *in { if !w.IsInitialism() { out = append(out, lower(w.GetOriginal())) } else { - out = append(out, w.GetOriginal()) + out = append(out, trim(w.GetOriginal())) } } + poolOfLexems.RedeemLexems(in) return strings.Join(out, " ") } // ToHumanNameTitle represents a code name as a human series of words with the first letters titleized func ToHumanNameTitle(name string) string { - in := newSplitter(withPostSplitInitialismCheck).split(name) + s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck) + in := s.split(name) + poolOfSplitters.RedeemSplitter(s) - out := make([]string, 0, len(in)) - for _, w := range in { - original := w.GetOriginal() + out := make([]string, 0, len(*in)) + for _, w := range *in { + original := trim(w.GetOriginal()) if !w.IsInitialism() { out = append(out, Camelize(original)) } else { out = append(out, original) } } + poolOfLexems.RedeemLexems(in) + return strings.Join(out, " ") } @@ -264,7 +209,7 @@ func ToJSONName(name string) string { out = append(out, lower(w)) continue } - out = append(out, Camelize(w)) + out = append(out, Camelize(trim(w))) } return strings.Join(out, "") } @@ -283,35 +228,70 @@ func ToVarName(name string) string { // ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes func ToGoName(name string) string { - lexems := newSplitter(withPostSplitInitialismCheck).split(name) + s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck) + lexems := s.split(name) + poolOfSplitters.RedeemSplitter(s) + defer func() { + poolOfLexems.RedeemLexems(lexems) + }() + lexemes := *lexems - result := "" - for _, lexem := range lexems { + if len(lexemes) == 0 { + return "" + } + + result := poolOfBuffers.BorrowBuffer(len(name)) + defer func() { + poolOfBuffers.RedeemBuffer(result) + }() + + // check if not starting with a letter, upper case + firstPart := lexemes[0].GetUnsafeGoName() + if lexemes[0].IsInitialism() { + firstPart = upper(firstPart) + } + + if c := firstPart[0]; c < utf8.RuneSelf { + // ASCII + switch { + case 'A' <= c && c <= 'Z': + result.WriteString(firstPart) + case 'a' <= c && c <= 'z': + result.WriteByte(c - 'a' + 'A') + result.WriteString(firstPart[1:]) + default: + result.WriteString(prefixFunc(name, firstPart)) + // NOTE: no longer check if prefixFunc returns a string that starts with uppercase: + // assume this is always the case + } + } else { + // unicode + firstRune, _ := utf8.DecodeRuneInString(firstPart) + switch { + case !unicode.IsLetter(firstRune): + result.WriteString(prefixFunc(name, firstPart)) + case !unicode.IsUpper(firstRune): + result.WriteString(prefixFunc(name, firstPart)) + /* + result.WriteRune(unicode.ToUpper(firstRune)) + result.WriteString(firstPart[offset:]) + */ + default: + result.WriteString(firstPart) + } + } + + for _, lexem := range lexemes[1:] { goName := lexem.GetUnsafeGoName() // to support old behavior if lexem.IsInitialism() { goName = upper(goName) } - result += goName + result.WriteString(goName) } - if len(result) > 0 { - // Only prefix with X when the first character isn't an ascii letter - first := []rune(result)[0] - if !unicode.IsLetter(first) || (first > unicode.MaxASCII && !unicode.IsUpper(first)) { - if GoNamePrefixFunc == nil { - return "X" + result - } - result = GoNamePrefixFunc(name) + result - } - first = []rune(result)[0] - if unicode.IsLetter(first) && !unicode.IsUpper(first) { - result = string(append([]rune{unicode.ToUpper(first)}, []rune(result)[1:]...)) - } - } - - return result + return result.String() } // ContainsStrings searches a slice of strings for a case-sensitive match @@ -343,7 +323,7 @@ type zeroable interface { func IsZero(data interface{}) bool { v := reflect.ValueOf(data) // check for nil data - switch v.Kind() { + switch v.Kind() { //nolint:exhaustive case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: if v.IsNil() { return true @@ -356,7 +336,7 @@ func IsZero(data interface{}) bool { } // continue with slightly more complex reflection - switch v.Kind() { + switch v.Kind() { //nolint:exhaustive case reflect.String: return v.Len() == 0 case reflect.Bool: @@ -376,16 +356,6 @@ func IsZero(data interface{}) bool { } } -// AddInitialisms add additional initialisms -func AddInitialisms(words ...string) { - for _, word := range words { - // commonInitialisms[upper(word)] = true - commonInitialisms.add(upper(word)) - } - // sort again - initialisms = commonInitialisms.sorted() -} - // CommandLineOptionsGroup represents a group of user-defined command line options type CommandLineOptionsGroup struct { ShortDescription string diff --git a/vendor/github.com/go-openapi/swag/yaml.go b/vendor/github.com/go-openapi/swag/yaml.go index f09ee609..f59e0259 100644 --- a/vendor/github.com/go-openapi/swag/yaml.go +++ b/vendor/github.com/go-openapi/swag/yaml.go @@ -16,8 +16,11 @@ package swag import ( "encoding/json" + "errors" "fmt" "path/filepath" + "reflect" + "sort" "strconv" "github.com/mailru/easyjson/jlexer" @@ -48,7 +51,7 @@ func BytesToYAMLDoc(data []byte) (interface{}, error) { return nil, err } if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode { - return nil, fmt.Errorf("only YAML documents that are objects are supported") + return nil, errors.New("only YAML documents that are objects are supported") } return &document, nil } @@ -147,7 +150,7 @@ func yamlScalar(node *yaml.Node) (interface{}, error) { case yamlTimestamp: return node.Value, nil case yamlNull: - return nil, nil + return nil, nil //nolint:nilnil default: return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag()) } @@ -245,7 +248,27 @@ func (s JSONMapSlice) MarshalYAML() (interface{}, error) { return yaml.Marshal(&n) } +func isNil(input interface{}) bool { + if input == nil { + return true + } + kind := reflect.TypeOf(input).Kind() + switch kind { //nolint:exhaustive + case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan: + return reflect.ValueOf(input).IsNil() + default: + return false + } +} + func json2yaml(item interface{}) (*yaml.Node, error) { + if isNil(item) { + return &yaml.Node{ + Kind: yaml.ScalarNode, + Value: "null", + }, nil + } + switch val := item.(type) { case JSONMapSlice: var n yaml.Node @@ -265,7 +288,14 @@ func json2yaml(item interface{}) (*yaml.Node, error) { case map[string]interface{}: var n yaml.Node n.Kind = yaml.MappingNode - for k, v := range val { + keys := make([]string, 0, len(val)) + for k := range val { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + v := val[k] childNode, err := json2yaml(v) if err != nil { return nil, err @@ -318,8 +348,9 @@ func json2yaml(item interface{}) (*yaml.Node, error) { Tag: yamlBoolScalar, Value: strconv.FormatBool(val), }, nil + default: + return nil, fmt.Errorf("unhandled type: %T", val) } - return nil, nil } // JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice diff --git a/vendor/github.com/go-playground/validator/v10/Makefile b/vendor/github.com/go-playground/validator/v10/Makefile index 09f171ba..e097dfaf 100644 --- a/vendor/github.com/go-playground/validator/v10/Makefile +++ b/vendor/github.com/go-playground/validator/v10/Makefile @@ -1,4 +1,4 @@ -GOCMD=GO111MODULE=on go +GOCMD=go linters-install: @golangci-lint --version >/dev/null 2>&1 || { \ @@ -15,4 +15,4 @@ test: bench: $(GOCMD) test -run=NONE -bench=. -benchmem ./... -.PHONY: test lint linters-install \ No newline at end of file +.PHONY: test lint linters-install diff --git a/vendor/github.com/go-playground/validator/v10/README.md b/vendor/github.com/go-playground/validator/v10/README.md index 30b60f80..a6e1d0b5 100644 --- a/vendor/github.com/go-playground/validator/v10/README.md +++ b/vendor/github.com/go-playground/validator/v10/README.md @@ -1,7 +1,7 @@ Package validator ================= [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![Project status](https://img.shields.io/badge/version-10.15.3-green.svg) +![Project status](https://img.shields.io/badge/version-10.19.0-green.svg) [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) @@ -178,6 +178,7 @@ validate := validator.New(validator.WithRequiredStructEnabled()) | isbn | International Standard Book Number | | isbn10 | International Standard Book Number 10 | | isbn13 | International Standard Book Number 13 | +| issn | International Standard Serial Number | | iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) | | iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) | | iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) | diff --git a/vendor/github.com/go-playground/validator/v10/baked_in.go b/vendor/github.com/go-playground/validator/v10/baked_in.go index cc92b784..95f56e00 100644 --- a/vendor/github.com/go-playground/validator/v10/baked_in.go +++ b/vendor/github.com/go-playground/validator/v10/baked_in.go @@ -51,6 +51,7 @@ var ( endKeysTag: {}, structOnlyTag: {}, omitempty: {}, + omitnil: {}, skipValidationTag: {}, utf8HexComma: {}, utf8Pipe: {}, @@ -149,6 +150,7 @@ var ( "isbn": isISBN, "isbn10": isISBN10, "isbn13": isISBN13, + "issn": isISSN, "eth_addr": isEthereumAddress, "eth_addr_checksum": isEthereumAddressChecksum, "btc_addr": isBitcoinAddress, @@ -373,9 +375,9 @@ func isMAC(fl FieldLevel) bool { // isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. func isCIDRv4(fl FieldLevel) bool { - ip, _, err := net.ParseCIDR(fl.Field().String()) + ip, net, err := net.ParseCIDR(fl.Field().String()) - return err == nil && ip.To4() != nil + return err == nil && ip.To4() != nil && net.IP.Equal(ip) } // isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. @@ -508,47 +510,47 @@ func isASCII(fl FieldLevel) bool { // isUUID5 is the validation function for validating if the field's value is a valid v5 UUID. func isUUID5(fl FieldLevel) bool { - return uUID5Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID5Regex, fl) } // isUUID4 is the validation function for validating if the field's value is a valid v4 UUID. func isUUID4(fl FieldLevel) bool { - return uUID4Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID4Regex, fl) } // isUUID3 is the validation function for validating if the field's value is a valid v3 UUID. func isUUID3(fl FieldLevel) bool { - return uUID3Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID3Regex, fl) } // isUUID is the validation function for validating if the field's value is a valid UUID of any version. func isUUID(fl FieldLevel) bool { - return uUIDRegex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUIDRegex, fl) } // isUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID. func isUUID5RFC4122(fl FieldLevel) bool { - return uUID5RFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID5RFC4122Regex, fl) } // isUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID. func isUUID4RFC4122(fl FieldLevel) bool { - return uUID4RFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID4RFC4122Regex, fl) } // isUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID. func isUUID3RFC4122(fl FieldLevel) bool { - return uUID3RFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUID3RFC4122Regex, fl) } // isUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version. func isUUIDRFC4122(fl FieldLevel) bool { - return uUIDRFC4122Regex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uUIDRFC4122Regex, fl) } // isULID is the validation function for validating if the field's value is a valid ULID. func isULID(fl FieldLevel) bool { - return uLIDRegex.MatchString(fl.Field().String()) + return fieldMatchesRegexByStringerValOrString(uLIDRegex, fl) } // isMD4 is the validation function for validating if the field's value is a valid MD4. @@ -650,6 +652,32 @@ func isISBN10(fl FieldLevel) bool { return checksum%11 == 0 } +// isISSN is the validation function for validating if the field's value is a valid ISSN. +func isISSN(fl FieldLevel) bool { + s := fl.Field().String() + + if !iSSNRegex.MatchString(s) { + return false + } + s = strings.ReplaceAll(s, "-", "") + + pos := 8 + checksum := 0 + + for i := 0; i < 7; i++ { + checksum += pos * int(s[i]-'0') + pos-- + } + + if s[7] == 'X' { + checksum += 10 + } else { + checksum += int(s[7] - '0') + } + + return checksum%11 == 0 +} + // isEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address. func isEthereumAddress(fl FieldLevel) bool { address := fl.Field().String() @@ -1413,6 +1441,15 @@ func isURI(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } +// isFileURL is the helper function for validating if the `path` valid file URL as per RFC8089 +func isFileURL(path string) bool { + if !strings.HasPrefix(path, "file:/") { + return false + } + _, err := url.ParseRequestURI(path) + return err == nil +} + // isURL is the validation function for validating if the current field's value is a valid URL. func isURL(fl FieldLevel) bool { field := fl.Field() @@ -1420,12 +1457,16 @@ func isURL(fl FieldLevel) bool { switch field.Kind() { case reflect.String: - s := field.String() + s := strings.ToLower(field.String()) if len(s) == 0 { return false } + if isFileURL(s) { + return true + } + url, err := url.Parse(s) if err != nil || url.Scheme == "" { return false diff --git a/vendor/github.com/go-playground/validator/v10/cache.go b/vendor/github.com/go-playground/validator/v10/cache.go index bbfd2a4a..b6bdd11a 100644 --- a/vendor/github.com/go-playground/validator/v10/cache.go +++ b/vendor/github.com/go-playground/validator/v10/cache.go @@ -20,6 +20,7 @@ const ( typeOr typeKeys typeEndKeys + typeOmitNil ) const ( @@ -125,7 +126,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr fld = typ.Field(i) - if !fld.Anonymous && len(fld.PkgPath) > 0 { + if !v.privateFieldValidation && !fld.Anonymous && len(fld.PkgPath) > 0 { continue } @@ -252,6 +253,10 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s current.typeof = typeOmitEmpty continue + case omitnil: + current.typeof = typeOmitNil + continue + case structOnlyTag: current.typeof = typeStructOnly continue diff --git a/vendor/github.com/go-playground/validator/v10/doc.go b/vendor/github.com/go-playground/validator/v10/doc.go index c4dbb595..b4740918 100644 --- a/vendor/github.com/go-playground/validator/v10/doc.go +++ b/vendor/github.com/go-playground/validator/v10/doc.go @@ -194,6 +194,13 @@ such as min or max won't run, but if a value is set validation will run. Usage: omitempty +# Omit Nil + +Allows to skip the validation if the value is nil (same as omitempty, but +only for the nil-values). + + Usage: omitnil + # Dive This tells the validator to dive into a slice, array or map and validate that diff --git a/vendor/github.com/go-playground/validator/v10/errors.go b/vendor/github.com/go-playground/validator/v10/errors.go index 5856d57c..be2676e9 100644 --- a/vendor/github.com/go-playground/validator/v10/errors.go +++ b/vendor/github.com/go-playground/validator/v10/errors.go @@ -257,15 +257,19 @@ func (fe *fieldError) Error() string { // NOTE: if no registered translation can be found, it returns the original // untranslated error message. func (fe *fieldError) Translate(ut ut.Translator) string { + var fn TranslationFunc m, ok := fe.v.transTagFunc[ut] if !ok { return fe.Error() } - fn, ok := m[fe.tag] + fn, ok = m[fe.tag] if !ok { - return fe.Error() + fn, ok = m[fe.actualTag] + if !ok { + return fe.Error() + } } return fn(ut, fe) diff --git a/vendor/github.com/go-playground/validator/v10/options.go b/vendor/github.com/go-playground/validator/v10/options.go index 1dea56fd..86a0db21 100644 --- a/vendor/github.com/go-playground/validator/v10/options.go +++ b/vendor/github.com/go-playground/validator/v10/options.go @@ -14,3 +14,13 @@ func WithRequiredStructEnabled() Option { v.requiredStructEnabled = true } } + +// WithPrivateFieldValidation activates validation for unexported fields via the use of the `unsafe` package. +// +// By opting into this feature you are acknowledging that you are aware of the risks and accept any current or future +// consequences of using this feature. +func WithPrivateFieldValidation() Option { + return func(v *Validate) { + v.privateFieldValidation = true + } +} diff --git a/vendor/github.com/go-playground/validator/v10/regexes.go b/vendor/github.com/go-playground/validator/v10/regexes.go index 6c8f9856..af98d8da 100644 --- a/vendor/github.com/go-playground/validator/v10/regexes.go +++ b/vendor/github.com/go-playground/validator/v10/regexes.go @@ -22,6 +22,7 @@ const ( base64RawURLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2,4})$" iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$" iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$" + iSSNRegexString = "^(?:[0-9]{4}-[0-9]{3}[0-9X])$" uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" @@ -93,6 +94,7 @@ var ( base64RawURLRegex = regexp.MustCompile(base64RawURLRegexString) iSBN10Regex = regexp.MustCompile(iSBN10RegexString) iSBN13Regex = regexp.MustCompile(iSBN13RegexString) + iSSNRegex = regexp.MustCompile(iSSNRegexString) uUID3Regex = regexp.MustCompile(uUID3RegexString) uUID4Regex = regexp.MustCompile(uUID4RegexString) uUID5Regex = regexp.MustCompile(uUID5RegexString) diff --git a/vendor/github.com/go-playground/validator/v10/util.go b/vendor/github.com/go-playground/validator/v10/util.go index 4bd947bd..16851593 100644 --- a/vendor/github.com/go-playground/validator/v10/util.go +++ b/vendor/github.com/go-playground/validator/v10/util.go @@ -1,7 +1,9 @@ package validator import ( + "fmt" "reflect" + "regexp" "strconv" "strings" "time" @@ -292,3 +294,18 @@ func panicIf(err error) { panic(err.Error()) } } + +// Checks if field value matches regex. If fl.Field can be cast to Stringer, it uses the Stringer interfaces +// String() return value. Otherwise, it uses fl.Field's String() value. +func fieldMatchesRegexByStringerValOrString(regex *regexp.Regexp, fl FieldLevel) bool { + switch fl.Field().Kind() { + case reflect.String: + return regex.MatchString(fl.Field().String()) + default: + if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok { + return regex.MatchString(stringer.String()) + } else { + return regex.MatchString(fl.Field().String()) + } + } +} diff --git a/vendor/github.com/go-playground/validator/v10/validator.go b/vendor/github.com/go-playground/validator/v10/validator.go index 2cae8f7e..901e7b50 100644 --- a/vendor/github.com/go-playground/validator/v10/validator.go +++ b/vendor/github.com/go-playground/validator/v10/validator.go @@ -5,6 +5,7 @@ import ( "fmt" "reflect" "strconv" + "unsafe" ) // per validate construct @@ -112,6 +113,10 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr return } + if ct.typeof == typeOmitNil && (kind != reflect.Invalid && current.IsNil()) { + return + } + if ct.hasTag { if kind == reflect.Invalid { v.str1 = string(append(ns, cf.altName...)) @@ -152,7 +157,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), - value: current.Interface(), + value: getValue(current), param: ct.param, kind: kind, typ: current.Type(), @@ -173,7 +178,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr // structs. Since it's basically nonsensical to use `required` with a non-pointer struct // are explicitly skipping the required validation for it. This WILL be removed in the // next major version. - if !v.v.requiredStructEnabled && ct != nil && ct.tag == requiredTag { + if isNestedStruct && !v.v.requiredStructEnabled && ct != nil && ct.tag == requiredTag { ct = ct.next } } @@ -233,6 +238,26 @@ OUTER: ct = ct.next continue + case typeOmitNil: + v.slflParent = parent + v.flField = current + v.cf = cf + v.ct = ct + + switch field := v.Field(); field.Kind() { + case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: + if field.IsNil() { + return + } + default: + if v.fldIsPointer && field.Interface() == nil { + return + } + } + + ct = ct.next + continue + case typeEndKeys: return @@ -386,7 +411,7 @@ OUTER: structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), - value: current.Interface(), + value: getValue(current), param: ct.param, kind: kind, typ: typ, @@ -406,7 +431,7 @@ OUTER: structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), - value: current.Interface(), + value: getValue(current), param: ct.param, kind: kind, typ: typ, @@ -446,7 +471,7 @@ OUTER: structNs: v.str2, fieldLen: uint8(len(cf.altName)), structfieldLen: uint8(len(cf.name)), - value: current.Interface(), + value: getValue(current), param: ct.param, kind: kind, typ: typ, @@ -460,3 +485,26 @@ OUTER: } } + +func getValue(val reflect.Value) interface{} { + if val.CanInterface() { + return val.Interface() + } + + if val.CanAddr() { + return reflect.NewAt(val.Type(), unsafe.Pointer(val.UnsafeAddr())).Elem().Interface() + } + + switch val.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return val.Int() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return val.Uint() + case reflect.Complex64, reflect.Complex128: + return val.Complex() + case reflect.Float32, reflect.Float64: + return val.Float() + default: + return val.String() + } +} diff --git a/vendor/github.com/go-playground/validator/v10/validator_instance.go b/vendor/github.com/go-playground/validator/v10/validator_instance.go index a4dbdd09..1a345138 100644 --- a/vendor/github.com/go-playground/validator/v10/validator_instance.go +++ b/vendor/github.com/go-playground/validator/v10/validator_instance.go @@ -22,6 +22,7 @@ const ( structOnlyTag = "structonly" noStructLevelTag = "nostructlevel" omitempty = "omitempty" + omitnil = "omitnil" isdefault = "isdefault" requiredWithoutAllTag = "required_without_all" requiredWithoutTag = "required_without" @@ -79,20 +80,21 @@ type internalValidationFuncWrapper struct { // Validate contains the validator settings and cache type Validate struct { - tagName string - pool *sync.Pool - tagNameFunc TagNameFunc - structLevelFuncs map[reflect.Type]StructLevelFuncCtx - customFuncs map[reflect.Type]CustomTypeFunc - aliases map[string]string - validations map[string]internalValidationFuncWrapper - transTagFunc map[ut.Translator]map[string]TranslationFunc // map[]map[]TranslationFunc - rules map[reflect.Type]map[string]string - tagCache *tagCache - structCache *structCache - hasCustomFuncs bool - hasTagNameFunc bool - requiredStructEnabled bool + tagName string + pool *sync.Pool + tagNameFunc TagNameFunc + structLevelFuncs map[reflect.Type]StructLevelFuncCtx + customFuncs map[reflect.Type]CustomTypeFunc + aliases map[string]string + validations map[string]internalValidationFuncWrapper + transTagFunc map[ut.Translator]map[string]TranslationFunc // map[]map[]TranslationFunc + rules map[reflect.Type]map[string]string + tagCache *tagCache + structCache *structCache + hasCustomFuncs bool + hasTagNameFunc bool + requiredStructEnabled bool + privateFieldValidation bool } // New returns a new instance of 'validate' with sane defaults. diff --git a/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md b/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md index 6ad1c22b..ff9c57e1 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md +++ b/vendor/github.com/golang-jwt/jwt/v5/MIGRATION_GUIDE.md @@ -17,7 +17,7 @@ and corresponding updates for existing programs. ## Parsing and Validation Options -Under the hood, a new `validator` struct takes care of validating the claims. A +Under the hood, a new `Validator` struct takes care of validating the claims. A long awaited feature has been the option to fine-tune the validation of tokens. This is now possible with several `ParserOption` functions that can be appended to most `Parse` functions, such as `ParseWithClaims`. The most important options @@ -68,6 +68,16 @@ type Claims interface { } ``` +Users that previously directly called the `Valid` function on their claims, +e.g., to perform validation independently of parsing/verifying a token, can now +use the `jwt.NewValidator` function to create a `Validator` independently of the +`Parser`. + +```go +var v = jwt.NewValidator(jwt.WithLeeway(5*time.Second)) +v.Validate(myClaims) +``` + ### Supported Claim Types and Removal of `StandardClaims` The two standard claim types supported by this library, `MapClaims` and @@ -169,7 +179,7 @@ be a drop-in replacement, if you're having troubles migrating, please open an issue. You can replace all occurrences of `github.com/dgrijalva/jwt-go` or -`github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v5`, either manually +`github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v4`, either manually or by using tools such as `sed` or `gofmt`. And then you'd typically run: diff --git a/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go b/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go index 4ccae2a8..c929e4a0 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go +++ b/vendor/github.com/golang-jwt/jwt/v5/ecdsa.go @@ -62,7 +62,7 @@ func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interf case *ecdsa.PublicKey: ecdsaKey = k default: - return ErrInvalidKeyType + return newError("ECDSA verify expects *ecdsa.PublicKey", ErrInvalidKeyType) } if len(sig) != 2*m.KeySize { @@ -96,7 +96,7 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) ([]byte case *ecdsa.PrivateKey: ecdsaKey = k default: - return nil, ErrInvalidKeyType + return nil, newError("ECDSA sign expects *ecdsa.PrivateKey", ErrInvalidKeyType) } // Create the hasher diff --git a/vendor/github.com/golang-jwt/jwt/v5/ed25519.go b/vendor/github.com/golang-jwt/jwt/v5/ed25519.go index 3db00e4a..c2138119 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/ed25519.go +++ b/vendor/github.com/golang-jwt/jwt/v5/ed25519.go @@ -1,11 +1,10 @@ package jwt import ( - "errors" - "crypto" "crypto/ed25519" "crypto/rand" + "errors" ) var ( @@ -39,7 +38,7 @@ func (m *SigningMethodEd25519) Verify(signingString string, sig []byte, key inte var ok bool if ed25519Key, ok = key.(ed25519.PublicKey); !ok { - return ErrInvalidKeyType + return newError("Ed25519 verify expects ed25519.PublicKey", ErrInvalidKeyType) } if len(ed25519Key) != ed25519.PublicKeySize { @@ -61,7 +60,7 @@ func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) ([]by var ok bool if ed25519Key, ok = key.(crypto.Signer); !ok { - return nil, ErrInvalidKeyType + return nil, newError("Ed25519 sign expects crypto.Signer", ErrInvalidKeyType) } if _, ok := ed25519Key.Public().(ed25519.PublicKey); !ok { diff --git a/vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go b/vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go index 3afb04e6..2ad542f0 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go +++ b/vendor/github.com/golang-jwt/jwt/v5/errors_go_other.go @@ -22,7 +22,7 @@ func (je joinedError) Is(err error) bool { // wrappedErrors is a workaround for wrapping multiple errors in environments // where Go 1.20 is not available. It basically uses the already implemented -// functionatlity of joinedError to handle multiple errors with supplies a +// functionality of joinedError to handle multiple errors with supplies a // custom error message that is identical to the one we produce in Go 1.20 using // multiple %w directives. type wrappedErrors struct { diff --git a/vendor/github.com/golang-jwt/jwt/v5/hmac.go b/vendor/github.com/golang-jwt/jwt/v5/hmac.go index 91b688ba..aca600ce 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/hmac.go +++ b/vendor/github.com/golang-jwt/jwt/v5/hmac.go @@ -59,7 +59,7 @@ func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interfa // Verify the key is the right type keyBytes, ok := key.([]byte) if !ok { - return ErrInvalidKeyType + return newError("HMAC verify expects []byte", ErrInvalidKeyType) } // Can we use the specified hashing method? @@ -100,5 +100,5 @@ func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, return hasher.Sum(nil), nil } - return nil, ErrInvalidKeyType + return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType) } diff --git a/vendor/github.com/golang-jwt/jwt/v5/none.go b/vendor/github.com/golang-jwt/jwt/v5/none.go index c93daa58..685c2ea3 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/none.go +++ b/vendor/github.com/golang-jwt/jwt/v5/none.go @@ -32,7 +32,7 @@ func (m *signingMethodNone) Verify(signingString string, sig []byte, key interfa return NoneSignatureTypeDisallowedError } // If signing method is none, signature must be an empty string - if string(sig) != "" { + if len(sig) != 0 { return newError("'none' signing method with non-empty signature", ErrTokenUnverifiable) } diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser.go b/vendor/github.com/golang-jwt/jwt/v5/parser.go index f4386fba..ecf99af7 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/parser.go +++ b/vendor/github.com/golang-jwt/jwt/v5/parser.go @@ -18,7 +18,7 @@ type Parser struct { // Skip claims validation during token parsing. skipClaimsValidation bool - validator *validator + validator *Validator decodeStrict bool @@ -28,7 +28,7 @@ type Parser struct { // NewParser creates a new Parser with the specified options func NewParser(options ...ParserOption) *Parser { p := &Parser{ - validator: &validator{}, + validator: &Validator{}, } // Loop through our parsing options and apply them @@ -74,24 +74,40 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf } } - // Lookup key - var key interface{} - if keyFunc == nil { - // keyFunc was not provided. short circuiting validation - return token, newError("no keyfunc was provided", ErrTokenUnverifiable) - } - if key, err = keyFunc(token); err != nil { - return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err) - } - // Decode signature token.Signature, err = p.DecodeSegment(parts[2]) if err != nil { return token, newError("could not base64 decode signature", ErrTokenMalformed, err) } + text := strings.Join(parts[0:2], ".") - // Perform signature validation - if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil { + // Lookup key(s) + if keyFunc == nil { + // keyFunc was not provided. short circuiting validation + return token, newError("no keyfunc was provided", ErrTokenUnverifiable) + } + + got, err := keyFunc(token) + if err != nil { + return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err) + } + + switch have := got.(type) { + case VerificationKeySet: + if len(have.Keys) == 0 { + return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable) + } + // Iterate through keys and verify signature, skipping the rest when a match is found. + // Return the last error if no match is found. + for _, key := range have.Keys { + if err = token.Method.Verify(text, token.Signature, key); err == nil { + break + } + } + default: + err = token.Method.Verify(text, token.Signature, have) + } + if err != nil { return token, newError("", ErrTokenSignatureInvalid, err) } @@ -99,7 +115,7 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf if !p.skipClaimsValidation { // Make sure we have at least a default validator if p.validator == nil { - p.validator = newValidator() + p.validator = NewValidator() } if err := p.validator.Validate(claims); err != nil { @@ -117,8 +133,8 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf // // WARNING: Don't use this method unless you know what you're doing. // -// It's only ever useful in cases where you know the signature is valid (because it has -// been checked previously in the stack) and you want to extract values from it. +// It's only ever useful in cases where you know the signature is valid (since it has already +// been or will be checked elsewhere in the stack) and you want to extract values from it. func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) { parts = strings.Split(tokenString, ".") if len(parts) != 3 { @@ -130,9 +146,6 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke // parse Header var headerBytes []byte if headerBytes, err = p.DecodeSegment(parts[0]); err != nil { - if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") { - return token, parts, newError("tokenstring should not contain 'bearer '", ErrTokenMalformed) - } return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err) } if err = json.Unmarshal(headerBytes, &token.Header); err != nil { @@ -140,23 +153,33 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke } // parse Claims - var claimBytes []byte token.Claims = claims - if claimBytes, err = p.DecodeSegment(parts[1]); err != nil { + claimBytes, err := p.DecodeSegment(parts[1]) + if err != nil { return token, parts, newError("could not base64 decode claim", ErrTokenMalformed, err) } - dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) - if p.useJSONNumber { - dec.UseNumber() - } - // JSON Decode. Special case for map type to avoid weird pointer behavior - if c, ok := token.Claims.(MapClaims); ok { - err = dec.Decode(&c) + + // If `useJSONNumber` is enabled then we must use *json.Decoder to decode + // the claims. However, this comes with a performance penalty so only use + // it if we must and, otherwise, simple use json.Unmarshal. + if !p.useJSONNumber { + // JSON Unmarshal. Special case for map type to avoid weird pointer behavior. + if c, ok := token.Claims.(MapClaims); ok { + err = json.Unmarshal(claimBytes, &c) + } else { + err = json.Unmarshal(claimBytes, &claims) + } } else { - err = dec.Decode(&claims) + dec := json.NewDecoder(bytes.NewBuffer(claimBytes)) + dec.UseNumber() + // JSON Decode. Special case for map type to avoid weird pointer behavior. + if c, ok := token.Claims.(MapClaims); ok { + err = dec.Decode(&c) + } else { + err = dec.Decode(&claims) + } } - // Handle decode error if err != nil { return token, parts, newError("could not JSON decode claim", ErrTokenMalformed, err) } diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser_option.go b/vendor/github.com/golang-jwt/jwt/v5/parser_option.go index 1b5af970..88a780fb 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/parser_option.go +++ b/vendor/github.com/golang-jwt/jwt/v5/parser_option.go @@ -58,6 +58,14 @@ func WithIssuedAt() ParserOption { } } +// WithExpirationRequired returns the ParserOption to make exp claim required. +// By default exp claim is optional. +func WithExpirationRequired() ParserOption { + return func(p *Parser) { + p.validator.requireExp = true + } +} + // WithAudience configures the validator to require the specified audience in // the `aud` claim. Validation will fail if the audience is not listed in the // token or the `aud` claim is missing. diff --git a/vendor/github.com/golang-jwt/jwt/v5/rsa.go b/vendor/github.com/golang-jwt/jwt/v5/rsa.go index daff0943..83cbee6a 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/rsa.go +++ b/vendor/github.com/golang-jwt/jwt/v5/rsa.go @@ -51,7 +51,7 @@ func (m *SigningMethodRSA) Verify(signingString string, sig []byte, key interfac var ok bool if rsaKey, ok = key.(*rsa.PublicKey); !ok { - return ErrInvalidKeyType + return newError("RSA verify expects *rsa.PublicKey", ErrInvalidKeyType) } // Create hasher @@ -73,7 +73,7 @@ func (m *SigningMethodRSA) Sign(signingString string, key interface{}) ([]byte, // Validate type of key if rsaKey, ok = key.(*rsa.PrivateKey); !ok { - return nil, ErrInvalidKey + return nil, newError("RSA sign expects *rsa.PrivateKey", ErrInvalidKeyType) } // Create the hasher diff --git a/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go b/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go index 9599f0a4..28c386ec 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go +++ b/vendor/github.com/golang-jwt/jwt/v5/rsa_pss.go @@ -88,7 +88,7 @@ func (m *SigningMethodRSAPSS) Verify(signingString string, sig []byte, key inter case *rsa.PublicKey: rsaKey = k default: - return ErrInvalidKey + return newError("RSA-PSS verify expects *rsa.PublicKey", ErrInvalidKeyType) } // Create hasher @@ -115,7 +115,7 @@ func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) ([]byt case *rsa.PrivateKey: rsaKey = k default: - return nil, ErrInvalidKeyType + return nil, newError("RSA-PSS sign expects *rsa.PrivateKey", ErrInvalidKeyType) } // Create the hasher diff --git a/vendor/github.com/golang-jwt/jwt/v5/token.go b/vendor/github.com/golang-jwt/jwt/v5/token.go index c8ad7c78..352873a2 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/token.go +++ b/vendor/github.com/golang-jwt/jwt/v5/token.go @@ -1,6 +1,7 @@ package jwt import ( + "crypto" "encoding/base64" "encoding/json" ) @@ -9,8 +10,21 @@ import ( // the key for verification. The function receives the parsed, but unverified // Token. This allows you to use properties in the Header of the token (such as // `kid`) to identify which key to use. +// +// The returned interface{} may be a single key or a VerificationKeySet containing +// multiple keys. type Keyfunc func(*Token) (interface{}, error) +// VerificationKey represents a public or secret key for verifying a token's signature. +type VerificationKey interface { + crypto.PublicKey | []uint8 +} + +// VerificationKeySet is a set of public or secret keys. It is used by the parser to verify a token. +type VerificationKeySet struct { + Keys []VerificationKey +} + // Token represents a JWT Token. Different fields will be used depending on // whether you're creating or parsing/verifying a token. type Token struct { diff --git a/vendor/github.com/golang-jwt/jwt/v5/types.go b/vendor/github.com/golang-jwt/jwt/v5/types.go index b82b3886..b2655a9e 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/types.go +++ b/vendor/github.com/golang-jwt/jwt/v5/types.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "math" - "reflect" "strconv" "time" ) @@ -121,14 +120,14 @@ func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error) { for _, vv := range v { vs, ok := vv.(string) if !ok { - return &json.UnsupportedTypeError{Type: reflect.TypeOf(vv)} + return ErrInvalidType } aud = append(aud, vs) } case nil: return nil default: - return &json.UnsupportedTypeError{Type: reflect.TypeOf(v)} + return ErrInvalidType } *s = aud diff --git a/vendor/github.com/golang-jwt/jwt/v5/validator.go b/vendor/github.com/golang-jwt/jwt/v5/validator.go index 38504389..008ecd87 100644 --- a/vendor/github.com/golang-jwt/jwt/v5/validator.go +++ b/vendor/github.com/golang-jwt/jwt/v5/validator.go @@ -28,13 +28,12 @@ type ClaimsValidator interface { Validate() error } -// validator is the core of the new Validation API. It is automatically used by +// Validator is the core of the new Validation API. It is automatically used by // a [Parser] during parsing and can be modified with various parser options. // -// Note: This struct is intentionally not exported (yet) as we want to -// internally finalize its API. In the future, we might make it publicly -// available. -type validator struct { +// The [NewValidator] function should be used to create an instance of this +// struct. +type Validator struct { // leeway is an optional leeway that can be provided to account for clock skew. leeway time.Duration @@ -42,6 +41,9 @@ type validator struct { // validation. If unspecified, this defaults to time.Now. timeFunc func() time.Time + // requireExp specifies whether the exp claim is required + requireExp bool + // verifyIat specifies whether the iat (Issued At) claim will be verified. // According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this // only specifies the age of the token, but no validation check is @@ -62,16 +64,28 @@ type validator struct { expectedSub string } -// newValidator can be used to create a stand-alone validator with the supplied +// NewValidator can be used to create a stand-alone validator with the supplied // options. This validator can then be used to validate already parsed claims. -func newValidator(opts ...ParserOption) *validator { +// +// Note: Under normal circumstances, explicitly creating a validator is not +// needed and can potentially be dangerous; instead functions of the [Parser] +// class should be used. +// +// The [Validator] is only checking the *validity* of the claims, such as its +// expiration time, but it does NOT perform *signature verification* of the +// token. +func NewValidator(opts ...ParserOption) *Validator { p := NewParser(opts...) return p.validator } // Validate validates the given claims. It will also perform any custom // validation if claims implements the [ClaimsValidator] interface. -func (v *validator) Validate(claims Claims) error { +// +// Note: It will NOT perform any *signature verification* on the token that +// contains the claims and expects that the [Claim] was already successfully +// verified. +func (v *Validator) Validate(claims Claims) error { var ( now time.Time errs []error = make([]error, 0, 6) @@ -86,8 +100,9 @@ func (v *validator) Validate(claims Claims) error { } // We always need to check the expiration time, but usage of the claim - // itself is OPTIONAL. - if err = v.verifyExpiresAt(claims, now, false); err != nil { + // itself is OPTIONAL by default. requireExp overrides this behavior + // and makes the exp claim mandatory. + if err = v.verifyExpiresAt(claims, now, v.requireExp); err != nil { errs = append(errs, err) } @@ -149,7 +164,7 @@ func (v *validator) Validate(claims Claims) error { // // Additionally, if any error occurs while retrieving the claim, e.g., when its // the wrong type, an ErrTokenUnverifiable error will be returned. -func (v *validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool) error { +func (v *Validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool) error { exp, err := claims.GetExpirationTime() if err != nil { return err @@ -170,7 +185,7 @@ func (v *validator) verifyExpiresAt(claims Claims, cmp time.Time, required bool) // // Additionally, if any error occurs while retrieving the claim, e.g., when its // the wrong type, an ErrTokenUnverifiable error will be returned. -func (v *validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool) error { +func (v *Validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool) error { iat, err := claims.GetIssuedAt() if err != nil { return err @@ -191,7 +206,7 @@ func (v *validator) verifyIssuedAt(claims Claims, cmp time.Time, required bool) // // Additionally, if any error occurs while retrieving the claim, e.g., when its // the wrong type, an ErrTokenUnverifiable error will be returned. -func (v *validator) verifyNotBefore(claims Claims, cmp time.Time, required bool) error { +func (v *Validator) verifyNotBefore(claims Claims, cmp time.Time, required bool) error { nbf, err := claims.GetNotBefore() if err != nil { return err @@ -211,7 +226,7 @@ func (v *validator) verifyNotBefore(claims Claims, cmp time.Time, required bool) // // Additionally, if any error occurs while retrieving the claim, e.g., when its // the wrong type, an ErrTokenUnverifiable error will be returned. -func (v *validator) verifyAudience(claims Claims, cmp string, required bool) error { +func (v *Validator) verifyAudience(claims Claims, cmp string, required bool) error { aud, err := claims.GetAudience() if err != nil { return err @@ -247,7 +262,7 @@ func (v *validator) verifyAudience(claims Claims, cmp string, required bool) err // // Additionally, if any error occurs while retrieving the claim, e.g., when its // the wrong type, an ErrTokenUnverifiable error will be returned. -func (v *validator) verifyIssuer(claims Claims, cmp string, required bool) error { +func (v *Validator) verifyIssuer(claims Claims, cmp string, required bool) error { iss, err := claims.GetIssuer() if err != nil { return err @@ -267,7 +282,7 @@ func (v *validator) verifyIssuer(claims Claims, cmp string, required bool) error // // Additionally, if any error occurs while retrieving the claim, e.g., when its // the wrong type, an ErrTokenUnverifiable error will be returned. -func (v *validator) verifySubject(claims Claims, cmp string, required bool) error { +func (v *Validator) verifySubject(claims Claims, cmp string, required bool) error { sub, err := claims.GetSubject() if err != nil { return err diff --git a/vendor/github.com/golang/protobuf/AUTHORS b/vendor/github.com/golang/protobuf/AUTHORS deleted file mode 100644 index 15167cd7..00000000 --- a/vendor/github.com/golang/protobuf/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/github.com/golang/protobuf/CONTRIBUTORS b/vendor/github.com/golang/protobuf/CONTRIBUTORS deleted file mode 100644 index 1c4577e9..00000000 --- a/vendor/github.com/golang/protobuf/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/github.com/golang/protobuf/proto/buffer.go b/vendor/github.com/golang/protobuf/proto/buffer.go deleted file mode 100644 index e810e6fe..00000000 --- a/vendor/github.com/golang/protobuf/proto/buffer.go +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "errors" - "fmt" - - "google.golang.org/protobuf/encoding/prototext" - "google.golang.org/protobuf/encoding/protowire" - "google.golang.org/protobuf/runtime/protoimpl" -) - -const ( - WireVarint = 0 - WireFixed32 = 5 - WireFixed64 = 1 - WireBytes = 2 - WireStartGroup = 3 - WireEndGroup = 4 -) - -// EncodeVarint returns the varint encoded bytes of v. -func EncodeVarint(v uint64) []byte { - return protowire.AppendVarint(nil, v) -} - -// SizeVarint returns the length of the varint encoded bytes of v. -// This is equal to len(EncodeVarint(v)). -func SizeVarint(v uint64) int { - return protowire.SizeVarint(v) -} - -// DecodeVarint parses a varint encoded integer from b, -// returning the integer value and the length of the varint. -// It returns (0, 0) if there is a parse error. -func DecodeVarint(b []byte) (uint64, int) { - v, n := protowire.ConsumeVarint(b) - if n < 0 { - return 0, 0 - } - return v, n -} - -// Buffer is a buffer for encoding and decoding the protobuf wire format. -// It may be reused between invocations to reduce memory usage. -type Buffer struct { - buf []byte - idx int - deterministic bool -} - -// NewBuffer allocates a new Buffer initialized with buf, -// where the contents of buf are considered the unread portion of the buffer. -func NewBuffer(buf []byte) *Buffer { - return &Buffer{buf: buf} -} - -// SetDeterministic specifies whether to use deterministic serialization. -// -// Deterministic serialization guarantees that for a given binary, equal -// messages will always be serialized to the same bytes. This implies: -// -// - Repeated serialization of a message will return the same bytes. -// - Different processes of the same binary (which may be executing on -// different machines) will serialize equal messages to the same bytes. -// -// Note that the deterministic serialization is NOT canonical across -// languages. It is not guaranteed to remain stable over time. It is unstable -// across different builds with schema changes due to unknown fields. -// Users who need canonical serialization (e.g., persistent storage in a -// canonical form, fingerprinting, etc.) should define their own -// canonicalization specification and implement their own serializer rather -// than relying on this API. -// -// If deterministic serialization is requested, map entries will be sorted -// by keys in lexographical order. This is an implementation detail and -// subject to change. -func (b *Buffer) SetDeterministic(deterministic bool) { - b.deterministic = deterministic -} - -// SetBuf sets buf as the internal buffer, -// where the contents of buf are considered the unread portion of the buffer. -func (b *Buffer) SetBuf(buf []byte) { - b.buf = buf - b.idx = 0 -} - -// Reset clears the internal buffer of all written and unread data. -func (b *Buffer) Reset() { - b.buf = b.buf[:0] - b.idx = 0 -} - -// Bytes returns the internal buffer. -func (b *Buffer) Bytes() []byte { - return b.buf -} - -// Unread returns the unread portion of the buffer. -func (b *Buffer) Unread() []byte { - return b.buf[b.idx:] -} - -// Marshal appends the wire-format encoding of m to the buffer. -func (b *Buffer) Marshal(m Message) error { - var err error - b.buf, err = marshalAppend(b.buf, m, b.deterministic) - return err -} - -// Unmarshal parses the wire-format message in the buffer and -// places the decoded results in m. -// It does not reset m before unmarshaling. -func (b *Buffer) Unmarshal(m Message) error { - err := UnmarshalMerge(b.Unread(), m) - b.idx = len(b.buf) - return err -} - -type unknownFields struct{ XXX_unrecognized protoimpl.UnknownFields } - -func (m *unknownFields) String() string { panic("not implemented") } -func (m *unknownFields) Reset() { panic("not implemented") } -func (m *unknownFields) ProtoMessage() { panic("not implemented") } - -// DebugPrint dumps the encoded bytes of b with a header and footer including s -// to stdout. This is only intended for debugging. -func (*Buffer) DebugPrint(s string, b []byte) { - m := MessageReflect(new(unknownFields)) - m.SetUnknown(b) - b, _ = prototext.MarshalOptions{AllowPartial: true, Indent: "\t"}.Marshal(m.Interface()) - fmt.Printf("==== %s ====\n%s==== %s ====\n", s, b, s) -} - -// EncodeVarint appends an unsigned varint encoding to the buffer. -func (b *Buffer) EncodeVarint(v uint64) error { - b.buf = protowire.AppendVarint(b.buf, v) - return nil -} - -// EncodeZigzag32 appends a 32-bit zig-zag varint encoding to the buffer. -func (b *Buffer) EncodeZigzag32(v uint64) error { - return b.EncodeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31)))) -} - -// EncodeZigzag64 appends a 64-bit zig-zag varint encoding to the buffer. -func (b *Buffer) EncodeZigzag64(v uint64) error { - return b.EncodeVarint(uint64((uint64(v) << 1) ^ uint64((int64(v) >> 63)))) -} - -// EncodeFixed32 appends a 32-bit little-endian integer to the buffer. -func (b *Buffer) EncodeFixed32(v uint64) error { - b.buf = protowire.AppendFixed32(b.buf, uint32(v)) - return nil -} - -// EncodeFixed64 appends a 64-bit little-endian integer to the buffer. -func (b *Buffer) EncodeFixed64(v uint64) error { - b.buf = protowire.AppendFixed64(b.buf, uint64(v)) - return nil -} - -// EncodeRawBytes appends a length-prefixed raw bytes to the buffer. -func (b *Buffer) EncodeRawBytes(v []byte) error { - b.buf = protowire.AppendBytes(b.buf, v) - return nil -} - -// EncodeStringBytes appends a length-prefixed raw bytes to the buffer. -// It does not validate whether v contains valid UTF-8. -func (b *Buffer) EncodeStringBytes(v string) error { - b.buf = protowire.AppendString(b.buf, v) - return nil -} - -// EncodeMessage appends a length-prefixed encoded message to the buffer. -func (b *Buffer) EncodeMessage(m Message) error { - var err error - b.buf = protowire.AppendVarint(b.buf, uint64(Size(m))) - b.buf, err = marshalAppend(b.buf, m, b.deterministic) - return err -} - -// DecodeVarint consumes an encoded unsigned varint from the buffer. -func (b *Buffer) DecodeVarint() (uint64, error) { - v, n := protowire.ConsumeVarint(b.buf[b.idx:]) - if n < 0 { - return 0, protowire.ParseError(n) - } - b.idx += n - return uint64(v), nil -} - -// DecodeZigzag32 consumes an encoded 32-bit zig-zag varint from the buffer. -func (b *Buffer) DecodeZigzag32() (uint64, error) { - v, err := b.DecodeVarint() - if err != nil { - return 0, err - } - return uint64((uint32(v) >> 1) ^ uint32((int32(v&1)<<31)>>31)), nil -} - -// DecodeZigzag64 consumes an encoded 64-bit zig-zag varint from the buffer. -func (b *Buffer) DecodeZigzag64() (uint64, error) { - v, err := b.DecodeVarint() - if err != nil { - return 0, err - } - return uint64((uint64(v) >> 1) ^ uint64((int64(v&1)<<63)>>63)), nil -} - -// DecodeFixed32 consumes a 32-bit little-endian integer from the buffer. -func (b *Buffer) DecodeFixed32() (uint64, error) { - v, n := protowire.ConsumeFixed32(b.buf[b.idx:]) - if n < 0 { - return 0, protowire.ParseError(n) - } - b.idx += n - return uint64(v), nil -} - -// DecodeFixed64 consumes a 64-bit little-endian integer from the buffer. -func (b *Buffer) DecodeFixed64() (uint64, error) { - v, n := protowire.ConsumeFixed64(b.buf[b.idx:]) - if n < 0 { - return 0, protowire.ParseError(n) - } - b.idx += n - return uint64(v), nil -} - -// DecodeRawBytes consumes a length-prefixed raw bytes from the buffer. -// If alloc is specified, it returns a copy the raw bytes -// rather than a sub-slice of the buffer. -func (b *Buffer) DecodeRawBytes(alloc bool) ([]byte, error) { - v, n := protowire.ConsumeBytes(b.buf[b.idx:]) - if n < 0 { - return nil, protowire.ParseError(n) - } - b.idx += n - if alloc { - v = append([]byte(nil), v...) - } - return v, nil -} - -// DecodeStringBytes consumes a length-prefixed raw bytes from the buffer. -// It does not validate whether the raw bytes contain valid UTF-8. -func (b *Buffer) DecodeStringBytes() (string, error) { - v, n := protowire.ConsumeString(b.buf[b.idx:]) - if n < 0 { - return "", protowire.ParseError(n) - } - b.idx += n - return v, nil -} - -// DecodeMessage consumes a length-prefixed message from the buffer. -// It does not reset m before unmarshaling. -func (b *Buffer) DecodeMessage(m Message) error { - v, err := b.DecodeRawBytes(false) - if err != nil { - return err - } - return UnmarshalMerge(v, m) -} - -// DecodeGroup consumes a message group from the buffer. -// It assumes that the start group marker has already been consumed and -// consumes all bytes until (and including the end group marker). -// It does not reset m before unmarshaling. -func (b *Buffer) DecodeGroup(m Message) error { - v, n, err := consumeGroup(b.buf[b.idx:]) - if err != nil { - return err - } - b.idx += n - return UnmarshalMerge(v, m) -} - -// consumeGroup parses b until it finds an end group marker, returning -// the raw bytes of the message (excluding the end group marker) and the -// the total length of the message (including the end group marker). -func consumeGroup(b []byte) ([]byte, int, error) { - b0 := b - depth := 1 // assume this follows a start group marker - for { - _, wtyp, tagLen := protowire.ConsumeTag(b) - if tagLen < 0 { - return nil, 0, protowire.ParseError(tagLen) - } - b = b[tagLen:] - - var valLen int - switch wtyp { - case protowire.VarintType: - _, valLen = protowire.ConsumeVarint(b) - case protowire.Fixed32Type: - _, valLen = protowire.ConsumeFixed32(b) - case protowire.Fixed64Type: - _, valLen = protowire.ConsumeFixed64(b) - case protowire.BytesType: - _, valLen = protowire.ConsumeBytes(b) - case protowire.StartGroupType: - depth++ - case protowire.EndGroupType: - depth-- - default: - return nil, 0, errors.New("proto: cannot parse reserved wire type") - } - if valLen < 0 { - return nil, 0, protowire.ParseError(valLen) - } - b = b[valLen:] - - if depth == 0 { - return b0[:len(b0)-len(b)-tagLen], len(b0) - len(b), nil - } - } -} diff --git a/vendor/github.com/golang/protobuf/proto/defaults.go b/vendor/github.com/golang/protobuf/proto/defaults.go deleted file mode 100644 index d399bf06..00000000 --- a/vendor/github.com/golang/protobuf/proto/defaults.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "google.golang.org/protobuf/reflect/protoreflect" -) - -// SetDefaults sets unpopulated scalar fields to their default values. -// Fields within a oneof are not set even if they have a default value. -// SetDefaults is recursively called upon any populated message fields. -func SetDefaults(m Message) { - if m != nil { - setDefaults(MessageReflect(m)) - } -} - -func setDefaults(m protoreflect.Message) { - fds := m.Descriptor().Fields() - for i := 0; i < fds.Len(); i++ { - fd := fds.Get(i) - if !m.Has(fd) { - if fd.HasDefault() && fd.ContainingOneof() == nil { - v := fd.Default() - if fd.Kind() == protoreflect.BytesKind { - v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...)) // copy the default bytes - } - m.Set(fd, v) - } - continue - } - } - - m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - switch { - // Handle singular message. - case fd.Cardinality() != protoreflect.Repeated: - if fd.Message() != nil { - setDefaults(m.Get(fd).Message()) - } - // Handle list of messages. - case fd.IsList(): - if fd.Message() != nil { - ls := m.Get(fd).List() - for i := 0; i < ls.Len(); i++ { - setDefaults(ls.Get(i).Message()) - } - } - // Handle map of messages. - case fd.IsMap(): - if fd.MapValue().Message() != nil { - ms := m.Get(fd).Map() - ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool { - setDefaults(v.Message()) - return true - }) - } - } - return true - }) -} diff --git a/vendor/github.com/golang/protobuf/proto/deprecated.go b/vendor/github.com/golang/protobuf/proto/deprecated.go deleted file mode 100644 index e8db57e0..00000000 --- a/vendor/github.com/golang/protobuf/proto/deprecated.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "encoding/json" - "errors" - "fmt" - "strconv" - - protoV2 "google.golang.org/protobuf/proto" -) - -var ( - // Deprecated: No longer returned. - ErrNil = errors.New("proto: Marshal called with nil") - - // Deprecated: No longer returned. - ErrTooLarge = errors.New("proto: message encodes to over 2 GB") - - // Deprecated: No longer returned. - ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof") -) - -// Deprecated: Do not use. -type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 } - -// Deprecated: Do not use. -func GetStats() Stats { return Stats{} } - -// Deprecated: Do not use. -func MarshalMessageSet(interface{}) ([]byte, error) { - return nil, errors.New("proto: not implemented") -} - -// Deprecated: Do not use. -func UnmarshalMessageSet([]byte, interface{}) error { - return errors.New("proto: not implemented") -} - -// Deprecated: Do not use. -func MarshalMessageSetJSON(interface{}) ([]byte, error) { - return nil, errors.New("proto: not implemented") -} - -// Deprecated: Do not use. -func UnmarshalMessageSetJSON([]byte, interface{}) error { - return errors.New("proto: not implemented") -} - -// Deprecated: Do not use. -func RegisterMessageSetType(Message, int32, string) {} - -// Deprecated: Do not use. -func EnumName(m map[int32]string, v int32) string { - s, ok := m[v] - if ok { - return s - } - return strconv.Itoa(int(v)) -} - -// Deprecated: Do not use. -func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) { - if data[0] == '"' { - // New style: enums are strings. - var repr string - if err := json.Unmarshal(data, &repr); err != nil { - return -1, err - } - val, ok := m[repr] - if !ok { - return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr) - } - return val, nil - } - // Old style: enums are ints. - var val int32 - if err := json.Unmarshal(data, &val); err != nil { - return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName) - } - return val, nil -} - -// Deprecated: Do not use; this type existed for intenal-use only. -type InternalMessageInfo struct{} - -// Deprecated: Do not use; this method existed for intenal-use only. -func (*InternalMessageInfo) DiscardUnknown(m Message) { - DiscardUnknown(m) -} - -// Deprecated: Do not use; this method existed for intenal-use only. -func (*InternalMessageInfo) Marshal(b []byte, m Message, deterministic bool) ([]byte, error) { - return protoV2.MarshalOptions{Deterministic: deterministic}.MarshalAppend(b, MessageV2(m)) -} - -// Deprecated: Do not use; this method existed for intenal-use only. -func (*InternalMessageInfo) Merge(dst, src Message) { - protoV2.Merge(MessageV2(dst), MessageV2(src)) -} - -// Deprecated: Do not use; this method existed for intenal-use only. -func (*InternalMessageInfo) Size(m Message) int { - return protoV2.Size(MessageV2(m)) -} - -// Deprecated: Do not use; this method existed for intenal-use only. -func (*InternalMessageInfo) Unmarshal(m Message, b []byte) error { - return protoV2.UnmarshalOptions{Merge: true}.Unmarshal(b, MessageV2(m)) -} diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go deleted file mode 100644 index 2187e877..00000000 --- a/vendor/github.com/golang/protobuf/proto/discard.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "google.golang.org/protobuf/reflect/protoreflect" -) - -// DiscardUnknown recursively discards all unknown fields from this message -// and all embedded messages. -// -// When unmarshaling a message with unrecognized fields, the tags and values -// of such fields are preserved in the Message. This allows a later call to -// marshal to be able to produce a message that continues to have those -// unrecognized fields. To avoid this, DiscardUnknown is used to -// explicitly clear the unknown fields after unmarshaling. -func DiscardUnknown(m Message) { - if m != nil { - discardUnknown(MessageReflect(m)) - } -} - -func discardUnknown(m protoreflect.Message) { - m.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool { - switch { - // Handle singular message. - case fd.Cardinality() != protoreflect.Repeated: - if fd.Message() != nil { - discardUnknown(m.Get(fd).Message()) - } - // Handle list of messages. - case fd.IsList(): - if fd.Message() != nil { - ls := m.Get(fd).List() - for i := 0; i < ls.Len(); i++ { - discardUnknown(ls.Get(i).Message()) - } - } - // Handle map of messages. - case fd.IsMap(): - if fd.MapValue().Message() != nil { - ms := m.Get(fd).Map() - ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool { - discardUnknown(v.Message()) - return true - }) - } - } - return true - }) - - // Discard unknown fields. - if len(m.GetUnknown()) > 0 { - m.SetUnknown(nil) - } -} diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go deleted file mode 100644 index 42fc120c..00000000 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "errors" - "fmt" - "reflect" - - "google.golang.org/protobuf/encoding/protowire" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - "google.golang.org/protobuf/runtime/protoiface" - "google.golang.org/protobuf/runtime/protoimpl" -) - -type ( - // ExtensionDesc represents an extension descriptor and - // is used to interact with an extension field in a message. - // - // Variables of this type are generated in code by protoc-gen-go. - ExtensionDesc = protoimpl.ExtensionInfo - - // ExtensionRange represents a range of message extensions. - // Used in code generated by protoc-gen-go. - ExtensionRange = protoiface.ExtensionRangeV1 - - // Deprecated: Do not use; this is an internal type. - Extension = protoimpl.ExtensionFieldV1 - - // Deprecated: Do not use; this is an internal type. - XXX_InternalExtensions = protoimpl.ExtensionFields -) - -// ErrMissingExtension reports whether the extension was not present. -var ErrMissingExtension = errors.New("proto: missing extension") - -var errNotExtendable = errors.New("proto: not an extendable proto.Message") - -// HasExtension reports whether the extension field is present in m -// either as an explicitly populated field or as an unknown field. -func HasExtension(m Message, xt *ExtensionDesc) (has bool) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() { - return false - } - - // Check whether any populated known field matches the field number. - xtd := xt.TypeDescriptor() - if isValidExtension(mr.Descriptor(), xtd) { - has = mr.Has(xtd) - } else { - mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool { - has = int32(fd.Number()) == xt.Field - return !has - }) - } - - // Check whether any unknown field matches the field number. - for b := mr.GetUnknown(); !has && len(b) > 0; { - num, _, n := protowire.ConsumeField(b) - has = int32(num) == xt.Field - b = b[n:] - } - return has -} - -// ClearExtension removes the extension field from m -// either as an explicitly populated field or as an unknown field. -func ClearExtension(m Message, xt *ExtensionDesc) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() { - return - } - - xtd := xt.TypeDescriptor() - if isValidExtension(mr.Descriptor(), xtd) { - mr.Clear(xtd) - } else { - mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool { - if int32(fd.Number()) == xt.Field { - mr.Clear(fd) - return false - } - return true - }) - } - clearUnknown(mr, fieldNum(xt.Field)) -} - -// ClearAllExtensions clears all extensions from m. -// This includes populated fields and unknown fields in the extension range. -func ClearAllExtensions(m Message) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() { - return - } - - mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool { - if fd.IsExtension() { - mr.Clear(fd) - } - return true - }) - clearUnknown(mr, mr.Descriptor().ExtensionRanges()) -} - -// GetExtension retrieves a proto2 extended field from m. -// -// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil), -// then GetExtension parses the encoded field and returns a Go value of the specified type. -// If the field is not present, then the default value is returned (if one is specified), -// otherwise ErrMissingExtension is reported. -// -// If the descriptor is type incomplete (i.e., ExtensionDesc.ExtensionType is nil), -// then GetExtension returns the raw encoded bytes for the extension field. -func GetExtension(m Message, xt *ExtensionDesc) (interface{}, error) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 { - return nil, errNotExtendable - } - - // Retrieve the unknown fields for this extension field. - var bo protoreflect.RawFields - for bi := mr.GetUnknown(); len(bi) > 0; { - num, _, n := protowire.ConsumeField(bi) - if int32(num) == xt.Field { - bo = append(bo, bi[:n]...) - } - bi = bi[n:] - } - - // For type incomplete descriptors, only retrieve the unknown fields. - if xt.ExtensionType == nil { - return []byte(bo), nil - } - - // If the extension field only exists as unknown fields, unmarshal it. - // This is rarely done since proto.Unmarshal eagerly unmarshals extensions. - xtd := xt.TypeDescriptor() - if !isValidExtension(mr.Descriptor(), xtd) { - return nil, fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m) - } - if !mr.Has(xtd) && len(bo) > 0 { - m2 := mr.New() - if err := (proto.UnmarshalOptions{ - Resolver: extensionResolver{xt}, - }.Unmarshal(bo, m2.Interface())); err != nil { - return nil, err - } - if m2.Has(xtd) { - mr.Set(xtd, m2.Get(xtd)) - clearUnknown(mr, fieldNum(xt.Field)) - } - } - - // Check whether the message has the extension field set or a default. - var pv protoreflect.Value - switch { - case mr.Has(xtd): - pv = mr.Get(xtd) - case xtd.HasDefault(): - pv = xtd.Default() - default: - return nil, ErrMissingExtension - } - - v := xt.InterfaceOf(pv) - rv := reflect.ValueOf(v) - if isScalarKind(rv.Kind()) { - rv2 := reflect.New(rv.Type()) - rv2.Elem().Set(rv) - v = rv2.Interface() - } - return v, nil -} - -// extensionResolver is a custom extension resolver that stores a single -// extension type that takes precedence over the global registry. -type extensionResolver struct{ xt protoreflect.ExtensionType } - -func (r extensionResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) { - if xtd := r.xt.TypeDescriptor(); xtd.FullName() == field { - return r.xt, nil - } - return protoregistry.GlobalTypes.FindExtensionByName(field) -} - -func (r extensionResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) { - if xtd := r.xt.TypeDescriptor(); xtd.ContainingMessage().FullName() == message && xtd.Number() == field { - return r.xt, nil - } - return protoregistry.GlobalTypes.FindExtensionByNumber(message, field) -} - -// GetExtensions returns a list of the extensions values present in m, -// corresponding with the provided list of extension descriptors, xts. -// If an extension is missing in m, the corresponding value is nil. -func GetExtensions(m Message, xts []*ExtensionDesc) ([]interface{}, error) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() { - return nil, errNotExtendable - } - - vs := make([]interface{}, len(xts)) - for i, xt := range xts { - v, err := GetExtension(m, xt) - if err != nil { - if err == ErrMissingExtension { - continue - } - return vs, err - } - vs[i] = v - } - return vs, nil -} - -// SetExtension sets an extension field in m to the provided value. -func SetExtension(m Message, xt *ExtensionDesc, v interface{}) error { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 { - return errNotExtendable - } - - rv := reflect.ValueOf(v) - if reflect.TypeOf(v) != reflect.TypeOf(xt.ExtensionType) { - return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", v, xt.ExtensionType) - } - if rv.Kind() == reflect.Ptr { - if rv.IsNil() { - return fmt.Errorf("proto: SetExtension called with nil value of type %T", v) - } - if isScalarKind(rv.Elem().Kind()) { - v = rv.Elem().Interface() - } - } - - xtd := xt.TypeDescriptor() - if !isValidExtension(mr.Descriptor(), xtd) { - return fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m) - } - mr.Set(xtd, xt.ValueOf(v)) - clearUnknown(mr, fieldNum(xt.Field)) - return nil -} - -// SetRawExtension inserts b into the unknown fields of m. -// -// Deprecated: Use Message.ProtoReflect.SetUnknown instead. -func SetRawExtension(m Message, fnum int32, b []byte) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() { - return - } - - // Verify that the raw field is valid. - for b0 := b; len(b0) > 0; { - num, _, n := protowire.ConsumeField(b0) - if int32(num) != fnum { - panic(fmt.Sprintf("mismatching field number: got %d, want %d", num, fnum)) - } - b0 = b0[n:] - } - - ClearExtension(m, &ExtensionDesc{Field: fnum}) - mr.SetUnknown(append(mr.GetUnknown(), b...)) -} - -// ExtensionDescs returns a list of extension descriptors found in m, -// containing descriptors for both populated extension fields in m and -// also unknown fields of m that are in the extension range. -// For the later case, an type incomplete descriptor is provided where only -// the ExtensionDesc.Field field is populated. -// The order of the extension descriptors is undefined. -func ExtensionDescs(m Message) ([]*ExtensionDesc, error) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 { - return nil, errNotExtendable - } - - // Collect a set of known extension descriptors. - extDescs := make(map[protoreflect.FieldNumber]*ExtensionDesc) - mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - if fd.IsExtension() { - xt := fd.(protoreflect.ExtensionTypeDescriptor) - if xd, ok := xt.Type().(*ExtensionDesc); ok { - extDescs[fd.Number()] = xd - } - } - return true - }) - - // Collect a set of unknown extension descriptors. - extRanges := mr.Descriptor().ExtensionRanges() - for b := mr.GetUnknown(); len(b) > 0; { - num, _, n := protowire.ConsumeField(b) - if extRanges.Has(num) && extDescs[num] == nil { - extDescs[num] = nil - } - b = b[n:] - } - - // Transpose the set of descriptors into a list. - var xts []*ExtensionDesc - for num, xt := range extDescs { - if xt == nil { - xt = &ExtensionDesc{Field: int32(num)} - } - xts = append(xts, xt) - } - return xts, nil -} - -// isValidExtension reports whether xtd is a valid extension descriptor for md. -func isValidExtension(md protoreflect.MessageDescriptor, xtd protoreflect.ExtensionTypeDescriptor) bool { - return xtd.ContainingMessage() == md && md.ExtensionRanges().Has(xtd.Number()) -} - -// isScalarKind reports whether k is a protobuf scalar kind (except bytes). -// This function exists for historical reasons since the representation of -// scalars differs between v1 and v2, where v1 uses *T and v2 uses T. -func isScalarKind(k reflect.Kind) bool { - switch k { - case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String: - return true - default: - return false - } -} - -// clearUnknown removes unknown fields from m where remover.Has reports true. -func clearUnknown(m protoreflect.Message, remover interface { - Has(protoreflect.FieldNumber) bool -}) { - var bo protoreflect.RawFields - for bi := m.GetUnknown(); len(bi) > 0; { - num, _, n := protowire.ConsumeField(bi) - if !remover.Has(num) { - bo = append(bo, bi[:n]...) - } - bi = bi[n:] - } - if bi := m.GetUnknown(); len(bi) != len(bo) { - m.SetUnknown(bo) - } -} - -type fieldNum protoreflect.FieldNumber - -func (n1 fieldNum) Has(n2 protoreflect.FieldNumber) bool { - return protoreflect.FieldNumber(n1) == n2 -} diff --git a/vendor/github.com/golang/protobuf/proto/properties.go b/vendor/github.com/golang/protobuf/proto/properties.go deleted file mode 100644 index dcdc2202..00000000 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "sync" - - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/runtime/protoimpl" -) - -// StructProperties represents protocol buffer type information for a -// generated protobuf message in the open-struct API. -// -// Deprecated: Do not use. -type StructProperties struct { - // Prop are the properties for each field. - // - // Fields belonging to a oneof are stored in OneofTypes instead, with a - // single Properties representing the parent oneof held here. - // - // The order of Prop matches the order of fields in the Go struct. - // Struct fields that are not related to protobufs have a "XXX_" prefix - // in the Properties.Name and must be ignored by the user. - Prop []*Properties - - // OneofTypes contains information about the oneof fields in this message. - // It is keyed by the protobuf field name. - OneofTypes map[string]*OneofProperties -} - -// Properties represents the type information for a protobuf message field. -// -// Deprecated: Do not use. -type Properties struct { - // Name is a placeholder name with little meaningful semantic value. - // If the name has an "XXX_" prefix, the entire Properties must be ignored. - Name string - // OrigName is the protobuf field name or oneof name. - OrigName string - // JSONName is the JSON name for the protobuf field. - JSONName string - // Enum is a placeholder name for enums. - // For historical reasons, this is neither the Go name for the enum, - // nor the protobuf name for the enum. - Enum string // Deprecated: Do not use. - // Weak contains the full name of the weakly referenced message. - Weak string - // Wire is a string representation of the wire type. - Wire string - // WireType is the protobuf wire type for the field. - WireType int - // Tag is the protobuf field number. - Tag int - // Required reports whether this is a required field. - Required bool - // Optional reports whether this is a optional field. - Optional bool - // Repeated reports whether this is a repeated field. - Repeated bool - // Packed reports whether this is a packed repeated field of scalars. - Packed bool - // Proto3 reports whether this field operates under the proto3 syntax. - Proto3 bool - // Oneof reports whether this field belongs within a oneof. - Oneof bool - - // Default is the default value in string form. - Default string - // HasDefault reports whether the field has a default value. - HasDefault bool - - // MapKeyProp is the properties for the key field for a map field. - MapKeyProp *Properties - // MapValProp is the properties for the value field for a map field. - MapValProp *Properties -} - -// OneofProperties represents the type information for a protobuf oneof. -// -// Deprecated: Do not use. -type OneofProperties struct { - // Type is a pointer to the generated wrapper type for the field value. - // This is nil for messages that are not in the open-struct API. - Type reflect.Type - // Field is the index into StructProperties.Prop for the containing oneof. - Field int - // Prop is the properties for the field. - Prop *Properties -} - -// String formats the properties in the protobuf struct field tag style. -func (p *Properties) String() string { - s := p.Wire - s += "," + strconv.Itoa(p.Tag) - if p.Required { - s += ",req" - } - if p.Optional { - s += ",opt" - } - if p.Repeated { - s += ",rep" - } - if p.Packed { - s += ",packed" - } - s += ",name=" + p.OrigName - if p.JSONName != "" { - s += ",json=" + p.JSONName - } - if len(p.Enum) > 0 { - s += ",enum=" + p.Enum - } - if len(p.Weak) > 0 { - s += ",weak=" + p.Weak - } - if p.Proto3 { - s += ",proto3" - } - if p.Oneof { - s += ",oneof" - } - if p.HasDefault { - s += ",def=" + p.Default - } - return s -} - -// Parse populates p by parsing a string in the protobuf struct field tag style. -func (p *Properties) Parse(tag string) { - // For example: "bytes,49,opt,name=foo,def=hello!" - for len(tag) > 0 { - i := strings.IndexByte(tag, ',') - if i < 0 { - i = len(tag) - } - switch s := tag[:i]; { - case strings.HasPrefix(s, "name="): - p.OrigName = s[len("name="):] - case strings.HasPrefix(s, "json="): - p.JSONName = s[len("json="):] - case strings.HasPrefix(s, "enum="): - p.Enum = s[len("enum="):] - case strings.HasPrefix(s, "weak="): - p.Weak = s[len("weak="):] - case strings.Trim(s, "0123456789") == "": - n, _ := strconv.ParseUint(s, 10, 32) - p.Tag = int(n) - case s == "opt": - p.Optional = true - case s == "req": - p.Required = true - case s == "rep": - p.Repeated = true - case s == "varint" || s == "zigzag32" || s == "zigzag64": - p.Wire = s - p.WireType = WireVarint - case s == "fixed32": - p.Wire = s - p.WireType = WireFixed32 - case s == "fixed64": - p.Wire = s - p.WireType = WireFixed64 - case s == "bytes": - p.Wire = s - p.WireType = WireBytes - case s == "group": - p.Wire = s - p.WireType = WireStartGroup - case s == "packed": - p.Packed = true - case s == "proto3": - p.Proto3 = true - case s == "oneof": - p.Oneof = true - case strings.HasPrefix(s, "def="): - // The default tag is special in that everything afterwards is the - // default regardless of the presence of commas. - p.HasDefault = true - p.Default, i = tag[len("def="):], len(tag) - } - tag = strings.TrimPrefix(tag[i:], ",") - } -} - -// Init populates the properties from a protocol buffer struct tag. -// -// Deprecated: Do not use. -func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) { - p.Name = name - p.OrigName = name - if tag == "" { - return - } - p.Parse(tag) - - if typ != nil && typ.Kind() == reflect.Map { - p.MapKeyProp = new(Properties) - p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil) - p.MapValProp = new(Properties) - p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil) - } -} - -var propertiesCache sync.Map // map[reflect.Type]*StructProperties - -// GetProperties returns the list of properties for the type represented by t, -// which must be a generated protocol buffer message in the open-struct API, -// where protobuf message fields are represented by exported Go struct fields. -// -// Deprecated: Use protobuf reflection instead. -func GetProperties(t reflect.Type) *StructProperties { - if p, ok := propertiesCache.Load(t); ok { - return p.(*StructProperties) - } - p, _ := propertiesCache.LoadOrStore(t, newProperties(t)) - return p.(*StructProperties) -} - -func newProperties(t reflect.Type) *StructProperties { - if t.Kind() != reflect.Struct { - panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t)) - } - - var hasOneof bool - prop := new(StructProperties) - - // Construct a list of properties for each field in the struct. - for i := 0; i < t.NumField(); i++ { - p := new(Properties) - f := t.Field(i) - tagField := f.Tag.Get("protobuf") - p.Init(f.Type, f.Name, tagField, &f) - - tagOneof := f.Tag.Get("protobuf_oneof") - if tagOneof != "" { - hasOneof = true - p.OrigName = tagOneof - } - - // Rename unrelated struct fields with the "XXX_" prefix since so much - // user code simply checks for this to exclude special fields. - if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") { - p.Name = "XXX_" + p.Name - p.OrigName = "XXX_" + p.OrigName - } else if p.Weak != "" { - p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field - } - - prop.Prop = append(prop.Prop, p) - } - - // Construct a mapping of oneof field names to properties. - if hasOneof { - var oneofWrappers []interface{} - if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok { - oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{}) - } - if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok { - oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{}) - } - if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok { - if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok { - oneofWrappers = m.ProtoMessageInfo().OneofWrappers - } - } - - prop.OneofTypes = make(map[string]*OneofProperties) - for _, wrapper := range oneofWrappers { - p := &OneofProperties{ - Type: reflect.ValueOf(wrapper).Type(), // *T - Prop: new(Properties), - } - f := p.Type.Elem().Field(0) - p.Prop.Name = f.Name - p.Prop.Parse(f.Tag.Get("protobuf")) - - // Determine the struct field that contains this oneof. - // Each wrapper is assignable to exactly one parent field. - var foundOneof bool - for i := 0; i < t.NumField() && !foundOneof; i++ { - if p.Type.AssignableTo(t.Field(i).Type) { - p.Field = i - foundOneof = true - } - } - if !foundOneof { - panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t)) - } - prop.OneofTypes[p.Prop.OrigName] = p - } - } - - return prop -} - -func (sp *StructProperties) Len() int { return len(sp.Prop) } -func (sp *StructProperties) Less(i, j int) bool { return false } -func (sp *StructProperties) Swap(i, j int) { return } diff --git a/vendor/github.com/golang/protobuf/proto/proto.go b/vendor/github.com/golang/protobuf/proto/proto.go deleted file mode 100644 index 5aee89c3..00000000 --- a/vendor/github.com/golang/protobuf/proto/proto.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package proto provides functionality for handling protocol buffer messages. -// In particular, it provides marshaling and unmarshaling between a protobuf -// message and the binary wire format. -// -// See https://developers.google.com/protocol-buffers/docs/gotutorial for -// more information. -// -// Deprecated: Use the "google.golang.org/protobuf/proto" package instead. -package proto - -import ( - protoV2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/runtime/protoiface" - "google.golang.org/protobuf/runtime/protoimpl" -) - -const ( - ProtoPackageIsVersion1 = true - ProtoPackageIsVersion2 = true - ProtoPackageIsVersion3 = true - ProtoPackageIsVersion4 = true -) - -// GeneratedEnum is any enum type generated by protoc-gen-go -// which is a named int32 kind. -// This type exists for documentation purposes. -type GeneratedEnum interface{} - -// GeneratedMessage is any message type generated by protoc-gen-go -// which is a pointer to a named struct kind. -// This type exists for documentation purposes. -type GeneratedMessage interface{} - -// Message is a protocol buffer message. -// -// This is the v1 version of the message interface and is marginally better -// than an empty interface as it lacks any method to programatically interact -// with the contents of the message. -// -// A v2 message is declared in "google.golang.org/protobuf/proto".Message and -// exposes protobuf reflection as a first-class feature of the interface. -// -// To convert a v1 message to a v2 message, use the MessageV2 function. -// To convert a v2 message to a v1 message, use the MessageV1 function. -type Message = protoiface.MessageV1 - -// MessageV1 converts either a v1 or v2 message to a v1 message. -// It returns nil if m is nil. -func MessageV1(m GeneratedMessage) protoiface.MessageV1 { - return protoimpl.X.ProtoMessageV1Of(m) -} - -// MessageV2 converts either a v1 or v2 message to a v2 message. -// It returns nil if m is nil. -func MessageV2(m GeneratedMessage) protoV2.Message { - return protoimpl.X.ProtoMessageV2Of(m) -} - -// MessageReflect returns a reflective view for a message. -// It returns nil if m is nil. -func MessageReflect(m Message) protoreflect.Message { - return protoimpl.X.MessageOf(m) -} - -// Marshaler is implemented by messages that can marshal themselves. -// This interface is used by the following functions: Size, Marshal, -// Buffer.Marshal, and Buffer.EncodeMessage. -// -// Deprecated: Do not implement. -type Marshaler interface { - // Marshal formats the encoded bytes of the message. - // It should be deterministic and emit valid protobuf wire data. - // The caller takes ownership of the returned buffer. - Marshal() ([]byte, error) -} - -// Unmarshaler is implemented by messages that can unmarshal themselves. -// This interface is used by the following functions: Unmarshal, UnmarshalMerge, -// Buffer.Unmarshal, Buffer.DecodeMessage, and Buffer.DecodeGroup. -// -// Deprecated: Do not implement. -type Unmarshaler interface { - // Unmarshal parses the encoded bytes of the protobuf wire input. - // The provided buffer is only valid for during method call. - // It should not reset the receiver message. - Unmarshal([]byte) error -} - -// Merger is implemented by messages that can merge themselves. -// This interface is used by the following functions: Clone and Merge. -// -// Deprecated: Do not implement. -type Merger interface { - // Merge merges the contents of src into the receiver message. - // It clones all data structures in src such that it aliases no mutable - // memory referenced by src. - Merge(src Message) -} - -// RequiredNotSetError is an error type returned when -// marshaling or unmarshaling a message with missing required fields. -type RequiredNotSetError struct { - err error -} - -func (e *RequiredNotSetError) Error() string { - if e.err != nil { - return e.err.Error() - } - return "proto: required field not set" -} -func (e *RequiredNotSetError) RequiredNotSet() bool { - return true -} - -func checkRequiredNotSet(m protoV2.Message) error { - if err := protoV2.CheckInitialized(m); err != nil { - return &RequiredNotSetError{err: err} - } - return nil -} - -// Clone returns a deep copy of src. -func Clone(src Message) Message { - return MessageV1(protoV2.Clone(MessageV2(src))) -} - -// Merge merges src into dst, which must be messages of the same type. -// -// Populated scalar fields in src are copied to dst, while populated -// singular messages in src are merged into dst by recursively calling Merge. -// The elements of every list field in src is appended to the corresponded -// list fields in dst. The entries of every map field in src is copied into -// the corresponding map field in dst, possibly replacing existing entries. -// The unknown fields of src are appended to the unknown fields of dst. -func Merge(dst, src Message) { - protoV2.Merge(MessageV2(dst), MessageV2(src)) -} - -// Equal reports whether two messages are equal. -// If two messages marshal to the same bytes under deterministic serialization, -// then Equal is guaranteed to report true. -// -// Two messages are equal if they are the same protobuf message type, -// have the same set of populated known and extension field values, -// and the same set of unknown fields values. -// -// Scalar values are compared with the equivalent of the == operator in Go, -// except bytes values which are compared using bytes.Equal and -// floating point values which specially treat NaNs as equal. -// Message values are compared by recursively calling Equal. -// Lists are equal if each element value is also equal. -// Maps are equal if they have the same set of keys, where the pair of values -// for each key is also equal. -func Equal(x, y Message) bool { - return protoV2.Equal(MessageV2(x), MessageV2(y)) -} - -func isMessageSet(md protoreflect.MessageDescriptor) bool { - ms, ok := md.(interface{ IsMessageSet() bool }) - return ok && ms.IsMessageSet() -} diff --git a/vendor/github.com/golang/protobuf/proto/registry.go b/vendor/github.com/golang/protobuf/proto/registry.go deleted file mode 100644 index 066b4323..00000000 --- a/vendor/github.com/golang/protobuf/proto/registry.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "bytes" - "compress/gzip" - "fmt" - "io/ioutil" - "reflect" - "strings" - "sync" - - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - "google.golang.org/protobuf/runtime/protoimpl" -) - -// filePath is the path to the proto source file. -type filePath = string // e.g., "google/protobuf/descriptor.proto" - -// fileDescGZIP is the compressed contents of the encoded FileDescriptorProto. -type fileDescGZIP = []byte - -var fileCache sync.Map // map[filePath]fileDescGZIP - -// RegisterFile is called from generated code to register the compressed -// FileDescriptorProto with the file path for a proto source file. -// -// Deprecated: Use protoregistry.GlobalFiles.RegisterFile instead. -func RegisterFile(s filePath, d fileDescGZIP) { - // Decompress the descriptor. - zr, err := gzip.NewReader(bytes.NewReader(d)) - if err != nil { - panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err)) - } - b, err := ioutil.ReadAll(zr) - if err != nil { - panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err)) - } - - // Construct a protoreflect.FileDescriptor from the raw descriptor. - // Note that DescBuilder.Build automatically registers the constructed - // file descriptor with the v2 registry. - protoimpl.DescBuilder{RawDescriptor: b}.Build() - - // Locally cache the raw descriptor form for the file. - fileCache.Store(s, d) -} - -// FileDescriptor returns the compressed FileDescriptorProto given the file path -// for a proto source file. It returns nil if not found. -// -// Deprecated: Use protoregistry.GlobalFiles.FindFileByPath instead. -func FileDescriptor(s filePath) fileDescGZIP { - if v, ok := fileCache.Load(s); ok { - return v.(fileDescGZIP) - } - - // Find the descriptor in the v2 registry. - var b []byte - if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil { - b, _ = Marshal(protodesc.ToFileDescriptorProto(fd)) - } - - // Locally cache the raw descriptor form for the file. - if len(b) > 0 { - v, _ := fileCache.LoadOrStore(s, protoimpl.X.CompressGZIP(b)) - return v.(fileDescGZIP) - } - return nil -} - -// enumName is the name of an enum. For historical reasons, the enum name is -// neither the full Go name nor the full protobuf name of the enum. -// The name is the dot-separated combination of just the proto package that the -// enum is declared within followed by the Go type name of the generated enum. -type enumName = string // e.g., "my.proto.package.GoMessage_GoEnum" - -// enumsByName maps enum values by name to their numeric counterpart. -type enumsByName = map[string]int32 - -// enumsByNumber maps enum values by number to their name counterpart. -type enumsByNumber = map[int32]string - -var enumCache sync.Map // map[enumName]enumsByName -var numFilesCache sync.Map // map[protoreflect.FullName]int - -// RegisterEnum is called from the generated code to register the mapping of -// enum value names to enum numbers for the enum identified by s. -// -// Deprecated: Use protoregistry.GlobalTypes.RegisterEnum instead. -func RegisterEnum(s enumName, _ enumsByNumber, m enumsByName) { - if _, ok := enumCache.Load(s); ok { - panic("proto: duplicate enum registered: " + s) - } - enumCache.Store(s, m) - - // This does not forward registration to the v2 registry since this API - // lacks sufficient information to construct a complete v2 enum descriptor. -} - -// EnumValueMap returns the mapping from enum value names to enum numbers for -// the enum of the given name. It returns nil if not found. -// -// Deprecated: Use protoregistry.GlobalTypes.FindEnumByName instead. -func EnumValueMap(s enumName) enumsByName { - if v, ok := enumCache.Load(s); ok { - return v.(enumsByName) - } - - // Check whether the cache is stale. If the number of files in the current - // package differs, then it means that some enums may have been recently - // registered upstream that we do not know about. - var protoPkg protoreflect.FullName - if i := strings.LastIndexByte(s, '.'); i >= 0 { - protoPkg = protoreflect.FullName(s[:i]) - } - v, _ := numFilesCache.Load(protoPkg) - numFiles, _ := v.(int) - if protoregistry.GlobalFiles.NumFilesByPackage(protoPkg) == numFiles { - return nil // cache is up-to-date; was not found earlier - } - - // Update the enum cache for all enums declared in the given proto package. - numFiles = 0 - protoregistry.GlobalFiles.RangeFilesByPackage(protoPkg, func(fd protoreflect.FileDescriptor) bool { - walkEnums(fd, func(ed protoreflect.EnumDescriptor) { - name := protoimpl.X.LegacyEnumName(ed) - if _, ok := enumCache.Load(name); !ok { - m := make(enumsByName) - evs := ed.Values() - for i := evs.Len() - 1; i >= 0; i-- { - ev := evs.Get(i) - m[string(ev.Name())] = int32(ev.Number()) - } - enumCache.LoadOrStore(name, m) - } - }) - numFiles++ - return true - }) - numFilesCache.Store(protoPkg, numFiles) - - // Check cache again for enum map. - if v, ok := enumCache.Load(s); ok { - return v.(enumsByName) - } - return nil -} - -// walkEnums recursively walks all enums declared in d. -func walkEnums(d interface { - Enums() protoreflect.EnumDescriptors - Messages() protoreflect.MessageDescriptors -}, f func(protoreflect.EnumDescriptor)) { - eds := d.Enums() - for i := eds.Len() - 1; i >= 0; i-- { - f(eds.Get(i)) - } - mds := d.Messages() - for i := mds.Len() - 1; i >= 0; i-- { - walkEnums(mds.Get(i), f) - } -} - -// messageName is the full name of protobuf message. -type messageName = string - -var messageTypeCache sync.Map // map[messageName]reflect.Type - -// RegisterType is called from generated code to register the message Go type -// for a message of the given name. -// -// Deprecated: Use protoregistry.GlobalTypes.RegisterMessage instead. -func RegisterType(m Message, s messageName) { - mt := protoimpl.X.LegacyMessageTypeOf(m, protoreflect.FullName(s)) - if err := protoregistry.GlobalTypes.RegisterMessage(mt); err != nil { - panic(err) - } - messageTypeCache.Store(s, reflect.TypeOf(m)) -} - -// RegisterMapType is called from generated code to register the Go map type -// for a protobuf message representing a map entry. -// -// Deprecated: Do not use. -func RegisterMapType(m interface{}, s messageName) { - t := reflect.TypeOf(m) - if t.Kind() != reflect.Map { - panic(fmt.Sprintf("invalid map kind: %v", t)) - } - if _, ok := messageTypeCache.Load(s); ok { - panic(fmt.Errorf("proto: duplicate proto message registered: %s", s)) - } - messageTypeCache.Store(s, t) -} - -// MessageType returns the message type for a named message. -// It returns nil if not found. -// -// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead. -func MessageType(s messageName) reflect.Type { - if v, ok := messageTypeCache.Load(s); ok { - return v.(reflect.Type) - } - - // Derive the message type from the v2 registry. - var t reflect.Type - if mt, _ := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(s)); mt != nil { - t = messageGoType(mt) - } - - // If we could not get a concrete type, it is possible that it is a - // pseudo-message for a map entry. - if t == nil { - d, _ := protoregistry.GlobalFiles.FindDescriptorByName(protoreflect.FullName(s)) - if md, _ := d.(protoreflect.MessageDescriptor); md != nil && md.IsMapEntry() { - kt := goTypeForField(md.Fields().ByNumber(1)) - vt := goTypeForField(md.Fields().ByNumber(2)) - t = reflect.MapOf(kt, vt) - } - } - - // Locally cache the message type for the given name. - if t != nil { - v, _ := messageTypeCache.LoadOrStore(s, t) - return v.(reflect.Type) - } - return nil -} - -func goTypeForField(fd protoreflect.FieldDescriptor) reflect.Type { - switch k := fd.Kind(); k { - case protoreflect.EnumKind: - if et, _ := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName()); et != nil { - return enumGoType(et) - } - return reflect.TypeOf(protoreflect.EnumNumber(0)) - case protoreflect.MessageKind, protoreflect.GroupKind: - if mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()); mt != nil { - return messageGoType(mt) - } - return reflect.TypeOf((*protoreflect.Message)(nil)).Elem() - default: - return reflect.TypeOf(fd.Default().Interface()) - } -} - -func enumGoType(et protoreflect.EnumType) reflect.Type { - return reflect.TypeOf(et.New(0)) -} - -func messageGoType(mt protoreflect.MessageType) reflect.Type { - return reflect.TypeOf(MessageV1(mt.Zero().Interface())) -} - -// MessageName returns the full protobuf name for the given message type. -// -// Deprecated: Use protoreflect.MessageDescriptor.FullName instead. -func MessageName(m Message) messageName { - if m == nil { - return "" - } - if m, ok := m.(interface{ XXX_MessageName() messageName }); ok { - return m.XXX_MessageName() - } - return messageName(protoimpl.X.MessageDescriptorOf(m).FullName()) -} - -// RegisterExtension is called from the generated code to register -// the extension descriptor. -// -// Deprecated: Use protoregistry.GlobalTypes.RegisterExtension instead. -func RegisterExtension(d *ExtensionDesc) { - if err := protoregistry.GlobalTypes.RegisterExtension(d); err != nil { - panic(err) - } -} - -type extensionsByNumber = map[int32]*ExtensionDesc - -var extensionCache sync.Map // map[messageName]extensionsByNumber - -// RegisteredExtensions returns a map of the registered extensions for the -// provided protobuf message, indexed by the extension field number. -// -// Deprecated: Use protoregistry.GlobalTypes.RangeExtensionsByMessage instead. -func RegisteredExtensions(m Message) extensionsByNumber { - // Check whether the cache is stale. If the number of extensions for - // the given message differs, then it means that some extensions were - // recently registered upstream that we do not know about. - s := MessageName(m) - v, _ := extensionCache.Load(s) - xs, _ := v.(extensionsByNumber) - if protoregistry.GlobalTypes.NumExtensionsByMessage(protoreflect.FullName(s)) == len(xs) { - return xs // cache is up-to-date - } - - // Cache is stale, re-compute the extensions map. - xs = make(extensionsByNumber) - protoregistry.GlobalTypes.RangeExtensionsByMessage(protoreflect.FullName(s), func(xt protoreflect.ExtensionType) bool { - if xd, ok := xt.(*ExtensionDesc); ok { - xs[int32(xt.TypeDescriptor().Number())] = xd - } else { - // TODO: This implies that the protoreflect.ExtensionType is a - // custom type not generated by protoc-gen-go. We could try and - // convert the type to an ExtensionDesc. - } - return true - }) - extensionCache.Store(s, xs) - return xs -} diff --git a/vendor/github.com/golang/protobuf/proto/text_decode.go b/vendor/github.com/golang/protobuf/proto/text_decode.go deleted file mode 100644 index 47eb3e44..00000000 --- a/vendor/github.com/golang/protobuf/proto/text_decode.go +++ /dev/null @@ -1,801 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "encoding" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "unicode/utf8" - - "google.golang.org/protobuf/encoding/prototext" - protoV2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -const wrapTextUnmarshalV2 = false - -// ParseError is returned by UnmarshalText. -type ParseError struct { - Message string - - // Deprecated: Do not use. - Line, Offset int -} - -func (e *ParseError) Error() string { - if wrapTextUnmarshalV2 { - return e.Message - } - if e.Line == 1 { - return fmt.Sprintf("line 1.%d: %v", e.Offset, e.Message) - } - return fmt.Sprintf("line %d: %v", e.Line, e.Message) -} - -// UnmarshalText parses a proto text formatted string into m. -func UnmarshalText(s string, m Message) error { - if u, ok := m.(encoding.TextUnmarshaler); ok { - return u.UnmarshalText([]byte(s)) - } - - m.Reset() - mi := MessageV2(m) - - if wrapTextUnmarshalV2 { - err := prototext.UnmarshalOptions{ - AllowPartial: true, - }.Unmarshal([]byte(s), mi) - if err != nil { - return &ParseError{Message: err.Error()} - } - return checkRequiredNotSet(mi) - } else { - if err := newTextParser(s).unmarshalMessage(mi.ProtoReflect(), ""); err != nil { - return err - } - return checkRequiredNotSet(mi) - } -} - -type textParser struct { - s string // remaining input - done bool // whether the parsing is finished (success or error) - backed bool // whether back() was called - offset, line int - cur token -} - -type token struct { - value string - err *ParseError - line int // line number - offset int // byte number from start of input, not start of line - unquoted string // the unquoted version of value, if it was a quoted string -} - -func newTextParser(s string) *textParser { - p := new(textParser) - p.s = s - p.line = 1 - p.cur.line = 1 - return p -} - -func (p *textParser) unmarshalMessage(m protoreflect.Message, terminator string) (err error) { - md := m.Descriptor() - fds := md.Fields() - - // A struct is a sequence of "name: value", terminated by one of - // '>' or '}', or the end of the input. A name may also be - // "[extension]" or "[type/url]". - // - // The whole struct can also be an expanded Any message, like: - // [type/url] < ... struct contents ... > - seen := make(map[protoreflect.FieldNumber]bool) - for { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value == terminator { - break - } - if tok.value == "[" { - if err := p.unmarshalExtensionOrAny(m, seen); err != nil { - return err - } - continue - } - - // This is a normal, non-extension field. - name := protoreflect.Name(tok.value) - fd := fds.ByName(name) - switch { - case fd == nil: - gd := fds.ByName(protoreflect.Name(strings.ToLower(string(name)))) - if gd != nil && gd.Kind() == protoreflect.GroupKind && gd.Message().Name() == name { - fd = gd - } - case fd.Kind() == protoreflect.GroupKind && fd.Message().Name() != name: - fd = nil - case fd.IsWeak() && fd.Message().IsPlaceholder(): - fd = nil - } - if fd == nil { - typeName := string(md.FullName()) - if m, ok := m.Interface().(Message); ok { - t := reflect.TypeOf(m) - if t.Kind() == reflect.Ptr { - typeName = t.Elem().String() - } - } - return p.errorf("unknown field name %q in %v", name, typeName) - } - if od := fd.ContainingOneof(); od != nil && m.WhichOneof(od) != nil { - return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, od.Name()) - } - if fd.Cardinality() != protoreflect.Repeated && seen[fd.Number()] { - return p.errorf("non-repeated field %q was repeated", fd.Name()) - } - seen[fd.Number()] = true - - // Consume any colon. - if err := p.checkForColon(fd); err != nil { - return err - } - - // Parse into the field. - v := m.Get(fd) - if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) { - v = m.Mutable(fd) - } - if v, err = p.unmarshalValue(v, fd); err != nil { - return err - } - m.Set(fd, v) - - if err := p.consumeOptionalSeparator(); err != nil { - return err - } - } - return nil -} - -func (p *textParser) unmarshalExtensionOrAny(m protoreflect.Message, seen map[protoreflect.FieldNumber]bool) error { - name, err := p.consumeExtensionOrAnyName() - if err != nil { - return err - } - - // If it contains a slash, it's an Any type URL. - if slashIdx := strings.LastIndex(name, "/"); slashIdx >= 0 { - tok := p.next() - if tok.err != nil { - return tok.err - } - // consume an optional colon - if tok.value == ":" { - tok = p.next() - if tok.err != nil { - return tok.err - } - } - - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return p.errorf("expected '{' or '<', found %q", tok.value) - } - - mt, err := protoregistry.GlobalTypes.FindMessageByURL(name) - if err != nil { - return p.errorf("unrecognized message %q in google.protobuf.Any", name[slashIdx+len("/"):]) - } - m2 := mt.New() - if err := p.unmarshalMessage(m2, terminator); err != nil { - return err - } - b, err := protoV2.Marshal(m2.Interface()) - if err != nil { - return p.errorf("failed to marshal message of type %q: %v", name[slashIdx+len("/"):], err) - } - - urlFD := m.Descriptor().Fields().ByName("type_url") - valFD := m.Descriptor().Fields().ByName("value") - if seen[urlFD.Number()] { - return p.errorf("Any message unpacked multiple times, or %q already set", urlFD.Name()) - } - if seen[valFD.Number()] { - return p.errorf("Any message unpacked multiple times, or %q already set", valFD.Name()) - } - m.Set(urlFD, protoreflect.ValueOfString(name)) - m.Set(valFD, protoreflect.ValueOfBytes(b)) - seen[urlFD.Number()] = true - seen[valFD.Number()] = true - return nil - } - - xname := protoreflect.FullName(name) - xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname) - if xt == nil && isMessageSet(m.Descriptor()) { - xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension")) - } - if xt == nil { - return p.errorf("unrecognized extension %q", name) - } - fd := xt.TypeDescriptor() - if fd.ContainingMessage().FullName() != m.Descriptor().FullName() { - return p.errorf("extension field %q does not extend message %q", name, m.Descriptor().FullName()) - } - - if err := p.checkForColon(fd); err != nil { - return err - } - - v := m.Get(fd) - if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) { - v = m.Mutable(fd) - } - v, err = p.unmarshalValue(v, fd) - if err != nil { - return err - } - m.Set(fd, v) - return p.consumeOptionalSeparator() -} - -func (p *textParser) unmarshalValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { - tok := p.next() - if tok.err != nil { - return v, tok.err - } - if tok.value == "" { - return v, p.errorf("unexpected EOF") - } - - switch { - case fd.IsList(): - lv := v.List() - var err error - if tok.value == "[" { - // Repeated field with list notation, like [1,2,3]. - for { - vv := lv.NewElement() - vv, err = p.unmarshalSingularValue(vv, fd) - if err != nil { - return v, err - } - lv.Append(vv) - - tok := p.next() - if tok.err != nil { - return v, tok.err - } - if tok.value == "]" { - break - } - if tok.value != "," { - return v, p.errorf("Expected ']' or ',' found %q", tok.value) - } - } - return v, nil - } - - // One value of the repeated field. - p.back() - vv := lv.NewElement() - vv, err = p.unmarshalSingularValue(vv, fd) - if err != nil { - return v, err - } - lv.Append(vv) - return v, nil - case fd.IsMap(): - // The map entry should be this sequence of tokens: - // < key : KEY value : VALUE > - // However, implementations may omit key or value, and technically - // we should support them in any order. - var terminator string - switch tok.value { - case "<": - terminator = ">" - case "{": - terminator = "}" - default: - return v, p.errorf("expected '{' or '<', found %q", tok.value) - } - - keyFD := fd.MapKey() - valFD := fd.MapValue() - - mv := v.Map() - kv := keyFD.Default() - vv := mv.NewValue() - for { - tok := p.next() - if tok.err != nil { - return v, tok.err - } - if tok.value == terminator { - break - } - var err error - switch tok.value { - case "key": - if err := p.consumeToken(":"); err != nil { - return v, err - } - if kv, err = p.unmarshalSingularValue(kv, keyFD); err != nil { - return v, err - } - if err := p.consumeOptionalSeparator(); err != nil { - return v, err - } - case "value": - if err := p.checkForColon(valFD); err != nil { - return v, err - } - if vv, err = p.unmarshalSingularValue(vv, valFD); err != nil { - return v, err - } - if err := p.consumeOptionalSeparator(); err != nil { - return v, err - } - default: - p.back() - return v, p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value) - } - } - mv.Set(kv.MapKey(), vv) - return v, nil - default: - p.back() - return p.unmarshalSingularValue(v, fd) - } -} - -func (p *textParser) unmarshalSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { - tok := p.next() - if tok.err != nil { - return v, tok.err - } - if tok.value == "" { - return v, p.errorf("unexpected EOF") - } - - switch fd.Kind() { - case protoreflect.BoolKind: - switch tok.value { - case "true", "1", "t", "True": - return protoreflect.ValueOfBool(true), nil - case "false", "0", "f", "False": - return protoreflect.ValueOfBool(false), nil - } - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: - if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { - return protoreflect.ValueOfInt32(int32(x)), nil - } - - // The C++ parser accepts large positive hex numbers that uses - // two's complement arithmetic to represent negative numbers. - // This feature is here for backwards compatibility with C++. - if strings.HasPrefix(tok.value, "0x") { - if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - return protoreflect.ValueOfInt32(int32(-(int64(^x) + 1))), nil - } - } - case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: - if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil { - return protoreflect.ValueOfInt64(int64(x)), nil - } - - // The C++ parser accepts large positive hex numbers that uses - // two's complement arithmetic to represent negative numbers. - // This feature is here for backwards compatibility with C++. - if strings.HasPrefix(tok.value, "0x") { - if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { - return protoreflect.ValueOfInt64(int64(-(int64(^x) + 1))), nil - } - } - case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: - if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - return protoreflect.ValueOfUint32(uint32(x)), nil - } - case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil { - return protoreflect.ValueOfUint64(uint64(x)), nil - } - case protoreflect.FloatKind: - // Ignore 'f' for compatibility with output generated by C++, - // but don't remove 'f' when the value is "-inf" or "inf". - v := tok.value - if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" { - v = v[:len(v)-len("f")] - } - if x, err := strconv.ParseFloat(v, 32); err == nil { - return protoreflect.ValueOfFloat32(float32(x)), nil - } - case protoreflect.DoubleKind: - // Ignore 'f' for compatibility with output generated by C++, - // but don't remove 'f' when the value is "-inf" or "inf". - v := tok.value - if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" { - v = v[:len(v)-len("f")] - } - if x, err := strconv.ParseFloat(v, 64); err == nil { - return protoreflect.ValueOfFloat64(float64(x)), nil - } - case protoreflect.StringKind: - if isQuote(tok.value[0]) { - return protoreflect.ValueOfString(tok.unquoted), nil - } - case protoreflect.BytesKind: - if isQuote(tok.value[0]) { - return protoreflect.ValueOfBytes([]byte(tok.unquoted)), nil - } - case protoreflect.EnumKind: - if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil { - return protoreflect.ValueOfEnum(protoreflect.EnumNumber(x)), nil - } - vd := fd.Enum().Values().ByName(protoreflect.Name(tok.value)) - if vd != nil { - return protoreflect.ValueOfEnum(vd.Number()), nil - } - case protoreflect.MessageKind, protoreflect.GroupKind: - var terminator string - switch tok.value { - case "{": - terminator = "}" - case "<": - terminator = ">" - default: - return v, p.errorf("expected '{' or '<', found %q", tok.value) - } - err := p.unmarshalMessage(v.Message(), terminator) - return v, err - default: - panic(fmt.Sprintf("invalid kind %v", fd.Kind())) - } - return v, p.errorf("invalid %v: %v", fd.Kind(), tok.value) -} - -// Consume a ':' from the input stream (if the next token is a colon), -// returning an error if a colon is needed but not present. -func (p *textParser) checkForColon(fd protoreflect.FieldDescriptor) *ParseError { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ":" { - if fd.Message() == nil { - return p.errorf("expected ':', found %q", tok.value) - } - p.back() - } - return nil -} - -// consumeExtensionOrAnyName consumes an extension name or an Any type URL and -// the following ']'. It returns the name or URL consumed. -func (p *textParser) consumeExtensionOrAnyName() (string, error) { - tok := p.next() - if tok.err != nil { - return "", tok.err - } - - // If extension name or type url is quoted, it's a single token. - if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] { - name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0])) - if err != nil { - return "", err - } - return name, p.consumeToken("]") - } - - // Consume everything up to "]" - var parts []string - for tok.value != "]" { - parts = append(parts, tok.value) - tok = p.next() - if tok.err != nil { - return "", p.errorf("unrecognized type_url or extension name: %s", tok.err) - } - if p.done && tok.value != "]" { - return "", p.errorf("unclosed type_url or extension name") - } - } - return strings.Join(parts, ""), nil -} - -// consumeOptionalSeparator consumes an optional semicolon or comma. -// It is used in unmarshalMessage to provide backward compatibility. -func (p *textParser) consumeOptionalSeparator() error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != ";" && tok.value != "," { - p.back() - } - return nil -} - -func (p *textParser) errorf(format string, a ...interface{}) *ParseError { - pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset} - p.cur.err = pe - p.done = true - return pe -} - -func (p *textParser) skipWhitespace() { - i := 0 - for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') { - if p.s[i] == '#' { - // comment; skip to end of line or input - for i < len(p.s) && p.s[i] != '\n' { - i++ - } - if i == len(p.s) { - break - } - } - if p.s[i] == '\n' { - p.line++ - } - i++ - } - p.offset += i - p.s = p.s[i:len(p.s)] - if len(p.s) == 0 { - p.done = true - } -} - -func (p *textParser) advance() { - // Skip whitespace - p.skipWhitespace() - if p.done { - return - } - - // Start of non-whitespace - p.cur.err = nil - p.cur.offset, p.cur.line = p.offset, p.line - p.cur.unquoted = "" - switch p.s[0] { - case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/': - // Single symbol - p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)] - case '"', '\'': - // Quoted string - i := 1 - for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' { - if p.s[i] == '\\' && i+1 < len(p.s) { - // skip escaped char - i++ - } - i++ - } - if i >= len(p.s) || p.s[i] != p.s[0] { - p.errorf("unmatched quote") - return - } - unq, err := unquoteC(p.s[1:i], rune(p.s[0])) - if err != nil { - p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err) - return - } - p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)] - p.cur.unquoted = unq - default: - i := 0 - for i < len(p.s) && isIdentOrNumberChar(p.s[i]) { - i++ - } - if i == 0 { - p.errorf("unexpected byte %#x", p.s[0]) - return - } - p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)] - } - p.offset += len(p.cur.value) -} - -// Back off the parser by one token. Can only be done between calls to next(). -// It makes the next advance() a no-op. -func (p *textParser) back() { p.backed = true } - -// Advances the parser and returns the new current token. -func (p *textParser) next() *token { - if p.backed || p.done { - p.backed = false - return &p.cur - } - p.advance() - if p.done { - p.cur.value = "" - } else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) { - // Look for multiple quoted strings separated by whitespace, - // and concatenate them. - cat := p.cur - for { - p.skipWhitespace() - if p.done || !isQuote(p.s[0]) { - break - } - p.advance() - if p.cur.err != nil { - return &p.cur - } - cat.value += " " + p.cur.value - cat.unquoted += p.cur.unquoted - } - p.done = false // parser may have seen EOF, but we want to return cat - p.cur = cat - } - return &p.cur -} - -func (p *textParser) consumeToken(s string) error { - tok := p.next() - if tok.err != nil { - return tok.err - } - if tok.value != s { - p.back() - return p.errorf("expected %q, found %q", s, tok.value) - } - return nil -} - -var errBadUTF8 = errors.New("proto: bad UTF-8") - -func unquoteC(s string, quote rune) (string, error) { - // This is based on C++'s tokenizer.cc. - // Despite its name, this is *not* parsing C syntax. - // For instance, "\0" is an invalid quoted string. - - // Avoid allocation in trivial cases. - simple := true - for _, r := range s { - if r == '\\' || r == quote { - simple = false - break - } - } - if simple { - return s, nil - } - - buf := make([]byte, 0, 3*len(s)/2) - for len(s) > 0 { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", errBadUTF8 - } - s = s[n:] - if r != '\\' { - if r < utf8.RuneSelf { - buf = append(buf, byte(r)) - } else { - buf = append(buf, string(r)...) - } - continue - } - - ch, tail, err := unescape(s) - if err != nil { - return "", err - } - buf = append(buf, ch...) - s = tail - } - return string(buf), nil -} - -func unescape(s string) (ch string, tail string, err error) { - r, n := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && n == 1 { - return "", "", errBadUTF8 - } - s = s[n:] - switch r { - case 'a': - return "\a", s, nil - case 'b': - return "\b", s, nil - case 'f': - return "\f", s, nil - case 'n': - return "\n", s, nil - case 'r': - return "\r", s, nil - case 't': - return "\t", s, nil - case 'v': - return "\v", s, nil - case '?': - return "?", s, nil // trigraph workaround - case '\'', '"', '\\': - return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7': - if len(s) < 2 { - return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) - } - ss := string(r) + s[:2] - s = s[2:] - i, err := strconv.ParseUint(ss, 8, 8) - if err != nil { - return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) - } - return string([]byte{byte(i)}), s, nil - case 'x', 'X', 'u', 'U': - var n int - switch r { - case 'x', 'X': - n = 2 - case 'u': - n = 4 - case 'U': - n = 8 - } - if len(s) < n { - return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) - } - ss := s[:n] - s = s[n:] - i, err := strconv.ParseUint(ss, 16, 64) - if err != nil { - return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss) - } - if r == 'x' || r == 'X' { - return string([]byte{byte(i)}), s, nil - } - if i > utf8.MaxRune { - return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) - } - return string(rune(i)), s, nil - } - return "", "", fmt.Errorf(`unknown escape \%c`, r) -} - -func isIdentOrNumberChar(c byte) bool { - switch { - case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z': - return true - case '0' <= c && c <= '9': - return true - } - switch c { - case '-', '+', '.', '_': - return true - } - return false -} - -func isWhitespace(c byte) bool { - switch c { - case ' ', '\t', '\n', '\r': - return true - } - return false -} - -func isQuote(c byte) bool { - switch c { - case '"', '\'': - return true - } - return false -} diff --git a/vendor/github.com/golang/protobuf/proto/text_encode.go b/vendor/github.com/golang/protobuf/proto/text_encode.go deleted file mode 100644 index a31134ee..00000000 --- a/vendor/github.com/golang/protobuf/proto/text_encode.go +++ /dev/null @@ -1,560 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - "bytes" - "encoding" - "fmt" - "io" - "math" - "sort" - "strings" - - "google.golang.org/protobuf/encoding/prototext" - "google.golang.org/protobuf/encoding/protowire" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -const wrapTextMarshalV2 = false - -// TextMarshaler is a configurable text format marshaler. -type TextMarshaler struct { - Compact bool // use compact text format (one line) - ExpandAny bool // expand google.protobuf.Any messages of known types -} - -// Marshal writes the proto text format of m to w. -func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error { - b, err := tm.marshal(m) - if len(b) > 0 { - if _, err := w.Write(b); err != nil { - return err - } - } - return err -} - -// Text returns a proto text formatted string of m. -func (tm *TextMarshaler) Text(m Message) string { - b, _ := tm.marshal(m) - return string(b) -} - -func (tm *TextMarshaler) marshal(m Message) ([]byte, error) { - mr := MessageReflect(m) - if mr == nil || !mr.IsValid() { - return []byte(""), nil - } - - if wrapTextMarshalV2 { - if m, ok := m.(encoding.TextMarshaler); ok { - return m.MarshalText() - } - - opts := prototext.MarshalOptions{ - AllowPartial: true, - EmitUnknown: true, - } - if !tm.Compact { - opts.Indent = " " - } - if !tm.ExpandAny { - opts.Resolver = (*protoregistry.Types)(nil) - } - return opts.Marshal(mr.Interface()) - } else { - w := &textWriter{ - compact: tm.Compact, - expandAny: tm.ExpandAny, - complete: true, - } - - if m, ok := m.(encoding.TextMarshaler); ok { - b, err := m.MarshalText() - if err != nil { - return nil, err - } - w.Write(b) - return w.buf, nil - } - - err := w.writeMessage(mr) - return w.buf, err - } -} - -var ( - defaultTextMarshaler = TextMarshaler{} - compactTextMarshaler = TextMarshaler{Compact: true} -) - -// MarshalText writes the proto text format of m to w. -func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) } - -// MarshalTextString returns a proto text formatted string of m. -func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) } - -// CompactText writes the compact proto text format of m to w. -func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) } - -// CompactTextString returns a compact proto text formatted string of m. -func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) } - -var ( - newline = []byte("\n") - endBraceNewline = []byte("}\n") - posInf = []byte("inf") - negInf = []byte("-inf") - nan = []byte("nan") -) - -// textWriter is an io.Writer that tracks its indentation level. -type textWriter struct { - compact bool // same as TextMarshaler.Compact - expandAny bool // same as TextMarshaler.ExpandAny - complete bool // whether the current position is a complete line - indent int // indentation level; never negative - buf []byte -} - -func (w *textWriter) Write(p []byte) (n int, _ error) { - newlines := bytes.Count(p, newline) - if newlines == 0 { - if !w.compact && w.complete { - w.writeIndent() - } - w.buf = append(w.buf, p...) - w.complete = false - return len(p), nil - } - - frags := bytes.SplitN(p, newline, newlines+1) - if w.compact { - for i, frag := range frags { - if i > 0 { - w.buf = append(w.buf, ' ') - n++ - } - w.buf = append(w.buf, frag...) - n += len(frag) - } - return n, nil - } - - for i, frag := range frags { - if w.complete { - w.writeIndent() - } - w.buf = append(w.buf, frag...) - n += len(frag) - if i+1 < len(frags) { - w.buf = append(w.buf, '\n') - n++ - } - } - w.complete = len(frags[len(frags)-1]) == 0 - return n, nil -} - -func (w *textWriter) WriteByte(c byte) error { - if w.compact && c == '\n' { - c = ' ' - } - if !w.compact && w.complete { - w.writeIndent() - } - w.buf = append(w.buf, c) - w.complete = c == '\n' - return nil -} - -func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) { - if !w.compact && w.complete { - w.writeIndent() - } - w.complete = false - - if fd.Kind() != protoreflect.GroupKind { - w.buf = append(w.buf, fd.Name()...) - w.WriteByte(':') - } else { - // Use message type name for group field name. - w.buf = append(w.buf, fd.Message().Name()...) - } - - if !w.compact { - w.WriteByte(' ') - } -} - -func requiresQuotes(u string) bool { - // When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted. - for _, ch := range u { - switch { - case ch == '.' || ch == '/' || ch == '_': - continue - case '0' <= ch && ch <= '9': - continue - case 'A' <= ch && ch <= 'Z': - continue - case 'a' <= ch && ch <= 'z': - continue - default: - return true - } - } - return false -} - -// writeProto3Any writes an expanded google.protobuf.Any message. -// -// It returns (false, nil) if sv value can't be unmarshaled (e.g. because -// required messages are not linked in). -// -// It returns (true, error) when sv was written in expanded format or an error -// was encountered. -func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) { - md := m.Descriptor() - fdURL := md.Fields().ByName("type_url") - fdVal := md.Fields().ByName("value") - - url := m.Get(fdURL).String() - mt, err := protoregistry.GlobalTypes.FindMessageByURL(url) - if err != nil { - return false, nil - } - - b := m.Get(fdVal).Bytes() - m2 := mt.New() - if err := proto.Unmarshal(b, m2.Interface()); err != nil { - return false, nil - } - w.Write([]byte("[")) - if requiresQuotes(url) { - w.writeQuotedString(url) - } else { - w.Write([]byte(url)) - } - if w.compact { - w.Write([]byte("]:<")) - } else { - w.Write([]byte("]: <\n")) - w.indent++ - } - if err := w.writeMessage(m2); err != nil { - return true, err - } - if w.compact { - w.Write([]byte("> ")) - } else { - w.indent-- - w.Write([]byte(">\n")) - } - return true, nil -} - -func (w *textWriter) writeMessage(m protoreflect.Message) error { - md := m.Descriptor() - if w.expandAny && md.FullName() == "google.protobuf.Any" { - if canExpand, err := w.writeProto3Any(m); canExpand { - return err - } - } - - fds := md.Fields() - for i := 0; i < fds.Len(); { - fd := fds.Get(i) - if od := fd.ContainingOneof(); od != nil { - fd = m.WhichOneof(od) - i += od.Fields().Len() - } else { - i++ - } - if fd == nil || !m.Has(fd) { - continue - } - - switch { - case fd.IsList(): - lv := m.Get(fd).List() - for j := 0; j < lv.Len(); j++ { - w.writeName(fd) - v := lv.Get(j) - if err := w.writeSingularValue(v, fd); err != nil { - return err - } - w.WriteByte('\n') - } - case fd.IsMap(): - kfd := fd.MapKey() - vfd := fd.MapValue() - mv := m.Get(fd).Map() - - type entry struct{ key, val protoreflect.Value } - var entries []entry - mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { - entries = append(entries, entry{k.Value(), v}) - return true - }) - sort.Slice(entries, func(i, j int) bool { - switch kfd.Kind() { - case protoreflect.BoolKind: - return !entries[i].key.Bool() && entries[j].key.Bool() - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: - return entries[i].key.Int() < entries[j].key.Int() - case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - return entries[i].key.Uint() < entries[j].key.Uint() - case protoreflect.StringKind: - return entries[i].key.String() < entries[j].key.String() - default: - panic("invalid kind") - } - }) - for _, entry := range entries { - w.writeName(fd) - w.WriteByte('<') - if !w.compact { - w.WriteByte('\n') - } - w.indent++ - w.writeName(kfd) - if err := w.writeSingularValue(entry.key, kfd); err != nil { - return err - } - w.WriteByte('\n') - w.writeName(vfd) - if err := w.writeSingularValue(entry.val, vfd); err != nil { - return err - } - w.WriteByte('\n') - w.indent-- - w.WriteByte('>') - w.WriteByte('\n') - } - default: - w.writeName(fd) - if err := w.writeSingularValue(m.Get(fd), fd); err != nil { - return err - } - w.WriteByte('\n') - } - } - - if b := m.GetUnknown(); len(b) > 0 { - w.writeUnknownFields(b) - } - return w.writeExtensions(m) -} - -func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error { - switch fd.Kind() { - case protoreflect.FloatKind, protoreflect.DoubleKind: - switch vf := v.Float(); { - case math.IsInf(vf, +1): - w.Write(posInf) - case math.IsInf(vf, -1): - w.Write(negInf) - case math.IsNaN(vf): - w.Write(nan) - default: - fmt.Fprint(w, v.Interface()) - } - case protoreflect.StringKind: - // NOTE: This does not validate UTF-8 for historical reasons. - w.writeQuotedString(string(v.String())) - case protoreflect.BytesKind: - w.writeQuotedString(string(v.Bytes())) - case protoreflect.MessageKind, protoreflect.GroupKind: - var bra, ket byte = '<', '>' - if fd.Kind() == protoreflect.GroupKind { - bra, ket = '{', '}' - } - w.WriteByte(bra) - if !w.compact { - w.WriteByte('\n') - } - w.indent++ - m := v.Message() - if m2, ok := m.Interface().(encoding.TextMarshaler); ok { - b, err := m2.MarshalText() - if err != nil { - return err - } - w.Write(b) - } else { - w.writeMessage(m) - } - w.indent-- - w.WriteByte(ket) - case protoreflect.EnumKind: - if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil { - fmt.Fprint(w, ev.Name()) - } else { - fmt.Fprint(w, v.Enum()) - } - default: - fmt.Fprint(w, v.Interface()) - } - return nil -} - -// writeQuotedString writes a quoted string in the protocol buffer text format. -func (w *textWriter) writeQuotedString(s string) { - w.WriteByte('"') - for i := 0; i < len(s); i++ { - switch c := s[i]; c { - case '\n': - w.buf = append(w.buf, `\n`...) - case '\r': - w.buf = append(w.buf, `\r`...) - case '\t': - w.buf = append(w.buf, `\t`...) - case '"': - w.buf = append(w.buf, `\"`...) - case '\\': - w.buf = append(w.buf, `\\`...) - default: - if isPrint := c >= 0x20 && c < 0x7f; isPrint { - w.buf = append(w.buf, c) - } else { - w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...) - } - } - } - w.WriteByte('"') -} - -func (w *textWriter) writeUnknownFields(b []byte) { - if !w.compact { - fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b)) - } - - for len(b) > 0 { - num, wtyp, n := protowire.ConsumeTag(b) - if n < 0 { - return - } - b = b[n:] - - if wtyp == protowire.EndGroupType { - w.indent-- - w.Write(endBraceNewline) - continue - } - fmt.Fprint(w, num) - if wtyp != protowire.StartGroupType { - w.WriteByte(':') - } - if !w.compact || wtyp == protowire.StartGroupType { - w.WriteByte(' ') - } - switch wtyp { - case protowire.VarintType: - v, n := protowire.ConsumeVarint(b) - if n < 0 { - return - } - b = b[n:] - fmt.Fprint(w, v) - case protowire.Fixed32Type: - v, n := protowire.ConsumeFixed32(b) - if n < 0 { - return - } - b = b[n:] - fmt.Fprint(w, v) - case protowire.Fixed64Type: - v, n := protowire.ConsumeFixed64(b) - if n < 0 { - return - } - b = b[n:] - fmt.Fprint(w, v) - case protowire.BytesType: - v, n := protowire.ConsumeBytes(b) - if n < 0 { - return - } - b = b[n:] - fmt.Fprintf(w, "%q", v) - case protowire.StartGroupType: - w.WriteByte('{') - w.indent++ - default: - fmt.Fprintf(w, "/* unknown wire type %d */", wtyp) - } - w.WriteByte('\n') - } -} - -// writeExtensions writes all the extensions in m. -func (w *textWriter) writeExtensions(m protoreflect.Message) error { - md := m.Descriptor() - if md.ExtensionRanges().Len() == 0 { - return nil - } - - type ext struct { - desc protoreflect.FieldDescriptor - val protoreflect.Value - } - var exts []ext - m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - if fd.IsExtension() { - exts = append(exts, ext{fd, v}) - } - return true - }) - sort.Slice(exts, func(i, j int) bool { - return exts[i].desc.Number() < exts[j].desc.Number() - }) - - for _, ext := range exts { - // For message set, use the name of the message as the extension name. - name := string(ext.desc.FullName()) - if isMessageSet(ext.desc.ContainingMessage()) { - name = strings.TrimSuffix(name, ".message_set_extension") - } - - if !ext.desc.IsList() { - if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil { - return err - } - } else { - lv := ext.val.List() - for i := 0; i < lv.Len(); i++ { - if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil { - return err - } - } - } - } - return nil -} - -func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error { - fmt.Fprintf(w, "[%s]:", name) - if !w.compact { - w.WriteByte(' ') - } - if err := w.writeSingularValue(v, fd); err != nil { - return err - } - w.WriteByte('\n') - return nil -} - -func (w *textWriter) writeIndent() { - if !w.complete { - return - } - for i := 0; i < w.indent*2; i++ { - w.buf = append(w.buf, ' ') - } - w.complete = false -} diff --git a/vendor/github.com/golang/protobuf/proto/wire.go b/vendor/github.com/golang/protobuf/proto/wire.go deleted file mode 100644 index d7c28da5..00000000 --- a/vendor/github.com/golang/protobuf/proto/wire.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -import ( - protoV2 "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoiface" -) - -// Size returns the size in bytes of the wire-format encoding of m. -func Size(m Message) int { - if m == nil { - return 0 - } - mi := MessageV2(m) - return protoV2.Size(mi) -} - -// Marshal returns the wire-format encoding of m. -func Marshal(m Message) ([]byte, error) { - b, err := marshalAppend(nil, m, false) - if b == nil { - b = zeroBytes - } - return b, err -} - -var zeroBytes = make([]byte, 0, 0) - -func marshalAppend(buf []byte, m Message, deterministic bool) ([]byte, error) { - if m == nil { - return nil, ErrNil - } - mi := MessageV2(m) - nbuf, err := protoV2.MarshalOptions{ - Deterministic: deterministic, - AllowPartial: true, - }.MarshalAppend(buf, mi) - if err != nil { - return buf, err - } - if len(buf) == len(nbuf) { - if !mi.ProtoReflect().IsValid() { - return buf, ErrNil - } - } - return nbuf, checkRequiredNotSet(mi) -} - -// Unmarshal parses a wire-format message in b and places the decoded results in m. -// -// Unmarshal resets m before starting to unmarshal, so any existing data in m is always -// removed. Use UnmarshalMerge to preserve and append to existing data. -func Unmarshal(b []byte, m Message) error { - m.Reset() - return UnmarshalMerge(b, m) -} - -// UnmarshalMerge parses a wire-format message in b and places the decoded results in m. -func UnmarshalMerge(b []byte, m Message) error { - mi := MessageV2(m) - out, err := protoV2.UnmarshalOptions{ - AllowPartial: true, - Merge: true, - }.UnmarshalState(protoiface.UnmarshalInput{ - Buf: b, - Message: mi.ProtoReflect(), - }) - if err != nil { - return err - } - if out.Flags&protoiface.UnmarshalInitialized > 0 { - return nil - } - return checkRequiredNotSet(mi) -} diff --git a/vendor/github.com/golang/protobuf/proto/wrappers.go b/vendor/github.com/golang/protobuf/proto/wrappers.go deleted file mode 100644 index 398e3485..00000000 --- a/vendor/github.com/golang/protobuf/proto/wrappers.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proto - -// Bool stores v in a new bool value and returns a pointer to it. -func Bool(v bool) *bool { return &v } - -// Int stores v in a new int32 value and returns a pointer to it. -// -// Deprecated: Use Int32 instead. -func Int(v int) *int32 { return Int32(int32(v)) } - -// Int32 stores v in a new int32 value and returns a pointer to it. -func Int32(v int32) *int32 { return &v } - -// Int64 stores v in a new int64 value and returns a pointer to it. -func Int64(v int64) *int64 { return &v } - -// Uint32 stores v in a new uint32 value and returns a pointer to it. -func Uint32(v uint32) *uint32 { return &v } - -// Uint64 stores v in a new uint64 value and returns a pointer to it. -func Uint64(v uint64) *uint64 { return &v } - -// Float32 stores v in a new float32 value and returns a pointer to it. -func Float32(v float32) *float32 { return &v } - -// Float64 stores v in a new float64 value and returns a pointer to it. -func Float64(v float64) *float64 { return &v } - -// String stores v in a new string value and returns a pointer to it. -func String(v string) *string { return &v } diff --git a/vendor/github.com/google/uuid/CHANGELOG.md b/vendor/github.com/google/uuid/CHANGELOG.md index 2bd78667..7ec5ac7e 100644 --- a/vendor/github.com/google/uuid/CHANGELOG.md +++ b/vendor/github.com/google/uuid/CHANGELOG.md @@ -1,5 +1,36 @@ # Changelog +## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16) + + +### Features + +* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3)) + + +### Bug Fixes + +* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06)) +* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6)) + +## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12) + + +### Features + +* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29)) + +## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26) + + +### Features + +* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4)) + +### Fixes + +* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior) + ## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18) diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md index 55668887..a502fdc5 100644 --- a/vendor/github.com/google/uuid/CONTRIBUTING.md +++ b/vendor/github.com/google/uuid/CONTRIBUTING.md @@ -11,7 +11,7 @@ please explain why in the pull request description. ### Releasing -Commits that would precipitate a SemVer change, as desrcibed in the Conventional +Commits that would precipitate a SemVer change, as described in the Conventional Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action) to create a release candidate pull request. Once submitted, `release-please` will create a release. diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go index b404f4be..dc60082d 100644 --- a/vendor/github.com/google/uuid/hash.go +++ b/vendor/github.com/google/uuid/hash.go @@ -17,6 +17,12 @@ var ( NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) Nil UUID // empty UUID, all zeros + + // The Max UUID is special form of UUID that is specified to have all 128 bits set to 1. + Max = UUID{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + } ) // NewHash returns a new UUID derived from the hash of space concatenated with diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go index e6ef06cd..c3511292 100644 --- a/vendor/github.com/google/uuid/time.go +++ b/vendor/github.com/google/uuid/time.go @@ -108,12 +108,23 @@ func setClockSequence(seq int) { } // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in -// uuid. The time is only defined for version 1 and 2 UUIDs. +// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs. func (uuid UUID) Time() Time { - time := int64(binary.BigEndian.Uint32(uuid[0:4])) - time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 - time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 - return Time(time) + var t Time + switch uuid.Version() { + case 6: + time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110 + t = Time(time) + case 7: + time := binary.BigEndian.Uint64(uuid[:8]) + t = Time((time>>16)*10000 + g1582ns100) + default: // forward compatible + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + t = Time(time) + } + return t } // ClockSequence returns the clock sequence encoded in uuid. diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index a56138cc..5232b486 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -56,11 +56,15 @@ func IsInvalidLengthError(err error) bool { return ok } -// Parse decodes s into a UUID or returns an error. Both the standard UUID -// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the -// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex -// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. +// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both +// the standard UUID forms defined in RFC 4122 +// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition, +// Parse accepts non-standard strings such as the raw hex encoding +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings, +// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are +// examined in the latter case. Parse should not be used to validate strings as +// it parses non-standard encodings as indicated above. func Parse(s string) (UUID, error) { var uuid UUID switch len(s) { @@ -182,6 +186,59 @@ func Must(uuid UUID, err error) UUID { return uuid } +// Validate returns an error if s is not a properly formatted UUID in one of the following formats: +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} +// It returns an error if the format is invalid, otherwise nil. +func Validate(s string) error { + switch len(s) { + // Standard UUID format + case 36: + + // UUID with "urn:uuid:" prefix + case 36 + 9: + if !strings.EqualFold(s[:9], "urn:uuid:") { + return fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // UUID enclosed in braces + case 36 + 2: + if s[0] != '{' || s[len(s)-1] != '}' { + return fmt.Errorf("invalid bracketed UUID format") + } + s = s[1 : len(s)-1] + + // UUID without hyphens + case 32: + for i := 0; i < len(s); i += 2 { + _, ok := xtob(s[i], s[i+1]) + if !ok { + return errors.New("invalid UUID format") + } + } + + default: + return invalidLengthError{len(s)} + } + + // Check for standard UUID format + if len(s) == 36 { + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return errors.New("invalid UUID format") + } + for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} { + if _, ok := xtob(s[x], s[x+1]); !ok { + return errors.New("invalid UUID format") + } + } + } + + return nil +} + // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // , or "" if uuid is invalid. func (uuid UUID) String() string { @@ -294,3 +351,15 @@ func DisableRandPool() { poolMu.Lock() poolPos = randPoolSize } + +// UUIDs is a slice of UUID types. +type UUIDs []UUID + +// Strings returns a string slice containing the string form of each UUID in uuids. +func (uuids UUIDs) Strings() []string { + var uuidStrs = make([]string, len(uuids)) + for i, uuid := range uuids { + uuidStrs[i] = uuid.String() + } + return uuidStrs +} diff --git a/vendor/github.com/google/uuid/version6.go b/vendor/github.com/google/uuid/version6.go new file mode 100644 index 00000000..339a959a --- /dev/null +++ b/vendor/github.com/google/uuid/version6.go @@ -0,0 +1,56 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "encoding/binary" + +// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality. +// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs. +// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6 +// +// NewV6 returns a Version 6 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewV6 returns Nil and an error. +func NewV6() (UUID, error) { + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_high | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time_mid | time_low_and_version | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |clk_seq_hi_res | clk_seq_low | node (0-1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | node (2-5) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + binary.BigEndian.PutUint64(uuid[0:], uint64(now)) + binary.BigEndian.PutUint16(uuid[8:], seq) + + uuid[6] = 0x60 | (uuid[6] & 0x0F) + uuid[8] = 0x80 | (uuid[8] & 0x3F) + + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + copy(uuid[10:], nodeID[:]) + nodeMu.Unlock() + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version7.go b/vendor/github.com/google/uuid/version7.go new file mode 100644 index 00000000..3167b643 --- /dev/null +++ b/vendor/github.com/google/uuid/version7.go @@ -0,0 +1,104 @@ +// Copyright 2023 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// UUID version 7 features a time-ordered value field derived from the widely +// implemented and well known Unix Epoch timestamp source, +// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded. +// As well as improved entropy characteristics over versions 1 or 6. +// +// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7 +// +// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible. +// +// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch). +// Uses the randomness pool if it was enabled with EnableRandPool. +// On error, NewV7 returns Nil and an error +func NewV7() (UUID, error) { + uuid, err := NewRandom() + if err != nil { + return uuid, err + } + makeV7(uuid[:]) + return uuid, nil +} + +// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch). +// it use NewRandomFromReader fill random bits. +// On error, NewV7FromReader returns Nil and an error. +func NewV7FromReader(r io.Reader) (UUID, error) { + uuid, err := NewRandomFromReader(r) + if err != nil { + return uuid, err + } + + makeV7(uuid[:]) + return uuid, nil +} + +// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6]) +// uuid[8] already has the right version number (Variant is 10) +// see function NewV7 and NewV7FromReader +func makeV7(uuid []byte) { + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | ver | rand_a (12 bit seq) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |var| rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + _ = uuid[15] // bounds check + + t, s := getV7Time() + + uuid[0] = byte(t >> 40) + uuid[1] = byte(t >> 32) + uuid[2] = byte(t >> 24) + uuid[3] = byte(t >> 16) + uuid[4] = byte(t >> 8) + uuid[5] = byte(t) + + uuid[6] = 0x70 | (0x0F & byte(s>>8)) + uuid[7] = byte(s) +} + +// lastV7time is the last time we returned stored as: +// +// 52 bits of time in milliseconds since epoch +// 12 bits of (fractional nanoseconds) >> 8 +var lastV7time int64 + +const nanoPerMilli = 1000000 + +// getV7Time returns the time in milliseconds and nanoseconds / 256. +// The returned (milli << 12 + seq) is guarenteed to be greater than +// (milli << 12 + seq) returned by any previous call to getV7Time. +func getV7Time() (milli, seq int64) { + timeMu.Lock() + defer timeMu.Unlock() + + nano := timeNow().UnixNano() + milli = nano / nanoPerMilli + // Sequence number is between 0 and 3906 (nanoPerMilli>>8) + seq = (nano - milli*nanoPerMilli) >> 8 + now := milli<<12 + seq + if now <= lastV7time { + now = lastV7time + 1 + milli = now >> 12 + seq = now & 0xfff + } + lastV7time = now + return milli, seq +} diff --git a/vendor/github.com/gorilla/websocket/.editorconfig b/vendor/github.com/gorilla/websocket/.editorconfig new file mode 100644 index 00000000..2940ec92 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/.editorconfig @@ -0,0 +1,20 @@ +; https://editorconfig.org/ + +root = true + +[*] +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[{Makefile,go.mod,go.sum,*.go,.gitmodules}] +indent_style = tab +indent_size = 4 + +[*.md] +indent_size = 4 +trim_trailing_whitespace = false + +eclint_indent_style = unset diff --git a/vendor/github.com/gorilla/websocket/.gitignore b/vendor/github.com/gorilla/websocket/.gitignore index cd3fcd1e..84039fec 100644 --- a/vendor/github.com/gorilla/websocket/.gitignore +++ b/vendor/github.com/gorilla/websocket/.gitignore @@ -1,25 +1 @@ -# 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 - -.idea/ -*.iml +coverage.coverprofile diff --git a/vendor/github.com/gorilla/websocket/.golangci.yml b/vendor/github.com/gorilla/websocket/.golangci.yml new file mode 100644 index 00000000..34882139 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/.golangci.yml @@ -0,0 +1,3 @@ +run: + skip-dirs: + - examples/*.go diff --git a/vendor/github.com/gorilla/websocket/AUTHORS b/vendor/github.com/gorilla/websocket/AUTHORS deleted file mode 100644 index 1931f400..00000000 --- a/vendor/github.com/gorilla/websocket/AUTHORS +++ /dev/null @@ -1,9 +0,0 @@ -# This is the official list of Gorilla WebSocket authors for copyright -# purposes. -# -# Please keep the list sorted. - -Gary Burd -Google LLC (https://opensource.google.com/) -Joachim Bauch - diff --git a/vendor/github.com/gorilla/websocket/LICENSE b/vendor/github.com/gorilla/websocket/LICENSE index 9171c972..bb9d80bc 100644 --- a/vendor/github.com/gorilla/websocket/LICENSE +++ b/vendor/github.com/gorilla/websocket/LICENSE @@ -1,22 +1,27 @@ -Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. +Copyright (c) 2023 The Gorilla Authors. All rights reserved. Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +modification, are permitted provided that the following conditions are +met: - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gorilla/websocket/Makefile b/vendor/github.com/gorilla/websocket/Makefile new file mode 100644 index 00000000..603a63f5 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/Makefile @@ -0,0 +1,34 @@ +GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '') +GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest + +GO_SEC=$(shell which gosec 2> /dev/null || echo '') +GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest + +GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '') +GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest + +.PHONY: golangci-lint +golangci-lint: + $(if $(GO_LINT), ,go install $(GO_LINT_URI)) + @echo "##### Running golangci-lint" + golangci-lint run -v + +.PHONY: gosec +gosec: + $(if $(GO_SEC), ,go install $(GO_SEC_URI)) + @echo "##### Running gosec" + gosec -exclude-dir examples ./... + +.PHONY: govulncheck +govulncheck: + $(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI)) + @echo "##### Running govulncheck" + govulncheck ./... + +.PHONY: verify +verify: golangci-lint gosec govulncheck + +.PHONY: test +test: + @echo "##### Running tests" + go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./... diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md index 2517a287..1fd5e9c4 100644 --- a/vendor/github.com/gorilla/websocket/README.md +++ b/vendor/github.com/gorilla/websocket/README.md @@ -1,17 +1,14 @@ -# Gorilla WebSocket +# gorilla/websocket -[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) -[![CircleCI](https://circleci.com/gh/gorilla/websocket.svg?style=svg)](https://circleci.com/gh/gorilla/websocket) +![testing](https://github.com/gorilla/websocket/actions/workflows/test.yml/badge.svg) +[![codecov](https://codecov.io/github/gorilla/websocket/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/websocket) +[![godoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) +[![sourcegraph](https://sourcegraph.com/github.com/gorilla/websocket/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/websocket?badge) -Gorilla WebSocket is a [Go](http://golang.org/) implementation of the -[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. +Gorilla WebSocket is a [Go](http://golang.org/) implementation of the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. +![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5) ---- - -âš ï¸ **[The Gorilla WebSocket Package is looking for a new maintainer](https://github.com/gorilla/websocket/issues/370)** - ---- ### Documentation @@ -20,6 +17,7 @@ Gorilla WebSocket is a [Go](http://golang.org/) implementation of the * [Command example](https://github.com/gorilla/websocket/tree/master/examples/command) * [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo) * [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch) +* [Write buffer pool example](https://github.com/gorilla/websocket/tree/master/examples/bufferpool) ### Status @@ -36,4 +34,3 @@ package API is stable. The Gorilla WebSocket package passes the server tests in the [Autobahn Test Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). - diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go index 2efd8355..815b0ca5 100644 --- a/vendor/github.com/gorilla/websocket/client.go +++ b/vendor/github.com/gorilla/websocket/client.go @@ -9,14 +9,18 @@ import ( "context" "crypto/tls" "errors" + "fmt" "io" - "io/ioutil" + "log" + "net" "net/http" "net/http/httptrace" "net/url" "strings" "time" + + "golang.org/x/net/proxy" ) // ErrBadHandshake is returned when the server response to opening handshake is @@ -224,6 +228,7 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h k == "Connection" || k == "Sec-Websocket-Key" || k == "Sec-Websocket-Version" || + //#nosec G101 (CWE-798): Potential HTTP request smuggling via parameter pollution k == "Sec-Websocket-Extensions" || (k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0): return nil, nil, errors.New("websocket: duplicate header not allowed: " + k) @@ -289,7 +294,9 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h } err = c.SetDeadline(deadline) if err != nil { - c.Close() + if err := c.Close(); err != nil { + log.Printf("websocket: failed to close network connection: %v", err) + } return nil, err } return c, nil @@ -303,7 +310,7 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h return nil, nil, err } if proxyURL != nil { - dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial)) + dialer, err := proxy.FromURL(proxyURL, netDialerFunc(netDial)) if err != nil { return nil, nil, err } @@ -318,18 +325,20 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h } netConn, err := netDial("tcp", hostPort) + if err != nil { + return nil, nil, err + } if trace != nil && trace.GotConn != nil { trace.GotConn(httptrace.GotConnInfo{ Conn: netConn, }) } - if err != nil { - return nil, nil, err - } defer func() { if netConn != nil { - netConn.Close() + if err := netConn.Close(); err != nil { + log.Printf("websocket: failed to close network connection: %v", err) + } } }() @@ -370,6 +379,17 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h resp, err := http.ReadResponse(conn.br, req) if err != nil { + if d.TLSClientConfig != nil { + for _, proto := range d.TLSClientConfig.NextProtos { + if proto != "http/1.1" { + return nil, nil, fmt.Errorf( + "websocket: protocol %q was given but is not supported;"+ + "sharing tls.Config with net/http Transport can cause this error: %w", + proto, err, + ) + } + } + } return nil, nil, err } @@ -388,7 +408,7 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h // debugging. buf := make([]byte, 1024) n, _ := io.ReadFull(resp.Body, buf) - resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n])) + resp.Body = io.NopCloser(bytes.NewReader(buf[:n])) return nil, resp, ErrBadHandshake } @@ -406,17 +426,19 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h break } - resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) + resp.Body = io.NopCloser(bytes.NewReader([]byte{})) conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") - netConn.SetDeadline(time.Time{}) + if err := netConn.SetDeadline(time.Time{}); err != nil { + return nil, nil, err + } netConn = nil // to avoid close in defer. return conn, resp, nil } func cloneTLSConfig(cfg *tls.Config) *tls.Config { if cfg == nil { - return &tls.Config{} + return &tls.Config{MinVersion: tls.VersionTLS12} } return cfg.Clone() } diff --git a/vendor/github.com/gorilla/websocket/compression.go b/vendor/github.com/gorilla/websocket/compression.go index 813ffb1e..9fed0ef5 100644 --- a/vendor/github.com/gorilla/websocket/compression.go +++ b/vendor/github.com/gorilla/websocket/compression.go @@ -8,6 +8,7 @@ import ( "compress/flate" "errors" "io" + "log" "strings" "sync" ) @@ -33,7 +34,9 @@ func decompressNoContextTakeover(r io.Reader) io.ReadCloser { "\x01\x00\x00\xff\xff" fr, _ := flateReaderPool.Get().(io.ReadCloser) - fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil) + if err := fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil); err != nil { + panic(err) + } return &flateReadWrapper{fr} } @@ -132,7 +135,9 @@ func (r *flateReadWrapper) Read(p []byte) (int, error) { // Preemptively place the reader back in the pool. This helps with // scenarios where the application does not call NextReader() soon after // this final read. - r.Close() + if err := r.Close(); err != nil { + log.Printf("websocket: flateReadWrapper.Close() returned error: %v", err) + } } return n, err } diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go index 331eebc8..221e6cf7 100644 --- a/vendor/github.com/gorilla/websocket/conn.go +++ b/vendor/github.com/gorilla/websocket/conn.go @@ -6,11 +6,11 @@ package websocket import ( "bufio" + "crypto/rand" "encoding/binary" "errors" "io" - "io/ioutil" - "math/rand" + "log" "net" "strconv" "strings" @@ -181,13 +181,20 @@ var ( errInvalidControlFrame = errors.New("websocket: invalid control frame") ) +// maskRand is an io.Reader for generating mask bytes. The reader is initialized +// to crypto/rand Reader. Tests swap the reader to a math/rand reader for +// reproducible results. +var maskRand = rand.Reader + +// newMaskKey returns a new 32 bit value for masking client frames. func newMaskKey() [4]byte { - n := rand.Uint32() - return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} + var k [4]byte + _, _ = io.ReadFull(maskRand, k[:]) + return k } func hideTempErr(err error) error { - if e, ok := err.(net.Error); ok && e.Temporary() { + if e, ok := err.(net.Error); ok { err = &netError{msg: e.Error(), timeout: e.Timeout()} } return err @@ -372,7 +379,9 @@ func (c *Conn) read(n int) ([]byte, error) { if err == io.EOF { err = errUnexpectedEOF } - c.br.Discard(len(p)) + if _, err := c.br.Discard(len(p)); err != nil { + return p, err + } return p, err } @@ -387,7 +396,9 @@ func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error return err } - c.conn.SetWriteDeadline(deadline) + if err := c.conn.SetWriteDeadline(deadline); err != nil { + return c.writeFatal(err) + } if len(buf1) == 0 { _, err = c.conn.Write(buf0) } else { @@ -397,7 +408,7 @@ func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error return c.writeFatal(err) } if frameType == CloseMessage { - c.writeFatal(ErrCloseSent) + _ = c.writeFatal(ErrCloseSent) } return nil } @@ -438,7 +449,7 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er d := 1000 * time.Hour if !deadline.IsZero() { - d = deadline.Sub(time.Now()) + d = time.Until(deadline) if d < 0 { return errWriteTimeout } @@ -460,13 +471,15 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er return err } - c.conn.SetWriteDeadline(deadline) + if err := c.conn.SetWriteDeadline(deadline); err != nil { + return c.writeFatal(err) + } _, err = c.conn.Write(buf) if err != nil { return c.writeFatal(err) } if messageType == CloseMessage { - c.writeFatal(ErrCloseSent) + _ = c.writeFatal(ErrCloseSent) } return err } @@ -477,7 +490,9 @@ func (c *Conn) beginMessage(mw *messageWriter, messageType int) error { // probably better to return an error in this situation, but we cannot // change this without breaking existing applications. if c.writer != nil { - c.writer.Close() + if err := c.writer.Close(); err != nil { + log.Printf("websocket: discarding writer close error: %v", err) + } c.writer = nil } @@ -630,7 +645,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error { } if final { - w.endMessage(errWriteClosed) + _ = w.endMessage(errWriteClosed) return nil } @@ -795,7 +810,7 @@ func (c *Conn) advanceFrame() (int, error) { // 1. Skip remainder of previous frame. if c.readRemaining > 0 { - if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil { + if _, err := io.CopyN(io.Discard, c.br, c.readRemaining); err != nil { return noFrame, err } } @@ -817,7 +832,9 @@ func (c *Conn) advanceFrame() (int, error) { rsv2 := p[0]&rsv2Bit != 0 rsv3 := p[0]&rsv3Bit != 0 mask := p[1]&maskBit != 0 - c.setReadRemaining(int64(p[1] & 0x7f)) + if err := c.setReadRemaining(int64(p[1] & 0x7f)); err != nil { + return noFrame, err + } c.readDecompress = false if rsv1 { @@ -922,7 +939,9 @@ func (c *Conn) advanceFrame() (int, error) { } if c.readLimit > 0 && c.readLength > c.readLimit { - c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)) + if err := c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)); err != nil { + return noFrame, err + } return noFrame, ErrReadLimit } @@ -934,7 +953,9 @@ func (c *Conn) advanceFrame() (int, error) { var payload []byte if c.readRemaining > 0 { payload, err = c.read(int(c.readRemaining)) - c.setReadRemaining(0) + if err := c.setReadRemaining(0); err != nil { + return noFrame, err + } if err != nil { return noFrame, err } @@ -981,7 +1002,9 @@ func (c *Conn) handleProtocolError(message string) error { if len(data) > maxControlFramePayloadSize { data = data[:maxControlFramePayloadSize] } - c.WriteControl(CloseMessage, data, time.Now().Add(writeWait)) + if err := c.WriteControl(CloseMessage, data, time.Now().Add(writeWait)); err != nil { + return err + } return errors.New("websocket: " + message) } @@ -998,7 +1021,9 @@ func (c *Conn) handleProtocolError(message string) error { func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { // Close previous reader, only relevant for decompression. if c.reader != nil { - c.reader.Close() + if err := c.reader.Close(); err != nil { + log.Printf("websocket: discarding reader close error: %v", err) + } c.reader = nil } @@ -1054,7 +1079,9 @@ func (r *messageReader) Read(b []byte) (int, error) { } rem := c.readRemaining rem -= int64(n) - c.setReadRemaining(rem) + if err := c.setReadRemaining(rem); err != nil { + return 0, err + } if c.readRemaining > 0 && c.readErr == io.EOF { c.readErr = errUnexpectedEOF } @@ -1094,7 +1121,7 @@ func (c *Conn) ReadMessage() (messageType int, p []byte, err error) { if err != nil { return messageType, nil, err } - p, err = ioutil.ReadAll(r) + p, err = io.ReadAll(r) return messageType, p, err } @@ -1136,7 +1163,9 @@ func (c *Conn) SetCloseHandler(h func(code int, text string) error) { if h == nil { h = func(code int, text string) error { message := FormatCloseMessage(code, "") - c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)) + if err := c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)); err != nil { + return err + } return nil } } @@ -1161,7 +1190,7 @@ func (c *Conn) SetPingHandler(h func(appData string) error) { err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait)) if err == ErrCloseSent { return nil - } else if e, ok := err.(net.Error); ok && e.Temporary() { + } else if _, ok := err.(net.Error); ok { return nil } return err @@ -1189,8 +1218,16 @@ func (c *Conn) SetPongHandler(h func(appData string) error) { c.handlePong = h } +// NetConn returns the underlying connection that is wrapped by c. +// Note that writing to or reading from this connection directly will corrupt the +// WebSocket connection. +func (c *Conn) NetConn() net.Conn { + return c.conn +} + // UnderlyingConn returns the internal net.Conn. This can be used to further // modifications to connection specific flags. +// Deprecated: Use the NetConn method. func (c *Conn) UnderlyingConn() net.Conn { return c.conn } diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go index d0742bf2..67d0968b 100644 --- a/vendor/github.com/gorilla/websocket/mask.go +++ b/vendor/github.com/gorilla/websocket/mask.go @@ -9,6 +9,7 @@ package websocket import "unsafe" +// #nosec G103 -- (CWE-242) Has been audited const wordSize = int(unsafe.Sizeof(uintptr(0))) func maskBytes(key [4]byte, pos int, b []byte) int { @@ -22,6 +23,7 @@ func maskBytes(key [4]byte, pos int, b []byte) int { } // Mask one byte at a time to word boundary. + //#nosec G103 -- (CWE-242) Has been audited if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 { n = wordSize - n for i := range b[:n] { @@ -36,11 +38,13 @@ func maskBytes(key [4]byte, pos int, b []byte) int { for i := range k { k[i] = key[(pos+i)&3] } + //#nosec G103 -- (CWE-242) Has been audited kw := *(*uintptr)(unsafe.Pointer(&k)) // Mask one word at a time. n := (len(b) / wordSize) * wordSize for i := 0; i < n; i += wordSize { + //#nosec G103 -- (CWE-242) Has been audited *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw } diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go index e0f466b7..80f55d1e 100644 --- a/vendor/github.com/gorilla/websocket/proxy.go +++ b/vendor/github.com/gorilla/websocket/proxy.go @@ -8,10 +8,13 @@ import ( "bufio" "encoding/base64" "errors" + "log" "net" "net/http" "net/url" "strings" + + "golang.org/x/net/proxy" ) type netDialerFunc func(network, addr string) (net.Conn, error) @@ -21,7 +24,7 @@ func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) { } func init() { - proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { + proxy.RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy.Dialer) (proxy.Dialer, error) { return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil }) } @@ -55,7 +58,9 @@ func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) } if err := connectReq.Write(conn); err != nil { - conn.Close() + if err := conn.Close(); err != nil { + log.Printf("httpProxyDialer: failed to close connection: %v", err) + } return nil, err } @@ -64,12 +69,16 @@ func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) br := bufio.NewReader(conn) resp, err := http.ReadResponse(br, connectReq) if err != nil { - conn.Close() + if err := conn.Close(); err != nil { + log.Printf("httpProxyDialer: failed to close connection: %v", err) + } return nil, err } if resp.StatusCode != 200 { - conn.Close() + if err := conn.Close(); err != nil { + log.Printf("httpProxyDialer: failed to close connection: %v", err) + } f := strings.SplitN(resp.Status, " ", 2) return nil, errors.New(f[1]) } diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go index 24d53b38..1e720e1d 100644 --- a/vendor/github.com/gorilla/websocket/server.go +++ b/vendor/github.com/gorilla/websocket/server.go @@ -8,6 +8,7 @@ import ( "bufio" "errors" "io" + "log" "net/http" "net/url" "strings" @@ -154,8 +155,8 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade } challengeKey := r.Header.Get("Sec-Websocket-Key") - if challengeKey == "" { - return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header is missing or blank") + if !isValidChallengeKey(challengeKey) { + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header must be Base64 encoded value of 16-byte in length") } subprotocol := u.selectSubprotocol(r, responseHeader) @@ -183,7 +184,9 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade } if brw.Reader.Buffered() > 0 { - netConn.Close() + if err := netConn.Close(); err != nil { + log.Printf("websocket: failed to close network connection: %v", err) + } return nil, errors.New("websocket: client sent data before handshake is complete") } @@ -248,17 +251,34 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade p = append(p, "\r\n"...) // Clear deadlines set by HTTP server. - netConn.SetDeadline(time.Time{}) + if err := netConn.SetDeadline(time.Time{}); err != nil { + if err := netConn.Close(); err != nil { + log.Printf("websocket: failed to close network connection: %v", err) + } + return nil, err + } if u.HandshakeTimeout > 0 { - netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)) + if err := netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)); err != nil { + if err := netConn.Close(); err != nil { + log.Printf("websocket: failed to close network connection: %v", err) + } + return nil, err + } } if _, err = netConn.Write(p); err != nil { - netConn.Close() + if err := netConn.Close(); err != nil { + log.Printf("websocket: failed to close network connection: %v", err) + } return nil, err } if u.HandshakeTimeout > 0 { - netConn.SetWriteDeadline(time.Time{}) + if err := netConn.SetWriteDeadline(time.Time{}); err != nil { + if err := netConn.Close(); err != nil { + log.Printf("websocket: failed to close network connection: %v", err) + } + return nil, err + } } return c, nil @@ -356,8 +376,12 @@ func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte { // bufio.Writer's underlying writer. var wh writeHook bw.Reset(&wh) - bw.WriteByte(0) - bw.Flush() + if err := bw.WriteByte(0); err != nil { + panic(err) + } + if err := bw.Flush(); err != nil { + log.Printf("websocket: bufioWriterBuffer: Flush: %v", err) + } bw.Reset(originalWriter) diff --git a/vendor/github.com/gorilla/websocket/tls_handshake.go b/vendor/github.com/gorilla/websocket/tls_handshake.go index a62b68cc..7f386453 100644 --- a/vendor/github.com/gorilla/websocket/tls_handshake.go +++ b/vendor/github.com/gorilla/websocket/tls_handshake.go @@ -1,6 +1,3 @@ -//go:build go1.17 -// +build go1.17 - package websocket import ( diff --git a/vendor/github.com/gorilla/websocket/tls_handshake_116.go b/vendor/github.com/gorilla/websocket/tls_handshake_116.go deleted file mode 100644 index e1b2b44f..00000000 --- a/vendor/github.com/gorilla/websocket/tls_handshake_116.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !go1.17 -// +build !go1.17 - -package websocket - -import ( - "context" - "crypto/tls" -) - -func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error { - if err := tlsConn.Handshake(); err != nil { - return err - } - if !cfg.InsecureSkipVerify { - if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go index 7bf2f66c..9b1a629b 100644 --- a/vendor/github.com/gorilla/websocket/util.go +++ b/vendor/github.com/gorilla/websocket/util.go @@ -6,7 +6,7 @@ package websocket import ( "crypto/rand" - "crypto/sha1" + "crypto/sha1" //#nosec G505 -- (CWE-327) https://datatracker.ietf.org/doc/html/rfc6455#page-54 "encoding/base64" "io" "net/http" @@ -17,7 +17,7 @@ import ( var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") func computeAcceptKey(challengeKey string) string { - h := sha1.New() + h := sha1.New() //#nosec G401 -- (CWE-326) https://datatracker.ietf.org/doc/html/rfc6455#page-54 h.Write([]byte(challengeKey)) h.Write(keyGUID) return base64.StdEncoding.EncodeToString(h.Sum(nil)) @@ -281,3 +281,18 @@ headers: } return result } + +// isValidChallengeKey checks if the argument meets RFC6455 specification. +func isValidChallengeKey(s string) bool { + // From RFC6455: + // + // A |Sec-WebSocket-Key| header field with a base64-encoded (see + // Section 4 of [RFC4648]) value that, when decoded, is 16 bytes in + // length. + + if s == "" { + return false + } + decoded, err := base64.StdEncoding.DecodeString(s) + return err == nil && len(decoded) == 16 +} diff --git a/vendor/github.com/gorilla/websocket/x_net_proxy.go b/vendor/github.com/gorilla/websocket/x_net_proxy.go deleted file mode 100644 index 2e668f6b..00000000 --- a/vendor/github.com/gorilla/websocket/x_net_proxy.go +++ /dev/null @@ -1,473 +0,0 @@ -// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. -//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy - -// Package proxy provides support for a variety of protocols to proxy network -// data. -// - -package websocket - -import ( - "errors" - "io" - "net" - "net/url" - "os" - "strconv" - "strings" - "sync" -) - -type proxy_direct struct{} - -// Direct is a direct proxy: one that makes network connections directly. -var proxy_Direct = proxy_direct{} - -func (proxy_direct) Dial(network, addr string) (net.Conn, error) { - return net.Dial(network, addr) -} - -// A PerHost directs connections to a default Dialer unless the host name -// requested matches one of a number of exceptions. -type proxy_PerHost struct { - def, bypass proxy_Dialer - - bypassNetworks []*net.IPNet - bypassIPs []net.IP - bypassZones []string - bypassHosts []string -} - -// NewPerHost returns a PerHost Dialer that directs connections to either -// defaultDialer or bypass, depending on whether the connection matches one of -// the configured rules. -func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost { - return &proxy_PerHost{ - def: defaultDialer, - bypass: bypass, - } -} - -// Dial connects to the address addr on the given network through either -// defaultDialer or bypass. -func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) { - host, _, err := net.SplitHostPort(addr) - if err != nil { - return nil, err - } - - return p.dialerForRequest(host).Dial(network, addr) -} - -func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer { - if ip := net.ParseIP(host); ip != nil { - for _, net := range p.bypassNetworks { - if net.Contains(ip) { - return p.bypass - } - } - for _, bypassIP := range p.bypassIPs { - if bypassIP.Equal(ip) { - return p.bypass - } - } - return p.def - } - - for _, zone := range p.bypassZones { - if strings.HasSuffix(host, zone) { - return p.bypass - } - if host == zone[1:] { - // For a zone ".example.com", we match "example.com" - // too. - return p.bypass - } - } - for _, bypassHost := range p.bypassHosts { - if bypassHost == host { - return p.bypass - } - } - return p.def -} - -// AddFromString parses a string that contains comma-separated values -// specifying hosts that should use the bypass proxy. Each value is either an -// IP address, a CIDR range, a zone (*.example.com) or a host name -// (localhost). A best effort is made to parse the string and errors are -// ignored. -func (p *proxy_PerHost) AddFromString(s string) { - hosts := strings.Split(s, ",") - for _, host := range hosts { - host = strings.TrimSpace(host) - if len(host) == 0 { - continue - } - if strings.Contains(host, "/") { - // We assume that it's a CIDR address like 127.0.0.0/8 - if _, net, err := net.ParseCIDR(host); err == nil { - p.AddNetwork(net) - } - continue - } - if ip := net.ParseIP(host); ip != nil { - p.AddIP(ip) - continue - } - if strings.HasPrefix(host, "*.") { - p.AddZone(host[1:]) - continue - } - p.AddHost(host) - } -} - -// AddIP specifies an IP address that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match an IP. -func (p *proxy_PerHost) AddIP(ip net.IP) { - p.bypassIPs = append(p.bypassIPs, ip) -} - -// AddNetwork specifies an IP range that will use the bypass proxy. Note that -// this will only take effect if a literal IP address is dialed. A connection -// to a named host will never match. -func (p *proxy_PerHost) AddNetwork(net *net.IPNet) { - p.bypassNetworks = append(p.bypassNetworks, net) -} - -// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of -// "example.com" matches "example.com" and all of its subdomains. -func (p *proxy_PerHost) AddZone(zone string) { - if strings.HasSuffix(zone, ".") { - zone = zone[:len(zone)-1] - } - if !strings.HasPrefix(zone, ".") { - zone = "." + zone - } - p.bypassZones = append(p.bypassZones, zone) -} - -// AddHost specifies a host name that will use the bypass proxy. -func (p *proxy_PerHost) AddHost(host string) { - if strings.HasSuffix(host, ".") { - host = host[:len(host)-1] - } - p.bypassHosts = append(p.bypassHosts, host) -} - -// A Dialer is a means to establish a connection. -type proxy_Dialer interface { - // Dial connects to the given address via the proxy. - Dial(network, addr string) (c net.Conn, err error) -} - -// Auth contains authentication parameters that specific Dialers may require. -type proxy_Auth struct { - User, Password string -} - -// FromEnvironment returns the dialer specified by the proxy related variables in -// the environment. -func proxy_FromEnvironment() proxy_Dialer { - allProxy := proxy_allProxyEnv.Get() - if len(allProxy) == 0 { - return proxy_Direct - } - - proxyURL, err := url.Parse(allProxy) - if err != nil { - return proxy_Direct - } - proxy, err := proxy_FromURL(proxyURL, proxy_Direct) - if err != nil { - return proxy_Direct - } - - noProxy := proxy_noProxyEnv.Get() - if len(noProxy) == 0 { - return proxy - } - - perHost := proxy_NewPerHost(proxy, proxy_Direct) - perHost.AddFromString(noProxy) - return perHost -} - -// proxySchemes is a map from URL schemes to a function that creates a Dialer -// from a URL with such a scheme. -var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error) - -// RegisterDialerType takes a URL scheme and a function to generate Dialers from -// a URL with that scheme and a forwarding Dialer. Registered schemes are used -// by FromURL. -func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) { - if proxy_proxySchemes == nil { - proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) - } - proxy_proxySchemes[scheme] = f -} - -// FromURL returns a Dialer given a URL specification and an underlying -// Dialer for it to make network requests. -func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) { - var auth *proxy_Auth - if u.User != nil { - auth = new(proxy_Auth) - auth.User = u.User.Username() - if p, ok := u.User.Password(); ok { - auth.Password = p - } - } - - switch u.Scheme { - case "socks5": - return proxy_SOCKS5("tcp", u.Host, auth, forward) - } - - // If the scheme doesn't match any of the built-in schemes, see if it - // was registered by another package. - if proxy_proxySchemes != nil { - if f, ok := proxy_proxySchemes[u.Scheme]; ok { - return f(u, forward) - } - } - - return nil, errors.New("proxy: unknown scheme: " + u.Scheme) -} - -var ( - proxy_allProxyEnv = &proxy_envOnce{ - names: []string{"ALL_PROXY", "all_proxy"}, - } - proxy_noProxyEnv = &proxy_envOnce{ - names: []string{"NO_PROXY", "no_proxy"}, - } -) - -// envOnce looks up an environment variable (optionally by multiple -// names) once. It mitigates expensive lookups on some platforms -// (e.g. Windows). -// (Borrowed from net/http/transport.go) -type proxy_envOnce struct { - names []string - once sync.Once - val string -} - -func (e *proxy_envOnce) Get() string { - e.once.Do(e.init) - return e.val -} - -func (e *proxy_envOnce) init() { - for _, n := range e.names { - e.val = os.Getenv(n) - if e.val != "" { - return - } - } -} - -// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address -// with an optional username and password. See RFC 1928 and RFC 1929. -func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) { - s := &proxy_socks5{ - network: network, - addr: addr, - forward: forward, - } - if auth != nil { - s.user = auth.User - s.password = auth.Password - } - - return s, nil -} - -type proxy_socks5 struct { - user, password string - network, addr string - forward proxy_Dialer -} - -const proxy_socks5Version = 5 - -const ( - proxy_socks5AuthNone = 0 - proxy_socks5AuthPassword = 2 -) - -const proxy_socks5Connect = 1 - -const ( - proxy_socks5IP4 = 1 - proxy_socks5Domain = 3 - proxy_socks5IP6 = 4 -) - -var proxy_socks5Errors = []string{ - "", - "general failure", - "connection forbidden", - "network unreachable", - "host unreachable", - "connection refused", - "TTL expired", - "command not supported", - "address type not supported", -} - -// Dial connects to the address addr on the given network via the SOCKS5 proxy. -func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) { - switch network { - case "tcp", "tcp6", "tcp4": - default: - return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network) - } - - conn, err := s.forward.Dial(s.network, s.addr) - if err != nil { - return nil, err - } - if err := s.connect(conn, addr); err != nil { - conn.Close() - return nil, err - } - return conn, nil -} - -// connect takes an existing connection to a socks5 proxy server, -// and commands the server to extend that connection to target, -// which must be a canonical address with a host and port. -func (s *proxy_socks5) connect(conn net.Conn, target string) error { - host, portStr, err := net.SplitHostPort(target) - if err != nil { - return err - } - - port, err := strconv.Atoi(portStr) - if err != nil { - return errors.New("proxy: failed to parse port number: " + portStr) - } - if port < 1 || port > 0xffff { - return errors.New("proxy: port number out of range: " + portStr) - } - - // the size here is just an estimate - buf := make([]byte, 0, 6+len(host)) - - buf = append(buf, proxy_socks5Version) - if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { - buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword) - } else { - buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone) - } - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - if buf[0] != 5 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) - } - if buf[1] == 0xff { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") - } - - // See RFC 1929 - if buf[1] == proxy_socks5AuthPassword { - buf = buf[:0] - buf = append(buf, 1 /* password protocol version */) - buf = append(buf, uint8(len(s.user))) - buf = append(buf, s.user...) - buf = append(buf, uint8(len(s.password))) - buf = append(buf, s.password...) - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if buf[1] != 0 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password") - } - } - - buf = buf[:0] - buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */) - - if ip := net.ParseIP(host); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - buf = append(buf, proxy_socks5IP4) - ip = ip4 - } else { - buf = append(buf, proxy_socks5IP6) - } - buf = append(buf, ip...) - } else { - if len(host) > 255 { - return errors.New("proxy: destination host name too long: " + host) - } - buf = append(buf, proxy_socks5Domain) - buf = append(buf, byte(len(host))) - buf = append(buf, host...) - } - buf = append(buf, byte(port>>8), byte(port)) - - if _, err := conn.Write(buf); err != nil { - return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - if _, err := io.ReadFull(conn, buf[:4]); err != nil { - return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - failure := "unknown error" - if int(buf[1]) < len(proxy_socks5Errors) { - failure = proxy_socks5Errors[buf[1]] - } - - if len(failure) > 0 { - return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure) - } - - bytesToDiscard := 0 - switch buf[3] { - case proxy_socks5IP4: - bytesToDiscard = net.IPv4len - case proxy_socks5IP6: - bytesToDiscard = net.IPv6len - case proxy_socks5Domain: - _, err := io.ReadFull(conn, buf[:1]) - if err != nil { - return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - bytesToDiscard = int(buf[0]) - default: - return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr) - } - - if cap(buf) < bytesToDiscard { - buf = make([]byte, bytesToDiscard) - } else { - buf = buf[:bytesToDiscard] - } - if _, err := io.ReadFull(conn, buf); err != nil { - return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - // Also need to discard the port number - if _, err := io.ReadFull(conn, buf[:2]); err != nil { - return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error()) - } - - return nil -} diff --git a/vendor/github.com/hashicorp/go-hclog/README.md b/vendor/github.com/hashicorp/go-hclog/README.md index 21a17c5a..983d44c7 100644 --- a/vendor/github.com/hashicorp/go-hclog/README.md +++ b/vendor/github.com/hashicorp/go-hclog/README.md @@ -140,9 +140,10 @@ log.Printf("[DEBUG] %d", 42) ... [DEBUG] my-app: 42 ``` -Notice that if `appLogger` is initialized with the `INFO` log level _and_ you +Notice that if `appLogger` is initialized with the `INFO` log level, _and_ you specify `InferLevels: true`, you will not see any output here. You must change `appLogger` to `DEBUG` to see output. See the docs for more information. If the log lines start with a timestamp you can use the -`InferLevelsWithTimestamp` option to try and ignore them. +`InferLevelsWithTimestamp` option to try and ignore them. Please note that in order +for `InferLevelsWithTimestamp` to be relevant, `InferLevels` must be set to `true`. diff --git a/vendor/github.com/hashicorp/go-hclog/intlogger.go b/vendor/github.com/hashicorp/go-hclog/intlogger.go index b45064ac..272a710c 100644 --- a/vendor/github.com/hashicorp/go-hclog/intlogger.go +++ b/vendor/github.com/hashicorp/go-hclog/intlogger.go @@ -55,23 +55,38 @@ var ( faintBoldColor = color.New(color.Faint, color.Bold) faintColor = color.New(color.Faint) - faintMultiLinePrefix = faintColor.Sprint(" | ") - faintFieldSeparator = faintColor.Sprint("=") - faintFieldSeparatorWithNewLine = faintColor.Sprint("=\n") + faintMultiLinePrefix string + faintFieldSeparator string + faintFieldSeparatorWithNewLine string ) +func init() { + // Force all the colors to enabled because we do our own detection of color usage. + for _, c := range _levelToColor { + c.EnableColor() + } + + faintBoldColor.EnableColor() + faintColor.EnableColor() + + faintMultiLinePrefix = faintColor.Sprint(" | ") + faintFieldSeparator = faintColor.Sprint("=") + faintFieldSeparatorWithNewLine = faintColor.Sprint("=\n") +} + // Make sure that intLogger is a Logger var _ Logger = &intLogger{} // intLogger is an internal logger implementation. Internal in that it is // defined entirely by this package. type intLogger struct { - json bool - callerOffset int - name string - timeFormat string - timeFn TimeFunction - disableTime bool + json bool + jsonEscapeEnabled bool + callerOffset int + name string + timeFormat string + timeFn TimeFunction + disableTime bool // This is an interface so that it's shared by any derived loggers, since // those derived loggers share the bufio.Writer as well. @@ -79,6 +94,19 @@ type intLogger struct { writer *writer level *int32 + // The value of curEpoch when our level was set + setEpoch uint64 + + // The value of curEpoch the last time we performed the level sync process + ownEpoch uint64 + + // Shared amongst all the loggers created in this hierachy, used to determine + // if the level sync process should be run by comparing it with ownEpoch + curEpoch *uint64 + + // The logger this one was created from. Only set when syncParentLevel is set + parent *intLogger + headerColor ColorOption fieldColor ColorOption @@ -88,6 +116,7 @@ type intLogger struct { // create subloggers with their own level setting independentLevels bool + syncParentLevel bool subloggerHook func(sub Logger) Logger } @@ -129,9 +158,9 @@ func newLogger(opts *LoggerOptions) *intLogger { } var ( - primaryColor ColorOption = ColorOff - headerColor ColorOption = ColorOff - fieldColor ColorOption = ColorOff + primaryColor = ColorOff + headerColor = ColorOff + fieldColor = ColorOff ) switch { case opts.ColorHeaderOnly: @@ -145,6 +174,7 @@ func newLogger(opts *LoggerOptions) *intLogger { l := &intLogger{ json: opts.JSONFormat, + jsonEscapeEnabled: !opts.JSONEscapeDisabled, name: opts.Name, timeFormat: TimeFormat, timeFn: time.Now, @@ -152,8 +182,10 @@ func newLogger(opts *LoggerOptions) *intLogger { mutex: mutex, writer: newWriter(output, primaryColor), level: new(int32), + curEpoch: new(uint64), exclude: opts.Exclude, independentLevels: opts.IndependentLevels, + syncParentLevel: opts.SyncParentLevel, headerColor: headerColor, fieldColor: fieldColor, subloggerHook: opts.SubloggerHook, @@ -194,7 +226,7 @@ const offsetIntLogger = 3 // Log a message and a set of key/value pairs if the given level is at // or more severe that the threshold configured in the Logger. func (l *intLogger) log(name string, level Level, msg string, args ...interface{}) { - if level < Level(atomic.LoadInt32(l.level)) { + if level < l.GetLevel() { return } @@ -597,7 +629,7 @@ func (l *intLogger) logJSON(t time.Time, name string, level Level, msg string, a vals := l.jsonMapEntry(t, name, level, msg) args = append(l.implied, args...) - if args != nil && len(args) > 0 { + if len(args) > 0 { if len(args)%2 != 0 { cs, ok := args[len(args)-1].(CapturedStacktrace) if ok { @@ -637,13 +669,17 @@ func (l *intLogger) logJSON(t time.Time, name string, level Level, msg string, a } } - err := json.NewEncoder(l.writer).Encode(vals) + encoder := json.NewEncoder(l.writer) + encoder.SetEscapeHTML(l.jsonEscapeEnabled) + err := encoder.Encode(vals) if err != nil { if _, ok := err.(*json.UnsupportedTypeError); ok { plainVal := l.jsonMapEntry(t, name, level, msg) plainVal["@warn"] = errJsonUnsupportedTypeMsg - json.NewEncoder(l.writer).Encode(plainVal) + errEncoder := json.NewEncoder(l.writer) + errEncoder.SetEscapeHTML(l.jsonEscapeEnabled) + errEncoder.Encode(plainVal) } } } @@ -718,27 +754,27 @@ func (l *intLogger) Error(msg string, args ...interface{}) { // Indicate that the logger would emit TRACE level logs func (l *intLogger) IsTrace() bool { - return Level(atomic.LoadInt32(l.level)) == Trace + return l.GetLevel() == Trace } // Indicate that the logger would emit DEBUG level logs func (l *intLogger) IsDebug() bool { - return Level(atomic.LoadInt32(l.level)) <= Debug + return l.GetLevel() <= Debug } // Indicate that the logger would emit INFO level logs func (l *intLogger) IsInfo() bool { - return Level(atomic.LoadInt32(l.level)) <= Info + return l.GetLevel() <= Info } // Indicate that the logger would emit WARN level logs func (l *intLogger) IsWarn() bool { - return Level(atomic.LoadInt32(l.level)) <= Warn + return l.GetLevel() <= Warn } // Indicate that the logger would emit ERROR level logs func (l *intLogger) IsError() bool { - return Level(atomic.LoadInt32(l.level)) <= Error + return l.GetLevel() <= Error } const MissingKey = "EXTRA_VALUE_AT_END" @@ -854,12 +890,63 @@ func (l *intLogger) resetOutput(opts *LoggerOptions) error { // Update the logging level on-the-fly. This will affect all subloggers as // well. func (l *intLogger) SetLevel(level Level) { - atomic.StoreInt32(l.level, int32(level)) + if !l.syncParentLevel { + atomic.StoreInt32(l.level, int32(level)) + return + } + + nsl := new(int32) + *nsl = int32(level) + + l.level = nsl + + l.ownEpoch = atomic.AddUint64(l.curEpoch, 1) + l.setEpoch = l.ownEpoch +} + +func (l *intLogger) searchLevelPtr() *int32 { + p := l.parent + + ptr := l.level + + max := l.setEpoch + + for p != nil { + if p.setEpoch > max { + max = p.setEpoch + ptr = p.level + } + + p = p.parent + } + + return ptr } // Returns the current level func (l *intLogger) GetLevel() Level { - return Level(atomic.LoadInt32(l.level)) + // We perform the loads immediately to keep the CPU pipeline busy, which + // effectively makes the second load cost nothing. Once loaded into registers + // the comparison returns the already loaded value. The comparison is almost + // always true, so the branch predictor should hit consistently with it. + var ( + curEpoch = atomic.LoadUint64(l.curEpoch) + level = Level(atomic.LoadInt32(l.level)) + own = l.ownEpoch + ) + + if curEpoch == own { + return level + } + + // Perform the level sync process. We'll avoid doing this next time by seeing the + // epoch as current. + + ptr := l.searchLevelPtr() + l.level = ptr + l.ownEpoch = curEpoch + + return Level(atomic.LoadInt32(ptr)) } // Create a *log.Logger that will send it's data through this Logger. This @@ -912,6 +999,8 @@ func (l *intLogger) copy() *intLogger { if l.independentLevels { sl.level = new(int32) *sl.level = *l.level + } else if l.syncParentLevel { + sl.parent = l } return &sl diff --git a/vendor/github.com/hashicorp/go-hclog/logger.go b/vendor/github.com/hashicorp/go-hclog/logger.go index 947ac0c9..ad17544f 100644 --- a/vendor/github.com/hashicorp/go-hclog/logger.go +++ b/vendor/github.com/hashicorp/go-hclog/logger.go @@ -233,6 +233,7 @@ type StandardLoggerOptions struct { // [DEBUG] and strip it off before reapplying it. // The timestamp detection may result in false positives and incomplete // string outputs. + // InferLevelsWithTimestamp is only relevant if InferLevels is true. InferLevelsWithTimestamp bool // ForceLevel is used to force all output from the standard logger to be at @@ -263,6 +264,9 @@ type LoggerOptions struct { // Control if the output should be in JSON. JSONFormat bool + // Control the escape switch of json.Encoder + JSONEscapeDisabled bool + // Include file and line information in each log line IncludeLocation bool @@ -303,6 +307,24 @@ type LoggerOptions struct { // will not affect the parent or sibling loggers. IndependentLevels bool + // When set, changing the level of a logger effects only it's direct sub-loggers + // rather than all sub-loggers. For example: + // a := logger.Named("a") + // a.SetLevel(Error) + // b := a.Named("b") + // c := a.Named("c") + // b.GetLevel() => Error + // c.GetLevel() => Error + // b.SetLevel(Info) + // a.GetLevel() => Error + // b.GetLevel() => Info + // c.GetLevel() => Error + // a.SetLevel(Warn) + // a.GetLevel() => Warn + // b.GetLevel() => Warn + // c.GetLevel() => Warn + SyncParentLevel bool + // SubloggerHook registers a function that is called when a sublogger via // Named, With, or ResetNamed is created. If defined, the function is passed // the newly created Logger and the returned Logger is returned from the diff --git a/vendor/github.com/hashicorp/go-msgpack/LICENSE b/vendor/github.com/hashicorp/go-msgpack/LICENSE deleted file mode 100644 index ccae99f6..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2012, 2013 Ugorji Nwoke. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of the author nor the names of its contributors may be used - to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/0doc.go b/vendor/github.com/hashicorp/go-msgpack/codec/0doc.go deleted file mode 100644 index c14d810a..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/0doc.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -/* -High Performance, Feature-Rich Idiomatic Go encoding library for msgpack and binc . - -Supported Serialization formats are: - - - msgpack: [https://github.com/msgpack/msgpack] - - binc: [http://github.com/ugorji/binc] - -To install: - - go get github.com/ugorji/go/codec - -The idiomatic Go support is as seen in other encoding packages in -the standard library (ie json, xml, gob, etc). - -Rich Feature Set includes: - - - Simple but extremely powerful and feature-rich API - - Very High Performance. - Our extensive benchmarks show us outperforming Gob, Json and Bson by 2-4X. - This was achieved by taking extreme care on: - - managing allocation - - function frame size (important due to Go's use of split stacks), - - reflection use (and by-passing reflection for common types) - - recursion implications - - zero-copy mode (encoding/decoding to byte slice without using temp buffers) - - Correct. - Care was taken to precisely handle corner cases like: - overflows, nil maps and slices, nil value in stream, etc. - - Efficient zero-copying into temporary byte buffers - when encoding into or decoding from a byte slice. - - Standard field renaming via tags - - Encoding from any value - (struct, slice, map, primitives, pointers, interface{}, etc) - - Decoding into pointer to any non-nil typed value - (struct, slice, map, int, float32, bool, string, reflect.Value, etc) - - Supports extension functions to handle the encode/decode of custom types - - Support Go 1.2 encoding.BinaryMarshaler/BinaryUnmarshaler - - Schema-less decoding - (decode into a pointer to a nil interface{} as opposed to a typed non-nil value). - Includes Options to configure what specific map or slice type to use - when decoding an encoded list or map into a nil interface{} - - Provides a RPC Server and Client Codec for net/rpc communication protocol. - - Msgpack Specific: - - Provides extension functions to handle spec-defined extensions (binary, timestamp) - - Options to resolve ambiguities in handling raw bytes (as string or []byte) - during schema-less decoding (decoding into a nil interface{}) - - RPC Server/Client Codec for msgpack-rpc protocol defined at: - https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md - - Fast Paths for some container types: - For some container types, we circumvent reflection and its associated overhead - and allocation costs, and encode/decode directly. These types are: - []interface{} - []int - []string - map[interface{}]interface{} - map[int]interface{} - map[string]interface{} - -Extension Support - -Users can register a function to handle the encoding or decoding of -their custom types. - -There are no restrictions on what the custom type can be. Some examples: - - type BisSet []int - type BitSet64 uint64 - type UUID string - type MyStructWithUnexportedFields struct { a int; b bool; c []int; } - type GifImage struct { ... } - -As an illustration, MyStructWithUnexportedFields would normally be -encoded as an empty map because it has no exported fields, while UUID -would be encoded as a string. However, with extension support, you can -encode any of these however you like. - -RPC - -RPC Client and Server Codecs are implemented, so the codecs can be used -with the standard net/rpc package. - -Usage - -Typical usage model: - - // create and configure Handle - var ( - bh codec.BincHandle - mh codec.MsgpackHandle - ) - - mh.MapType = reflect.TypeOf(map[string]interface{}(nil)) - - // configure extensions - // e.g. for msgpack, define functions and enable Time support for tag 1 - // mh.AddExt(reflect.TypeOf(time.Time{}), 1, myMsgpackTimeEncodeExtFn, myMsgpackTimeDecodeExtFn) - - // create and use decoder/encoder - var ( - r io.Reader - w io.Writer - b []byte - h = &bh // or mh to use msgpack - ) - - dec = codec.NewDecoder(r, h) - dec = codec.NewDecoderBytes(b, h) - err = dec.Decode(&v) - - enc = codec.NewEncoder(w, h) - enc = codec.NewEncoderBytes(&b, h) - err = enc.Encode(v) - - //RPC Server - go func() { - for { - conn, err := listener.Accept() - rpcCodec := codec.GoRpc.ServerCodec(conn, h) - //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h) - rpc.ServeCodec(rpcCodec) - } - }() - - //RPC Communication (client side) - conn, err = net.Dial("tcp", "localhost:5555") - rpcCodec := codec.GoRpc.ClientCodec(conn, h) - //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) - client := rpc.NewClientWithCodec(rpcCodec) - -Representative Benchmark Results - -Run the benchmark suite using: - go test -bi -bench=. -benchmem - -To run full benchmark suite (including against vmsgpack and bson), -see notes in ext_dep_test.go - -*/ -package codec diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/README.md b/vendor/github.com/hashicorp/go-msgpack/codec/README.md deleted file mode 100644 index 6c95d1bf..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# Codec - -High Performance and Feature-Rich Idiomatic Go Library providing -encode/decode support for different serialization formats. - -Supported Serialization formats are: - - - msgpack: [https://github.com/msgpack/msgpack] - - binc: [http://github.com/ugorji/binc] - -To install: - - go get github.com/ugorji/go/codec - -Online documentation: [http://godoc.org/github.com/ugorji/go/codec] - -The idiomatic Go support is as seen in other encoding packages in -the standard library (ie json, xml, gob, etc). - -Rich Feature Set includes: - - - Simple but extremely powerful and feature-rich API - - Very High Performance. - Our extensive benchmarks show us outperforming Gob, Json and Bson by 2-4X. - This was achieved by taking extreme care on: - - managing allocation - - function frame size (important due to Go's use of split stacks), - - reflection use (and by-passing reflection for common types) - - recursion implications - - zero-copy mode (encoding/decoding to byte slice without using temp buffers) - - Correct. - Care was taken to precisely handle corner cases like: - overflows, nil maps and slices, nil value in stream, etc. - - Efficient zero-copying into temporary byte buffers - when encoding into or decoding from a byte slice. - - Standard field renaming via tags - - Encoding from any value - (struct, slice, map, primitives, pointers, interface{}, etc) - - Decoding into pointer to any non-nil typed value - (struct, slice, map, int, float32, bool, string, reflect.Value, etc) - - Supports extension functions to handle the encode/decode of custom types - - Support Go 1.2 encoding.BinaryMarshaler/BinaryUnmarshaler - - Schema-less decoding - (decode into a pointer to a nil interface{} as opposed to a typed non-nil value). - Includes Options to configure what specific map or slice type to use - when decoding an encoded list or map into a nil interface{} - - Provides a RPC Server and Client Codec for net/rpc communication protocol. - - Msgpack Specific: - - Provides extension functions to handle spec-defined extensions (binary, timestamp) - - Options to resolve ambiguities in handling raw bytes (as string or []byte) - during schema-less decoding (decoding into a nil interface{}) - - RPC Server/Client Codec for msgpack-rpc protocol defined at: - https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md - - Fast Paths for some container types: - For some container types, we circumvent reflection and its associated overhead - and allocation costs, and encode/decode directly. These types are: - []interface{} - []int - []string - map[interface{}]interface{} - map[int]interface{} - map[string]interface{} - -## Extension Support - -Users can register a function to handle the encoding or decoding of -their custom types. - -There are no restrictions on what the custom type can be. Some examples: - - type BisSet []int - type BitSet64 uint64 - type UUID string - type MyStructWithUnexportedFields struct { a int; b bool; c []int; } - type GifImage struct { ... } - -As an illustration, MyStructWithUnexportedFields would normally be -encoded as an empty map because it has no exported fields, while UUID -would be encoded as a string. However, with extension support, you can -encode any of these however you like. - -## RPC - -RPC Client and Server Codecs are implemented, so the codecs can be used -with the standard net/rpc package. - -## Usage - -Typical usage model: - - // create and configure Handle - var ( - bh codec.BincHandle - mh codec.MsgpackHandle - ) - - mh.MapType = reflect.TypeOf(map[string]interface{}(nil)) - - // configure extensions - // e.g. for msgpack, define functions and enable Time support for tag 1 - // mh.AddExt(reflect.TypeOf(time.Time{}), 1, myMsgpackTimeEncodeExtFn, myMsgpackTimeDecodeExtFn) - - // create and use decoder/encoder - var ( - r io.Reader - w io.Writer - b []byte - h = &bh // or mh to use msgpack - ) - - dec = codec.NewDecoder(r, h) - dec = codec.NewDecoderBytes(b, h) - err = dec.Decode(&v) - - enc = codec.NewEncoder(w, h) - enc = codec.NewEncoderBytes(&b, h) - err = enc.Encode(v) - - //RPC Server - go func() { - for { - conn, err := listener.Accept() - rpcCodec := codec.GoRpc.ServerCodec(conn, h) - //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h) - rpc.ServeCodec(rpcCodec) - } - }() - - //RPC Communication (client side) - conn, err = net.Dial("tcp", "localhost:5555") - rpcCodec := codec.GoRpc.ClientCodec(conn, h) - //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) - client := rpc.NewClientWithCodec(rpcCodec) - -## Representative Benchmark Results - -A sample run of benchmark using "go test -bi -bench=. -benchmem": - - /proc/cpuinfo: Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz (HT) - - .............................................. - BENCHMARK INIT: 2013-10-16 11:02:50.345970786 -0400 EDT - To run full benchmark comparing encodings (MsgPack, Binc, JSON, GOB, etc), use: "go test -bench=." - Benchmark: - Struct recursive Depth: 1 - ApproxDeepSize Of benchmark Struct: 4694 bytes - Benchmark One-Pass Run: - v-msgpack: len: 1600 bytes - bson: len: 3025 bytes - msgpack: len: 1560 bytes - binc: len: 1187 bytes - gob: len: 1972 bytes - json: len: 2538 bytes - .............................................. - PASS - Benchmark__Msgpack____Encode 50000 54359 ns/op 14953 B/op 83 allocs/op - Benchmark__Msgpack____Decode 10000 106531 ns/op 14990 B/op 410 allocs/op - Benchmark__Binc_NoSym_Encode 50000 53956 ns/op 14966 B/op 83 allocs/op - Benchmark__Binc_NoSym_Decode 10000 103751 ns/op 14529 B/op 386 allocs/op - Benchmark__Binc_Sym___Encode 50000 65961 ns/op 17130 B/op 88 allocs/op - Benchmark__Binc_Sym___Decode 10000 106310 ns/op 15857 B/op 287 allocs/op - Benchmark__Gob________Encode 10000 135944 ns/op 21189 B/op 237 allocs/op - Benchmark__Gob________Decode 5000 405390 ns/op 83460 B/op 1841 allocs/op - Benchmark__Json_______Encode 20000 79412 ns/op 13874 B/op 102 allocs/op - Benchmark__Json_______Decode 10000 247979 ns/op 14202 B/op 493 allocs/op - Benchmark__Bson_______Encode 10000 121762 ns/op 27814 B/op 514 allocs/op - Benchmark__Bson_______Decode 10000 162126 ns/op 16514 B/op 789 allocs/op - Benchmark__VMsgpack___Encode 50000 69155 ns/op 12370 B/op 344 allocs/op - Benchmark__VMsgpack___Decode 10000 151609 ns/op 20307 B/op 571 allocs/op - ok ugorji.net/codec 30.827s - -To run full benchmark suite (including against vmsgpack and bson), -see notes in ext\_dep\_test.go - diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/binc.go b/vendor/github.com/hashicorp/go-msgpack/codec/binc.go deleted file mode 100644 index 2bb5e8fe..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/binc.go +++ /dev/null @@ -1,786 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -import ( - "math" - // "reflect" - // "sync/atomic" - "time" - //"fmt" -) - -const bincDoPrune = true // No longer needed. Needed before as C lib did not support pruning. - -//var _ = fmt.Printf - -// vd as low 4 bits (there are 16 slots) -const ( - bincVdSpecial byte = iota - bincVdPosInt - bincVdNegInt - bincVdFloat - - bincVdString - bincVdByteArray - bincVdArray - bincVdMap - - bincVdTimestamp - bincVdSmallInt - bincVdUnicodeOther - bincVdSymbol - - bincVdDecimal - _ // open slot - _ // open slot - bincVdCustomExt = 0x0f -) - -const ( - bincSpNil byte = iota - bincSpFalse - bincSpTrue - bincSpNan - bincSpPosInf - bincSpNegInf - bincSpZeroFloat - bincSpZero - bincSpNegOne -) - -const ( - bincFlBin16 byte = iota - bincFlBin32 - _ // bincFlBin32e - bincFlBin64 - _ // bincFlBin64e - // others not currently supported -) - -type bincEncDriver struct { - w encWriter - m map[string]uint16 // symbols - s uint32 // symbols sequencer - b [8]byte -} - -func (e *bincEncDriver) isBuiltinType(rt uintptr) bool { - return rt == timeTypId -} - -func (e *bincEncDriver) encodeBuiltin(rt uintptr, v interface{}) { - switch rt { - case timeTypId: - bs := encodeTime(v.(time.Time)) - e.w.writen1(bincVdTimestamp<<4 | uint8(len(bs))) - e.w.writeb(bs) - } -} - -func (e *bincEncDriver) encodeNil() { - e.w.writen1(bincVdSpecial<<4 | bincSpNil) -} - -func (e *bincEncDriver) encodeBool(b bool) { - if b { - e.w.writen1(bincVdSpecial<<4 | bincSpTrue) - } else { - e.w.writen1(bincVdSpecial<<4 | bincSpFalse) - } -} - -func (e *bincEncDriver) encodeFloat32(f float32) { - if f == 0 { - e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat) - return - } - e.w.writen1(bincVdFloat<<4 | bincFlBin32) - e.w.writeUint32(math.Float32bits(f)) -} - -func (e *bincEncDriver) encodeFloat64(f float64) { - if f == 0 { - e.w.writen1(bincVdSpecial<<4 | bincSpZeroFloat) - return - } - bigen.PutUint64(e.b[:], math.Float64bits(f)) - if bincDoPrune { - i := 7 - for ; i >= 0 && (e.b[i] == 0); i-- { - } - i++ - if i <= 6 { - e.w.writen1(bincVdFloat<<4 | 0x8 | bincFlBin64) - e.w.writen1(byte(i)) - e.w.writeb(e.b[:i]) - return - } - } - e.w.writen1(bincVdFloat<<4 | bincFlBin64) - e.w.writeb(e.b[:]) -} - -func (e *bincEncDriver) encIntegerPrune(bd byte, pos bool, v uint64, lim uint8) { - if lim == 4 { - bigen.PutUint32(e.b[:lim], uint32(v)) - } else { - bigen.PutUint64(e.b[:lim], v) - } - if bincDoPrune { - i := pruneSignExt(e.b[:lim], pos) - e.w.writen1(bd | lim - 1 - byte(i)) - e.w.writeb(e.b[i:lim]) - } else { - e.w.writen1(bd | lim - 1) - e.w.writeb(e.b[:lim]) - } -} - -func (e *bincEncDriver) encodeInt(v int64) { - const nbd byte = bincVdNegInt << 4 - switch { - case v >= 0: - e.encUint(bincVdPosInt<<4, true, uint64(v)) - case v == -1: - e.w.writen1(bincVdSpecial<<4 | bincSpNegOne) - default: - e.encUint(bincVdNegInt<<4, false, uint64(-v)) - } -} - -func (e *bincEncDriver) encodeUint(v uint64) { - e.encUint(bincVdPosInt<<4, true, v) -} - -func (e *bincEncDriver) encUint(bd byte, pos bool, v uint64) { - switch { - case v == 0: - e.w.writen1(bincVdSpecial<<4 | bincSpZero) - case pos && v >= 1 && v <= 16: - e.w.writen1(bincVdSmallInt<<4 | byte(v-1)) - case v <= math.MaxUint8: - e.w.writen2(bd|0x0, byte(v)) - case v <= math.MaxUint16: - e.w.writen1(bd | 0x01) - e.w.writeUint16(uint16(v)) - case v <= math.MaxUint32: - e.encIntegerPrune(bd, pos, v, 4) - default: - e.encIntegerPrune(bd, pos, v, 8) - } -} - -func (e *bincEncDriver) encodeExtPreamble(xtag byte, length int) { - e.encLen(bincVdCustomExt<<4, uint64(length)) - e.w.writen1(xtag) -} - -func (e *bincEncDriver) encodeArrayPreamble(length int) { - e.encLen(bincVdArray<<4, uint64(length)) -} - -func (e *bincEncDriver) encodeMapPreamble(length int) { - e.encLen(bincVdMap<<4, uint64(length)) -} - -func (e *bincEncDriver) encodeString(c charEncoding, v string) { - l := uint64(len(v)) - e.encBytesLen(c, l) - if l > 0 { - e.w.writestr(v) - } -} - -func (e *bincEncDriver) encodeSymbol(v string) { - // if WriteSymbolsNoRefs { - // e.encodeString(c_UTF8, v) - // return - // } - - //symbols only offer benefit when string length > 1. - //This is because strings with length 1 take only 2 bytes to store - //(bd with embedded length, and single byte for string val). - - l := len(v) - switch l { - case 0: - e.encBytesLen(c_UTF8, 0) - return - case 1: - e.encBytesLen(c_UTF8, 1) - e.w.writen1(v[0]) - return - } - if e.m == nil { - e.m = make(map[string]uint16, 16) - } - ui, ok := e.m[v] - if ok { - if ui <= math.MaxUint8 { - e.w.writen2(bincVdSymbol<<4, byte(ui)) - } else { - e.w.writen1(bincVdSymbol<<4 | 0x8) - e.w.writeUint16(ui) - } - } else { - e.s++ - ui = uint16(e.s) - //ui = uint16(atomic.AddUint32(&e.s, 1)) - e.m[v] = ui - var lenprec uint8 - switch { - case l <= math.MaxUint8: - // lenprec = 0 - case l <= math.MaxUint16: - lenprec = 1 - case int64(l) <= math.MaxUint32: - lenprec = 2 - default: - lenprec = 3 - } - if ui <= math.MaxUint8 { - e.w.writen2(bincVdSymbol<<4|0x0|0x4|lenprec, byte(ui)) - } else { - e.w.writen1(bincVdSymbol<<4 | 0x8 | 0x4 | lenprec) - e.w.writeUint16(ui) - } - switch lenprec { - case 0: - e.w.writen1(byte(l)) - case 1: - e.w.writeUint16(uint16(l)) - case 2: - e.w.writeUint32(uint32(l)) - default: - e.w.writeUint64(uint64(l)) - } - e.w.writestr(v) - } -} - -func (e *bincEncDriver) encodeStringBytes(c charEncoding, v []byte) { - l := uint64(len(v)) - e.encBytesLen(c, l) - if l > 0 { - e.w.writeb(v) - } -} - -func (e *bincEncDriver) encBytesLen(c charEncoding, length uint64) { - //TODO: support bincUnicodeOther (for now, just use string or bytearray) - if c == c_RAW { - e.encLen(bincVdByteArray<<4, length) - } else { - e.encLen(bincVdString<<4, length) - } -} - -func (e *bincEncDriver) encLen(bd byte, l uint64) { - if l < 12 { - e.w.writen1(bd | uint8(l+4)) - } else { - e.encLenNumber(bd, l) - } -} - -func (e *bincEncDriver) encLenNumber(bd byte, v uint64) { - switch { - case v <= math.MaxUint8: - e.w.writen2(bd, byte(v)) - case v <= math.MaxUint16: - e.w.writen1(bd | 0x01) - e.w.writeUint16(uint16(v)) - case v <= math.MaxUint32: - e.w.writen1(bd | 0x02) - e.w.writeUint32(uint32(v)) - default: - e.w.writen1(bd | 0x03) - e.w.writeUint64(uint64(v)) - } -} - -//------------------------------------ - -type bincDecDriver struct { - r decReader - bdRead bool - bdType valueType - bd byte - vd byte - vs byte - b [8]byte - m map[uint32]string // symbols (use uint32 as key, as map optimizes for it) -} - -func (d *bincDecDriver) initReadNext() { - if d.bdRead { - return - } - d.bd = d.r.readn1() - d.vd = d.bd >> 4 - d.vs = d.bd & 0x0f - d.bdRead = true - d.bdType = valueTypeUnset -} - -func (d *bincDecDriver) currentEncodedType() valueType { - if d.bdType == valueTypeUnset { - switch d.vd { - case bincVdSpecial: - switch d.vs { - case bincSpNil: - d.bdType = valueTypeNil - case bincSpFalse, bincSpTrue: - d.bdType = valueTypeBool - case bincSpNan, bincSpNegInf, bincSpPosInf, bincSpZeroFloat: - d.bdType = valueTypeFloat - case bincSpZero: - d.bdType = valueTypeUint - case bincSpNegOne: - d.bdType = valueTypeInt - default: - decErr("currentEncodedType: Unrecognized special value 0x%x", d.vs) - } - case bincVdSmallInt: - d.bdType = valueTypeUint - case bincVdPosInt: - d.bdType = valueTypeUint - case bincVdNegInt: - d.bdType = valueTypeInt - case bincVdFloat: - d.bdType = valueTypeFloat - case bincVdString: - d.bdType = valueTypeString - case bincVdSymbol: - d.bdType = valueTypeSymbol - case bincVdByteArray: - d.bdType = valueTypeBytes - case bincVdTimestamp: - d.bdType = valueTypeTimestamp - case bincVdCustomExt: - d.bdType = valueTypeExt - case bincVdArray: - d.bdType = valueTypeArray - case bincVdMap: - d.bdType = valueTypeMap - default: - decErr("currentEncodedType: Unrecognized d.vd: 0x%x", d.vd) - } - } - return d.bdType -} - -func (d *bincDecDriver) tryDecodeAsNil() bool { - if d.bd == bincVdSpecial<<4|bincSpNil { - d.bdRead = false - return true - } - return false -} - -func (d *bincDecDriver) isBuiltinType(rt uintptr) bool { - return rt == timeTypId -} - -func (d *bincDecDriver) decodeBuiltin(rt uintptr, v interface{}) { - switch rt { - case timeTypId: - if d.vd != bincVdTimestamp { - decErr("Invalid d.vd. Expecting 0x%x. Received: 0x%x", bincVdTimestamp, d.vd) - } - tt, err := decodeTime(d.r.readn(int(d.vs))) - if err != nil { - panic(err) - } - var vt *time.Time = v.(*time.Time) - *vt = tt - d.bdRead = false - } -} - -func (d *bincDecDriver) decFloatPre(vs, defaultLen byte) { - if vs&0x8 == 0 { - d.r.readb(d.b[0:defaultLen]) - } else { - l := d.r.readn1() - if l > 8 { - decErr("At most 8 bytes used to represent float. Received: %v bytes", l) - } - for i := l; i < 8; i++ { - d.b[i] = 0 - } - d.r.readb(d.b[0:l]) - } -} - -func (d *bincDecDriver) decFloat() (f float64) { - //if true { f = math.Float64frombits(d.r.readUint64()); break; } - switch vs := d.vs; vs & 0x7 { - case bincFlBin32: - d.decFloatPre(vs, 4) - f = float64(math.Float32frombits(bigen.Uint32(d.b[0:4]))) - case bincFlBin64: - d.decFloatPre(vs, 8) - f = math.Float64frombits(bigen.Uint64(d.b[0:8])) - default: - decErr("only float32 and float64 are supported. d.vd: 0x%x, d.vs: 0x%x", d.vd, d.vs) - } - return -} - -func (d *bincDecDriver) decUint() (v uint64) { - // need to inline the code (interface conversion and type assertion expensive) - switch d.vs { - case 0: - v = uint64(d.r.readn1()) - case 1: - d.r.readb(d.b[6:]) - v = uint64(bigen.Uint16(d.b[6:])) - case 2: - d.b[4] = 0 - d.r.readb(d.b[5:]) - v = uint64(bigen.Uint32(d.b[4:])) - case 3: - d.r.readb(d.b[4:]) - v = uint64(bigen.Uint32(d.b[4:])) - case 4, 5, 6: - lim := int(7 - d.vs) - d.r.readb(d.b[lim:]) - for i := 0; i < lim; i++ { - d.b[i] = 0 - } - v = uint64(bigen.Uint64(d.b[:])) - case 7: - d.r.readb(d.b[:]) - v = uint64(bigen.Uint64(d.b[:])) - default: - decErr("unsigned integers with greater than 64 bits of precision not supported") - } - return -} - -func (d *bincDecDriver) decIntAny() (ui uint64, i int64, neg bool) { - switch d.vd { - case bincVdPosInt: - ui = d.decUint() - i = int64(ui) - case bincVdNegInt: - ui = d.decUint() - i = -(int64(ui)) - neg = true - case bincVdSmallInt: - i = int64(d.vs) + 1 - ui = uint64(d.vs) + 1 - case bincVdSpecial: - switch d.vs { - case bincSpZero: - //i = 0 - case bincSpNegOne: - neg = true - ui = 1 - i = -1 - default: - decErr("numeric decode fails for special value: d.vs: 0x%x", d.vs) - } - default: - decErr("number can only be decoded from uint or int values. d.bd: 0x%x, d.vd: 0x%x", d.bd, d.vd) - } - return -} - -func (d *bincDecDriver) decodeInt(bitsize uint8) (i int64) { - _, i, _ = d.decIntAny() - checkOverflow(0, i, bitsize) - d.bdRead = false - return -} - -func (d *bincDecDriver) decodeUint(bitsize uint8) (ui uint64) { - ui, i, neg := d.decIntAny() - if neg { - decErr("Assigning negative signed value: %v, to unsigned type", i) - } - checkOverflow(ui, 0, bitsize) - d.bdRead = false - return -} - -func (d *bincDecDriver) decodeFloat(chkOverflow32 bool) (f float64) { - switch d.vd { - case bincVdSpecial: - d.bdRead = false - switch d.vs { - case bincSpNan: - return math.NaN() - case bincSpPosInf: - return math.Inf(1) - case bincSpZeroFloat, bincSpZero: - return - case bincSpNegInf: - return math.Inf(-1) - default: - decErr("Invalid d.vs decoding float where d.vd=bincVdSpecial: %v", d.vs) - } - case bincVdFloat: - f = d.decFloat() - default: - _, i, _ := d.decIntAny() - f = float64(i) - } - checkOverflowFloat32(f, chkOverflow32) - d.bdRead = false - return -} - -// bool can be decoded from bool only (single byte). -func (d *bincDecDriver) decodeBool() (b bool) { - switch d.bd { - case (bincVdSpecial | bincSpFalse): - // b = false - case (bincVdSpecial | bincSpTrue): - b = true - default: - decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd) - } - d.bdRead = false - return -} - -func (d *bincDecDriver) readMapLen() (length int) { - if d.vd != bincVdMap { - decErr("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd) - } - length = d.decLen() - d.bdRead = false - return -} - -func (d *bincDecDriver) readArrayLen() (length int) { - if d.vd != bincVdArray { - decErr("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd) - } - length = d.decLen() - d.bdRead = false - return -} - -func (d *bincDecDriver) decLen() int { - if d.vs <= 3 { - return int(d.decUint()) - } - return int(d.vs - 4) -} - -func (d *bincDecDriver) decodeString() (s string) { - switch d.vd { - case bincVdString, bincVdByteArray: - if length := d.decLen(); length > 0 { - s = string(d.r.readn(length)) - } - case bincVdSymbol: - //from vs: extract numSymbolBytes, containsStringVal, strLenPrecision, - //extract symbol - //if containsStringVal, read it and put in map - //else look in map for string value - var symbol uint32 - vs := d.vs - //fmt.Printf(">>>> d.vs: 0b%b, & 0x8: %v, & 0x4: %v\n", d.vs, vs & 0x8, vs & 0x4) - if vs&0x8 == 0 { - symbol = uint32(d.r.readn1()) - } else { - symbol = uint32(d.r.readUint16()) - } - if d.m == nil { - d.m = make(map[uint32]string, 16) - } - - if vs&0x4 == 0 { - s = d.m[symbol] - } else { - var slen int - switch vs & 0x3 { - case 0: - slen = int(d.r.readn1()) - case 1: - slen = int(d.r.readUint16()) - case 2: - slen = int(d.r.readUint32()) - case 3: - slen = int(d.r.readUint64()) - } - s = string(d.r.readn(slen)) - d.m[symbol] = s - } - default: - decErr("Invalid d.vd for string. Expecting string:0x%x, bytearray:0x%x or symbol: 0x%x. Got: 0x%x", - bincVdString, bincVdByteArray, bincVdSymbol, d.vd) - } - d.bdRead = false - return -} - -func (d *bincDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) { - var clen int - switch d.vd { - case bincVdString, bincVdByteArray: - clen = d.decLen() - default: - decErr("Invalid d.vd for bytes. Expecting string:0x%x or bytearray:0x%x. Got: 0x%x", - bincVdString, bincVdByteArray, d.vd) - } - if clen > 0 { - // if no contents in stream, don't update the passed byteslice - if len(bs) != clen { - if len(bs) > clen { - bs = bs[:clen] - } else { - bs = make([]byte, clen) - } - bsOut = bs - changed = true - } - d.r.readb(bs) - } - d.bdRead = false - return -} - -func (d *bincDecDriver) decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) { - switch d.vd { - case bincVdCustomExt: - l := d.decLen() - xtag = d.r.readn1() - if verifyTag && xtag != tag { - decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag) - } - xbs = d.r.readn(l) - case bincVdByteArray: - xbs, _ = d.decodeBytes(nil) - default: - decErr("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.vd) - } - d.bdRead = false - return -} - -func (d *bincDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurther bool) { - d.initReadNext() - - switch d.vd { - case bincVdSpecial: - switch d.vs { - case bincSpNil: - vt = valueTypeNil - case bincSpFalse: - vt = valueTypeBool - v = false - case bincSpTrue: - vt = valueTypeBool - v = true - case bincSpNan: - vt = valueTypeFloat - v = math.NaN() - case bincSpPosInf: - vt = valueTypeFloat - v = math.Inf(1) - case bincSpNegInf: - vt = valueTypeFloat - v = math.Inf(-1) - case bincSpZeroFloat: - vt = valueTypeFloat - v = float64(0) - case bincSpZero: - vt = valueTypeUint - v = int64(0) // int8(0) - case bincSpNegOne: - vt = valueTypeInt - v = int64(-1) // int8(-1) - default: - decErr("decodeNaked: Unrecognized special value 0x%x", d.vs) - } - case bincVdSmallInt: - vt = valueTypeUint - v = uint64(int8(d.vs)) + 1 // int8(d.vs) + 1 - case bincVdPosInt: - vt = valueTypeUint - v = d.decUint() - case bincVdNegInt: - vt = valueTypeInt - v = -(int64(d.decUint())) - case bincVdFloat: - vt = valueTypeFloat - v = d.decFloat() - case bincVdSymbol: - vt = valueTypeSymbol - v = d.decodeString() - case bincVdString: - vt = valueTypeString - v = d.decodeString() - case bincVdByteArray: - vt = valueTypeBytes - v, _ = d.decodeBytes(nil) - case bincVdTimestamp: - vt = valueTypeTimestamp - tt, err := decodeTime(d.r.readn(int(d.vs))) - if err != nil { - panic(err) - } - v = tt - case bincVdCustomExt: - vt = valueTypeExt - l := d.decLen() - var re RawExt - re.Tag = d.r.readn1() - re.Data = d.r.readn(l) - v = &re - vt = valueTypeExt - case bincVdArray: - vt = valueTypeArray - decodeFurther = true - case bincVdMap: - vt = valueTypeMap - decodeFurther = true - default: - decErr("decodeNaked: Unrecognized d.vd: 0x%x", d.vd) - } - - if !decodeFurther { - d.bdRead = false - } - return -} - -//------------------------------------ - -//BincHandle is a Handle for the Binc Schema-Free Encoding Format -//defined at https://github.com/ugorji/binc . -// -//BincHandle currently supports all Binc features with the following EXCEPTIONS: -// - only integers up to 64 bits of precision are supported. -// big integers are unsupported. -// - Only IEEE 754 binary32 and binary64 floats are supported (ie Go float32 and float64 types). -// extended precision and decimal IEEE 754 floats are unsupported. -// - Only UTF-8 strings supported. -// Unicode_Other Binc types (UTF16, UTF32) are currently unsupported. -//Note that these EXCEPTIONS are temporary and full support is possible and may happen soon. -type BincHandle struct { - BasicHandle -} - -func (h *BincHandle) newEncDriver(w encWriter) encDriver { - return &bincEncDriver{w: w} -} - -func (h *BincHandle) newDecDriver(r decReader) decDriver { - return &bincDecDriver{r: r} -} - -func (_ *BincHandle) writeExt() bool { - return true -} - -func (h *BincHandle) getBasicHandle() *BasicHandle { - return &h.BasicHandle -} diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/decode.go b/vendor/github.com/hashicorp/go-msgpack/codec/decode.go deleted file mode 100644 index 851b54ac..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/decode.go +++ /dev/null @@ -1,1048 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -import ( - "io" - "reflect" - // "runtime/debug" -) - -// Some tagging information for error messages. -const ( - msgTagDec = "codec.decoder" - msgBadDesc = "Unrecognized descriptor byte" - msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v" -) - -// decReader abstracts the reading source, allowing implementations that can -// read from an io.Reader or directly off a byte slice with zero-copying. -type decReader interface { - readn(n int) []byte - readb([]byte) - readn1() uint8 - readUint16() uint16 - readUint32() uint32 - readUint64() uint64 -} - -type decDriver interface { - initReadNext() - tryDecodeAsNil() bool - currentEncodedType() valueType - isBuiltinType(rt uintptr) bool - decodeBuiltin(rt uintptr, v interface{}) - //decodeNaked: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types). - decodeNaked() (v interface{}, vt valueType, decodeFurther bool) - decodeInt(bitsize uint8) (i int64) - decodeUint(bitsize uint8) (ui uint64) - decodeFloat(chkOverflow32 bool) (f float64) - decodeBool() (b bool) - // decodeString can also decode symbols - decodeString() (s string) - decodeBytes(bs []byte) (bsOut []byte, changed bool) - decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) - readMapLen() int - readArrayLen() int -} - -type DecodeOptions struct { - // An instance of MapType is used during schema-less decoding of a map in the stream. - // If nil, we use map[interface{}]interface{} - MapType reflect.Type - // An instance of SliceType is used during schema-less decoding of an array in the stream. - // If nil, we use []interface{} - SliceType reflect.Type - // ErrorIfNoField controls whether an error is returned when decoding a map - // from a codec stream into a struct, and no matching struct field is found. - ErrorIfNoField bool -} - -// ------------------------------------ - -// ioDecReader is a decReader that reads off an io.Reader -type ioDecReader struct { - r io.Reader - br io.ByteReader - x [8]byte //temp byte array re-used internally for efficiency -} - -func (z *ioDecReader) readn(n int) (bs []byte) { - if n <= 0 { - return - } - bs = make([]byte, n) - if _, err := io.ReadAtLeast(z.r, bs, n); err != nil { - panic(err) - } - return -} - -func (z *ioDecReader) readb(bs []byte) { - if _, err := io.ReadAtLeast(z.r, bs, len(bs)); err != nil { - panic(err) - } -} - -func (z *ioDecReader) readn1() uint8 { - if z.br != nil { - b, err := z.br.ReadByte() - if err != nil { - panic(err) - } - return b - } - z.readb(z.x[:1]) - return z.x[0] -} - -func (z *ioDecReader) readUint16() uint16 { - z.readb(z.x[:2]) - return bigen.Uint16(z.x[:2]) -} - -func (z *ioDecReader) readUint32() uint32 { - z.readb(z.x[:4]) - return bigen.Uint32(z.x[:4]) -} - -func (z *ioDecReader) readUint64() uint64 { - z.readb(z.x[:8]) - return bigen.Uint64(z.x[:8]) -} - -// ------------------------------------ - -// bytesDecReader is a decReader that reads off a byte slice with zero copying -type bytesDecReader struct { - b []byte // data - c int // cursor - a int // available -} - -func (z *bytesDecReader) consume(n int) (oldcursor int) { - if z.a == 0 { - panic(io.EOF) - } - if n > z.a { - decErr("Trying to read %v bytes. Only %v available", n, z.a) - } - // z.checkAvailable(n) - oldcursor = z.c - z.c = oldcursor + n - z.a = z.a - n - return -} - -func (z *bytesDecReader) readn(n int) (bs []byte) { - if n <= 0 { - return - } - c0 := z.consume(n) - bs = z.b[c0:z.c] - return -} - -func (z *bytesDecReader) readb(bs []byte) { - copy(bs, z.readn(len(bs))) -} - -func (z *bytesDecReader) readn1() uint8 { - c0 := z.consume(1) - return z.b[c0] -} - -// Use binaryEncoding helper for 4 and 8 bits, but inline it for 2 bits -// creating temp slice variable and copying it to helper function is expensive -// for just 2 bits. - -func (z *bytesDecReader) readUint16() uint16 { - c0 := z.consume(2) - return uint16(z.b[c0+1]) | uint16(z.b[c0])<<8 -} - -func (z *bytesDecReader) readUint32() uint32 { - c0 := z.consume(4) - return bigen.Uint32(z.b[c0:z.c]) -} - -func (z *bytesDecReader) readUint64() uint64 { - c0 := z.consume(8) - return bigen.Uint64(z.b[c0:z.c]) -} - -// ------------------------------------ - -// decFnInfo has methods for registering handling decoding of a specific type -// based on some characteristics (builtin, extension, reflect Kind, etc) -type decFnInfo struct { - ti *typeInfo - d *Decoder - dd decDriver - xfFn func(reflect.Value, []byte) error - xfTag byte - array bool -} - -func (f *decFnInfo) builtin(rv reflect.Value) { - f.dd.decodeBuiltin(f.ti.rtid, rv.Addr().Interface()) -} - -func (f *decFnInfo) rawExt(rv reflect.Value) { - xtag, xbs := f.dd.decodeExt(false, 0) - rv.Field(0).SetUint(uint64(xtag)) - rv.Field(1).SetBytes(xbs) -} - -func (f *decFnInfo) ext(rv reflect.Value) { - _, xbs := f.dd.decodeExt(true, f.xfTag) - if fnerr := f.xfFn(rv, xbs); fnerr != nil { - panic(fnerr) - } -} - -func (f *decFnInfo) binaryMarshal(rv reflect.Value) { - var bm binaryUnmarshaler - if f.ti.unmIndir == -1 { - bm = rv.Addr().Interface().(binaryUnmarshaler) - } else if f.ti.unmIndir == 0 { - bm = rv.Interface().(binaryUnmarshaler) - } else { - for j, k := int8(0), f.ti.unmIndir; j < k; j++ { - if rv.IsNil() { - rv.Set(reflect.New(rv.Type().Elem())) - } - rv = rv.Elem() - } - bm = rv.Interface().(binaryUnmarshaler) - } - xbs, _ := f.dd.decodeBytes(nil) - if fnerr := bm.UnmarshalBinary(xbs); fnerr != nil { - panic(fnerr) - } -} - -func (f *decFnInfo) kErr(rv reflect.Value) { - decErr("Unhandled value for kind: %v: %s", rv.Kind(), msgBadDesc) -} - -func (f *decFnInfo) kString(rv reflect.Value) { - rv.SetString(f.dd.decodeString()) -} - -func (f *decFnInfo) kBool(rv reflect.Value) { - rv.SetBool(f.dd.decodeBool()) -} - -func (f *decFnInfo) kInt(rv reflect.Value) { - rv.SetInt(f.dd.decodeInt(intBitsize)) -} - -func (f *decFnInfo) kInt64(rv reflect.Value) { - rv.SetInt(f.dd.decodeInt(64)) -} - -func (f *decFnInfo) kInt32(rv reflect.Value) { - rv.SetInt(f.dd.decodeInt(32)) -} - -func (f *decFnInfo) kInt8(rv reflect.Value) { - rv.SetInt(f.dd.decodeInt(8)) -} - -func (f *decFnInfo) kInt16(rv reflect.Value) { - rv.SetInt(f.dd.decodeInt(16)) -} - -func (f *decFnInfo) kFloat32(rv reflect.Value) { - rv.SetFloat(f.dd.decodeFloat(true)) -} - -func (f *decFnInfo) kFloat64(rv reflect.Value) { - rv.SetFloat(f.dd.decodeFloat(false)) -} - -func (f *decFnInfo) kUint8(rv reflect.Value) { - rv.SetUint(f.dd.decodeUint(8)) -} - -func (f *decFnInfo) kUint64(rv reflect.Value) { - rv.SetUint(f.dd.decodeUint(64)) -} - -func (f *decFnInfo) kUint(rv reflect.Value) { - rv.SetUint(f.dd.decodeUint(uintBitsize)) -} - -func (f *decFnInfo) kUint32(rv reflect.Value) { - rv.SetUint(f.dd.decodeUint(32)) -} - -func (f *decFnInfo) kUint16(rv reflect.Value) { - rv.SetUint(f.dd.decodeUint(16)) -} - -// func (f *decFnInfo) kPtr(rv reflect.Value) { -// debugf(">>>>>>> ??? decode kPtr called - shouldn't get called") -// if rv.IsNil() { -// rv.Set(reflect.New(rv.Type().Elem())) -// } -// f.d.decodeValue(rv.Elem()) -// } - -func (f *decFnInfo) kInterface(rv reflect.Value) { - // debugf("\t===> kInterface") - if !rv.IsNil() { - f.d.decodeValue(rv.Elem()) - return - } - // nil interface: - // use some hieristics to set the nil interface to an - // appropriate value based on the first byte read (byte descriptor bd) - v, vt, decodeFurther := f.dd.decodeNaked() - if vt == valueTypeNil { - return - } - // Cannot decode into nil interface with methods (e.g. error, io.Reader, etc) - // if non-nil value in stream. - if num := f.ti.rt.NumMethod(); num > 0 { - decErr("decodeValue: Cannot decode non-nil codec value into nil %v (%v methods)", - f.ti.rt, num) - } - var rvn reflect.Value - var useRvn bool - switch vt { - case valueTypeMap: - if f.d.h.MapType == nil { - var m2 map[interface{}]interface{} - v = &m2 - } else { - rvn = reflect.New(f.d.h.MapType).Elem() - useRvn = true - } - case valueTypeArray: - if f.d.h.SliceType == nil { - var m2 []interface{} - v = &m2 - } else { - rvn = reflect.New(f.d.h.SliceType).Elem() - useRvn = true - } - case valueTypeExt: - re := v.(*RawExt) - var bfn func(reflect.Value, []byte) error - rvn, bfn = f.d.h.getDecodeExtForTag(re.Tag) - if bfn == nil { - rvn = reflect.ValueOf(*re) - } else if fnerr := bfn(rvn, re.Data); fnerr != nil { - panic(fnerr) - } - rv.Set(rvn) - return - } - if decodeFurther { - if useRvn { - f.d.decodeValue(rvn) - } else if v != nil { - // this v is a pointer, so we need to dereference it when done - f.d.decode(v) - rvn = reflect.ValueOf(v).Elem() - useRvn = true - } - } - if useRvn { - rv.Set(rvn) - } else if v != nil { - rv.Set(reflect.ValueOf(v)) - } -} - -func (f *decFnInfo) kStruct(rv reflect.Value) { - fti := f.ti - if currEncodedType := f.dd.currentEncodedType(); currEncodedType == valueTypeMap { - containerLen := f.dd.readMapLen() - if containerLen == 0 { - return - } - tisfi := fti.sfi - for j := 0; j < containerLen; j++ { - // var rvkencname string - // ddecode(&rvkencname) - f.dd.initReadNext() - rvkencname := f.dd.decodeString() - // rvksi := ti.getForEncName(rvkencname) - if k := fti.indexForEncName(rvkencname); k > -1 { - sfik := tisfi[k] - if sfik.i != -1 { - f.d.decodeValue(rv.Field(int(sfik.i))) - } else { - f.d.decEmbeddedField(rv, sfik.is) - } - // f.d.decodeValue(ti.field(k, rv)) - } else { - if f.d.h.ErrorIfNoField { - decErr("No matching struct field found when decoding stream map with key: %v", - rvkencname) - } else { - var nilintf0 interface{} - f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem()) - } - } - } - } else if currEncodedType == valueTypeArray { - containerLen := f.dd.readArrayLen() - if containerLen == 0 { - return - } - for j, si := range fti.sfip { - if j == containerLen { - break - } - if si.i != -1 { - f.d.decodeValue(rv.Field(int(si.i))) - } else { - f.d.decEmbeddedField(rv, si.is) - } - } - if containerLen > len(fti.sfip) { - // read remaining values and throw away - for j := len(fti.sfip); j < containerLen; j++ { - var nilintf0 interface{} - f.d.decodeValue(reflect.ValueOf(&nilintf0).Elem()) - } - } - } else { - decErr("Only encoded map or array can be decoded into a struct. (valueType: %x)", - currEncodedType) - } -} - -func (f *decFnInfo) kSlice(rv reflect.Value) { - // A slice can be set from a map or array in stream. - currEncodedType := f.dd.currentEncodedType() - - switch currEncodedType { - case valueTypeBytes, valueTypeString: - if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 { - if bs2, changed2 := f.dd.decodeBytes(rv.Bytes()); changed2 { - rv.SetBytes(bs2) - } - return - } - } - - if shortCircuitReflectToFastPath && rv.CanAddr() { - switch f.ti.rtid { - case intfSliceTypId: - f.d.decSliceIntf(rv.Addr().Interface().(*[]interface{}), currEncodedType, f.array) - return - case uint64SliceTypId: - f.d.decSliceUint64(rv.Addr().Interface().(*[]uint64), currEncodedType, f.array) - return - case int64SliceTypId: - f.d.decSliceInt64(rv.Addr().Interface().(*[]int64), currEncodedType, f.array) - return - case strSliceTypId: - f.d.decSliceStr(rv.Addr().Interface().(*[]string), currEncodedType, f.array) - return - } - } - - containerLen, containerLenS := decContLens(f.dd, currEncodedType) - - // an array can never return a nil slice. so no need to check f.array here. - - if rv.IsNil() { - rv.Set(reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS)) - } - - if containerLen == 0 { - return - } - - if rvcap, rvlen := rv.Len(), rv.Cap(); containerLenS > rvcap { - if f.array { // !rv.CanSet() - decErr(msgDecCannotExpandArr, rvcap, containerLenS) - } - rvn := reflect.MakeSlice(f.ti.rt, containerLenS, containerLenS) - if rvlen > 0 { - reflect.Copy(rvn, rv) - } - rv.Set(rvn) - } else if containerLenS > rvlen { - rv.SetLen(containerLenS) - } - - for j := 0; j < containerLenS; j++ { - f.d.decodeValue(rv.Index(j)) - } -} - -func (f *decFnInfo) kArray(rv reflect.Value) { - // f.d.decodeValue(rv.Slice(0, rv.Len())) - f.kSlice(rv.Slice(0, rv.Len())) -} - -func (f *decFnInfo) kMap(rv reflect.Value) { - if shortCircuitReflectToFastPath && rv.CanAddr() { - switch f.ti.rtid { - case mapStrIntfTypId: - f.d.decMapStrIntf(rv.Addr().Interface().(*map[string]interface{})) - return - case mapIntfIntfTypId: - f.d.decMapIntfIntf(rv.Addr().Interface().(*map[interface{}]interface{})) - return - case mapInt64IntfTypId: - f.d.decMapInt64Intf(rv.Addr().Interface().(*map[int64]interface{})) - return - case mapUint64IntfTypId: - f.d.decMapUint64Intf(rv.Addr().Interface().(*map[uint64]interface{})) - return - } - } - - containerLen := f.dd.readMapLen() - - if rv.IsNil() { - rv.Set(reflect.MakeMap(f.ti.rt)) - } - - if containerLen == 0 { - return - } - - ktype, vtype := f.ti.rt.Key(), f.ti.rt.Elem() - ktypeId := reflect.ValueOf(ktype).Pointer() - for j := 0; j < containerLen; j++ { - rvk := reflect.New(ktype).Elem() - f.d.decodeValue(rvk) - - // special case if a byte array. - // if ktype == intfTyp { - if ktypeId == intfTypId { - rvk = rvk.Elem() - if rvk.Type() == uint8SliceTyp { - rvk = reflect.ValueOf(string(rvk.Bytes())) - } - } - rvv := rv.MapIndex(rvk) - if !rvv.IsValid() || !rvv.CanSet() { - rvv = reflect.New(vtype).Elem() - } - - f.d.decodeValue(rvv) - rv.SetMapIndex(rvk, rvv) - } -} - -// ---------------------------------------- - -type decFn struct { - i *decFnInfo - f func(*decFnInfo, reflect.Value) -} - -// A Decoder reads and decodes an object from an input stream in the codec format. -type Decoder struct { - r decReader - d decDriver - h *BasicHandle - f map[uintptr]decFn - x []uintptr - s []decFn -} - -// NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader. -// -// For efficiency, Users are encouraged to pass in a memory buffered writer -// (eg bufio.Reader, bytes.Buffer). -func NewDecoder(r io.Reader, h Handle) *Decoder { - z := ioDecReader{ - r: r, - } - z.br, _ = r.(io.ByteReader) - return &Decoder{r: &z, d: h.newDecDriver(&z), h: h.getBasicHandle()} -} - -// NewDecoderBytes returns a Decoder which efficiently decodes directly -// from a byte slice with zero copying. -func NewDecoderBytes(in []byte, h Handle) *Decoder { - z := bytesDecReader{ - b: in, - a: len(in), - } - return &Decoder{r: &z, d: h.newDecDriver(&z), h: h.getBasicHandle()} -} - -// Decode decodes the stream from reader and stores the result in the -// value pointed to by v. v cannot be a nil pointer. v can also be -// a reflect.Value of a pointer. -// -// Note that a pointer to a nil interface is not a nil pointer. -// If you do not know what type of stream it is, pass in a pointer to a nil interface. -// We will decode and store a value in that nil interface. -// -// Sample usages: -// // Decoding into a non-nil typed value -// var f float32 -// err = codec.NewDecoder(r, handle).Decode(&f) -// -// // Decoding into nil interface -// var v interface{} -// dec := codec.NewDecoder(r, handle) -// err = dec.Decode(&v) -// -// When decoding into a nil interface{}, we will decode into an appropriate value based -// on the contents of the stream: -// - Numbers are decoded as float64, int64 or uint64. -// - Other values are decoded appropriately depending on the type: -// bool, string, []byte, time.Time, etc -// - Extensions are decoded as RawExt (if no ext function registered for the tag) -// Configurations exist on the Handle to override defaults -// (e.g. for MapType, SliceType and how to decode raw bytes). -// -// When decoding into a non-nil interface{} value, the mode of encoding is based on the -// type of the value. When a value is seen: -// - If an extension is registered for it, call that extension function -// - If it implements BinaryUnmarshaler, call its UnmarshalBinary(data []byte) error -// - Else decode it based on its reflect.Kind -// -// There are some special rules when decoding into containers (slice/array/map/struct). -// Decode will typically use the stream contents to UPDATE the container. -// - A map can be decoded from a stream map, by updating matching keys. -// - A slice can be decoded from a stream array, -// by updating the first n elements, where n is length of the stream. -// - A slice can be decoded from a stream map, by decoding as if -// it contains a sequence of key-value pairs. -// - A struct can be decoded from a stream map, by updating matching fields. -// - A struct can be decoded from a stream array, -// by updating fields as they occur in the struct (by index). -// -// When decoding a stream map or array with length of 0 into a nil map or slice, -// we reset the destination map or slice to a zero-length value. -// -// However, when decoding a stream nil, we reset the destination container -// to its "zero" value (e.g. nil for slice/map, etc). -// -func (d *Decoder) Decode(v interface{}) (err error) { - defer panicToErr(&err) - d.decode(v) - return -} - -func (d *Decoder) decode(iv interface{}) { - d.d.initReadNext() - - switch v := iv.(type) { - case nil: - decErr("Cannot decode into nil.") - - case reflect.Value: - d.chkPtrValue(v) - d.decodeValue(v.Elem()) - - case *string: - *v = d.d.decodeString() - case *bool: - *v = d.d.decodeBool() - case *int: - *v = int(d.d.decodeInt(intBitsize)) - case *int8: - *v = int8(d.d.decodeInt(8)) - case *int16: - *v = int16(d.d.decodeInt(16)) - case *int32: - *v = int32(d.d.decodeInt(32)) - case *int64: - *v = d.d.decodeInt(64) - case *uint: - *v = uint(d.d.decodeUint(uintBitsize)) - case *uint8: - *v = uint8(d.d.decodeUint(8)) - case *uint16: - *v = uint16(d.d.decodeUint(16)) - case *uint32: - *v = uint32(d.d.decodeUint(32)) - case *uint64: - *v = d.d.decodeUint(64) - case *float32: - *v = float32(d.d.decodeFloat(true)) - case *float64: - *v = d.d.decodeFloat(false) - case *[]byte: - *v, _ = d.d.decodeBytes(*v) - - case *[]interface{}: - d.decSliceIntf(v, valueTypeInvalid, false) - case *[]uint64: - d.decSliceUint64(v, valueTypeInvalid, false) - case *[]int64: - d.decSliceInt64(v, valueTypeInvalid, false) - case *[]string: - d.decSliceStr(v, valueTypeInvalid, false) - case *map[string]interface{}: - d.decMapStrIntf(v) - case *map[interface{}]interface{}: - d.decMapIntfIntf(v) - case *map[uint64]interface{}: - d.decMapUint64Intf(v) - case *map[int64]interface{}: - d.decMapInt64Intf(v) - - case *interface{}: - d.decodeValue(reflect.ValueOf(iv).Elem()) - - default: - rv := reflect.ValueOf(iv) - d.chkPtrValue(rv) - d.decodeValue(rv.Elem()) - } -} - -func (d *Decoder) decodeValue(rv reflect.Value) { - d.d.initReadNext() - - if d.d.tryDecodeAsNil() { - // If value in stream is nil, set the dereferenced value to its "zero" value (if settable) - if rv.Kind() == reflect.Ptr { - if !rv.IsNil() { - rv.Set(reflect.Zero(rv.Type())) - } - return - } - // for rv.Kind() == reflect.Ptr { - // rv = rv.Elem() - // } - if rv.IsValid() { // rv.CanSet() // always settable, except it's invalid - rv.Set(reflect.Zero(rv.Type())) - } - return - } - - // If stream is not containing a nil value, then we can deref to the base - // non-pointer value, and decode into that. - for rv.Kind() == reflect.Ptr { - if rv.IsNil() { - rv.Set(reflect.New(rv.Type().Elem())) - } - rv = rv.Elem() - } - - rt := rv.Type() - rtid := reflect.ValueOf(rt).Pointer() - - // retrieve or register a focus'ed function for this type - // to eliminate need to do the retrieval multiple times - - // if d.f == nil && d.s == nil { debugf("---->Creating new dec f map for type: %v\n", rt) } - var fn decFn - var ok bool - if useMapForCodecCache { - fn, ok = d.f[rtid] - } else { - for i, v := range d.x { - if v == rtid { - fn, ok = d.s[i], true - break - } - } - } - if !ok { - // debugf("\tCreating new dec fn for type: %v\n", rt) - fi := decFnInfo{ti: getTypeInfo(rtid, rt), d: d, dd: d.d} - fn.i = &fi - // An extension can be registered for any type, regardless of the Kind - // (e.g. type BitSet int64, type MyStruct { / * unexported fields * / }, type X []int, etc. - // - // We can't check if it's an extension byte here first, because the user may have - // registered a pointer or non-pointer type, meaning we may have to recurse first - // before matching a mapped type, even though the extension byte is already detected. - // - // NOTE: if decoding into a nil interface{}, we return a non-nil - // value except even if the container registers a length of 0. - if rtid == rawExtTypId { - fn.f = (*decFnInfo).rawExt - } else if d.d.isBuiltinType(rtid) { - fn.f = (*decFnInfo).builtin - } else if xfTag, xfFn := d.h.getDecodeExt(rtid); xfFn != nil { - fi.xfTag, fi.xfFn = xfTag, xfFn - fn.f = (*decFnInfo).ext - } else if supportBinaryMarshal && fi.ti.unm { - fn.f = (*decFnInfo).binaryMarshal - } else { - switch rk := rt.Kind(); rk { - case reflect.String: - fn.f = (*decFnInfo).kString - case reflect.Bool: - fn.f = (*decFnInfo).kBool - case reflect.Int: - fn.f = (*decFnInfo).kInt - case reflect.Int64: - fn.f = (*decFnInfo).kInt64 - case reflect.Int32: - fn.f = (*decFnInfo).kInt32 - case reflect.Int8: - fn.f = (*decFnInfo).kInt8 - case reflect.Int16: - fn.f = (*decFnInfo).kInt16 - case reflect.Float32: - fn.f = (*decFnInfo).kFloat32 - case reflect.Float64: - fn.f = (*decFnInfo).kFloat64 - case reflect.Uint8: - fn.f = (*decFnInfo).kUint8 - case reflect.Uint64: - fn.f = (*decFnInfo).kUint64 - case reflect.Uint: - fn.f = (*decFnInfo).kUint - case reflect.Uint32: - fn.f = (*decFnInfo).kUint32 - case reflect.Uint16: - fn.f = (*decFnInfo).kUint16 - // case reflect.Ptr: - // fn.f = (*decFnInfo).kPtr - case reflect.Interface: - fn.f = (*decFnInfo).kInterface - case reflect.Struct: - fn.f = (*decFnInfo).kStruct - case reflect.Slice: - fn.f = (*decFnInfo).kSlice - case reflect.Array: - fi.array = true - fn.f = (*decFnInfo).kArray - case reflect.Map: - fn.f = (*decFnInfo).kMap - default: - fn.f = (*decFnInfo).kErr - } - } - if useMapForCodecCache { - if d.f == nil { - d.f = make(map[uintptr]decFn, 16) - } - d.f[rtid] = fn - } else { - d.s = append(d.s, fn) - d.x = append(d.x, rtid) - } - } - - fn.f(fn.i, rv) - - return -} - -func (d *Decoder) chkPtrValue(rv reflect.Value) { - // We can only decode into a non-nil pointer - if rv.Kind() == reflect.Ptr && !rv.IsNil() { - return - } - if !rv.IsValid() { - decErr("Cannot decode into a zero (ie invalid) reflect.Value") - } - if !rv.CanInterface() { - decErr("Cannot decode into a value without an interface: %v", rv) - } - rvi := rv.Interface() - decErr("Cannot decode into non-pointer or nil pointer. Got: %v, %T, %v", - rv.Kind(), rvi, rvi) -} - -func (d *Decoder) decEmbeddedField(rv reflect.Value, index []int) { - // d.decodeValue(rv.FieldByIndex(index)) - // nil pointers may be here; so reproduce FieldByIndex logic + enhancements - for _, j := range index { - if rv.Kind() == reflect.Ptr { - if rv.IsNil() { - rv.Set(reflect.New(rv.Type().Elem())) - } - // If a pointer, it must be a pointer to struct (based on typeInfo contract) - rv = rv.Elem() - } - rv = rv.Field(j) - } - d.decodeValue(rv) -} - -// -------------------------------------------------- - -// short circuit functions for common maps and slices - -func (d *Decoder) decSliceIntf(v *[]interface{}, currEncodedType valueType, doNotReset bool) { - _, containerLenS := decContLens(d.d, currEncodedType) - s := *v - if s == nil { - s = make([]interface{}, containerLenS, containerLenS) - } else if containerLenS > cap(s) { - if doNotReset { - decErr(msgDecCannotExpandArr, cap(s), containerLenS) - } - s = make([]interface{}, containerLenS, containerLenS) - copy(s, *v) - } else if containerLenS > len(s) { - s = s[:containerLenS] - } - for j := 0; j < containerLenS; j++ { - d.decode(&s[j]) - } - *v = s -} - -func (d *Decoder) decSliceInt64(v *[]int64, currEncodedType valueType, doNotReset bool) { - _, containerLenS := decContLens(d.d, currEncodedType) - s := *v - if s == nil { - s = make([]int64, containerLenS, containerLenS) - } else if containerLenS > cap(s) { - if doNotReset { - decErr(msgDecCannotExpandArr, cap(s), containerLenS) - } - s = make([]int64, containerLenS, containerLenS) - copy(s, *v) - } else if containerLenS > len(s) { - s = s[:containerLenS] - } - for j := 0; j < containerLenS; j++ { - // d.decode(&s[j]) - d.d.initReadNext() - s[j] = d.d.decodeInt(intBitsize) - } - *v = s -} - -func (d *Decoder) decSliceUint64(v *[]uint64, currEncodedType valueType, doNotReset bool) { - _, containerLenS := decContLens(d.d, currEncodedType) - s := *v - if s == nil { - s = make([]uint64, containerLenS, containerLenS) - } else if containerLenS > cap(s) { - if doNotReset { - decErr(msgDecCannotExpandArr, cap(s), containerLenS) - } - s = make([]uint64, containerLenS, containerLenS) - copy(s, *v) - } else if containerLenS > len(s) { - s = s[:containerLenS] - } - for j := 0; j < containerLenS; j++ { - // d.decode(&s[j]) - d.d.initReadNext() - s[j] = d.d.decodeUint(intBitsize) - } - *v = s -} - -func (d *Decoder) decSliceStr(v *[]string, currEncodedType valueType, doNotReset bool) { - _, containerLenS := decContLens(d.d, currEncodedType) - s := *v - if s == nil { - s = make([]string, containerLenS, containerLenS) - } else if containerLenS > cap(s) { - if doNotReset { - decErr(msgDecCannotExpandArr, cap(s), containerLenS) - } - s = make([]string, containerLenS, containerLenS) - copy(s, *v) - } else if containerLenS > len(s) { - s = s[:containerLenS] - } - for j := 0; j < containerLenS; j++ { - // d.decode(&s[j]) - d.d.initReadNext() - s[j] = d.d.decodeString() - } - *v = s -} - -func (d *Decoder) decMapIntfIntf(v *map[interface{}]interface{}) { - containerLen := d.d.readMapLen() - m := *v - if m == nil { - m = make(map[interface{}]interface{}, containerLen) - *v = m - } - for j := 0; j < containerLen; j++ { - var mk interface{} - d.decode(&mk) - // special case if a byte array. - if bv, bok := mk.([]byte); bok { - mk = string(bv) - } - mv := m[mk] - d.decode(&mv) - m[mk] = mv - } -} - -func (d *Decoder) decMapInt64Intf(v *map[int64]interface{}) { - containerLen := d.d.readMapLen() - m := *v - if m == nil { - m = make(map[int64]interface{}, containerLen) - *v = m - } - for j := 0; j < containerLen; j++ { - d.d.initReadNext() - mk := d.d.decodeInt(intBitsize) - mv := m[mk] - d.decode(&mv) - m[mk] = mv - } -} - -func (d *Decoder) decMapUint64Intf(v *map[uint64]interface{}) { - containerLen := d.d.readMapLen() - m := *v - if m == nil { - m = make(map[uint64]interface{}, containerLen) - *v = m - } - for j := 0; j < containerLen; j++ { - d.d.initReadNext() - mk := d.d.decodeUint(intBitsize) - mv := m[mk] - d.decode(&mv) - m[mk] = mv - } -} - -func (d *Decoder) decMapStrIntf(v *map[string]interface{}) { - containerLen := d.d.readMapLen() - m := *v - if m == nil { - m = make(map[string]interface{}, containerLen) - *v = m - } - for j := 0; j < containerLen; j++ { - d.d.initReadNext() - mk := d.d.decodeString() - mv := m[mk] - d.decode(&mv) - m[mk] = mv - } -} - -// ---------------------------------------- - -func decContLens(dd decDriver, currEncodedType valueType) (containerLen, containerLenS int) { - if currEncodedType == valueTypeInvalid { - currEncodedType = dd.currentEncodedType() - } - switch currEncodedType { - case valueTypeArray: - containerLen = dd.readArrayLen() - containerLenS = containerLen - case valueTypeMap: - containerLen = dd.readMapLen() - containerLenS = containerLen * 2 - default: - decErr("Only encoded map or array can be decoded into a slice. (valueType: %0x)", - currEncodedType) - } - return -} - -func decErr(format string, params ...interface{}) { - doPanic(msgTagDec, format, params...) -} diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/encode.go b/vendor/github.com/hashicorp/go-msgpack/codec/encode.go deleted file mode 100644 index 4914be0c..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/encode.go +++ /dev/null @@ -1,1001 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -import ( - "io" - "reflect" -) - -const ( - // Some tagging information for error messages. - msgTagEnc = "codec.encoder" - defEncByteBufSize = 1 << 6 // 4:16, 6:64, 8:256, 10:1024 - // maxTimeSecs32 = math.MaxInt32 / 60 / 24 / 366 -) - -// AsSymbolFlag defines what should be encoded as symbols. -type AsSymbolFlag uint8 - -const ( - // AsSymbolDefault is default. - // Currently, this means only encode struct field names as symbols. - // The default is subject to change. - AsSymbolDefault AsSymbolFlag = iota - - // AsSymbolAll means encode anything which could be a symbol as a symbol. - AsSymbolAll = 0xfe - - // AsSymbolNone means do not encode anything as a symbol. - AsSymbolNone = 1 << iota - - // AsSymbolMapStringKeys means encode keys in map[string]XXX as symbols. - AsSymbolMapStringKeysFlag - - // AsSymbolStructFieldName means encode struct field names as symbols. - AsSymbolStructFieldNameFlag -) - -// encWriter abstracting writing to a byte array or to an io.Writer. -type encWriter interface { - writeUint16(uint16) - writeUint32(uint32) - writeUint64(uint64) - writeb([]byte) - writestr(string) - writen1(byte) - writen2(byte, byte) - atEndOfEncode() -} - -// encDriver abstracts the actual codec (binc vs msgpack, etc) -type encDriver interface { - isBuiltinType(rt uintptr) bool - encodeBuiltin(rt uintptr, v interface{}) - encodeNil() - encodeInt(i int64) - encodeUint(i uint64) - encodeBool(b bool) - encodeFloat32(f float32) - encodeFloat64(f float64) - encodeExtPreamble(xtag byte, length int) - encodeArrayPreamble(length int) - encodeMapPreamble(length int) - encodeString(c charEncoding, v string) - encodeSymbol(v string) - encodeStringBytes(c charEncoding, v []byte) - //TODO - //encBignum(f *big.Int) - //encStringRunes(c charEncoding, v []rune) -} - -type ioEncWriterWriter interface { - WriteByte(c byte) error - WriteString(s string) (n int, err error) - Write(p []byte) (n int, err error) -} - -type ioEncStringWriter interface { - WriteString(s string) (n int, err error) -} - -type EncodeOptions struct { - // Encode a struct as an array, and not as a map. - StructToArray bool - - // AsSymbols defines what should be encoded as symbols. - // - // Encoding as symbols can reduce the encoded size significantly. - // - // However, during decoding, each string to be encoded as a symbol must - // be checked to see if it has been seen before. Consequently, encoding time - // will increase if using symbols, because string comparisons has a clear cost. - // - // Sample values: - // AsSymbolNone - // AsSymbolAll - // AsSymbolMapStringKeys - // AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag - AsSymbols AsSymbolFlag -} - -// --------------------------------------------- - -type simpleIoEncWriterWriter struct { - w io.Writer - bw io.ByteWriter - sw ioEncStringWriter -} - -func (o *simpleIoEncWriterWriter) WriteByte(c byte) (err error) { - if o.bw != nil { - return o.bw.WriteByte(c) - } - _, err = o.w.Write([]byte{c}) - return -} - -func (o *simpleIoEncWriterWriter) WriteString(s string) (n int, err error) { - if o.sw != nil { - return o.sw.WriteString(s) - } - return o.w.Write([]byte(s)) -} - -func (o *simpleIoEncWriterWriter) Write(p []byte) (n int, err error) { - return o.w.Write(p) -} - -// ---------------------------------------- - -// ioEncWriter implements encWriter and can write to an io.Writer implementation -type ioEncWriter struct { - w ioEncWriterWriter - x [8]byte // temp byte array re-used internally for efficiency -} - -func (z *ioEncWriter) writeUint16(v uint16) { - bigen.PutUint16(z.x[:2], v) - z.writeb(z.x[:2]) -} - -func (z *ioEncWriter) writeUint32(v uint32) { - bigen.PutUint32(z.x[:4], v) - z.writeb(z.x[:4]) -} - -func (z *ioEncWriter) writeUint64(v uint64) { - bigen.PutUint64(z.x[:8], v) - z.writeb(z.x[:8]) -} - -func (z *ioEncWriter) writeb(bs []byte) { - if len(bs) == 0 { - return - } - n, err := z.w.Write(bs) - if err != nil { - panic(err) - } - if n != len(bs) { - encErr("write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(bs), n) - } -} - -func (z *ioEncWriter) writestr(s string) { - n, err := z.w.WriteString(s) - if err != nil { - panic(err) - } - if n != len(s) { - encErr("write: Incorrect num bytes written. Expecting: %v, Wrote: %v", len(s), n) - } -} - -func (z *ioEncWriter) writen1(b byte) { - if err := z.w.WriteByte(b); err != nil { - panic(err) - } -} - -func (z *ioEncWriter) writen2(b1 byte, b2 byte) { - z.writen1(b1) - z.writen1(b2) -} - -func (z *ioEncWriter) atEndOfEncode() {} - -// ---------------------------------------- - -// bytesEncWriter implements encWriter and can write to an byte slice. -// It is used by Marshal function. -type bytesEncWriter struct { - b []byte - c int // cursor - out *[]byte // write out on atEndOfEncode -} - -func (z *bytesEncWriter) writeUint16(v uint16) { - c := z.grow(2) - z.b[c] = byte(v >> 8) - z.b[c+1] = byte(v) -} - -func (z *bytesEncWriter) writeUint32(v uint32) { - c := z.grow(4) - z.b[c] = byte(v >> 24) - z.b[c+1] = byte(v >> 16) - z.b[c+2] = byte(v >> 8) - z.b[c+3] = byte(v) -} - -func (z *bytesEncWriter) writeUint64(v uint64) { - c := z.grow(8) - z.b[c] = byte(v >> 56) - z.b[c+1] = byte(v >> 48) - z.b[c+2] = byte(v >> 40) - z.b[c+3] = byte(v >> 32) - z.b[c+4] = byte(v >> 24) - z.b[c+5] = byte(v >> 16) - z.b[c+6] = byte(v >> 8) - z.b[c+7] = byte(v) -} - -func (z *bytesEncWriter) writeb(s []byte) { - if len(s) == 0 { - return - } - c := z.grow(len(s)) - copy(z.b[c:], s) -} - -func (z *bytesEncWriter) writestr(s string) { - c := z.grow(len(s)) - copy(z.b[c:], s) -} - -func (z *bytesEncWriter) writen1(b1 byte) { - c := z.grow(1) - z.b[c] = b1 -} - -func (z *bytesEncWriter) writen2(b1 byte, b2 byte) { - c := z.grow(2) - z.b[c] = b1 - z.b[c+1] = b2 -} - -func (z *bytesEncWriter) atEndOfEncode() { - *(z.out) = z.b[:z.c] -} - -func (z *bytesEncWriter) grow(n int) (oldcursor int) { - oldcursor = z.c - z.c = oldcursor + n - if z.c > cap(z.b) { - // Tried using appendslice logic: (if cap < 1024, *2, else *1.25). - // However, it was too expensive, causing too many iterations of copy. - // Using bytes.Buffer model was much better (2*cap + n) - bs := make([]byte, 2*cap(z.b)+n) - copy(bs, z.b[:oldcursor]) - z.b = bs - } else if z.c > len(z.b) { - z.b = z.b[:cap(z.b)] - } - return -} - -// --------------------------------------------- - -type encFnInfo struct { - ti *typeInfo - e *Encoder - ee encDriver - xfFn func(reflect.Value) ([]byte, error) - xfTag byte -} - -func (f *encFnInfo) builtin(rv reflect.Value) { - f.ee.encodeBuiltin(f.ti.rtid, rv.Interface()) -} - -func (f *encFnInfo) rawExt(rv reflect.Value) { - f.e.encRawExt(rv.Interface().(RawExt)) -} - -func (f *encFnInfo) ext(rv reflect.Value) { - bs, fnerr := f.xfFn(rv) - if fnerr != nil { - panic(fnerr) - } - if bs == nil { - f.ee.encodeNil() - return - } - if f.e.hh.writeExt() { - f.ee.encodeExtPreamble(f.xfTag, len(bs)) - f.e.w.writeb(bs) - } else { - f.ee.encodeStringBytes(c_RAW, bs) - } - -} - -func (f *encFnInfo) binaryMarshal(rv reflect.Value) { - var bm binaryMarshaler - if f.ti.mIndir == 0 { - bm = rv.Interface().(binaryMarshaler) - } else if f.ti.mIndir == -1 { - bm = rv.Addr().Interface().(binaryMarshaler) - } else { - for j, k := int8(0), f.ti.mIndir; j < k; j++ { - if rv.IsNil() { - f.ee.encodeNil() - return - } - rv = rv.Elem() - } - bm = rv.Interface().(binaryMarshaler) - } - // debugf(">>>> binaryMarshaler: %T", rv.Interface()) - bs, fnerr := bm.MarshalBinary() - if fnerr != nil { - panic(fnerr) - } - if bs == nil { - f.ee.encodeNil() - } else { - f.ee.encodeStringBytes(c_RAW, bs) - } -} - -func (f *encFnInfo) kBool(rv reflect.Value) { - f.ee.encodeBool(rv.Bool()) -} - -func (f *encFnInfo) kString(rv reflect.Value) { - f.ee.encodeString(c_UTF8, rv.String()) -} - -func (f *encFnInfo) kFloat64(rv reflect.Value) { - f.ee.encodeFloat64(rv.Float()) -} - -func (f *encFnInfo) kFloat32(rv reflect.Value) { - f.ee.encodeFloat32(float32(rv.Float())) -} - -func (f *encFnInfo) kInt(rv reflect.Value) { - f.ee.encodeInt(rv.Int()) -} - -func (f *encFnInfo) kUint(rv reflect.Value) { - f.ee.encodeUint(rv.Uint()) -} - -func (f *encFnInfo) kInvalid(rv reflect.Value) { - f.ee.encodeNil() -} - -func (f *encFnInfo) kErr(rv reflect.Value) { - encErr("Unsupported kind: %s, for: %#v", rv.Kind(), rv) -} - -func (f *encFnInfo) kSlice(rv reflect.Value) { - if rv.IsNil() { - f.ee.encodeNil() - return - } - - if shortCircuitReflectToFastPath { - switch f.ti.rtid { - case intfSliceTypId: - f.e.encSliceIntf(rv.Interface().([]interface{})) - return - case strSliceTypId: - f.e.encSliceStr(rv.Interface().([]string)) - return - case uint64SliceTypId: - f.e.encSliceUint64(rv.Interface().([]uint64)) - return - case int64SliceTypId: - f.e.encSliceInt64(rv.Interface().([]int64)) - return - } - } - - // If in this method, then there was no extension function defined. - // So it's okay to treat as []byte. - if f.ti.rtid == uint8SliceTypId || f.ti.rt.Elem().Kind() == reflect.Uint8 { - f.ee.encodeStringBytes(c_RAW, rv.Bytes()) - return - } - - l := rv.Len() - if f.ti.mbs { - if l%2 == 1 { - encErr("mapBySlice: invalid length (must be divisible by 2): %v", l) - } - f.ee.encodeMapPreamble(l / 2) - } else { - f.ee.encodeArrayPreamble(l) - } - if l == 0 { - return - } - for j := 0; j < l; j++ { - // TODO: Consider perf implication of encoding odd index values as symbols if type is string - f.e.encodeValue(rv.Index(j)) - } -} - -func (f *encFnInfo) kArray(rv reflect.Value) { - // We cannot share kSlice method, because the array may be non-addressable. - // E.g. type struct S{B [2]byte}; Encode(S{}) will bomb on "panic: slice of unaddressable array". - // So we have to duplicate the functionality here. - // f.e.encodeValue(rv.Slice(0, rv.Len())) - // f.kSlice(rv.Slice(0, rv.Len())) - - l := rv.Len() - // Handle an array of bytes specially (in line with what is done for slices) - if f.ti.rt.Elem().Kind() == reflect.Uint8 { - if l == 0 { - f.ee.encodeStringBytes(c_RAW, nil) - return - } - var bs []byte - if rv.CanAddr() { - bs = rv.Slice(0, l).Bytes() - } else { - bs = make([]byte, l) - for i := 0; i < l; i++ { - bs[i] = byte(rv.Index(i).Uint()) - } - } - f.ee.encodeStringBytes(c_RAW, bs) - return - } - - if f.ti.mbs { - if l%2 == 1 { - encErr("mapBySlice: invalid length (must be divisible by 2): %v", l) - } - f.ee.encodeMapPreamble(l / 2) - } else { - f.ee.encodeArrayPreamble(l) - } - if l == 0 { - return - } - for j := 0; j < l; j++ { - // TODO: Consider perf implication of encoding odd index values as symbols if type is string - f.e.encodeValue(rv.Index(j)) - } -} - -func (f *encFnInfo) kStruct(rv reflect.Value) { - fti := f.ti - newlen := len(fti.sfi) - rvals := make([]reflect.Value, newlen) - var encnames []string - e := f.e - tisfi := fti.sfip - toMap := !(fti.toArray || e.h.StructToArray) - // if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct) - if toMap { - tisfi = fti.sfi - encnames = make([]string, newlen) - } - newlen = 0 - for _, si := range tisfi { - if si.i != -1 { - rvals[newlen] = rv.Field(int(si.i)) - } else { - rvals[newlen] = rv.FieldByIndex(si.is) - } - if toMap { - if si.omitEmpty && isEmptyValue(rvals[newlen]) { - continue - } - encnames[newlen] = si.encName - } else { - if si.omitEmpty && isEmptyValue(rvals[newlen]) { - rvals[newlen] = reflect.Value{} //encode as nil - } - } - newlen++ - } - - // debugf(">>>> kStruct: newlen: %v", newlen) - if toMap { - ee := f.ee //don't dereference everytime - ee.encodeMapPreamble(newlen) - // asSymbols := e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0 - asSymbols := e.h.AsSymbols == AsSymbolDefault || e.h.AsSymbols&AsSymbolStructFieldNameFlag != 0 - for j := 0; j < newlen; j++ { - if asSymbols { - ee.encodeSymbol(encnames[j]) - } else { - ee.encodeString(c_UTF8, encnames[j]) - } - e.encodeValue(rvals[j]) - } - } else { - f.ee.encodeArrayPreamble(newlen) - for j := 0; j < newlen; j++ { - e.encodeValue(rvals[j]) - } - } -} - -// func (f *encFnInfo) kPtr(rv reflect.Value) { -// debugf(">>>>>>> ??? encode kPtr called - shouldn't get called") -// if rv.IsNil() { -// f.ee.encodeNil() -// return -// } -// f.e.encodeValue(rv.Elem()) -// } - -func (f *encFnInfo) kInterface(rv reflect.Value) { - if rv.IsNil() { - f.ee.encodeNil() - return - } - f.e.encodeValue(rv.Elem()) -} - -func (f *encFnInfo) kMap(rv reflect.Value) { - if rv.IsNil() { - f.ee.encodeNil() - return - } - - if shortCircuitReflectToFastPath { - switch f.ti.rtid { - case mapIntfIntfTypId: - f.e.encMapIntfIntf(rv.Interface().(map[interface{}]interface{})) - return - case mapStrIntfTypId: - f.e.encMapStrIntf(rv.Interface().(map[string]interface{})) - return - case mapStrStrTypId: - f.e.encMapStrStr(rv.Interface().(map[string]string)) - return - case mapInt64IntfTypId: - f.e.encMapInt64Intf(rv.Interface().(map[int64]interface{})) - return - case mapUint64IntfTypId: - f.e.encMapUint64Intf(rv.Interface().(map[uint64]interface{})) - return - } - } - - l := rv.Len() - f.ee.encodeMapPreamble(l) - if l == 0 { - return - } - // keyTypeIsString := f.ti.rt.Key().Kind() == reflect.String - keyTypeIsString := f.ti.rt.Key() == stringTyp - var asSymbols bool - if keyTypeIsString { - asSymbols = f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0 - } - mks := rv.MapKeys() - // for j, lmks := 0, len(mks); j < lmks; j++ { - for j := range mks { - if keyTypeIsString { - if asSymbols { - f.ee.encodeSymbol(mks[j].String()) - } else { - f.ee.encodeString(c_UTF8, mks[j].String()) - } - } else { - f.e.encodeValue(mks[j]) - } - f.e.encodeValue(rv.MapIndex(mks[j])) - } - -} - -// -------------------------------------------------- - -// encFn encapsulates the captured variables and the encode function. -// This way, we only do some calculations one times, and pass to the -// code block that should be called (encapsulated in a function) -// instead of executing the checks every time. -type encFn struct { - i *encFnInfo - f func(*encFnInfo, reflect.Value) -} - -// -------------------------------------------------- - -// An Encoder writes an object to an output stream in the codec format. -type Encoder struct { - w encWriter - e encDriver - h *BasicHandle - hh Handle - f map[uintptr]encFn - x []uintptr - s []encFn -} - -// NewEncoder returns an Encoder for encoding into an io.Writer. -// -// For efficiency, Users are encouraged to pass in a memory buffered writer -// (eg bufio.Writer, bytes.Buffer). -func NewEncoder(w io.Writer, h Handle) *Encoder { - ww, ok := w.(ioEncWriterWriter) - if !ok { - sww := simpleIoEncWriterWriter{w: w} - sww.bw, _ = w.(io.ByteWriter) - sww.sw, _ = w.(ioEncStringWriter) - ww = &sww - //ww = bufio.NewWriterSize(w, defEncByteBufSize) - } - z := ioEncWriter{ - w: ww, - } - return &Encoder{w: &z, hh: h, h: h.getBasicHandle(), e: h.newEncDriver(&z)} -} - -// NewEncoderBytes returns an encoder for encoding directly and efficiently -// into a byte slice, using zero-copying to temporary slices. -// -// It will potentially replace the output byte slice pointed to. -// After encoding, the out parameter contains the encoded contents. -func NewEncoderBytes(out *[]byte, h Handle) *Encoder { - in := *out - if in == nil { - in = make([]byte, defEncByteBufSize) - } - z := bytesEncWriter{ - b: in, - out: out, - } - return &Encoder{w: &z, hh: h, h: h.getBasicHandle(), e: h.newEncDriver(&z)} -} - -// Encode writes an object into a stream in the codec format. -// -// Encoding can be configured via the "codec" struct tag for the fields. -// -// The "codec" key in struct field's tag value is the key name, -// followed by an optional comma and options. -// -// To set an option on all fields (e.g. omitempty on all fields), you -// can create a field called _struct, and set flags on it. -// -// Struct values "usually" encode as maps. Each exported struct field is encoded unless: -// - the field's codec tag is "-", OR -// - the field is empty and its codec tag specifies the "omitempty" option. -// -// When encoding as a map, the first string in the tag (before the comma) -// is the map key string to use when encoding. -// -// However, struct values may encode as arrays. This happens when: -// - StructToArray Encode option is set, OR -// - the codec tag on the _struct field sets the "toarray" option -// -// Values with types that implement MapBySlice are encoded as stream maps. -// -// The empty values (for omitempty option) are false, 0, any nil pointer -// or interface value, and any array, slice, map, or string of length zero. -// -// Anonymous fields are encoded inline if no struct tag is present. -// Else they are encoded as regular fields. -// -// Examples: -// -// type MyStruct struct { -// _struct bool `codec:",omitempty"` //set omitempty for every field -// Field1 string `codec:"-"` //skip this field -// Field2 int `codec:"myName"` //Use key "myName" in encode stream -// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty. -// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty. -// ... -// } -// -// type MyStruct struct { -// _struct bool `codec:",omitempty,toarray"` //set omitempty for every field -// //and encode struct as an array -// } -// -// The mode of encoding is based on the type of the value. When a value is seen: -// - If an extension is registered for it, call that extension function -// - If it implements BinaryMarshaler, call its MarshalBinary() (data []byte, err error) -// - Else encode it based on its reflect.Kind -// -// Note that struct field names and keys in map[string]XXX will be treated as symbols. -// Some formats support symbols (e.g. binc) and will properly encode the string -// only once in the stream, and use a tag to refer to it thereafter. -func (e *Encoder) Encode(v interface{}) (err error) { - defer panicToErr(&err) - e.encode(v) - e.w.atEndOfEncode() - return -} - -func (e *Encoder) encode(iv interface{}) { - switch v := iv.(type) { - case nil: - e.e.encodeNil() - - case reflect.Value: - e.encodeValue(v) - - case string: - e.e.encodeString(c_UTF8, v) - case bool: - e.e.encodeBool(v) - case int: - e.e.encodeInt(int64(v)) - case int8: - e.e.encodeInt(int64(v)) - case int16: - e.e.encodeInt(int64(v)) - case int32: - e.e.encodeInt(int64(v)) - case int64: - e.e.encodeInt(v) - case uint: - e.e.encodeUint(uint64(v)) - case uint8: - e.e.encodeUint(uint64(v)) - case uint16: - e.e.encodeUint(uint64(v)) - case uint32: - e.e.encodeUint(uint64(v)) - case uint64: - e.e.encodeUint(v) - case float32: - e.e.encodeFloat32(v) - case float64: - e.e.encodeFloat64(v) - - case []interface{}: - e.encSliceIntf(v) - case []string: - e.encSliceStr(v) - case []int64: - e.encSliceInt64(v) - case []uint64: - e.encSliceUint64(v) - case []uint8: - e.e.encodeStringBytes(c_RAW, v) - - case map[interface{}]interface{}: - e.encMapIntfIntf(v) - case map[string]interface{}: - e.encMapStrIntf(v) - case map[string]string: - e.encMapStrStr(v) - case map[int64]interface{}: - e.encMapInt64Intf(v) - case map[uint64]interface{}: - e.encMapUint64Intf(v) - - case *string: - e.e.encodeString(c_UTF8, *v) - case *bool: - e.e.encodeBool(*v) - case *int: - e.e.encodeInt(int64(*v)) - case *int8: - e.e.encodeInt(int64(*v)) - case *int16: - e.e.encodeInt(int64(*v)) - case *int32: - e.e.encodeInt(int64(*v)) - case *int64: - e.e.encodeInt(*v) - case *uint: - e.e.encodeUint(uint64(*v)) - case *uint8: - e.e.encodeUint(uint64(*v)) - case *uint16: - e.e.encodeUint(uint64(*v)) - case *uint32: - e.e.encodeUint(uint64(*v)) - case *uint64: - e.e.encodeUint(*v) - case *float32: - e.e.encodeFloat32(*v) - case *float64: - e.e.encodeFloat64(*v) - - case *[]interface{}: - e.encSliceIntf(*v) - case *[]string: - e.encSliceStr(*v) - case *[]int64: - e.encSliceInt64(*v) - case *[]uint64: - e.encSliceUint64(*v) - case *[]uint8: - e.e.encodeStringBytes(c_RAW, *v) - - case *map[interface{}]interface{}: - e.encMapIntfIntf(*v) - case *map[string]interface{}: - e.encMapStrIntf(*v) - case *map[string]string: - e.encMapStrStr(*v) - case *map[int64]interface{}: - e.encMapInt64Intf(*v) - case *map[uint64]interface{}: - e.encMapUint64Intf(*v) - - default: - e.encodeValue(reflect.ValueOf(iv)) - } -} - -func (e *Encoder) encodeValue(rv reflect.Value) { - for rv.Kind() == reflect.Ptr { - if rv.IsNil() { - e.e.encodeNil() - return - } - rv = rv.Elem() - } - - rt := rv.Type() - rtid := reflect.ValueOf(rt).Pointer() - - // if e.f == nil && e.s == nil { debugf("---->Creating new enc f map for type: %v\n", rt) } - var fn encFn - var ok bool - if useMapForCodecCache { - fn, ok = e.f[rtid] - } else { - for i, v := range e.x { - if v == rtid { - fn, ok = e.s[i], true - break - } - } - } - if !ok { - // debugf("\tCreating new enc fn for type: %v\n", rt) - fi := encFnInfo{ti: getTypeInfo(rtid, rt), e: e, ee: e.e} - fn.i = &fi - if rtid == rawExtTypId { - fn.f = (*encFnInfo).rawExt - } else if e.e.isBuiltinType(rtid) { - fn.f = (*encFnInfo).builtin - } else if xfTag, xfFn := e.h.getEncodeExt(rtid); xfFn != nil { - fi.xfTag, fi.xfFn = xfTag, xfFn - fn.f = (*encFnInfo).ext - } else if supportBinaryMarshal && fi.ti.m { - fn.f = (*encFnInfo).binaryMarshal - } else { - switch rk := rt.Kind(); rk { - case reflect.Bool: - fn.f = (*encFnInfo).kBool - case reflect.String: - fn.f = (*encFnInfo).kString - case reflect.Float64: - fn.f = (*encFnInfo).kFloat64 - case reflect.Float32: - fn.f = (*encFnInfo).kFloat32 - case reflect.Int, reflect.Int8, reflect.Int64, reflect.Int32, reflect.Int16: - fn.f = (*encFnInfo).kInt - case reflect.Uint8, reflect.Uint64, reflect.Uint, reflect.Uint32, reflect.Uint16: - fn.f = (*encFnInfo).kUint - case reflect.Invalid: - fn.f = (*encFnInfo).kInvalid - case reflect.Slice: - fn.f = (*encFnInfo).kSlice - case reflect.Array: - fn.f = (*encFnInfo).kArray - case reflect.Struct: - fn.f = (*encFnInfo).kStruct - // case reflect.Ptr: - // fn.f = (*encFnInfo).kPtr - case reflect.Interface: - fn.f = (*encFnInfo).kInterface - case reflect.Map: - fn.f = (*encFnInfo).kMap - default: - fn.f = (*encFnInfo).kErr - } - } - if useMapForCodecCache { - if e.f == nil { - e.f = make(map[uintptr]encFn, 16) - } - e.f[rtid] = fn - } else { - e.s = append(e.s, fn) - e.x = append(e.x, rtid) - } - } - - fn.f(fn.i, rv) - -} - -func (e *Encoder) encRawExt(re RawExt) { - if re.Data == nil { - e.e.encodeNil() - return - } - if e.hh.writeExt() { - e.e.encodeExtPreamble(re.Tag, len(re.Data)) - e.w.writeb(re.Data) - } else { - e.e.encodeStringBytes(c_RAW, re.Data) - } -} - -// --------------------------------------------- -// short circuit functions for common maps and slices - -func (e *Encoder) encSliceIntf(v []interface{}) { - e.e.encodeArrayPreamble(len(v)) - for _, v2 := range v { - e.encode(v2) - } -} - -func (e *Encoder) encSliceStr(v []string) { - e.e.encodeArrayPreamble(len(v)) - for _, v2 := range v { - e.e.encodeString(c_UTF8, v2) - } -} - -func (e *Encoder) encSliceInt64(v []int64) { - e.e.encodeArrayPreamble(len(v)) - for _, v2 := range v { - e.e.encodeInt(v2) - } -} - -func (e *Encoder) encSliceUint64(v []uint64) { - e.e.encodeArrayPreamble(len(v)) - for _, v2 := range v { - e.e.encodeUint(v2) - } -} - -func (e *Encoder) encMapStrStr(v map[string]string) { - e.e.encodeMapPreamble(len(v)) - asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0 - for k2, v2 := range v { - if asSymbols { - e.e.encodeSymbol(k2) - } else { - e.e.encodeString(c_UTF8, k2) - } - e.e.encodeString(c_UTF8, v2) - } -} - -func (e *Encoder) encMapStrIntf(v map[string]interface{}) { - e.e.encodeMapPreamble(len(v)) - asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0 - for k2, v2 := range v { - if asSymbols { - e.e.encodeSymbol(k2) - } else { - e.e.encodeString(c_UTF8, k2) - } - e.encode(v2) - } -} - -func (e *Encoder) encMapInt64Intf(v map[int64]interface{}) { - e.e.encodeMapPreamble(len(v)) - for k2, v2 := range v { - e.e.encodeInt(k2) - e.encode(v2) - } -} - -func (e *Encoder) encMapUint64Intf(v map[uint64]interface{}) { - e.e.encodeMapPreamble(len(v)) - for k2, v2 := range v { - e.e.encodeUint(uint64(k2)) - e.encode(v2) - } -} - -func (e *Encoder) encMapIntfIntf(v map[interface{}]interface{}) { - e.e.encodeMapPreamble(len(v)) - for k2, v2 := range v { - e.encode(k2) - e.encode(v2) - } -} - -// ---------------------------------------- - -func encErr(format string, params ...interface{}) { - doPanic(msgTagEnc, format, params...) -} diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/helper.go b/vendor/github.com/hashicorp/go-msgpack/codec/helper.go deleted file mode 100644 index 7da3955e..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/helper.go +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -// Contains code shared by both encode and decode. - -import ( - "encoding/binary" - "fmt" - "math" - "reflect" - "sort" - "strings" - "sync" - "time" - "unicode" - "unicode/utf8" -) - -const ( - structTagName = "codec" - - // Support - // encoding.BinaryMarshaler: MarshalBinary() (data []byte, err error) - // encoding.BinaryUnmarshaler: UnmarshalBinary(data []byte) error - // This constant flag will enable or disable it. - supportBinaryMarshal = true - - // Each Encoder or Decoder uses a cache of functions based on conditionals, - // so that the conditionals are not run every time. - // - // Either a map or a slice is used to keep track of the functions. - // The map is more natural, but has a higher cost than a slice/array. - // This flag (useMapForCodecCache) controls which is used. - useMapForCodecCache = false - - // For some common container types, we can short-circuit an elaborate - // reflection dance and call encode/decode directly. - // The currently supported types are: - // - slices of strings, or id's (int64,uint64) or interfaces. - // - maps of str->str, str->intf, id(int64,uint64)->intf, intf->intf - shortCircuitReflectToFastPath = true - - // for debugging, set this to false, to catch panic traces. - // Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic. - recoverPanicToErr = true - - // if checkStructForEmptyValue, check structs fields to see if an empty value. - // This could be an expensive call, so possibly disable it. - checkStructForEmptyValue = false - - // if derefForIsEmptyValue, deref pointers and interfaces when checking isEmptyValue - derefForIsEmptyValue = false -) - -type charEncoding uint8 - -const ( - c_RAW charEncoding = iota - c_UTF8 - c_UTF16LE - c_UTF16BE - c_UTF32LE - c_UTF32BE -) - -// valueType is the stream type -type valueType uint8 - -const ( - valueTypeUnset valueType = iota - valueTypeNil - valueTypeInt - valueTypeUint - valueTypeFloat - valueTypeBool - valueTypeString - valueTypeSymbol - valueTypeBytes - valueTypeMap - valueTypeArray - valueTypeTimestamp - valueTypeExt - - valueTypeInvalid = 0xff -) - -var ( - bigen = binary.BigEndian - structInfoFieldName = "_struct" - - cachedTypeInfo = make(map[uintptr]*typeInfo, 4) - cachedTypeInfoMutex sync.RWMutex - - intfSliceTyp = reflect.TypeOf([]interface{}(nil)) - intfTyp = intfSliceTyp.Elem() - - strSliceTyp = reflect.TypeOf([]string(nil)) - boolSliceTyp = reflect.TypeOf([]bool(nil)) - uintSliceTyp = reflect.TypeOf([]uint(nil)) - uint8SliceTyp = reflect.TypeOf([]uint8(nil)) - uint16SliceTyp = reflect.TypeOf([]uint16(nil)) - uint32SliceTyp = reflect.TypeOf([]uint32(nil)) - uint64SliceTyp = reflect.TypeOf([]uint64(nil)) - intSliceTyp = reflect.TypeOf([]int(nil)) - int8SliceTyp = reflect.TypeOf([]int8(nil)) - int16SliceTyp = reflect.TypeOf([]int16(nil)) - int32SliceTyp = reflect.TypeOf([]int32(nil)) - int64SliceTyp = reflect.TypeOf([]int64(nil)) - float32SliceTyp = reflect.TypeOf([]float32(nil)) - float64SliceTyp = reflect.TypeOf([]float64(nil)) - - mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil)) - mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil)) - mapStrStrTyp = reflect.TypeOf(map[string]string(nil)) - - mapIntIntfTyp = reflect.TypeOf(map[int]interface{}(nil)) - mapInt64IntfTyp = reflect.TypeOf(map[int64]interface{}(nil)) - mapUintIntfTyp = reflect.TypeOf(map[uint]interface{}(nil)) - mapUint64IntfTyp = reflect.TypeOf(map[uint64]interface{}(nil)) - - stringTyp = reflect.TypeOf("") - timeTyp = reflect.TypeOf(time.Time{}) - rawExtTyp = reflect.TypeOf(RawExt{}) - - mapBySliceTyp = reflect.TypeOf((*MapBySlice)(nil)).Elem() - binaryMarshalerTyp = reflect.TypeOf((*binaryMarshaler)(nil)).Elem() - binaryUnmarshalerTyp = reflect.TypeOf((*binaryUnmarshaler)(nil)).Elem() - - rawExtTypId = reflect.ValueOf(rawExtTyp).Pointer() - intfTypId = reflect.ValueOf(intfTyp).Pointer() - timeTypId = reflect.ValueOf(timeTyp).Pointer() - - intfSliceTypId = reflect.ValueOf(intfSliceTyp).Pointer() - strSliceTypId = reflect.ValueOf(strSliceTyp).Pointer() - - boolSliceTypId = reflect.ValueOf(boolSliceTyp).Pointer() - uintSliceTypId = reflect.ValueOf(uintSliceTyp).Pointer() - uint8SliceTypId = reflect.ValueOf(uint8SliceTyp).Pointer() - uint16SliceTypId = reflect.ValueOf(uint16SliceTyp).Pointer() - uint32SliceTypId = reflect.ValueOf(uint32SliceTyp).Pointer() - uint64SliceTypId = reflect.ValueOf(uint64SliceTyp).Pointer() - intSliceTypId = reflect.ValueOf(intSliceTyp).Pointer() - int8SliceTypId = reflect.ValueOf(int8SliceTyp).Pointer() - int16SliceTypId = reflect.ValueOf(int16SliceTyp).Pointer() - int32SliceTypId = reflect.ValueOf(int32SliceTyp).Pointer() - int64SliceTypId = reflect.ValueOf(int64SliceTyp).Pointer() - float32SliceTypId = reflect.ValueOf(float32SliceTyp).Pointer() - float64SliceTypId = reflect.ValueOf(float64SliceTyp).Pointer() - - mapStrStrTypId = reflect.ValueOf(mapStrStrTyp).Pointer() - mapIntfIntfTypId = reflect.ValueOf(mapIntfIntfTyp).Pointer() - mapStrIntfTypId = reflect.ValueOf(mapStrIntfTyp).Pointer() - mapIntIntfTypId = reflect.ValueOf(mapIntIntfTyp).Pointer() - mapInt64IntfTypId = reflect.ValueOf(mapInt64IntfTyp).Pointer() - mapUintIntfTypId = reflect.ValueOf(mapUintIntfTyp).Pointer() - mapUint64IntfTypId = reflect.ValueOf(mapUint64IntfTyp).Pointer() - // Id = reflect.ValueOf().Pointer() - // mapBySliceTypId = reflect.ValueOf(mapBySliceTyp).Pointer() - - binaryMarshalerTypId = reflect.ValueOf(binaryMarshalerTyp).Pointer() - binaryUnmarshalerTypId = reflect.ValueOf(binaryUnmarshalerTyp).Pointer() - - intBitsize uint8 = uint8(reflect.TypeOf(int(0)).Bits()) - uintBitsize uint8 = uint8(reflect.TypeOf(uint(0)).Bits()) - - bsAll0x00 = []byte{0, 0, 0, 0, 0, 0, 0, 0} - bsAll0xff = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} -) - -type binaryUnmarshaler interface { - UnmarshalBinary(data []byte) error -} - -type binaryMarshaler interface { - MarshalBinary() (data []byte, err error) -} - -// MapBySlice represents a slice which should be encoded as a map in the stream. -// The slice contains a sequence of key-value pairs. -type MapBySlice interface { - MapBySlice() -} - -// WARNING: DO NOT USE DIRECTLY. EXPORTED FOR GODOC BENEFIT. WILL BE REMOVED. -// -// BasicHandle encapsulates the common options and extension functions. -type BasicHandle struct { - extHandle - EncodeOptions - DecodeOptions -} - -// Handle is the interface for a specific encoding format. -// -// Typically, a Handle is pre-configured before first time use, -// and not modified while in use. Such a pre-configured Handle -// is safe for concurrent access. -type Handle interface { - writeExt() bool - getBasicHandle() *BasicHandle - newEncDriver(w encWriter) encDriver - newDecDriver(r decReader) decDriver -} - -// RawExt represents raw unprocessed extension data. -type RawExt struct { - Tag byte - Data []byte -} - -type extTypeTagFn struct { - rtid uintptr - rt reflect.Type - tag byte - encFn func(reflect.Value) ([]byte, error) - decFn func(reflect.Value, []byte) error -} - -type extHandle []*extTypeTagFn - -// AddExt registers an encode and decode function for a reflect.Type. -// Note that the type must be a named type, and specifically not -// a pointer or Interface. An error is returned if that is not honored. -// -// To Deregister an ext, call AddExt with 0 tag, nil encfn and nil decfn. -func (o *extHandle) AddExt( - rt reflect.Type, - tag byte, - encfn func(reflect.Value) ([]byte, error), - decfn func(reflect.Value, []byte) error, -) (err error) { - // o is a pointer, because we may need to initialize it - if rt.PkgPath() == "" || rt.Kind() == reflect.Interface { - err = fmt.Errorf("codec.Handle.AddExt: Takes named type, especially not a pointer or interface: %T", - reflect.Zero(rt).Interface()) - return - } - - // o cannot be nil, since it is always embedded in a Handle. - // if nil, let it panic. - // if o == nil { - // err = errors.New("codec.Handle.AddExt: extHandle cannot be a nil pointer.") - // return - // } - - rtid := reflect.ValueOf(rt).Pointer() - for _, v := range *o { - if v.rtid == rtid { - v.tag, v.encFn, v.decFn = tag, encfn, decfn - return - } - } - - *o = append(*o, &extTypeTagFn{rtid, rt, tag, encfn, decfn}) - return -} - -func (o extHandle) getExt(rtid uintptr) *extTypeTagFn { - for _, v := range o { - if v.rtid == rtid { - return v - } - } - return nil -} - -func (o extHandle) getExtForTag(tag byte) *extTypeTagFn { - for _, v := range o { - if v.tag == tag { - return v - } - } - return nil -} - -func (o extHandle) getDecodeExtForTag(tag byte) ( - rv reflect.Value, fn func(reflect.Value, []byte) error) { - if x := o.getExtForTag(tag); x != nil { - // ext is only registered for base - rv = reflect.New(x.rt).Elem() - fn = x.decFn - } - return -} - -func (o extHandle) getDecodeExt(rtid uintptr) (tag byte, fn func(reflect.Value, []byte) error) { - if x := o.getExt(rtid); x != nil { - tag = x.tag - fn = x.decFn - } - return -} - -func (o extHandle) getEncodeExt(rtid uintptr) (tag byte, fn func(reflect.Value) ([]byte, error)) { - if x := o.getExt(rtid); x != nil { - tag = x.tag - fn = x.encFn - } - return -} - -type structFieldInfo struct { - encName string // encode name - - // only one of 'i' or 'is' can be set. If 'i' is -1, then 'is' has been set. - - is []int // (recursive/embedded) field index in struct - i int16 // field index in struct - omitEmpty bool - toArray bool // if field is _struct, is the toArray set? - - // tag string // tag - // name string // field name - // encNameBs []byte // encoded name as byte stream - // ikind int // kind of the field as an int i.e. int(reflect.Kind) -} - -func parseStructFieldInfo(fname string, stag string) *structFieldInfo { - if fname == "" { - panic("parseStructFieldInfo: No Field Name") - } - si := structFieldInfo{ - // name: fname, - encName: fname, - // tag: stag, - } - - if stag != "" { - for i, s := range strings.Split(stag, ",") { - if i == 0 { - if s != "" { - si.encName = s - } - } else { - switch s { - case "omitempty": - si.omitEmpty = true - case "toarray": - si.toArray = true - } - } - } - } - // si.encNameBs = []byte(si.encName) - return &si -} - -type sfiSortedByEncName []*structFieldInfo - -func (p sfiSortedByEncName) Len() int { - return len(p) -} - -func (p sfiSortedByEncName) Less(i, j int) bool { - return p[i].encName < p[j].encName -} - -func (p sfiSortedByEncName) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} - -// typeInfo keeps information about each type referenced in the encode/decode sequence. -// -// During an encode/decode sequence, we work as below: -// - If base is a built in type, en/decode base value -// - If base is registered as an extension, en/decode base value -// - If type is binary(M/Unm)arshaler, call Binary(M/Unm)arshal method -// - Else decode appropriately based on the reflect.Kind -type typeInfo struct { - sfi []*structFieldInfo // sorted. Used when enc/dec struct to map. - sfip []*structFieldInfo // unsorted. Used when enc/dec struct to array. - - rt reflect.Type - rtid uintptr - - // baseId gives pointer to the base reflect.Type, after deferencing - // the pointers. E.g. base type of ***time.Time is time.Time. - base reflect.Type - baseId uintptr - baseIndir int8 // number of indirections to get to base - - mbs bool // base type (T or *T) is a MapBySlice - - m bool // base type (T or *T) is a binaryMarshaler - unm bool // base type (T or *T) is a binaryUnmarshaler - mIndir int8 // number of indirections to get to binaryMarshaler type - unmIndir int8 // number of indirections to get to binaryUnmarshaler type - toArray bool // whether this (struct) type should be encoded as an array -} - -func (ti *typeInfo) indexForEncName(name string) int { - //tisfi := ti.sfi - const binarySearchThreshold = 16 - if sfilen := len(ti.sfi); sfilen < binarySearchThreshold { - // linear search. faster than binary search in my testing up to 16-field structs. - for i, si := range ti.sfi { - if si.encName == name { - return i - } - } - } else { - // binary search. adapted from sort/search.go. - h, i, j := 0, 0, sfilen - for i < j { - h = i + (j-i)/2 - if ti.sfi[h].encName < name { - i = h + 1 - } else { - j = h - } - } - if i < sfilen && ti.sfi[i].encName == name { - return i - } - } - return -1 -} - -func getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) { - var ok bool - cachedTypeInfoMutex.RLock() - pti, ok = cachedTypeInfo[rtid] - cachedTypeInfoMutex.RUnlock() - if ok { - return - } - - cachedTypeInfoMutex.Lock() - defer cachedTypeInfoMutex.Unlock() - if pti, ok = cachedTypeInfo[rtid]; ok { - return - } - - ti := typeInfo{rt: rt, rtid: rtid} - pti = &ti - - var indir int8 - if ok, indir = implementsIntf(rt, binaryMarshalerTyp); ok { - ti.m, ti.mIndir = true, indir - } - if ok, indir = implementsIntf(rt, binaryUnmarshalerTyp); ok { - ti.unm, ti.unmIndir = true, indir - } - if ok, _ = implementsIntf(rt, mapBySliceTyp); ok { - ti.mbs = true - } - - pt := rt - var ptIndir int8 - // for ; pt.Kind() == reflect.Ptr; pt, ptIndir = pt.Elem(), ptIndir+1 { } - for pt.Kind() == reflect.Ptr { - pt = pt.Elem() - ptIndir++ - } - if ptIndir == 0 { - ti.base = rt - ti.baseId = rtid - } else { - ti.base = pt - ti.baseId = reflect.ValueOf(pt).Pointer() - ti.baseIndir = ptIndir - } - - if rt.Kind() == reflect.Struct { - var siInfo *structFieldInfo - if f, ok := rt.FieldByName(structInfoFieldName); ok { - siInfo = parseStructFieldInfo(structInfoFieldName, f.Tag.Get(structTagName)) - ti.toArray = siInfo.toArray - } - sfip := make([]*structFieldInfo, 0, rt.NumField()) - rgetTypeInfo(rt, nil, make(map[string]bool), &sfip, siInfo) - - // // try to put all si close together - // const tryToPutAllStructFieldInfoTogether = true - // if tryToPutAllStructFieldInfoTogether { - // sfip2 := make([]structFieldInfo, len(sfip)) - // for i, si := range sfip { - // sfip2[i] = *si - // } - // for i := range sfip { - // sfip[i] = &sfip2[i] - // } - // } - - ti.sfip = make([]*structFieldInfo, len(sfip)) - ti.sfi = make([]*structFieldInfo, len(sfip)) - copy(ti.sfip, sfip) - sort.Sort(sfiSortedByEncName(sfip)) - copy(ti.sfi, sfip) - } - // sfi = sfip - cachedTypeInfo[rtid] = pti - return -} - -func rgetTypeInfo(rt reflect.Type, indexstack []int, fnameToHastag map[string]bool, - sfi *[]*structFieldInfo, siInfo *structFieldInfo, -) { - // for rt.Kind() == reflect.Ptr { - // // indexstack = append(indexstack, 0) - // rt = rt.Elem() - // } - for j := 0; j < rt.NumField(); j++ { - f := rt.Field(j) - stag := f.Tag.Get(structTagName) - if stag == "-" { - continue - } - if r1, _ := utf8.DecodeRuneInString(f.Name); r1 == utf8.RuneError || !unicode.IsUpper(r1) { - continue - } - // if anonymous and there is no struct tag and its a struct (or pointer to struct), inline it. - if f.Anonymous && stag == "" { - ft := f.Type - for ft.Kind() == reflect.Ptr { - ft = ft.Elem() - } - if ft.Kind() == reflect.Struct { - indexstack2 := append(append(make([]int, 0, len(indexstack)+4), indexstack...), j) - rgetTypeInfo(ft, indexstack2, fnameToHastag, sfi, siInfo) - continue - } - } - // do not let fields with same name in embedded structs override field at higher level. - // this must be done after anonymous check, to allow anonymous field - // still include their child fields - if _, ok := fnameToHastag[f.Name]; ok { - continue - } - si := parseStructFieldInfo(f.Name, stag) - // si.ikind = int(f.Type.Kind()) - if len(indexstack) == 0 { - si.i = int16(j) - } else { - si.i = -1 - si.is = append(append(make([]int, 0, len(indexstack)+4), indexstack...), j) - } - - if siInfo != nil { - if siInfo.omitEmpty { - si.omitEmpty = true - } - } - *sfi = append(*sfi, si) - fnameToHastag[f.Name] = stag != "" - } -} - -func panicToErr(err *error) { - if recoverPanicToErr { - if x := recover(); x != nil { - //debug.PrintStack() - panicValToErr(x, err) - } - } -} - -func doPanic(tag string, format string, params ...interface{}) { - params2 := make([]interface{}, len(params)+1) - params2[0] = tag - copy(params2[1:], params) - panic(fmt.Errorf("%s: "+format, params2...)) -} - -func checkOverflowFloat32(f float64, doCheck bool) { - if !doCheck { - return - } - // check overflow (logic adapted from std pkg reflect/value.go OverflowFloat() - f2 := f - if f2 < 0 { - f2 = -f - } - if math.MaxFloat32 < f2 && f2 <= math.MaxFloat64 { - decErr("Overflow float32 value: %v", f2) - } -} - -func checkOverflow(ui uint64, i int64, bitsize uint8) { - // check overflow (logic adapted from std pkg reflect/value.go OverflowUint() - if bitsize == 0 { - return - } - if i != 0 { - if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc { - decErr("Overflow int value: %v", i) - } - } - if ui != 0 { - if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc { - decErr("Overflow uint value: %v", ui) - } - } -} diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/helper_internal.go b/vendor/github.com/hashicorp/go-msgpack/codec/helper_internal.go deleted file mode 100644 index 93f12854..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/helper_internal.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -// All non-std package dependencies live in this file, -// so porting to different environment is easy (just update functions). - -import ( - "errors" - "fmt" - "math" - "reflect" -) - -var ( - raisePanicAfterRecover = false - debugging = true -) - -func panicValToErr(panicVal interface{}, err *error) { - switch xerr := panicVal.(type) { - case error: - *err = xerr - case string: - *err = errors.New(xerr) - default: - *err = fmt.Errorf("%v", panicVal) - } - if raisePanicAfterRecover { - panic(panicVal) - } - return -} - -func hIsEmptyValue(v reflect.Value, deref, checkStruct bool) bool { - switch v.Kind() { - case reflect.Invalid: - return true - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Interface, reflect.Ptr: - if deref { - if v.IsNil() { - return true - } - return hIsEmptyValue(v.Elem(), deref, checkStruct) - } else { - return v.IsNil() - } - case reflect.Struct: - if !checkStruct { - return false - } - // return true if all fields are empty. else return false. - - // we cannot use equality check, because some fields may be maps/slices/etc - // and consequently the structs are not comparable. - // return v.Interface() == reflect.Zero(v.Type()).Interface() - for i, n := 0, v.NumField(); i < n; i++ { - if !hIsEmptyValue(v.Field(i), deref, checkStruct) { - return false - } - } - return true - } - return false -} - -func isEmptyValue(v reflect.Value) bool { - return hIsEmptyValue(v, derefForIsEmptyValue, checkStructForEmptyValue) -} - -func debugf(format string, args ...interface{}) { - if debugging { - if len(format) == 0 || format[len(format)-1] != '\n' { - format = format + "\n" - } - fmt.Printf(format, args...) - } -} - -func pruneSignExt(v []byte, pos bool) (n int) { - if len(v) < 2 { - } else if pos && v[0] == 0 { - for ; v[n] == 0 && n+1 < len(v) && (v[n+1]&(1<<7) == 0); n++ { - } - } else if !pos && v[0] == 0xff { - for ; v[n] == 0xff && n+1 < len(v) && (v[n+1]&(1<<7) != 0); n++ { - } - } - return -} - -func implementsIntf(typ, iTyp reflect.Type) (success bool, indir int8) { - if typ == nil { - return - } - rt := typ - // The type might be a pointer and we need to keep - // dereferencing to the base type until we find an implementation. - for { - if rt.Implements(iTyp) { - return true, indir - } - if p := rt; p.Kind() == reflect.Ptr { - indir++ - if indir >= math.MaxInt8 { // insane number of indirections - return false, 0 - } - rt = p.Elem() - continue - } - break - } - // No luck yet, but if this is a base type (non-pointer), the pointer might satisfy. - if typ.Kind() != reflect.Ptr { - // Not a pointer, but does the pointer work? - if reflect.PtrTo(typ).Implements(iTyp) { - return true, -1 - } - } - return false, 0 -} diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/msgpack.go b/vendor/github.com/hashicorp/go-msgpack/codec/msgpack.go deleted file mode 100644 index da0500d1..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/msgpack.go +++ /dev/null @@ -1,816 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -/* -MSGPACK - -Msgpack-c implementation powers the c, c++, python, ruby, etc libraries. -We need to maintain compatibility with it and how it encodes integer values -without caring about the type. - -For compatibility with behaviour of msgpack-c reference implementation: - - Go intX (>0) and uintX - IS ENCODED AS - msgpack +ve fixnum, unsigned - - Go intX (<0) - IS ENCODED AS - msgpack -ve fixnum, signed - -*/ -package codec - -import ( - "fmt" - "io" - "math" - "net/rpc" -) - -const ( - mpPosFixNumMin byte = 0x00 - mpPosFixNumMax = 0x7f - mpFixMapMin = 0x80 - mpFixMapMax = 0x8f - mpFixArrayMin = 0x90 - mpFixArrayMax = 0x9f - mpFixStrMin = 0xa0 - mpFixStrMax = 0xbf - mpNil = 0xc0 - _ = 0xc1 - mpFalse = 0xc2 - mpTrue = 0xc3 - mpFloat = 0xca - mpDouble = 0xcb - mpUint8 = 0xcc - mpUint16 = 0xcd - mpUint32 = 0xce - mpUint64 = 0xcf - mpInt8 = 0xd0 - mpInt16 = 0xd1 - mpInt32 = 0xd2 - mpInt64 = 0xd3 - - // extensions below - mpBin8 = 0xc4 - mpBin16 = 0xc5 - mpBin32 = 0xc6 - mpExt8 = 0xc7 - mpExt16 = 0xc8 - mpExt32 = 0xc9 - mpFixExt1 = 0xd4 - mpFixExt2 = 0xd5 - mpFixExt4 = 0xd6 - mpFixExt8 = 0xd7 - mpFixExt16 = 0xd8 - - mpStr8 = 0xd9 // new - mpStr16 = 0xda - mpStr32 = 0xdb - - mpArray16 = 0xdc - mpArray32 = 0xdd - - mpMap16 = 0xde - mpMap32 = 0xdf - - mpNegFixNumMin = 0xe0 - mpNegFixNumMax = 0xff -) - -// MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec -// that the backend RPC service takes multiple arguments, which have been arranged -// in sequence in the slice. -// -// The Codec then passes it AS-IS to the rpc service (without wrapping it in an -// array of 1 element). -type MsgpackSpecRpcMultiArgs []interface{} - -// A MsgpackContainer type specifies the different types of msgpackContainers. -type msgpackContainerType struct { - fixCutoff int - bFixMin, b8, b16, b32 byte - hasFixMin, has8, has8Always bool -} - -var ( - msgpackContainerStr = msgpackContainerType{32, mpFixStrMin, mpStr8, mpStr16, mpStr32, true, true, false} - msgpackContainerBin = msgpackContainerType{0, 0, mpBin8, mpBin16, mpBin32, false, true, true} - msgpackContainerList = msgpackContainerType{16, mpFixArrayMin, 0, mpArray16, mpArray32, true, false, false} - msgpackContainerMap = msgpackContainerType{16, mpFixMapMin, 0, mpMap16, mpMap32, true, false, false} -) - -//--------------------------------------------- - -type msgpackEncDriver struct { - w encWriter - h *MsgpackHandle -} - -func (e *msgpackEncDriver) isBuiltinType(rt uintptr) bool { - //no builtin types. All encodings are based on kinds. Types supported as extensions. - return false -} - -func (e *msgpackEncDriver) encodeBuiltin(rt uintptr, v interface{}) {} - -func (e *msgpackEncDriver) encodeNil() { - e.w.writen1(mpNil) -} - -func (e *msgpackEncDriver) encodeInt(i int64) { - - switch { - case i >= 0: - e.encodeUint(uint64(i)) - case i >= -32: - e.w.writen1(byte(i)) - case i >= math.MinInt8: - e.w.writen2(mpInt8, byte(i)) - case i >= math.MinInt16: - e.w.writen1(mpInt16) - e.w.writeUint16(uint16(i)) - case i >= math.MinInt32: - e.w.writen1(mpInt32) - e.w.writeUint32(uint32(i)) - default: - e.w.writen1(mpInt64) - e.w.writeUint64(uint64(i)) - } -} - -func (e *msgpackEncDriver) encodeUint(i uint64) { - switch { - case i <= math.MaxInt8: - e.w.writen1(byte(i)) - case i <= math.MaxUint8: - e.w.writen2(mpUint8, byte(i)) - case i <= math.MaxUint16: - e.w.writen1(mpUint16) - e.w.writeUint16(uint16(i)) - case i <= math.MaxUint32: - e.w.writen1(mpUint32) - e.w.writeUint32(uint32(i)) - default: - e.w.writen1(mpUint64) - e.w.writeUint64(uint64(i)) - } -} - -func (e *msgpackEncDriver) encodeBool(b bool) { - if b { - e.w.writen1(mpTrue) - } else { - e.w.writen1(mpFalse) - } -} - -func (e *msgpackEncDriver) encodeFloat32(f float32) { - e.w.writen1(mpFloat) - e.w.writeUint32(math.Float32bits(f)) -} - -func (e *msgpackEncDriver) encodeFloat64(f float64) { - e.w.writen1(mpDouble) - e.w.writeUint64(math.Float64bits(f)) -} - -func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) { - switch { - case l == 1: - e.w.writen2(mpFixExt1, xtag) - case l == 2: - e.w.writen2(mpFixExt2, xtag) - case l == 4: - e.w.writen2(mpFixExt4, xtag) - case l == 8: - e.w.writen2(mpFixExt8, xtag) - case l == 16: - e.w.writen2(mpFixExt16, xtag) - case l < 256: - e.w.writen2(mpExt8, byte(l)) - e.w.writen1(xtag) - case l < 65536: - e.w.writen1(mpExt16) - e.w.writeUint16(uint16(l)) - e.w.writen1(xtag) - default: - e.w.writen1(mpExt32) - e.w.writeUint32(uint32(l)) - e.w.writen1(xtag) - } -} - -func (e *msgpackEncDriver) encodeArrayPreamble(length int) { - e.writeContainerLen(msgpackContainerList, length) -} - -func (e *msgpackEncDriver) encodeMapPreamble(length int) { - e.writeContainerLen(msgpackContainerMap, length) -} - -func (e *msgpackEncDriver) encodeString(c charEncoding, s string) { - if c == c_RAW && e.h.WriteExt { - e.writeContainerLen(msgpackContainerBin, len(s)) - } else { - e.writeContainerLen(msgpackContainerStr, len(s)) - } - if len(s) > 0 { - e.w.writestr(s) - } -} - -func (e *msgpackEncDriver) encodeSymbol(v string) { - e.encodeString(c_UTF8, v) -} - -func (e *msgpackEncDriver) encodeStringBytes(c charEncoding, bs []byte) { - if c == c_RAW && e.h.WriteExt { - e.writeContainerLen(msgpackContainerBin, len(bs)) - } else { - e.writeContainerLen(msgpackContainerStr, len(bs)) - } - if len(bs) > 0 { - e.w.writeb(bs) - } -} - -func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) { - switch { - case ct.hasFixMin && l < ct.fixCutoff: - e.w.writen1(ct.bFixMin | byte(l)) - case ct.has8 && l < 256 && (ct.has8Always || e.h.WriteExt): - e.w.writen2(ct.b8, uint8(l)) - case l < 65536: - e.w.writen1(ct.b16) - e.w.writeUint16(uint16(l)) - default: - e.w.writen1(ct.b32) - e.w.writeUint32(uint32(l)) - } -} - -//--------------------------------------------- - -type msgpackDecDriver struct { - r decReader - h *MsgpackHandle - bd byte - bdRead bool - bdType valueType -} - -func (d *msgpackDecDriver) isBuiltinType(rt uintptr) bool { - //no builtin types. All encodings are based on kinds. Types supported as extensions. - return false -} - -func (d *msgpackDecDriver) decodeBuiltin(rt uintptr, v interface{}) {} - -// Note: This returns either a primitive (int, bool, etc) for non-containers, -// or a containerType, or a specific type denoting nil or extension. -// It is called when a nil interface{} is passed, leaving it up to the DecDriver -// to introspect the stream and decide how best to decode. -// It deciphers the value by looking at the stream first. -func (d *msgpackDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurther bool) { - d.initReadNext() - bd := d.bd - - switch bd { - case mpNil: - vt = valueTypeNil - d.bdRead = false - case mpFalse: - vt = valueTypeBool - v = false - case mpTrue: - vt = valueTypeBool - v = true - - case mpFloat: - vt = valueTypeFloat - v = float64(math.Float32frombits(d.r.readUint32())) - case mpDouble: - vt = valueTypeFloat - v = math.Float64frombits(d.r.readUint64()) - - case mpUint8: - vt = valueTypeUint - v = uint64(d.r.readn1()) - case mpUint16: - vt = valueTypeUint - v = uint64(d.r.readUint16()) - case mpUint32: - vt = valueTypeUint - v = uint64(d.r.readUint32()) - case mpUint64: - vt = valueTypeUint - v = uint64(d.r.readUint64()) - - case mpInt8: - vt = valueTypeInt - v = int64(int8(d.r.readn1())) - case mpInt16: - vt = valueTypeInt - v = int64(int16(d.r.readUint16())) - case mpInt32: - vt = valueTypeInt - v = int64(int32(d.r.readUint32())) - case mpInt64: - vt = valueTypeInt - v = int64(int64(d.r.readUint64())) - - default: - switch { - case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax: - // positive fixnum (always signed) - vt = valueTypeInt - v = int64(int8(bd)) - case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax: - // negative fixnum - vt = valueTypeInt - v = int64(int8(bd)) - case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax: - if d.h.RawToString { - var rvm string - vt = valueTypeString - v = &rvm - } else { - var rvm = []byte{} - vt = valueTypeBytes - v = &rvm - } - decodeFurther = true - case bd == mpBin8, bd == mpBin16, bd == mpBin32: - var rvm = []byte{} - vt = valueTypeBytes - v = &rvm - decodeFurther = true - case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: - vt = valueTypeArray - decodeFurther = true - case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax: - vt = valueTypeMap - decodeFurther = true - case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32: - clen := d.readExtLen() - var re RawExt - re.Tag = d.r.readn1() - re.Data = d.r.readn(clen) - v = &re - vt = valueTypeExt - default: - decErr("Nil-Deciphered DecodeValue: %s: hex: %x, dec: %d", msgBadDesc, bd, bd) - } - } - if !decodeFurther { - d.bdRead = false - } - return -} - -// int can be decoded from msgpack type: intXXX or uintXXX -func (d *msgpackDecDriver) decodeInt(bitsize uint8) (i int64) { - switch d.bd { - case mpUint8: - i = int64(uint64(d.r.readn1())) - case mpUint16: - i = int64(uint64(d.r.readUint16())) - case mpUint32: - i = int64(uint64(d.r.readUint32())) - case mpUint64: - i = int64(d.r.readUint64()) - case mpInt8: - i = int64(int8(d.r.readn1())) - case mpInt16: - i = int64(int16(d.r.readUint16())) - case mpInt32: - i = int64(int32(d.r.readUint32())) - case mpInt64: - i = int64(d.r.readUint64()) - default: - switch { - case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax: - i = int64(int8(d.bd)) - case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: - i = int64(int8(d.bd)) - default: - decErr("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd) - } - } - // check overflow (logic adapted from std pkg reflect/value.go OverflowUint() - if bitsize > 0 { - if trunc := (i << (64 - bitsize)) >> (64 - bitsize); i != trunc { - decErr("Overflow int value: %v", i) - } - } - d.bdRead = false - return -} - -// uint can be decoded from msgpack type: intXXX or uintXXX -func (d *msgpackDecDriver) decodeUint(bitsize uint8) (ui uint64) { - switch d.bd { - case mpUint8: - ui = uint64(d.r.readn1()) - case mpUint16: - ui = uint64(d.r.readUint16()) - case mpUint32: - ui = uint64(d.r.readUint32()) - case mpUint64: - ui = d.r.readUint64() - case mpInt8: - if i := int64(int8(d.r.readn1())); i >= 0 { - ui = uint64(i) - } else { - decErr("Assigning negative signed value: %v, to unsigned type", i) - } - case mpInt16: - if i := int64(int16(d.r.readUint16())); i >= 0 { - ui = uint64(i) - } else { - decErr("Assigning negative signed value: %v, to unsigned type", i) - } - case mpInt32: - if i := int64(int32(d.r.readUint32())); i >= 0 { - ui = uint64(i) - } else { - decErr("Assigning negative signed value: %v, to unsigned type", i) - } - case mpInt64: - if i := int64(d.r.readUint64()); i >= 0 { - ui = uint64(i) - } else { - decErr("Assigning negative signed value: %v, to unsigned type", i) - } - default: - switch { - case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax: - ui = uint64(d.bd) - case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: - decErr("Assigning negative signed value: %v, to unsigned type", int(d.bd)) - default: - decErr("Unhandled single-byte unsigned integer value: %s: %x", msgBadDesc, d.bd) - } - } - // check overflow (logic adapted from std pkg reflect/value.go OverflowUint() - if bitsize > 0 { - if trunc := (ui << (64 - bitsize)) >> (64 - bitsize); ui != trunc { - decErr("Overflow uint value: %v", ui) - } - } - d.bdRead = false - return -} - -// float can either be decoded from msgpack type: float, double or intX -func (d *msgpackDecDriver) decodeFloat(chkOverflow32 bool) (f float64) { - switch d.bd { - case mpFloat: - f = float64(math.Float32frombits(d.r.readUint32())) - case mpDouble: - f = math.Float64frombits(d.r.readUint64()) - default: - f = float64(d.decodeInt(0)) - } - checkOverflowFloat32(f, chkOverflow32) - d.bdRead = false - return -} - -// bool can be decoded from bool, fixnum 0 or 1. -func (d *msgpackDecDriver) decodeBool() (b bool) { - switch d.bd { - case mpFalse, 0: - // b = false - case mpTrue, 1: - b = true - default: - decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd) - } - d.bdRead = false - return -} - -func (d *msgpackDecDriver) decodeString() (s string) { - clen := d.readContainerLen(msgpackContainerStr) - if clen > 0 { - s = string(d.r.readn(clen)) - } - d.bdRead = false - return -} - -// Callers must check if changed=true (to decide whether to replace the one they have) -func (d *msgpackDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) { - // bytes can be decoded from msgpackContainerStr or msgpackContainerBin - var clen int - switch d.bd { - case mpBin8, mpBin16, mpBin32: - clen = d.readContainerLen(msgpackContainerBin) - default: - clen = d.readContainerLen(msgpackContainerStr) - } - // if clen < 0 { - // changed = true - // panic("length cannot be zero. this cannot be nil.") - // } - if clen > 0 { - // if no contents in stream, don't update the passed byteslice - if len(bs) != clen { - // Return changed=true if length of passed slice diff from length of bytes in stream - if len(bs) > clen { - bs = bs[:clen] - } else { - bs = make([]byte, clen) - } - bsOut = bs - changed = true - } - d.r.readb(bs) - } - d.bdRead = false - return -} - -// Every top-level decode funcs (i.e. decodeValue, decode) must call this first. -func (d *msgpackDecDriver) initReadNext() { - if d.bdRead { - return - } - d.bd = d.r.readn1() - d.bdRead = true - d.bdType = valueTypeUnset -} - -func (d *msgpackDecDriver) currentEncodedType() valueType { - if d.bdType == valueTypeUnset { - bd := d.bd - switch bd { - case mpNil: - d.bdType = valueTypeNil - case mpFalse, mpTrue: - d.bdType = valueTypeBool - case mpFloat, mpDouble: - d.bdType = valueTypeFloat - case mpUint8, mpUint16, mpUint32, mpUint64: - d.bdType = valueTypeUint - case mpInt8, mpInt16, mpInt32, mpInt64: - d.bdType = valueTypeInt - default: - switch { - case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax: - d.bdType = valueTypeInt - case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax: - d.bdType = valueTypeInt - case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax: - if d.h.RawToString { - d.bdType = valueTypeString - } else { - d.bdType = valueTypeBytes - } - case bd == mpBin8, bd == mpBin16, bd == mpBin32: - d.bdType = valueTypeBytes - case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: - d.bdType = valueTypeArray - case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax: - d.bdType = valueTypeMap - case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32: - d.bdType = valueTypeExt - default: - decErr("currentEncodedType: Undeciphered descriptor: %s: hex: %x, dec: %d", msgBadDesc, bd, bd) - } - } - } - return d.bdType -} - -func (d *msgpackDecDriver) tryDecodeAsNil() bool { - if d.bd == mpNil { - d.bdRead = false - return true - } - return false -} - -func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int) { - bd := d.bd - switch { - case bd == mpNil: - clen = -1 // to represent nil - case bd == ct.b8: - clen = int(d.r.readn1()) - case bd == ct.b16: - clen = int(d.r.readUint16()) - case bd == ct.b32: - clen = int(d.r.readUint32()) - case (ct.bFixMin & bd) == ct.bFixMin: - clen = int(ct.bFixMin ^ bd) - default: - decErr("readContainerLen: %s: hex: %x, dec: %d", msgBadDesc, bd, bd) - } - d.bdRead = false - return -} - -func (d *msgpackDecDriver) readMapLen() int { - return d.readContainerLen(msgpackContainerMap) -} - -func (d *msgpackDecDriver) readArrayLen() int { - return d.readContainerLen(msgpackContainerList) -} - -func (d *msgpackDecDriver) readExtLen() (clen int) { - switch d.bd { - case mpNil: - clen = -1 // to represent nil - case mpFixExt1: - clen = 1 - case mpFixExt2: - clen = 2 - case mpFixExt4: - clen = 4 - case mpFixExt8: - clen = 8 - case mpFixExt16: - clen = 16 - case mpExt8: - clen = int(d.r.readn1()) - case mpExt16: - clen = int(d.r.readUint16()) - case mpExt32: - clen = int(d.r.readUint32()) - default: - decErr("decoding ext bytes: found unexpected byte: %x", d.bd) - } - return -} - -func (d *msgpackDecDriver) decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) { - xbd := d.bd - switch { - case xbd == mpBin8, xbd == mpBin16, xbd == mpBin32: - xbs, _ = d.decodeBytes(nil) - case xbd == mpStr8, xbd == mpStr16, xbd == mpStr32, - xbd >= mpFixStrMin && xbd <= mpFixStrMax: - xbs = []byte(d.decodeString()) - default: - clen := d.readExtLen() - xtag = d.r.readn1() - if verifyTag && xtag != tag { - decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag) - } - xbs = d.r.readn(clen) - } - d.bdRead = false - return -} - -//-------------------------------------------------- - -//MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format. -type MsgpackHandle struct { - BasicHandle - - // RawToString controls how raw bytes are decoded into a nil interface{}. - RawToString bool - // WriteExt flag supports encoding configured extensions with extension tags. - // It also controls whether other elements of the new spec are encoded (ie Str8). - // - // With WriteExt=false, configured extensions are serialized as raw bytes - // and Str8 is not encoded. - // - // A stream can still be decoded into a typed value, provided an appropriate value - // is provided, but the type cannot be inferred from the stream. If no appropriate - // type is provided (e.g. decoding into a nil interface{}), you get back - // a []byte or string based on the setting of RawToString. - WriteExt bool -} - -func (h *MsgpackHandle) newEncDriver(w encWriter) encDriver { - return &msgpackEncDriver{w: w, h: h} -} - -func (h *MsgpackHandle) newDecDriver(r decReader) decDriver { - return &msgpackDecDriver{r: r, h: h} -} - -func (h *MsgpackHandle) writeExt() bool { - return h.WriteExt -} - -func (h *MsgpackHandle) getBasicHandle() *BasicHandle { - return &h.BasicHandle -} - -//-------------------------------------------------- - -type msgpackSpecRpcCodec struct { - rpcCodec -} - -// /////////////// Spec RPC Codec /////////////////// -func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error { - // WriteRequest can write to both a Go service, and other services that do - // not abide by the 1 argument rule of a Go service. - // We discriminate based on if the body is a MsgpackSpecRpcMultiArgs - var bodyArr []interface{} - if m, ok := body.(MsgpackSpecRpcMultiArgs); ok { - bodyArr = ([]interface{})(m) - } else { - bodyArr = []interface{}{body} - } - r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr} - return c.write(r2, nil, false, true) -} - -func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { - var moe interface{} - if r.Error != "" { - moe = r.Error - } - if moe != nil && body != nil { - body = nil - } - r2 := []interface{}{1, uint32(r.Seq), moe, body} - return c.write(r2, nil, false, true) -} - -func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error { - return c.parseCustomHeader(1, &r.Seq, &r.Error) -} - -func (c *msgpackSpecRpcCodec) ReadRequestHeader(r *rpc.Request) error { - return c.parseCustomHeader(0, &r.Seq, &r.ServiceMethod) -} - -func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error { - if body == nil { // read and discard - return c.read(nil) - } - bodyArr := []interface{}{body} - return c.read(&bodyArr) -} - -func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) { - - if c.cls { - return io.EOF - } - - // We read the response header by hand - // so that the body can be decoded on its own from the stream at a later time. - - const fia byte = 0x94 //four item array descriptor value - // Not sure why the panic of EOF is swallowed above. - // if bs1 := c.dec.r.readn1(); bs1 != fia { - // err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, bs1) - // return - // } - var b byte - b, err = c.br.ReadByte() - if err != nil { - return - } - if b != fia { - err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, b) - return - } - - if err = c.read(&b); err != nil { - return - } - if b != expectTypeByte { - err = fmt.Errorf("Unexpected byte descriptor in header. Expecting %v. Received %v", expectTypeByte, b) - return - } - if err = c.read(msgid); err != nil { - return - } - if err = c.read(methodOrError); err != nil { - return - } - return -} - -//-------------------------------------------------- - -// msgpackSpecRpc is the implementation of Rpc that uses custom communication protocol -// as defined in the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md -type msgpackSpecRpc struct{} - -// MsgpackSpecRpc implements Rpc using the communication protocol defined in -// the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md . -// Its methods (ServerCodec and ClientCodec) return values that implement RpcCodecBuffered. -var MsgpackSpecRpc msgpackSpecRpc - -func (x msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { - return &msgpackSpecRpcCodec{newRPCCodec(conn, h)} -} - -func (x msgpackSpecRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec { - return &msgpackSpecRpcCodec{newRPCCodec(conn, h)} -} - -var _ decDriver = (*msgpackDecDriver)(nil) -var _ encDriver = (*msgpackEncDriver)(nil) diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/rpc.go b/vendor/github.com/hashicorp/go-msgpack/codec/rpc.go deleted file mode 100644 index d014dbdc..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/rpc.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -import ( - "bufio" - "io" - "net/rpc" - "sync" -) - -// Rpc provides a rpc Server or Client Codec for rpc communication. -type Rpc interface { - ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec - ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec -} - -// RpcCodecBuffered allows access to the underlying bufio.Reader/Writer -// used by the rpc connection. It accomodates use-cases where the connection -// should be used by rpc and non-rpc functions, e.g. streaming a file after -// sending an rpc response. -type RpcCodecBuffered interface { - BufferedReader() *bufio.Reader - BufferedWriter() *bufio.Writer -} - -// ------------------------------------- - -// rpcCodec defines the struct members and common methods. -type rpcCodec struct { - rwc io.ReadWriteCloser - dec *Decoder - enc *Encoder - bw *bufio.Writer - br *bufio.Reader - mu sync.Mutex - cls bool -} - -func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec { - bw := bufio.NewWriter(conn) - br := bufio.NewReader(conn) - return rpcCodec{ - rwc: conn, - bw: bw, - br: br, - enc: NewEncoder(bw, h), - dec: NewDecoder(br, h), - } -} - -func (c *rpcCodec) BufferedReader() *bufio.Reader { - return c.br -} - -func (c *rpcCodec) BufferedWriter() *bufio.Writer { - return c.bw -} - -func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2, doFlush bool) (err error) { - if c.cls { - return io.EOF - } - if err = c.enc.Encode(obj1); err != nil { - return - } - if writeObj2 { - if err = c.enc.Encode(obj2); err != nil { - return - } - } - if doFlush && c.bw != nil { - return c.bw.Flush() - } - return -} - -func (c *rpcCodec) read(obj interface{}) (err error) { - if c.cls { - return io.EOF - } - //If nil is passed in, we should still attempt to read content to nowhere. - if obj == nil { - var obj2 interface{} - return c.dec.Decode(&obj2) - } - return c.dec.Decode(obj) -} - -func (c *rpcCodec) Close() error { - if c.cls { - return io.EOF - } - c.cls = true - return c.rwc.Close() -} - -func (c *rpcCodec) ReadResponseBody(body interface{}) error { - return c.read(body) -} - -// ------------------------------------- - -type goRpcCodec struct { - rpcCodec -} - -func (c *goRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error { - // Must protect for concurrent access as per API - c.mu.Lock() - defer c.mu.Unlock() - return c.write(r, body, true, true) -} - -func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { - c.mu.Lock() - defer c.mu.Unlock() - return c.write(r, body, true, true) -} - -func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error { - return c.read(r) -} - -func (c *goRpcCodec) ReadRequestHeader(r *rpc.Request) error { - return c.read(r) -} - -func (c *goRpcCodec) ReadRequestBody(body interface{}) error { - return c.read(body) -} - -// ------------------------------------- - -// goRpc is the implementation of Rpc that uses the communication protocol -// as defined in net/rpc package. -type goRpc struct{} - -// GoRpc implements Rpc using the communication protocol defined in net/rpc package. -// Its methods (ServerCodec and ClientCodec) return values that implement RpcCodecBuffered. -var GoRpc goRpc - -func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { - return &goRpcCodec{newRPCCodec(conn, h)} -} - -func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec { - return &goRpcCodec{newRPCCodec(conn, h)} -} - -var _ RpcCodecBuffered = (*rpcCodec)(nil) // ensure *rpcCodec implements RpcCodecBuffered diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/simple.go b/vendor/github.com/hashicorp/go-msgpack/codec/simple.go deleted file mode 100644 index 9e4d148a..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/simple.go +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -import "math" - -const ( - _ uint8 = iota - simpleVdNil = 1 - simpleVdFalse = 2 - simpleVdTrue = 3 - simpleVdFloat32 = 4 - simpleVdFloat64 = 5 - - // each lasts for 4 (ie n, n+1, n+2, n+3) - simpleVdPosInt = 8 - simpleVdNegInt = 12 - - // containers: each lasts for 4 (ie n, n+1, n+2, ... n+7) - simpleVdString = 216 - simpleVdByteArray = 224 - simpleVdArray = 232 - simpleVdMap = 240 - simpleVdExt = 248 -) - -type simpleEncDriver struct { - h *SimpleHandle - w encWriter - //b [8]byte -} - -func (e *simpleEncDriver) isBuiltinType(rt uintptr) bool { - return false -} - -func (e *simpleEncDriver) encodeBuiltin(rt uintptr, v interface{}) { -} - -func (e *simpleEncDriver) encodeNil() { - e.w.writen1(simpleVdNil) -} - -func (e *simpleEncDriver) encodeBool(b bool) { - if b { - e.w.writen1(simpleVdTrue) - } else { - e.w.writen1(simpleVdFalse) - } -} - -func (e *simpleEncDriver) encodeFloat32(f float32) { - e.w.writen1(simpleVdFloat32) - e.w.writeUint32(math.Float32bits(f)) -} - -func (e *simpleEncDriver) encodeFloat64(f float64) { - e.w.writen1(simpleVdFloat64) - e.w.writeUint64(math.Float64bits(f)) -} - -func (e *simpleEncDriver) encodeInt(v int64) { - if v < 0 { - e.encUint(uint64(-v), simpleVdNegInt) - } else { - e.encUint(uint64(v), simpleVdPosInt) - } -} - -func (e *simpleEncDriver) encodeUint(v uint64) { - e.encUint(v, simpleVdPosInt) -} - -func (e *simpleEncDriver) encUint(v uint64, bd uint8) { - switch { - case v <= math.MaxUint8: - e.w.writen2(bd, uint8(v)) - case v <= math.MaxUint16: - e.w.writen1(bd + 1) - e.w.writeUint16(uint16(v)) - case v <= math.MaxUint32: - e.w.writen1(bd + 2) - e.w.writeUint32(uint32(v)) - case v <= math.MaxUint64: - e.w.writen1(bd + 3) - e.w.writeUint64(v) - } -} - -func (e *simpleEncDriver) encLen(bd byte, length int) { - switch { - case length == 0: - e.w.writen1(bd) - case length <= math.MaxUint8: - e.w.writen1(bd + 1) - e.w.writen1(uint8(length)) - case length <= math.MaxUint16: - e.w.writen1(bd + 2) - e.w.writeUint16(uint16(length)) - case int64(length) <= math.MaxUint32: - e.w.writen1(bd + 3) - e.w.writeUint32(uint32(length)) - default: - e.w.writen1(bd + 4) - e.w.writeUint64(uint64(length)) - } -} - -func (e *simpleEncDriver) encodeExtPreamble(xtag byte, length int) { - e.encLen(simpleVdExt, length) - e.w.writen1(xtag) -} - -func (e *simpleEncDriver) encodeArrayPreamble(length int) { - e.encLen(simpleVdArray, length) -} - -func (e *simpleEncDriver) encodeMapPreamble(length int) { - e.encLen(simpleVdMap, length) -} - -func (e *simpleEncDriver) encodeString(c charEncoding, v string) { - e.encLen(simpleVdString, len(v)) - e.w.writestr(v) -} - -func (e *simpleEncDriver) encodeSymbol(v string) { - e.encodeString(c_UTF8, v) -} - -func (e *simpleEncDriver) encodeStringBytes(c charEncoding, v []byte) { - e.encLen(simpleVdByteArray, len(v)) - e.w.writeb(v) -} - -//------------------------------------ - -type simpleDecDriver struct { - h *SimpleHandle - r decReader - bdRead bool - bdType valueType - bd byte - //b [8]byte -} - -func (d *simpleDecDriver) initReadNext() { - if d.bdRead { - return - } - d.bd = d.r.readn1() - d.bdRead = true - d.bdType = valueTypeUnset -} - -func (d *simpleDecDriver) currentEncodedType() valueType { - if d.bdType == valueTypeUnset { - switch d.bd { - case simpleVdNil: - d.bdType = valueTypeNil - case simpleVdTrue, simpleVdFalse: - d.bdType = valueTypeBool - case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3: - d.bdType = valueTypeUint - case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3: - d.bdType = valueTypeInt - case simpleVdFloat32, simpleVdFloat64: - d.bdType = valueTypeFloat - case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4: - d.bdType = valueTypeString - case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: - d.bdType = valueTypeBytes - case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4: - d.bdType = valueTypeExt - case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4: - d.bdType = valueTypeArray - case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4: - d.bdType = valueTypeMap - default: - decErr("currentEncodedType: Unrecognized d.vd: 0x%x", d.bd) - } - } - return d.bdType -} - -func (d *simpleDecDriver) tryDecodeAsNil() bool { - if d.bd == simpleVdNil { - d.bdRead = false - return true - } - return false -} - -func (d *simpleDecDriver) isBuiltinType(rt uintptr) bool { - return false -} - -func (d *simpleDecDriver) decodeBuiltin(rt uintptr, v interface{}) { -} - -func (d *simpleDecDriver) decIntAny() (ui uint64, i int64, neg bool) { - switch d.bd { - case simpleVdPosInt: - ui = uint64(d.r.readn1()) - i = int64(ui) - case simpleVdPosInt + 1: - ui = uint64(d.r.readUint16()) - i = int64(ui) - case simpleVdPosInt + 2: - ui = uint64(d.r.readUint32()) - i = int64(ui) - case simpleVdPosInt + 3: - ui = uint64(d.r.readUint64()) - i = int64(ui) - case simpleVdNegInt: - ui = uint64(d.r.readn1()) - i = -(int64(ui)) - neg = true - case simpleVdNegInt + 1: - ui = uint64(d.r.readUint16()) - i = -(int64(ui)) - neg = true - case simpleVdNegInt + 2: - ui = uint64(d.r.readUint32()) - i = -(int64(ui)) - neg = true - case simpleVdNegInt + 3: - ui = uint64(d.r.readUint64()) - i = -(int64(ui)) - neg = true - default: - decErr("decIntAny: Integer only valid from pos/neg integer1..8. Invalid descriptor: %v", d.bd) - } - // don't do this check, because callers may only want the unsigned value. - // if ui > math.MaxInt64 { - // decErr("decIntAny: Integer out of range for signed int64: %v", ui) - // } - return -} - -func (d *simpleDecDriver) decodeInt(bitsize uint8) (i int64) { - _, i, _ = d.decIntAny() - checkOverflow(0, i, bitsize) - d.bdRead = false - return -} - -func (d *simpleDecDriver) decodeUint(bitsize uint8) (ui uint64) { - ui, i, neg := d.decIntAny() - if neg { - decErr("Assigning negative signed value: %v, to unsigned type", i) - } - checkOverflow(ui, 0, bitsize) - d.bdRead = false - return -} - -func (d *simpleDecDriver) decodeFloat(chkOverflow32 bool) (f float64) { - switch d.bd { - case simpleVdFloat32: - f = float64(math.Float32frombits(d.r.readUint32())) - case simpleVdFloat64: - f = math.Float64frombits(d.r.readUint64()) - default: - if d.bd >= simpleVdPosInt && d.bd <= simpleVdNegInt+3 { - _, i, _ := d.decIntAny() - f = float64(i) - } else { - decErr("Float only valid from float32/64: Invalid descriptor: %v", d.bd) - } - } - checkOverflowFloat32(f, chkOverflow32) - d.bdRead = false - return -} - -// bool can be decoded from bool only (single byte). -func (d *simpleDecDriver) decodeBool() (b bool) { - switch d.bd { - case simpleVdTrue: - b = true - case simpleVdFalse: - default: - decErr("Invalid single-byte value for bool: %s: %x", msgBadDesc, d.bd) - } - d.bdRead = false - return -} - -func (d *simpleDecDriver) readMapLen() (length int) { - d.bdRead = false - return d.decLen() -} - -func (d *simpleDecDriver) readArrayLen() (length int) { - d.bdRead = false - return d.decLen() -} - -func (d *simpleDecDriver) decLen() int { - switch d.bd % 8 { - case 0: - return 0 - case 1: - return int(d.r.readn1()) - case 2: - return int(d.r.readUint16()) - case 3: - ui := uint64(d.r.readUint32()) - checkOverflow(ui, 0, intBitsize) - return int(ui) - case 4: - ui := d.r.readUint64() - checkOverflow(ui, 0, intBitsize) - return int(ui) - } - decErr("decLen: Cannot read length: bd%8 must be in range 0..4. Got: %d", d.bd%8) - return -1 -} - -func (d *simpleDecDriver) decodeString() (s string) { - s = string(d.r.readn(d.decLen())) - d.bdRead = false - return -} - -func (d *simpleDecDriver) decodeBytes(bs []byte) (bsOut []byte, changed bool) { - if clen := d.decLen(); clen > 0 { - // if no contents in stream, don't update the passed byteslice - if len(bs) != clen { - if len(bs) > clen { - bs = bs[:clen] - } else { - bs = make([]byte, clen) - } - bsOut = bs - changed = true - } - d.r.readb(bs) - } - d.bdRead = false - return -} - -func (d *simpleDecDriver) decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) { - switch d.bd { - case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4: - l := d.decLen() - xtag = d.r.readn1() - if verifyTag && xtag != tag { - decErr("Wrong extension tag. Got %b. Expecting: %v", xtag, tag) - } - xbs = d.r.readn(l) - case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: - xbs, _ = d.decodeBytes(nil) - default: - decErr("Invalid d.vd for extensions (Expecting extensions or byte array). Got: 0x%x", d.bd) - } - d.bdRead = false - return -} - -func (d *simpleDecDriver) decodeNaked() (v interface{}, vt valueType, decodeFurther bool) { - d.initReadNext() - - switch d.bd { - case simpleVdNil: - vt = valueTypeNil - case simpleVdFalse: - vt = valueTypeBool - v = false - case simpleVdTrue: - vt = valueTypeBool - v = true - case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3: - vt = valueTypeUint - ui, _, _ := d.decIntAny() - v = ui - case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3: - vt = valueTypeInt - _, i, _ := d.decIntAny() - v = i - case simpleVdFloat32: - vt = valueTypeFloat - v = d.decodeFloat(true) - case simpleVdFloat64: - vt = valueTypeFloat - v = d.decodeFloat(false) - case simpleVdString, simpleVdString + 1, simpleVdString + 2, simpleVdString + 3, simpleVdString + 4: - vt = valueTypeString - v = d.decodeString() - case simpleVdByteArray, simpleVdByteArray + 1, simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4: - vt = valueTypeBytes - v, _ = d.decodeBytes(nil) - case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4: - vt = valueTypeExt - l := d.decLen() - var re RawExt - re.Tag = d.r.readn1() - re.Data = d.r.readn(l) - v = &re - vt = valueTypeExt - case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4: - vt = valueTypeArray - decodeFurther = true - case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4: - vt = valueTypeMap - decodeFurther = true - default: - decErr("decodeNaked: Unrecognized d.vd: 0x%x", d.bd) - } - - if !decodeFurther { - d.bdRead = false - } - return -} - -//------------------------------------ - -// SimpleHandle is a Handle for a very simple encoding format. -// -// simple is a simplistic codec similar to binc, but not as compact. -// - Encoding of a value is always preceeded by the descriptor byte (bd) -// - True, false, nil are encoded fully in 1 byte (the descriptor) -// - Integers (intXXX, uintXXX) are encoded in 1, 2, 4 or 8 bytes (plus a descriptor byte). -// There are positive (uintXXX and intXXX >= 0) and negative (intXXX < 0) integers. -// - Floats are encoded in 4 or 8 bytes (plus a descriptor byte) -// - Lenght of containers (strings, bytes, array, map, extensions) -// are encoded in 0, 1, 2, 4 or 8 bytes. -// Zero-length containers have no length encoded. -// For others, the number of bytes is given by pow(2, bd%3) -// - maps are encoded as [bd] [length] [[key][value]]... -// - arrays are encoded as [bd] [length] [value]... -// - extensions are encoded as [bd] [length] [tag] [byte]... -// - strings/bytearrays are encoded as [bd] [length] [byte]... -// -// The full spec will be published soon. -type SimpleHandle struct { - BasicHandle -} - -func (h *SimpleHandle) newEncDriver(w encWriter) encDriver { - return &simpleEncDriver{w: w, h: h} -} - -func (h *SimpleHandle) newDecDriver(r decReader) decDriver { - return &simpleDecDriver{r: r, h: h} -} - -func (_ *SimpleHandle) writeExt() bool { - return true -} - -func (h *SimpleHandle) getBasicHandle() *BasicHandle { - return &h.BasicHandle -} - -var _ decDriver = (*simpleDecDriver)(nil) -var _ encDriver = (*simpleEncDriver)(nil) diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/time.go b/vendor/github.com/hashicorp/go-msgpack/codec/time.go deleted file mode 100644 index c86d6532..00000000 --- a/vendor/github.com/hashicorp/go-msgpack/codec/time.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. -// Use of this source code is governed by a BSD-style license found in the LICENSE file. - -package codec - -import ( - "time" -) - -var ( - timeDigits = [...]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} -) - -// EncodeTime encodes a time.Time as a []byte, including -// information on the instant in time and UTC offset. -// -// Format Description -// -// A timestamp is composed of 3 components: -// -// - secs: signed integer representing seconds since unix epoch -// - nsces: unsigned integer representing fractional seconds as a -// nanosecond offset within secs, in the range 0 <= nsecs < 1e9 -// - tz: signed integer representing timezone offset in minutes east of UTC, -// and a dst (daylight savings time) flag -// -// When encoding a timestamp, the first byte is the descriptor, which -// defines which components are encoded and how many bytes are used to -// encode secs and nsecs components. *If secs/nsecs is 0 or tz is UTC, it -// is not encoded in the byte array explicitly*. -// -// Descriptor 8 bits are of the form `A B C DDD EE`: -// A: Is secs component encoded? 1 = true -// B: Is nsecs component encoded? 1 = true -// C: Is tz component encoded? 1 = true -// DDD: Number of extra bytes for secs (range 0-7). -// If A = 1, secs encoded in DDD+1 bytes. -// If A = 0, secs is not encoded, and is assumed to be 0. -// If A = 1, then we need at least 1 byte to encode secs. -// DDD says the number of extra bytes beyond that 1. -// E.g. if DDD=0, then secs is represented in 1 byte. -// if DDD=2, then secs is represented in 3 bytes. -// EE: Number of extra bytes for nsecs (range 0-3). -// If B = 1, nsecs encoded in EE+1 bytes (similar to secs/DDD above) -// -// Following the descriptor bytes, subsequent bytes are: -// -// secs component encoded in `DDD + 1` bytes (if A == 1) -// nsecs component encoded in `EE + 1` bytes (if B == 1) -// tz component encoded in 2 bytes (if C == 1) -// -// secs and nsecs components are integers encoded in a BigEndian -// 2-complement encoding format. -// -// tz component is encoded as 2 bytes (16 bits). Most significant bit 15 to -// Least significant bit 0 are described below: -// -// Timezone offset has a range of -12:00 to +14:00 (ie -720 to +840 minutes). -// Bit 15 = have\_dst: set to 1 if we set the dst flag. -// Bit 14 = dst\_on: set to 1 if dst is in effect at the time, or 0 if not. -// Bits 13..0 = timezone offset in minutes. It is a signed integer in Big Endian format. -// -func encodeTime(t time.Time) []byte { - //t := rv.Interface().(time.Time) - tsecs, tnsecs := t.Unix(), t.Nanosecond() - var ( - bd byte - btmp [8]byte - bs [16]byte - i int = 1 - ) - l := t.Location() - if l == time.UTC { - l = nil - } - if tsecs != 0 { - bd = bd | 0x80 - bigen.PutUint64(btmp[:], uint64(tsecs)) - f := pruneSignExt(btmp[:], tsecs >= 0) - bd = bd | (byte(7-f) << 2) - copy(bs[i:], btmp[f:]) - i = i + (8 - f) - } - if tnsecs != 0 { - bd = bd | 0x40 - bigen.PutUint32(btmp[:4], uint32(tnsecs)) - f := pruneSignExt(btmp[:4], true) - bd = bd | byte(3-f) - copy(bs[i:], btmp[f:4]) - i = i + (4 - f) - } - if l != nil { - bd = bd | 0x20 - // Note that Go Libs do not give access to dst flag. - _, zoneOffset := t.Zone() - //zoneName, zoneOffset := t.Zone() - zoneOffset /= 60 - z := uint16(zoneOffset) - bigen.PutUint16(btmp[:2], z) - // clear dst flags - bs[i] = btmp[0] & 0x3f - bs[i+1] = btmp[1] - i = i + 2 - } - bs[0] = bd - return bs[0:i] -} - -// DecodeTime decodes a []byte into a time.Time. -func decodeTime(bs []byte) (tt time.Time, err error) { - bd := bs[0] - var ( - tsec int64 - tnsec uint32 - tz uint16 - i byte = 1 - i2 byte - n byte - ) - if bd&(1<<7) != 0 { - var btmp [8]byte - n = ((bd >> 2) & 0x7) + 1 - i2 = i + n - copy(btmp[8-n:], bs[i:i2]) - //if first bit of bs[i] is set, then fill btmp[0..8-n] with 0xff (ie sign extend it) - if bs[i]&(1<<7) != 0 { - copy(btmp[0:8-n], bsAll0xff) - //for j,k := byte(0), 8-n; j < k; j++ { btmp[j] = 0xff } - } - i = i2 - tsec = int64(bigen.Uint64(btmp[:])) - } - if bd&(1<<6) != 0 { - var btmp [4]byte - n = (bd & 0x3) + 1 - i2 = i + n - copy(btmp[4-n:], bs[i:i2]) - i = i2 - tnsec = bigen.Uint32(btmp[:]) - } - if bd&(1<<5) == 0 { - tt = time.Unix(tsec, int64(tnsec)).UTC() - return - } - // In stdlib time.Parse, when a date is parsed without a zone name, it uses "" as zone name. - // However, we need name here, so it can be shown when time is printed. - // Zone name is in form: UTC-08:00. - // Note that Go Libs do not give access to dst flag, so we ignore dst bits - - i2 = i + 2 - tz = bigen.Uint16(bs[i:i2]) - i = i2 - // sign extend sign bit into top 2 MSB (which were dst bits): - if tz&(1<<13) == 0 { // positive - tz = tz & 0x3fff //clear 2 MSBs: dst bits - } else { // negative - tz = tz | 0xc000 //set 2 MSBs: dst bits - //tzname[3] = '-' (TODO: verify. this works here) - } - tzint := int16(tz) - if tzint == 0 { - tt = time.Unix(tsec, int64(tnsec)).UTC() - } else { - // For Go Time, do not use a descriptive timezone. - // It's unnecessary, and makes it harder to do a reflect.DeepEqual. - // The Offset already tells what the offset should be, if not on UTC and unknown zone name. - // var zoneName = timeLocUTCName(tzint) - tt = time.Unix(tsec, int64(tnsec)).In(time.FixedZone("", int(tzint)*60)) - } - return -} - -func timeLocUTCName(tzint int16) string { - if tzint == 0 { - return "UTC" - } - var tzname = []byte("UTC+00:00") - //tzname := fmt.Sprintf("UTC%s%02d:%02d", tzsign, tz/60, tz%60) //perf issue using Sprintf. inline below. - //tzhr, tzmin := tz/60, tz%60 //faster if u convert to int first - var tzhr, tzmin int16 - if tzint < 0 { - tzname[3] = '-' // (TODO: verify. this works here) - tzhr, tzmin = -tzint/60, (-tzint)%60 - } else { - tzhr, tzmin = tzint/60, tzint%60 - } - tzname[4] = timeDigits[tzhr/10] - tzname[5] = timeDigits[tzhr%10] - tzname[7] = timeDigits[tzmin/10] - tzname[8] = timeDigits[tzmin%10] - return string(tzname) - //return time.FixedZone(string(tzname), int(tzint)*60) -} diff --git a/vendor/github.com/sirupsen/logrus/LICENSE b/vendor/github.com/hashicorp/go-msgpack/v2/LICENSE similarity index 86% rename from vendor/github.com/sirupsen/logrus/LICENSE rename to vendor/github.com/hashicorp/go-msgpack/v2/LICENSE index f090cb42..95a0f054 100644 --- a/vendor/github.com/sirupsen/logrus/LICENSE +++ b/vendor/github.com/hashicorp/go-msgpack/v2/LICENSE @@ -1,6 +1,7 @@ The MIT License (MIT) -Copyright (c) 2014 Simon Eskildsen +Copyright (c) 2012-2015 Ugorji Nwoke. +All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -9,13 +10,13 @@ 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 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. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/build.sh b/vendor/github.com/hashicorp/go-msgpack/v2/codec/build.sh new file mode 100644 index 00000000..831bd864 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/build.sh @@ -0,0 +1,263 @@ +#!/bin/bash + +# Run all the different permutations of all the tests and other things +# This helps ensure that nothing gets broken. + +_tests() { + local gover=$( go version | cut -f 3 -d ' ' ) + local a=( "" "codecgen" ) + for i in "${a[@]}" + do + echo ">>>> TAGS: $i" + local i2=${i:-default} + case $gover in + go1.[0-6]*) go vet -printfuncs "errorf" "$@" && + go test ${zargs[*]} -vet off -tags "$i" "$@" ;; + *) go vet -printfuncs "errorf" "$@" && + go test ${zargs[*]} -vet off -tags "alltests $i" -run "Suite" -coverprofile "${i2// /-}.cov.out" "$@" ;; + esac + if [[ "$?" != 0 ]]; then return 1; fi + done + echo "++++++++ TEST SUITES ALL PASSED ++++++++" +} + + +# is a generation needed? +_ng() { + local a="$1" + if [[ ! -e "$a" ]]; then echo 1; return; fi + for i in `ls -1 *.go.tmpl gen.go values_test.go` + do + if [[ "$a" -ot "$i" ]]; then echo 1; return; fi + done +} + +_prependbt() { + cat > ${2} <> ${2} + rm -f ${1} +} + +# _build generates gen-helper.go. +_build() { + if ! [[ "${zforce}" || $(_ng "gen-helper.generated.go") || $(_ng "gen.generated.go") ]]; then return 0; fi + + if [ "${zbak}" ]; then + _zts=`date '+%m%d%Y_%H%M%S'` + _gg=".generated.go" + [ -e "gen-helper${_gg}" ] && mv gen-helper${_gg} gen-helper${_gg}__${_zts}.bak + [ -e "gen${_gg}" ] && mv gen${_gg} gen${_gg}__${_zts}.bak + fi + rm -f gen-helper.generated.go gen.generated.go \ + *_generated_test.go *.generated_ffjson_expose.go + + cat > gen.generated.go <> gen.generated.go < gen-dec-map.go.tmpl + cat >> gen.generated.go <> gen.generated.go < gen-dec-array.go.tmpl + cat >> gen.generated.go <> gen.generated.go < gen-enc-chan.go.tmpl + cat >> gen.generated.go < gen-from-tmpl.codec.generated.go < gen-from-tmpl.generated.go < " + fnameOut + " ______") +fin, err := os.Open(fnameIn) +if err != nil { panic(err) } +defer fin.Close() +fout, err := os.Create(fnameOut) +if err != nil { panic(err) } +defer fout.Close() +err = codec.GenInternalGoFile(fin, fout) +if err != nil { panic(err) } +} + +func main() { +run("gen-helper.go.tmpl", "gen-helper.generated.go") +run("mammoth-test.go.tmpl", "mammoth_generated_test.go") +run("mammoth2-test.go.tmpl", "mammoth2_generated_test.go") +} +EOF + + sed -e 's+// __DO_NOT_REMOVE__NEEDED_FOR_REPLACING__IMPORT_PATH__FOR_CODEC_BENCH__+import . "github.com/hashicorp/go-msgpack/v2/codec"+' \ + shared_test.go > bench/shared_test.go + + # explicitly return 0 if this passes, else return 1 + go run -tags "codecgen.exec" gen-from-tmpl.generated.go && + rm -f gen-from-tmpl.*generated.go && + return 0 + return 1 +} + +_codegenerators() { + local c5="_generated_test.go" + local c7="$PWD/codecgen" + local c8="$c7/__codecgen" + local c9="codecgen-scratch.go" + + if ! [[ $zforce || $(_ng "values_codecgen${c5}") ]]; then return 0; fi + + # Note: ensure you run the codecgen for this codebase/directory i.e. ./codecgen/codecgen + true && + echo "codecgen ... " && + if [[ $zforce || ! -f "$c8" || "$c7/gen.go" -nt "$c8" ]]; then + echo "rebuilding codecgen ... " && ( cd codecgen && go build -o $c8 ${zargs[*]} . ) + fi && + $c8 -rt codecgen -t 'codecgen generated' -o values_codecgen${c5} -d 19780 $zfin $zfin2 && + cp mammoth2_generated_test.go $c9 && + $c8 -o mammoth2_codecgen${c5} -d 19781 mammoth2_generated_test.go && + rm -f $c9 && + echo "generators done!" +} + +_prebuild() { + echo "prebuild: zforce: $zforce" + local d="$PWD" + zfin="test_values.generated.go" + zfin2="test_values_flex.generated.go" + zpkg="github.com/hashicorp/go-msgpack/v2/codec" + # zpkg=${d##*/src/} + # zgobase=${d%%/src/*} + # rm -f *_generated_test.go + rm -f codecgen-*.go && + _build && + cp $d/values_test.go $d/$zfin && + cp $d/values_flex_test.go $d/$zfin2 && + _codegenerators && + if [[ "$(type -t _codegenerators_external )" = "function" ]]; then _codegenerators_external ; fi && + if [[ $zforce ]]; then go install ${zargs[*]} .; fi && + echo "prebuild done successfully" + rm -f $d/$zfin $d/$zfin2 + unset zfin zfin2 zpkg +} + +_make() { + zforce=1 + (cd codecgen && go install ${zargs[*]} .) && _prebuild && go install ${zargs[*]} . + unset zforce +} + +_clean() { + rm -f gen-from-tmpl.*generated.go \ + codecgen-*.go \ + test_values.generated.go test_values_flex.generated.go +} + +_release() { + local reply + read -p "Pre-release validation takes a few minutes and MUST be run from within GOPATH/src. Confirm y/n? " -n 1 -r reply + echo + if [[ ! $reply =~ ^[Yy]$ ]]; then return 1; fi + + # expects GOROOT, GOROOT_BOOTSTRAP to have been set. + if [[ -z "${GOROOT// }" || -z "${GOROOT_BOOTSTRAP// }" ]]; then return 1; fi + # (cd $GOROOT && git checkout -f master && git pull && git reset --hard) + (cd $GOROOT && git pull) + local f=`pwd`/make.release.out + cat > $f <>$f + if [[ "$i" != "master" ]]; then i="release-branch.go$i"; fi + (false || + (echo "===== BUILDING GO SDK for branch: $i ... =====" && + cd $GOROOT && + git checkout -f $i && git reset --hard && git clean -f . && + cd src && ./make.bash >>$f 2>&1 && sleep 1 ) ) && + echo "===== GO SDK BUILD DONE =====" && + _prebuild && + echo "===== PREBUILD DONE with exit: $? =====" && + _tests "$@" + if [[ "$?" != 0 ]]; then return 1; fi + done + unset zforce + echo "++++++++ RELEASE TEST SUITES ALL PASSED ++++++++" +} + +_usage() { + cat < [tests, make, prebuild (force) (external), inlining diagnostics, mid-stack inlining, race detector] + -v -> verbose +EOF + if [[ "$(type -t _usage_run)" = "function" ]]; then _usage_run ; fi +} + +_main() { + if [[ -z "$1" ]]; then _usage; return 1; fi + local x + unset zforce + zargs=() + zbenchflags="" + OPTIND=1 + while getopts ":ctmnrgpfvlzdb:" flag + do + case "x$flag" in + 'xf') zforce=1 ;; + 'xv') zverbose=1 ;; + 'xl') zargs+=("-gcflags"); zargs+=("-l=4") ;; + 'xn') zargs+=("-gcflags"); zargs+=("-m=2") ;; + 'xd') zargs+=("-race") ;; + 'xb') x='b'; zbenchflags=${OPTARG} ;; + x\?) _usage; return 1 ;; + *) x=$flag ;; + esac + done + shift $((OPTIND-1)) + # echo ">>>> _main: extra args: $@" + case "x$x" in + 'xt') _tests "$@" ;; + 'xm') _make "$@" ;; + 'xr') _release "$@" ;; + 'xg') _go ;; + 'xp') _prebuild "$@" ;; + 'xc') _clean "$@" ;; + 'xz') _analyze "$@" ;; + 'xb') _bench "$@" ;; + esac + unset zforce zargs zbenchflags +} + +[ "." = `dirname $0` ] && _main "$@" \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/codecgen.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/codecgen.go new file mode 100644 index 00000000..28fa8105 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/codecgen.go @@ -0,0 +1,14 @@ +//go:build codecgen || generated +// +build codecgen generated + +package codec + +// this file is here, to set the codecgen variable to true +// when the build tag codecgen is set. +// +// this allows us do specific things e.g. skip missing fields tests, +// when running in codecgen mode. + +func init() { + codecgen = true +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/decode.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/decode.go new file mode 100644 index 00000000..e0fb62df --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/decode.go @@ -0,0 +1,3111 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +import ( + "encoding" + "errors" + "fmt" + "io" + "reflect" + "runtime" + "strconv" + "time" +) + +// Some tagging information for error messages. +const ( + msgBadDesc = "unrecognized descriptor byte" + // msgDecCannotExpandArr = "cannot expand go array from %v to stream length: %v" +) + +const ( + decDefMaxDepth = 1024 // maximum depth + decDefSliceCap = 8 + decDefChanCap = 64 // should be large, as cap cannot be expanded + decScratchByteArrayLen = cacheLineSize // + (8 * 2) // - (8 * 1) +) + +var ( + errstrOnlyMapOrArrayCanDecodeIntoStruct = "only encoded map or array can be decoded into a struct" + errstrCannotDecodeIntoNil = "cannot decode into nil" + + errmsgExpandSliceOverflow = "expand slice: slice overflow" + errmsgExpandSliceCannotChange = "expand slice: cannot change" + + errDecoderNotInitialized = errors.New("Decoder not initialized") + + errDecUnreadByteNothingToRead = errors.New("cannot unread - nothing has been read") + errDecUnreadByteLastByteNotRead = errors.New("cannot unread - last byte has not been read") + errDecUnreadByteUnknown = errors.New("cannot unread - reason unknown") + errMaxDepthExceeded = errors.New("maximum decoding depth exceeded") +) + +/* + +// decReader abstracts the reading source, allowing implementations that can +// read from an io.Reader or directly off a byte slice with zero-copying. +// +// Deprecated: Use decReaderSwitch instead. +type decReader interface { + unreadn1() + // readx will use the implementation scratch buffer if possible i.e. n < len(scratchbuf), OR + // just return a view of the []byte being decoded from. + // Ensure you call detachZeroCopyBytes later if this needs to be sent outside codec control. + readx(n int) []byte + readb([]byte) + readn1() uint8 + numread() uint // number of bytes read + track() + stopTrack() []byte + + // skip will skip any byte that matches, and return the first non-matching byte + skip(accept *bitset256) (token byte) + // readTo will read any byte that matches, stopping once no-longer matching. + readTo(in []byte, accept *bitset256) (out []byte) + // readUntil will read, only stopping once it matches the 'stop' byte. + readUntil(in []byte, stop byte) (out []byte) +} + +*/ + +type decDriver interface { + // this will check if the next token is a break. + CheckBreak() bool + // TryDecodeAsNil tries to decode as nil. + // Note: TryDecodeAsNil should be careful not to share any temporary []byte with + // the rest of the decDriver. This is because sometimes, we optimize by holding onto + // a transient []byte, and ensuring the only other call we make to the decDriver + // during that time is maybe a TryDecodeAsNil() call. + TryDecodeAsNil() bool + // ContainerType returns one of: Bytes, String, Nil, Slice or Map. Return unSet if not known. + ContainerType() (vt valueType) + // IsBuiltinType(rt uintptr) bool + + // DecodeNaked will decode primitives (number, bool, string, []byte) and RawExt. + // For maps and arrays, it will not do the decoding in-band, but will signal + // the decoder, so that is done later, by setting the decNaked.valueType field. + // + // Note: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types). + // for extensions, DecodeNaked must read the tag and the []byte if it exists. + // if the []byte is not read, then kInterfaceNaked will treat it as a Handle + // that stores the subsequent value in-band, and complete reading the RawExt. + // + // extensions should also use readx to decode them, for efficiency. + // kInterface will extract the detached byte slice if it has to pass it outside its realm. + DecodeNaked() + + // Deprecated: use DecodeInt64 and DecodeUint64 instead + // DecodeInt(bitsize uint8) (i int64) + // DecodeUint(bitsize uint8) (ui uint64) + + DecodeInt64() (i int64) + DecodeUint64() (ui uint64) + + DecodeFloat64() (f float64) + DecodeBool() (b bool) + // DecodeString can also decode symbols. + // It looks redundant as DecodeBytes is available. + // However, some codecs (e.g. binc) support symbols and can + // return a pre-stored string value, meaning that it can bypass + // the cost of []byte->string conversion. + DecodeString() (s string) + DecodeStringAsBytes() (v []byte) + + // DecodeBytes may be called directly, without going through reflection. + // Consequently, it must be designed to handle possible nil. + DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) + // DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte) + + // decodeExt will decode into a *RawExt or into an extension. + DecodeExt(v interface{}, xtag uint64, ext Ext) (realxtag uint64) + // decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte) + + DecodeTime() (t time.Time) + + ReadArrayStart() int + ReadArrayElem() + ReadArrayEnd() + ReadMapStart() int + ReadMapElemKey() + ReadMapElemValue() + ReadMapEnd() + + reset() + uncacheRead() +} + +type decodeError struct { + codecError + pos int +} + +func (d decodeError) Error() string { + return fmt.Sprintf("%s decode error [pos %d]: %v", d.name, d.pos, d.err) +} + +type decDriverNoopContainerReader struct{} + +func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { return } +func (x decDriverNoopContainerReader) ReadArrayElem() {} +func (x decDriverNoopContainerReader) ReadArrayEnd() {} +func (x decDriverNoopContainerReader) ReadMapStart() (v int) { return } +func (x decDriverNoopContainerReader) ReadMapElemKey() {} +func (x decDriverNoopContainerReader) ReadMapElemValue() {} +func (x decDriverNoopContainerReader) ReadMapEnd() {} +func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return } + +// func (x decNoSeparator) uncacheRead() {} + +// DecodeOptions captures configuration options during decode. +type DecodeOptions struct { + // MapType specifies type to use during schema-less decoding of a map in the stream. + // If nil (unset), we default to map[string]interface{} iff json handle and MapStringAsKey=true, + // else map[interface{}]interface{}. + MapType reflect.Type + + // SliceType specifies type to use during schema-less decoding of an array in the stream. + // If nil (unset), we default to []interface{} for all formats. + SliceType reflect.Type + + // MaxInitLen defines the maxinum initial length that we "make" a collection + // (string, slice, map, chan). If 0 or negative, we default to a sensible value + // based on the size of an element in the collection. + // + // For example, when decoding, a stream may say that it has 2^64 elements. + // We should not auto-matically provision a slice of that size, to prevent Out-Of-Memory crash. + // Instead, we provision up to MaxInitLen, fill that up, and start appending after that. + MaxInitLen int + + // ReaderBufferSize is the size of the buffer used when reading. + // + // if > 0, we use a smart buffer internally for performance purposes. + ReaderBufferSize int + + // MaxDepth defines the maximum depth when decoding nested + // maps and slices. If 0 or negative, we default to a suitably large number (currently 1024). + MaxDepth int16 + + // If ErrorIfNoField, return an error when decoding a map + // from a codec stream into a struct, and no matching struct field is found. + ErrorIfNoField bool + + // If ErrorIfNoArrayExpand, return an error when decoding a slice/array that cannot be expanded. + // For example, the stream contains an array of 8 items, but you are decoding into a [4]T array, + // or you are decoding into a slice of length 4 which is non-addressable (and so cannot be set). + ErrorIfNoArrayExpand bool + + // If SignedInteger, use the int64 during schema-less decoding of unsigned values (not uint64). + SignedInteger bool + + // MapValueReset controls how we decode into a map value. + // + // By default, we MAY retrieve the mapping for a key, and then decode into that. + // However, especially with big maps, that retrieval may be expensive and unnecessary + // if the stream already contains all that is necessary to recreate the value. + // + // If true, we will never retrieve the previous mapping, + // but rather decode into a new value and set that in the map. + // + // If false, we will retrieve the previous mapping if necessary e.g. + // the previous mapping is a pointer, or is a struct or array with pre-set state, + // or is an interface. + MapValueReset bool + + // SliceElementReset: on decoding a slice, reset the element to a zero value first. + // + // concern: if the slice already contained some garbage, we will decode into that garbage. + SliceElementReset bool + + // InterfaceReset controls how we decode into an interface. + // + // By default, when we see a field that is an interface{...}, + // or a map with interface{...} value, we will attempt decoding into the + // "contained" value. + // + // However, this prevents us from reading a string into an interface{} + // that formerly contained a number. + // + // If true, we will decode into a new "blank" value, and set that in the interface. + // If false, we will decode into whatever is contained in the interface. + InterfaceReset bool + + // InternString controls interning of strings during decoding. + // + // Some handles, e.g. json, typically will read map keys as strings. + // If the set of keys are finite, it may help reduce allocation to + // look them up from a map (than to allocate them afresh). + // + // Note: Handles will be smart when using the intern functionality. + // Every string should not be interned. + // An excellent use-case for interning is struct field names, + // or map keys where key type is string. + InternString bool + + // PreferArrayOverSlice controls whether to decode to an array or a slice. + // + // This only impacts decoding into a nil interface{}. + // Consequently, it has no effect on codecgen. + // + // *Note*: This only applies if using go1.5 and above, + // as it requires reflect.ArrayOf support which was absent before go1.5. + PreferArrayOverSlice bool + + // DeleteOnNilMapValue controls how to decode a nil value in the stream. + // + // If true, we will delete the mapping of the key. + // Else, just set the mapping to the zero value of the type. + DeleteOnNilMapValue bool + + // RawToString controls how raw bytes in a stream are decoded into a nil interface{}. + // By default, they are decoded as []byte, but can be decoded as string (if configured). + RawToString bool +} + +// ------------------------------------------------ + +type unreadByteStatus uint8 + +// unreadByteStatus goes from +// undefined (when initialized) -- (read) --> canUnread -- (unread) --> canRead ... +const ( + unreadByteUndefined unreadByteStatus = iota + unreadByteCanRead + unreadByteCanUnread +) + +type ioDecReaderCommon struct { + r io.Reader // the reader passed in + + n uint // num read + + l byte // last byte + ls unreadByteStatus // last byte status + trb bool // tracking bytes turned on + _ bool + b [4]byte // tiny buffer for reading single bytes + + tr []byte // tracking bytes read +} + +func (z *ioDecReaderCommon) reset(r io.Reader) { + z.r = r + z.ls = unreadByteUndefined + z.l, z.n = 0, 0 + z.trb = false + if z.tr != nil { + z.tr = z.tr[:0] + } +} + +func (z *ioDecReaderCommon) numread() uint { + return z.n +} + +func (z *ioDecReaderCommon) track() { + if z.tr != nil { + z.tr = z.tr[:0] + } + z.trb = true +} + +func (z *ioDecReaderCommon) stopTrack() (bs []byte) { + z.trb = false + return z.tr +} + +// ------------------------------------------ + +// ioDecReader is a decReader that reads off an io.Reader. +// +// It also has a fallback implementation of ByteScanner if needed. +type ioDecReader struct { + ioDecReaderCommon + + rr io.Reader + br io.ByteScanner + + x [scratchByteArrayLen]byte // for: get struct field name, swallow valueTypeBytes, etc + _ [1]uint64 // padding +} + +func (z *ioDecReader) reset(r io.Reader) { + z.ioDecReaderCommon.reset(r) + + var ok bool + z.rr = r + z.br, ok = r.(io.ByteScanner) + if !ok { + z.br = z + z.rr = z + } +} + +func (z *ioDecReader) Read(p []byte) (n int, err error) { + if len(p) == 0 { + return + } + var firstByte bool + if z.ls == unreadByteCanRead { + z.ls = unreadByteCanUnread + p[0] = z.l + if len(p) == 1 { + n = 1 + return + } + firstByte = true + p = p[1:] + } + n, err = z.r.Read(p) + if n > 0 { + if err == io.EOF && n == len(p) { + err = nil // read was successful, so postpone EOF (till next time) + } + z.l = p[n-1] + z.ls = unreadByteCanUnread + } + if firstByte { + n++ + } + return +} + +func (z *ioDecReader) ReadByte() (c byte, err error) { + n, err := z.Read(z.b[:1]) + if n == 1 { + c = z.b[0] + if err == io.EOF { + err = nil // read was successful, so postpone EOF (till next time) + } + } + return +} + +func (z *ioDecReader) UnreadByte() (err error) { + switch z.ls { + case unreadByteCanUnread: + z.ls = unreadByteCanRead + case unreadByteCanRead: + err = errDecUnreadByteLastByteNotRead + case unreadByteUndefined: + err = errDecUnreadByteNothingToRead + default: + err = errDecUnreadByteUnknown + } + return +} + +func (z *ioDecReader) readx(n uint) (bs []byte) { + if n == 0 { + return + } + if n < uint(len(z.x)) { + bs = z.x[:n] + } else { + bs = make([]byte, n) + } + if _, err := decReadFull(z.rr, bs); err != nil { + panic(err) + } + z.n += uint(len(bs)) + if z.trb { + z.tr = append(z.tr, bs...) + } + return +} + +func (z *ioDecReader) readb(bs []byte) { + if len(bs) == 0 { + return + } + if _, err := decReadFull(z.rr, bs); err != nil { + panic(err) + } + z.n += uint(len(bs)) + if z.trb { + z.tr = append(z.tr, bs...) + } +} + +func (z *ioDecReader) readn1eof() (b uint8, eof bool) { + b, err := z.br.ReadByte() + if err == nil { + z.n++ + if z.trb { + z.tr = append(z.tr, b) + } + } else if err == io.EOF { + eof = true + } else { + panic(err) + } + return +} + +func (z *ioDecReader) readn1() (b uint8) { + b, err := z.br.ReadByte() + if err == nil { + z.n++ + if z.trb { + z.tr = append(z.tr, b) + } + return + } + panic(err) +} + +func (z *ioDecReader) skip(accept *bitset256) (token byte) { + var eof bool + // for { + // token, eof = z.readn1eof() + // if eof { + // return + // } + // if accept.isset(token) { + // continue + // } + // return + // } +LOOP: + token, eof = z.readn1eof() + if eof { + return + } + if accept.isset(token) { + goto LOOP + } + return +} + +func (z *ioDecReader) readTo(in []byte, accept *bitset256) []byte { + // out = in + + // for { + // token, eof := z.readn1eof() + // if eof { + // return + // } + // if accept.isset(token) { + // out = append(out, token) + // } else { + // z.unreadn1() + // return + // } + // } +LOOP: + token, eof := z.readn1eof() + if eof { + return in + } + if accept.isset(token) { + // out = append(out, token) + in = append(in, token) + goto LOOP + } + z.unreadn1() + return in +} + +func (z *ioDecReader) readUntil(in []byte, stop byte) (out []byte) { + out = in + // for { + // token, eof := z.readn1eof() + // if eof { + // panic(io.EOF) + // } + // out = append(out, token) + // if token == stop { + // return + // } + // } +LOOP: + token, eof := z.readn1eof() + if eof { + panic(io.EOF) + } + out = append(out, token) + if token == stop { + return + } + goto LOOP +} + +//go:noinline +func (z *ioDecReader) unreadn1() { + err := z.br.UnreadByte() + if err != nil { + panic(err) + } + z.n-- + if z.trb { + if l := len(z.tr) - 1; l >= 0 { + z.tr = z.tr[:l] + } + } +} + +// ------------------------------------ + +type bufioDecReader struct { + ioDecReaderCommon + + c uint // cursor + buf []byte + + bytesBufPooler + + // err error + + // Extensions can call Decode() within a current Decode() call. + // We need to know when the top level Decode() call returns, + // so we can decide whether to Release() or not. + calls uint16 // what depth in mustDecode are we in now. + + _ [6]uint8 // padding + + _ [1]uint64 // padding +} + +func (z *bufioDecReader) reset(r io.Reader, bufsize int) { + z.ioDecReaderCommon.reset(r) + z.c = 0 + z.calls = 0 + if cap(z.buf) >= bufsize { + z.buf = z.buf[:0] + } else { + z.buf = z.bytesBufPooler.get(bufsize)[:0] + // z.buf = make([]byte, 0, bufsize) + } +} + +func (z *bufioDecReader) release() { + z.buf = nil + z.bytesBufPooler.end() +} + +func (z *bufioDecReader) readb(p []byte) { + var n = uint(copy(p, z.buf[z.c:])) + z.n += n + z.c += n + if len(p) == int(n) { + if z.trb { + z.tr = append(z.tr, p...) // cost=9 + } + } else { + z.readbFill(p, n) + } +} + +//go:noinline - fallback when z.buf is consumed +func (z *bufioDecReader) readbFill(p0 []byte, n uint) { + // at this point, there's nothing in z.buf to read (z.buf is fully consumed) + p := p0[n:] + var n2 uint + var err error + if len(p) > cap(z.buf) { + n2, err = decReadFull(z.r, p) + if err != nil { + panic(err) + } + n += n2 + z.n += n2 + // always keep last byte in z.buf + z.buf = z.buf[:1] + z.buf[0] = p[len(p)-1] + z.c = 1 + if z.trb { + z.tr = append(z.tr, p0[:n]...) + } + return + } + // z.c is now 0, and len(p) <= cap(z.buf) +LOOP: + // for len(p) > 0 && z.err == nil { + if len(p) > 0 { + z.buf = z.buf[0:cap(z.buf)] + var n1 int + n1, err = z.r.Read(z.buf) + n2 = uint(n1) + if n2 == 0 && err != nil { + panic(err) + } + z.buf = z.buf[:n2] + n2 = uint(copy(p, z.buf)) + z.c = n2 + n += n2 + z.n += n2 + p = p[n2:] + goto LOOP + } + if z.c == 0 { + z.buf = z.buf[:1] + z.buf[0] = p[len(p)-1] + z.c = 1 + } + if z.trb { + z.tr = append(z.tr, p0[:n]...) + } +} + +func (z *bufioDecReader) readn1() (b byte) { + // fast-path, so we elide calling into Read() most of the time + if z.c < uint(len(z.buf)) { + b = z.buf[z.c] + z.c++ + z.n++ + if z.trb { + z.tr = append(z.tr, b) + } + } else { // meaning z.c == len(z.buf) or greater ... so need to fill + z.readbFill(z.b[:1], 0) + b = z.b[0] + } + return +} + +func (z *bufioDecReader) unreadn1() { + if z.c == 0 { + panic(errDecUnreadByteNothingToRead) + } + z.c-- + z.n-- + if z.trb { + z.tr = z.tr[:len(z.tr)-1] + } +} + +func (z *bufioDecReader) readx(n uint) (bs []byte) { + if n == 0 { + // return + } else if z.c+n <= uint(len(z.buf)) { + bs = z.buf[z.c : z.c+n] + z.n += n + z.c += n + if z.trb { + z.tr = append(z.tr, bs...) + } + } else { + bs = make([]byte, n) + // n no longer used - can reuse + n = uint(copy(bs, z.buf[z.c:])) + z.n += n + z.c += n + z.readbFill(bs, n) + } + return +} + +//go:noinline - track called by Decoder.nextValueBytes() (called by jsonUnmarshal,rawBytes) +func (z *bufioDecReader) doTrack(y uint) { + z.tr = append(z.tr, z.buf[z.c:y]...) // cost=14??? +} + +func (z *bufioDecReader) skipLoopFn(i uint) { + z.n += (i - z.c) - 1 + i++ + if z.trb { + // z.tr = append(z.tr, z.buf[z.c:i]...) + z.doTrack(i) + } + z.c = i +} + +func (z *bufioDecReader) skip(accept *bitset256) (token byte) { + // token, _ = z.search(nil, accept, 0, 1); return + + // for i := z.c; i < len(z.buf); i++ { + // if token = z.buf[i]; !accept.isset(token) { + // z.skipLoopFn(i) + // return + // } + // } + + i := z.c +LOOP: + if i < uint(len(z.buf)) { + // inline z.skipLoopFn(i) and refactor, so cost is within inline budget + token = z.buf[i] + i++ + if accept.isset(token) { + goto LOOP + } + z.n += i - 2 - z.c + if z.trb { + z.doTrack(i) + } + z.c = i + return + } + return z.skipFill(accept) +} + +func (z *bufioDecReader) skipFill(accept *bitset256) (token byte) { + z.n += uint(len(z.buf)) - z.c + if z.trb { + z.tr = append(z.tr, z.buf[z.c:]...) + } + var n2 int + var err error + for { + z.c = 0 + z.buf = z.buf[0:cap(z.buf)] + n2, err = z.r.Read(z.buf) + if n2 == 0 && err != nil { + panic(err) + } + z.buf = z.buf[:n2] + var i int + for i, token = range z.buf { + if !accept.isset(token) { + z.skipLoopFn(uint(i)) + return + } + } + // for i := 0; i < n2; i++ { + // if token = z.buf[i]; !accept.isset(token) { + // z.skipLoopFn(i) + // return + // } + // } + z.n += uint(n2) + if z.trb { + z.tr = append(z.tr, z.buf...) + } + } +} + +func (z *bufioDecReader) readToLoopFn(i uint, out0 []byte) (out []byte) { + // out0 is never nil + z.n += (i - z.c) - 1 + out = append(out0, z.buf[z.c:i]...) + if z.trb { + z.doTrack(i) + } + z.c = i + return +} + +func (z *bufioDecReader) readTo(in []byte, accept *bitset256) (out []byte) { + // _, out = z.search(in, accept, 0, 2); return + + // for i := z.c; i < len(z.buf); i++ { + // if !accept.isset(z.buf[i]) { + // return z.readToLoopFn(i, nil) + // } + // } + + i := z.c +LOOP: + if i < uint(len(z.buf)) { + if !accept.isset(z.buf[i]) { + // return z.readToLoopFn(i, nil) + // inline readToLoopFn here (for performance) + z.n += (i - z.c) - 1 + out = z.buf[z.c:i] + if z.trb { + z.doTrack(i) + } + z.c = i + return + } + i++ + goto LOOP + } + return z.readToFill(in, accept) +} + +func (z *bufioDecReader) readToFill(in []byte, accept *bitset256) (out []byte) { + z.n += uint(len(z.buf)) - z.c + out = append(in, z.buf[z.c:]...) + if z.trb { + z.tr = append(z.tr, z.buf[z.c:]...) + } + var n2 int + var err error + for { + z.c = 0 + z.buf = z.buf[0:cap(z.buf)] + n2, err = z.r.Read(z.buf) + if n2 == 0 && err != nil { + if err == io.EOF { + return // readTo should read until it matches or end is reached + } + panic(err) + } + z.buf = z.buf[:n2] + for i, token := range z.buf { + if !accept.isset(token) { + return z.readToLoopFn(uint(i), out) + } + } + // for i := 0; i < n2; i++ { + // if !accept.isset(z.buf[i]) { + // return z.readToLoopFn(i, out) + // } + // } + out = append(out, z.buf...) + z.n += uint(n2) + if z.trb { + z.tr = append(z.tr, z.buf...) + } + } +} + +func (z *bufioDecReader) readUntilLoopFn(i uint, out0 []byte) (out []byte) { + z.n += (i - z.c) - 1 + i++ + out = append(out0, z.buf[z.c:i]...) + if z.trb { + // z.tr = append(z.tr, z.buf[z.c:i]...) + z.doTrack(i) + } + z.c = i + return +} + +func (z *bufioDecReader) readUntil(in []byte, stop byte) (out []byte) { + // _, out = z.search(in, nil, stop, 4); return + + // for i := z.c; i < len(z.buf); i++ { + // if z.buf[i] == stop { + // return z.readUntilLoopFn(i, nil) + // } + // } + + i := z.c +LOOP: + if i < uint(len(z.buf)) { + if z.buf[i] == stop { + // inline readUntilLoopFn + // return z.readUntilLoopFn(i, nil) + z.n += (i - z.c) - 1 + i++ + out = z.buf[z.c:i] + if z.trb { + z.doTrack(i) + } + z.c = i + return + } + i++ + goto LOOP + } + return z.readUntilFill(in, stop) +} + +func (z *bufioDecReader) readUntilFill(in []byte, stop byte) (out []byte) { + z.n += uint(len(z.buf)) - z.c + out = append(in, z.buf[z.c:]...) + if z.trb { + z.tr = append(z.tr, z.buf[z.c:]...) + } + var n1 int + var n2 uint + var err error + for { + z.c = 0 + z.buf = z.buf[0:cap(z.buf)] + n1, err = z.r.Read(z.buf) + n2 = uint(n1) + if n2 == 0 && err != nil { + panic(err) + } + z.buf = z.buf[:n2] + for i, token := range z.buf { + if token == stop { + return z.readUntilLoopFn(uint(i), out) + } + } + // for i := 0; i < n2; i++ { + // if z.buf[i] == stop { + // return z.readUntilLoopFn(i, out) + // } + // } + out = append(out, z.buf...) + z.n += n2 + if z.trb { + z.tr = append(z.tr, z.buf...) + } + } +} + +// ------------------------------------ + +var errBytesDecReaderCannotUnread = errors.New("cannot unread last byte read") + +// bytesDecReader is a decReader that reads off a byte slice with zero copying +type bytesDecReader struct { + b []byte // data + c uint // cursor + t uint // track start + // a int // available +} + +func (z *bytesDecReader) reset(in []byte) { + z.b = in + // z.a = len(in) + z.c = 0 + z.t = 0 +} + +func (z *bytesDecReader) numread() uint { + return z.c +} + +func (z *bytesDecReader) unreadn1() { + if z.c == 0 || len(z.b) == 0 { + panic(errBytesDecReaderCannotUnread) + } + z.c-- + // z.a++ +} + +func (z *bytesDecReader) readx(n uint) (bs []byte) { + // slicing from a non-constant start position is more expensive, + // as more computation is required to decipher the pointer start position. + // However, we do it only once, and it's better than reslicing both z.b and return value. + + // if n <= 0 { + // } else if z.a == 0 { + // panic(io.EOF) + // } else if n > z.a { + // panic(io.ErrUnexpectedEOF) + // } else { + // c0 := z.c + // z.c = c0 + n + // z.a = z.a - n + // bs = z.b[c0:z.c] + // } + // return + + if n != 0 { + z.c += n + if z.c > uint(len(z.b)) { + z.c = uint(len(z.b)) + panic(io.EOF) + } + bs = z.b[z.c-n : z.c] + } + return + + // if n == 0 { + // } else if z.c+n > uint(len(z.b)) { + // z.c = uint(len(z.b)) + // panic(io.EOF) + // } else { + // z.c += n + // bs = z.b[z.c-n : z.c] + // } + // return + + // if n == 0 { + // return + // } + // if z.c == uint(len(z.b)) { + // panic(io.EOF) + // } + // if z.c+n > uint(len(z.b)) { + // panic(io.ErrUnexpectedEOF) + // } + // // z.a -= n + // z.c += n + // return z.b[z.c-n : z.c] +} + +func (z *bytesDecReader) readb(bs []byte) { + copy(bs, z.readx(uint(len(bs)))) +} + +func (z *bytesDecReader) readn1() (v uint8) { + if z.c == uint(len(z.b)) { + panic(io.EOF) + } + v = z.b[z.c] + z.c++ + // z.a-- + return +} + +// func (z *bytesDecReader) readn1eof() (v uint8, eof bool) { +// if z.a == 0 { +// eof = true +// return +// } +// v = z.b[z.c] +// z.c++ +// z.a-- +// return +// } + +func (z *bytesDecReader) skip(accept *bitset256) (token byte) { + i := z.c + // if i == len(z.b) { + // goto END + // // panic(io.EOF) + // } + + // Replace loop with goto construct, so that this can be inlined + // for i := z.c; i < blen; i++ { + // if !accept.isset(z.b[i]) { + // token = z.b[i] + // i++ + // z.a -= (i - z.c) + // z.c = i + // return + // } + // } + + // i := z.c +LOOP: + if i < uint(len(z.b)) { + token = z.b[i] + i++ + if accept.isset(token) { + goto LOOP + } + // z.a -= (i - z.c) + z.c = i + return + } + // END: + panic(io.EOF) + // // z.a = 0 + // z.c = blen + // return +} + +func (z *bytesDecReader) readTo(_ []byte, accept *bitset256) (out []byte) { + return z.readToNoInput(accept) +} + +func (z *bytesDecReader) readToNoInput(accept *bitset256) (out []byte) { + i := z.c + if i == uint(len(z.b)) { + panic(io.EOF) + } + + // Replace loop with goto construct, so that this can be inlined + // for i := z.c; i < blen; i++ { + // if !accept.isset(z.b[i]) { + // out = z.b[z.c:i] + // z.a -= (i - z.c) + // z.c = i + // return + // } + // } + // out = z.b[z.c:] + // z.a, z.c = 0, blen + // return + + // i := z.c + // LOOP: + // if i < blen { + // if accept.isset(z.b[i]) { + // i++ + // goto LOOP + // } + // out = z.b[z.c:i] + // z.a -= (i - z.c) + // z.c = i + // return + // } + // out = z.b[z.c:] + // // z.a, z.c = 0, blen + // z.a = 0 + // z.c = blen + // return + + // c := i +LOOP: + if i < uint(len(z.b)) { + if accept.isset(z.b[i]) { + i++ + goto LOOP + } + } + + out = z.b[z.c:i] + // z.a -= (i - z.c) + z.c = i + return // z.b[c:i] + // z.c, i = i, z.c + // return z.b[i:z.c] +} + +func (z *bytesDecReader) readUntil(_ []byte, stop byte) (out []byte) { + return z.readUntilNoInput(stop) +} + +func (z *bytesDecReader) readUntilNoInput(stop byte) (out []byte) { + i := z.c + // if i == len(z.b) { + // panic(io.EOF) + // } + + // Replace loop with goto construct, so that this can be inlined + // for i := z.c; i < blen; i++ { + // if z.b[i] == stop { + // i++ + // out = z.b[z.c:i] + // z.a -= (i - z.c) + // z.c = i + // return + // } + // } +LOOP: + if i < uint(len(z.b)) { + if z.b[i] == stop { + i++ + out = z.b[z.c:i] + // z.a -= (i - z.c) + z.c = i + return + } + i++ + goto LOOP + } + // z.a = 0 + // z.c = blen + panic(io.EOF) +} + +func (z *bytesDecReader) track() { + z.t = z.c +} + +func (z *bytesDecReader) stopTrack() (bs []byte) { + return z.b[z.t:z.c] +} + +// ---------------------------------------- + +// func (d *Decoder) builtin(f *codecFnInfo, rv reflect.Value) { +// d.d.DecodeBuiltin(f.ti.rtid, rv2i(rv)) +// } + +func (d *Decoder) rawExt(f *codecFnInfo, rv reflect.Value) { + d.d.DecodeExt(rv2i(rv), 0, nil) +} + +func (d *Decoder) ext(f *codecFnInfo, rv reflect.Value) { + d.d.DecodeExt(rv2i(rv), f.xfTag, f.xfFn) +} + +func (d *Decoder) selferUnmarshal(f *codecFnInfo, rv reflect.Value) { + rv2i(rv).(Selfer).CodecDecodeSelf(d) +} + +func (d *Decoder) binaryUnmarshal(f *codecFnInfo, rv reflect.Value) { + bm := rv2i(rv).(encoding.BinaryUnmarshaler) + xbs := d.d.DecodeBytes(nil, true) + if fnerr := bm.UnmarshalBinary(xbs); fnerr != nil { + panic(fnerr) + } +} + +func (d *Decoder) textUnmarshal(f *codecFnInfo, rv reflect.Value) { + tm := rv2i(rv).(encoding.TextUnmarshaler) + fnerr := tm.UnmarshalText(d.d.DecodeStringAsBytes()) + if fnerr != nil { + panic(fnerr) + } +} + +func (d *Decoder) jsonUnmarshal(f *codecFnInfo, rv reflect.Value) { + tm := rv2i(rv).(jsonUnmarshaler) + // bs := d.d.DecodeBytes(d.b[:], true, true) + // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. + fnerr := tm.UnmarshalJSON(d.nextValueBytes()) + if fnerr != nil { + panic(fnerr) + } +} + +func (d *Decoder) kErr(f *codecFnInfo, rv reflect.Value) { + d.errorf("no decoding function defined for kind %v", rv.Kind()) +} + +// var kIntfCtr uint64 + +func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) { + // nil interface: + // use some hieristics to decode it appropriately + // based on the detected next value in the stream. + n := d.naked() + d.d.DecodeNaked() + if n.v == valueTypeNil { + return + } + // We cannot decode non-nil stream value into nil interface with methods (e.g. io.Reader). + if f.ti.numMeth > 0 { + d.errorf("cannot decode non-nil codec value into nil %v (%v methods)", f.ti.rt, f.ti.numMeth) + return + } + // var useRvn bool + switch n.v { + case valueTypeMap: + // if json, default to a map type with string keys + mtid := d.mtid + if mtid == 0 { + if d.jsms { + mtid = mapStrIntfTypId + } else { + mtid = mapIntfIntfTypId + } + } + if mtid == mapIntfIntfTypId { + var v2 map[interface{}]interface{} + d.decode(&v2) + rvn = reflect.ValueOf(&v2).Elem() + } else if mtid == mapStrIntfTypId { // for json performance + var v2 map[string]interface{} + d.decode(&v2) + rvn = reflect.ValueOf(&v2).Elem() + } else { + if d.mtr { + rvn = reflect.New(d.h.MapType) + d.decode(rv2i(rvn)) + rvn = rvn.Elem() + } else { + rvn = reflect.New(d.h.MapType).Elem() + d.decodeValue(rvn, nil, true) + } + } + case valueTypeArray: + if d.stid == 0 || d.stid == intfSliceTypId { + var v2 []interface{} + d.decode(&v2) + rvn = reflect.ValueOf(&v2).Elem() + if d.stid == 0 && d.h.PreferArrayOverSlice { + rvn2 := reflect.New(reflect.ArrayOf(rvn.Len(), intfTyp)).Elem() + reflect.Copy(rvn2, rvn) + rvn = rvn2 + } + } else { + if d.str { + rvn = reflect.New(d.h.SliceType) + d.decode(rv2i(rvn)) + rvn = rvn.Elem() + } else { + rvn = reflect.New(d.h.SliceType).Elem() + d.decodeValue(rvn, nil, true) + } + } + case valueTypeExt: + var v interface{} + tag, bytes := n.u, n.l // calling decode below might taint the values + if bytes == nil { + d.decode(&v) + } + bfn := d.h.getExtForTag(tag) + if bfn == nil { + var re RawExt + re.Tag = tag + re.Data = detachZeroCopyBytes(d.bytes, nil, bytes) + re.Value = v + rvn = reflect.ValueOf(&re).Elem() + } else { + rvnA := reflect.New(bfn.rt) + if bytes != nil { + bfn.ext.ReadExt(rv2i(rvnA), bytes) + } else { + bfn.ext.UpdateExt(rv2i(rvnA), v) + } + rvn = rvnA.Elem() + } + case valueTypeNil: + // no-op + case valueTypeInt: + rvn = n.ri() + case valueTypeUint: + rvn = n.ru() + case valueTypeFloat: + rvn = n.rf() + case valueTypeBool: + rvn = n.rb() + case valueTypeString, valueTypeSymbol: + rvn = n.rs() + case valueTypeBytes: + rvn = n.rl() + case valueTypeTime: + rvn = n.rt() + default: + panicv.errorf("kInterfaceNaked: unexpected valueType: %d", n.v) + } + return +} + +func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) { + // Note: + // A consequence of how kInterface works, is that + // if an interface already contains something, we try + // to decode into what was there before. + // We do not replace with a generic value (as got from decodeNaked). + + // every interface passed here MUST be settable. + var rvn reflect.Value + if rv.IsNil() || d.h.InterfaceReset { + // check if mapping to a type: if so, initialize it and move on + rvn = d.h.intf2impl(f.ti.rtid) + if rvn.IsValid() { + rv.Set(rvn) + } else { + rvn = d.kInterfaceNaked(f) + if rvn.IsValid() { + rv.Set(rvn) + } else if d.h.InterfaceReset { + // reset to zero value based on current type in there. + rv.Set(reflect.Zero(rv.Elem().Type())) + } + return + } + } else { + // now we have a non-nil interface value, meaning it contains a type + rvn = rv.Elem() + } + if d.d.TryDecodeAsNil() { + rv.Set(reflect.Zero(rvn.Type())) + return + } + + // Note: interface{} is settable, but underlying type may not be. + // Consequently, we MAY have to create a decodable value out of the underlying value, + // decode into it, and reset the interface itself. + // fmt.Printf(">>>> kInterface: rvn type: %v, rv type: %v\n", rvn.Type(), rv.Type()) + + rvn2, canDecode := isDecodeable(rvn) + if canDecode { + d.decodeValue(rvn2, nil, true) + return + } + + rvn2 = reflect.New(rvn.Type()).Elem() + rvn2.Set(rvn) + d.decodeValue(rvn2, nil, true) + rv.Set(rvn2) +} + +func decStructFieldKey(dd decDriver, keyType valueType, b *[decScratchByteArrayLen]byte) (rvkencname []byte) { + // use if-else-if, not switch (which compiles to binary-search) + // since keyType is typically valueTypeString, branch prediction is pretty good. + + if keyType == valueTypeString { + rvkencname = dd.DecodeStringAsBytes() + } else if keyType == valueTypeInt { + rvkencname = strconv.AppendInt(b[:0], dd.DecodeInt64(), 10) + } else if keyType == valueTypeUint { + rvkencname = strconv.AppendUint(b[:0], dd.DecodeUint64(), 10) + } else if keyType == valueTypeFloat { + rvkencname = strconv.AppendFloat(b[:0], dd.DecodeFloat64(), 'f', -1, 64) + } else { + rvkencname = dd.DecodeStringAsBytes() + } + return rvkencname +} + +func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) { + fti := f.ti + dd := d.d + elemsep := d.esep + sfn := structFieldNode{v: rv, update: true} + ctyp := dd.ContainerType() + var mf MissingFielder + if fti.mf { + mf = rv2i(rv).(MissingFielder) + } else if fti.mfp { + mf = rv2i(rv.Addr()).(MissingFielder) + } + if ctyp == valueTypeMap { + containerLen := dd.ReadMapStart() + if containerLen == 0 { + dd.ReadMapEnd() + return + } + d.depthIncr() + tisfi := fti.sfiSort + hasLen := containerLen >= 0 + + var rvkencname []byte + for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { + if elemsep { + dd.ReadMapElemKey() + } + rvkencname = decStructFieldKey(dd, fti.keyType, &d.b) + if elemsep { + dd.ReadMapElemValue() + } + if k := fti.indexForEncName(rvkencname); k > -1 { + si := tisfi[k] + if dd.TryDecodeAsNil() { + si.setToZeroValue(rv) + } else { + d.decodeValue(sfn.field(si), nil, true) + } + } else if mf != nil { + // store rvkencname in new []byte, as it previously shares Decoder.b, which is used in decode + name2 := rvkencname + rvkencname = make([]byte, len(rvkencname)) + copy(rvkencname, name2) + + var f interface{} + // xdebugf("kStruct: mf != nil: before decode: rvkencname: %s", rvkencname) + d.decode(&f) + // xdebugf("kStruct: mf != nil: after decode: rvkencname: %s", rvkencname) + if !mf.CodecMissingField(rvkencname, f) && d.h.ErrorIfNoField { + d.errorf("no matching struct field found when decoding stream map with key: %s ", + stringView(rvkencname)) + } + } else { + d.structFieldNotFound(-1, stringView(rvkencname)) + } + // keepAlive4StringView(rvkencnameB) // not needed, as reference is outside loop + } + dd.ReadMapEnd() + d.depthDecr() + } else if ctyp == valueTypeArray { + containerLen := dd.ReadArrayStart() + if containerLen == 0 { + dd.ReadArrayEnd() + return + } + d.depthIncr() + // Not much gain from doing it two ways for array. + // Arrays are not used as much for structs. + hasLen := containerLen >= 0 + var checkbreak bool + for j, si := range fti.sfiSrc { + if hasLen && j == containerLen { + break + } + if !hasLen && dd.CheckBreak() { + checkbreak = true + break + } + if elemsep { + dd.ReadArrayElem() + } + if dd.TryDecodeAsNil() { + si.setToZeroValue(rv) + } else { + d.decodeValue(sfn.field(si), nil, true) + } + } + if (hasLen && containerLen > len(fti.sfiSrc)) || (!hasLen && !checkbreak) { + // read remaining values and throw away + for j := len(fti.sfiSrc); ; j++ { + if (hasLen && j == containerLen) || (!hasLen && dd.CheckBreak()) { + break + } + if elemsep { + dd.ReadArrayElem() + } + d.structFieldNotFound(j, "") + } + } + dd.ReadArrayEnd() + d.depthDecr() + } else { + d.errorstr(errstrOnlyMapOrArrayCanDecodeIntoStruct) + return + } +} + +func (d *Decoder) kSlice(f *codecFnInfo, rv reflect.Value) { + // A slice can be set from a map or array in stream. + // This way, the order can be kept (as order is lost with map). + ti := f.ti + if f.seq == seqTypeChan && ti.chandir&uint8(reflect.SendDir) == 0 { + d.errorf("receive-only channel cannot be decoded") + } + dd := d.d + rtelem0 := ti.elem + ctyp := dd.ContainerType() + if ctyp == valueTypeBytes || ctyp == valueTypeString { + // you can only decode bytes or string in the stream into a slice or array of bytes + if !(ti.rtid == uint8SliceTypId || rtelem0.Kind() == reflect.Uint8) { + d.errorf("bytes/string in stream must decode into slice/array of bytes, not %v", ti.rt) + } + if f.seq == seqTypeChan { + bs2 := dd.DecodeBytes(nil, true) + irv := rv2i(rv) + ch, ok := irv.(chan<- byte) + if !ok { + ch = irv.(chan byte) + } + for _, b := range bs2 { + ch <- b + } + } else { + rvbs := rv.Bytes() + bs2 := dd.DecodeBytes(rvbs, false) + // if rvbs == nil && bs2 != nil || rvbs != nil && bs2 == nil || len(bs2) != len(rvbs) { + if !(len(bs2) > 0 && len(bs2) == len(rvbs) && &bs2[0] == &rvbs[0]) { + if rv.CanSet() { + rv.SetBytes(bs2) + } else if len(rvbs) > 0 && len(bs2) > 0 { + copy(rvbs, bs2) + } + } + } + return + } + + // array := f.seq == seqTypeChan + + slh, containerLenS := d.decSliceHelperStart() // only expects valueType(Array|Map) + + // an array can never return a nil slice. so no need to check f.array here. + if containerLenS == 0 { + if rv.CanSet() { + if f.seq == seqTypeSlice { + if rv.IsNil() { + rv.Set(reflect.MakeSlice(ti.rt, 0, 0)) + } else { + rv.SetLen(0) + } + } else if f.seq == seqTypeChan { + if rv.IsNil() { + rv.Set(reflect.MakeChan(ti.rt, 0)) + } + } + } + slh.End() + return + } + + d.depthIncr() + + rtelem0Size := int(rtelem0.Size()) + rtElem0Kind := rtelem0.Kind() + rtelem0Mut := !isImmutableKind(rtElem0Kind) + rtelem := rtelem0 + rtelemkind := rtelem.Kind() + for rtelemkind == reflect.Ptr { + rtelem = rtelem.Elem() + rtelemkind = rtelem.Kind() + } + + var fn *codecFn + + var rvCanset = rv.CanSet() + var rvChanged bool + var rv0 = rv + var rv9 reflect.Value + + rvlen := rv.Len() + rvcap := rv.Cap() + hasLen := containerLenS > 0 + if hasLen && f.seq == seqTypeSlice { + if containerLenS > rvcap { + oldRvlenGtZero := rvlen > 0 + rvlen = decInferLen(containerLenS, d.h.MaxInitLen, int(rtelem0.Size())) + if rvlen <= rvcap { + if rvCanset { + rv.SetLen(rvlen) + } + } else if rvCanset { + rv = reflect.MakeSlice(ti.rt, rvlen, rvlen) + rvcap = rvlen + rvChanged = true + } else { + d.errorf("cannot decode into non-settable slice") + } + if rvChanged && oldRvlenGtZero && !isImmutableKind(rtelem0.Kind()) { + reflect.Copy(rv, rv0) // only copy up to length NOT cap i.e. rv0.Slice(0, rvcap) + } + } else if containerLenS != rvlen { + rvlen = containerLenS + if rvCanset { + rv.SetLen(rvlen) + } + // else { + // rv = rv.Slice(0, rvlen) + // rvChanged = true + // d.errorf("cannot decode into non-settable slice") + // } + } + } + + // consider creating new element once, and just decoding into it. + var rtelem0Zero reflect.Value + var rtelem0ZeroValid bool + var decodeAsNil bool + var j int + + for ; (hasLen && j < containerLenS) || !(hasLen || dd.CheckBreak()); j++ { + if j == 0 && (f.seq == seqTypeSlice || f.seq == seqTypeChan) && rv.IsNil() { + if hasLen { + rvlen = decInferLen(containerLenS, d.h.MaxInitLen, rtelem0Size) + } else if f.seq == seqTypeSlice { + rvlen = decDefSliceCap + } else { + rvlen = decDefChanCap + } + if rvCanset { + if f.seq == seqTypeSlice { + rv = reflect.MakeSlice(ti.rt, rvlen, rvlen) + rvChanged = true + } else { // chan + rv = reflect.MakeChan(ti.rt, rvlen) + rvChanged = true + } + } else { + d.errorf("cannot decode into non-settable slice") + } + } + slh.ElemContainerState(j) + decodeAsNil = dd.TryDecodeAsNil() + if f.seq == seqTypeChan { + if decodeAsNil { + rv.Send(reflect.Zero(rtelem0)) + continue + } + if rtelem0Mut || !rv9.IsValid() { // || (rtElem0Kind == reflect.Ptr && rv9.IsNil()) { + rv9 = reflect.New(rtelem0).Elem() + } + if fn == nil { + fn = d.h.fn(rtelem, true, true) + } + d.decodeValue(rv9, fn, true) + rv.Send(rv9) + } else { + // if indefinite, etc, then expand the slice if necessary + var decodeIntoBlank bool + if j >= rvlen { + if f.seq == seqTypeArray { + d.arrayCannotExpand(rvlen, j+1) + decodeIntoBlank = true + } else { // if f.seq == seqTypeSlice + // rv = reflect.Append(rv, reflect.Zero(rtelem0)) // append logic + varargs + var rvcap2 int + var rvErrmsg2 string + rv9, rvcap2, rvChanged, rvErrmsg2 = + expandSliceRV(rv, ti.rt, rvCanset, rtelem0Size, 1, rvlen, rvcap) + if rvErrmsg2 != "" { + d.errorf(rvErrmsg2) + } + rvlen++ + if rvChanged { + rv = rv9 + rvcap = rvcap2 + } + } + } + if decodeIntoBlank { + if !decodeAsNil { + d.swallow() + } + } else { + rv9 = rv.Index(j) + if d.h.SliceElementReset || decodeAsNil { + if !rtelem0ZeroValid { + rtelem0ZeroValid = true + rtelem0Zero = reflect.Zero(rtelem0) + } + rv9.Set(rtelem0Zero) + if decodeAsNil { + continue + } + } + + if fn == nil { + fn = d.h.fn(rtelem, true, true) + } + d.decodeValue(rv9, fn, true) + } + } + } + if f.seq == seqTypeSlice { + if j < rvlen { + if rv.CanSet() { + rv.SetLen(j) + } else if rvCanset { + rv = rv.Slice(0, j) + rvChanged = true + } // else { d.errorf("kSlice: cannot change non-settable slice") } + rvlen = j + } else if j == 0 && rv.IsNil() { + if rvCanset { + rv = reflect.MakeSlice(ti.rt, 0, 0) + rvChanged = true + } // else { d.errorf("kSlice: cannot change non-settable slice") } + } + } + slh.End() + + if rvChanged { // infers rvCanset=true, so it can be reset + rv0.Set(rv) + } + + d.depthDecr() +} + +// func (d *Decoder) kArray(f *codecFnInfo, rv reflect.Value) { +// // d.decodeValueFn(rv.Slice(0, rv.Len())) +// f.kSlice(rv.Slice(0, rv.Len())) +// } + +func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) { + dd := d.d + containerLen := dd.ReadMapStart() + elemsep := d.esep + ti := f.ti + if rv.IsNil() { + rvlen := decInferLen(containerLen, d.h.MaxInitLen, int(ti.key.Size()+ti.elem.Size())) + rv.Set(makeMapReflect(ti.rt, rvlen)) + } + + if containerLen == 0 { + dd.ReadMapEnd() + return + } + + d.depthIncr() + + ktype, vtype := ti.key, ti.elem + ktypeId := rt2id(ktype) + vtypeKind := vtype.Kind() + + var keyFn, valFn *codecFn + var ktypeLo, vtypeLo reflect.Type + + for ktypeLo = ktype; ktypeLo.Kind() == reflect.Ptr; ktypeLo = ktypeLo.Elem() { + } + + for vtypeLo = vtype; vtypeLo.Kind() == reflect.Ptr; vtypeLo = vtypeLo.Elem() { + } + + var mapGet, mapSet bool + rvvImmut := isImmutableKind(vtypeKind) + if !d.h.MapValueReset { + // if pointer, mapGet = true + // if interface, mapGet = true if !DecodeNakedAlways (else false) + // if builtin, mapGet = false + // else mapGet = true + if vtypeKind == reflect.Ptr { + mapGet = true + } else if vtypeKind == reflect.Interface { + if !d.h.InterfaceReset { + mapGet = true + } + } else if !rvvImmut { + mapGet = true + } + } + + var rvk, rvkp, rvv, rvz reflect.Value + rvkMut := !isImmutableKind(ktype.Kind()) // if ktype is immutable, then re-use the same rvk. + ktypeIsString := ktypeId == stringTypId + ktypeIsIntf := ktypeId == intfTypId + hasLen := containerLen > 0 + var kstrbs []byte + + for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { + if rvkMut || !rvkp.IsValid() { + rvkp = reflect.New(ktype) + rvk = rvkp.Elem() + } + if elemsep { + dd.ReadMapElemKey() + } + // if false && dd.TryDecodeAsNil() { // nil cannot be a map key, so disregard this block + // // Previously, if a nil key, we just ignored the mapped value and continued. + // // However, that makes the result of encoding and then decoding map[intf]intf{nil:nil} + // // to be an empty map. + // // Instead, we treat a nil key as the zero value of the type. + // rvk.Set(reflect.Zero(ktype)) + // } else if ktypeIsString { + if ktypeIsString { + kstrbs = dd.DecodeStringAsBytes() + rvk.SetString(stringView(kstrbs)) + // NOTE: if doing an insert, you MUST use a real string (not stringview) + } else { + if keyFn == nil { + keyFn = d.h.fn(ktypeLo, true, true) + } + d.decodeValue(rvk, keyFn, true) + } + // special case if a byte array. + if ktypeIsIntf { + if rvk2 := rvk.Elem(); rvk2.IsValid() { + if rvk2.Type() == uint8SliceTyp { + rvk = reflect.ValueOf(d.string(rvk2.Bytes())) + } else { + rvk = rvk2 + } + } + } + + if elemsep { + dd.ReadMapElemValue() + } + + // Brittle, but OK per TryDecodeAsNil() contract. + // i.e. TryDecodeAsNil never shares slices with other decDriver procedures + if dd.TryDecodeAsNil() { + if ktypeIsString { + rvk.SetString(d.string(kstrbs)) + } + if d.h.DeleteOnNilMapValue { + rv.SetMapIndex(rvk, reflect.Value{}) + } else { + rv.SetMapIndex(rvk, reflect.Zero(vtype)) + } + continue + } + + mapSet = true // set to false if u do a get, and its a non-nil pointer + if mapGet { + // mapGet true only in case where kind=Ptr|Interface or kind is otherwise mutable. + rvv = rv.MapIndex(rvk) + if !rvv.IsValid() { + rvv = reflect.New(vtype).Elem() + } else if vtypeKind == reflect.Ptr { + if rvv.IsNil() { + rvv = reflect.New(vtype).Elem() + } else { + mapSet = false + } + } else if vtypeKind == reflect.Interface { + // not addressable, and thus not settable. + // e MUST create a settable/addressable variant + rvv2 := reflect.New(rvv.Type()).Elem() + if !rvv.IsNil() { + rvv2.Set(rvv) + } + rvv = rvv2 + } + // else it is ~mutable, and we can just decode into it directly + } else if rvvImmut { + if !rvz.IsValid() { + rvz = reflect.New(vtype).Elem() + } + rvv = rvz + } else { + rvv = reflect.New(vtype).Elem() + } + + // We MUST be done with the stringview of the key, before decoding the value + // so that we don't bastardize the reused byte array. + if mapSet && ktypeIsString { + rvk.SetString(d.string(kstrbs)) + } + if valFn == nil { + valFn = d.h.fn(vtypeLo, true, true) + } + d.decodeValue(rvv, valFn, true) + // d.decodeValueFn(rvv, valFn) + if mapSet { + rv.SetMapIndex(rvk, rvv) + } + // if ktypeIsString { + // // keepAlive4StringView(kstrbs) // not needed, as reference is outside loop + // } + } + + dd.ReadMapEnd() + + d.depthDecr() +} + +// decNaked is used to keep track of the primitives decoded. +// Without it, we would have to decode each primitive and wrap it +// in an interface{}, causing an allocation. +// In this model, the primitives are decoded in a "pseudo-atomic" fashion, +// so we can rest assured that no other decoding happens while these +// primitives are being decoded. +// +// maps and arrays are not handled by this mechanism. +// However, RawExt is, and we accommodate for extensions that decode +// RawExt from DecodeNaked, but need to decode the value subsequently. +// kInterfaceNaked and swallow, which call DecodeNaked, handle this caveat. +// +// However, decNaked also keeps some arrays of default maps and slices +// used in DecodeNaked. This way, we can get a pointer to it +// without causing a new heap allocation. +// +// kInterfaceNaked will ensure that there is no allocation for the common +// uses. + +type decNaked struct { + // r RawExt // used for RawExt, uint, []byte. + + // primitives below + u uint64 + i int64 + f float64 + l []byte + s string + + // ---- cpu cache line boundary? + t time.Time + b bool + + // state + v valueType + _ [6]bool // padding + + // ru, ri, rf, rl, rs, rb, rt reflect.Value // mapping to the primitives above + // + // _ [3]uint64 // padding +} + +// func (n *decNaked) init() { +// n.ru = reflect.ValueOf(&n.u).Elem() +// n.ri = reflect.ValueOf(&n.i).Elem() +// n.rf = reflect.ValueOf(&n.f).Elem() +// n.rl = reflect.ValueOf(&n.l).Elem() +// n.rs = reflect.ValueOf(&n.s).Elem() +// n.rt = reflect.ValueOf(&n.t).Elem() +// n.rb = reflect.ValueOf(&n.b).Elem() +// // n.rr[] = reflect.ValueOf(&n.) +// } + +// type decNakedPooler struct { +// n *decNaked +// nsp *sync.Pool +// } + +// // naked must be called before each call to .DecodeNaked, as they will use it. +// func (d *decNakedPooler) naked() *decNaked { +// if d.n == nil { +// // consider one of: +// // - get from sync.Pool (if GC is frequent, there's no value here) +// // - new alloc (safest. only init'ed if it a naked decode will be done) +// // - field in Decoder (makes the Decoder struct very big) +// // To support using a decoder where a DecodeNaked is not needed, +// // we prefer #1 or #2. +// // d.n = new(decNaked) // &d.nv // new(decNaked) // grab from a sync.Pool +// // d.n.init() +// var v interface{} +// d.nsp, v = pool.decNaked() +// d.n = v.(*decNaked) +// } +// return d.n +// } + +// func (d *decNakedPooler) end() { +// if d.n != nil { +// // if n != nil, then nsp != nil (they are always set together) +// d.nsp.Put(d.n) +// d.n, d.nsp = nil, nil +// } +// } + +// type rtid2rv struct { +// rtid uintptr +// rv reflect.Value +// } + +// -------------- + +type decReaderSwitch struct { + rb bytesDecReader + // ---- cpu cache line boundary? + ri *ioDecReader + bi *bufioDecReader + + mtr, str bool // whether maptype or slicetype are known types + + be bool // is binary encoding + js bool // is json handle + jsms bool // is json handle, and MapKeyAsString + esep bool // has elem separators + + // typ entryType + bytes bool // is bytes reader + bufio bool // is this a bufioDecReader? +} + +// numread, track and stopTrack are always inlined, as they just check int fields, etc. + +/* +func (z *decReaderSwitch) numread() int { + switch z.typ { + case entryTypeBytes: + return z.rb.numread() + case entryTypeIo: + return z.ri.numread() + default: + return z.bi.numread() + } +} +func (z *decReaderSwitch) track() { + switch z.typ { + case entryTypeBytes: + z.rb.track() + case entryTypeIo: + z.ri.track() + default: + z.bi.track() + } +} +func (z *decReaderSwitch) stopTrack() []byte { + switch z.typ { + case entryTypeBytes: + return z.rb.stopTrack() + case entryTypeIo: + return z.ri.stopTrack() + default: + return z.bi.stopTrack() + } +} + +func (z *decReaderSwitch) unreadn1() { + switch z.typ { + case entryTypeBytes: + z.rb.unreadn1() + case entryTypeIo: + z.ri.unreadn1() + default: + z.bi.unreadn1() + } +} +func (z *decReaderSwitch) readx(n int) []byte { + switch z.typ { + case entryTypeBytes: + return z.rb.readx(n) + case entryTypeIo: + return z.ri.readx(n) + default: + return z.bi.readx(n) + } +} +func (z *decReaderSwitch) readb(s []byte) { + switch z.typ { + case entryTypeBytes: + z.rb.readb(s) + case entryTypeIo: + z.ri.readb(s) + default: + z.bi.readb(s) + } +} +func (z *decReaderSwitch) readn1() uint8 { + switch z.typ { + case entryTypeBytes: + return z.rb.readn1() + case entryTypeIo: + return z.ri.readn1() + default: + return z.bi.readn1() + } +} +func (z *decReaderSwitch) skip(accept *bitset256) (token byte) { + switch z.typ { + case entryTypeBytes: + return z.rb.skip(accept) + case entryTypeIo: + return z.ri.skip(accept) + default: + return z.bi.skip(accept) + } +} +func (z *decReaderSwitch) readTo(in []byte, accept *bitset256) (out []byte) { + switch z.typ { + case entryTypeBytes: + return z.rb.readTo(in, accept) + case entryTypeIo: + return z.ri.readTo(in, accept) + default: + return z.bi.readTo(in, accept) + } +} +func (z *decReaderSwitch) readUntil(in []byte, stop byte) (out []byte) { + switch z.typ { + case entryTypeBytes: + return z.rb.readUntil(in, stop) + case entryTypeIo: + return z.ri.readUntil(in, stop) + default: + return z.bi.readUntil(in, stop) + } +} + +*/ + +// the if/else-if/else block is expensive to inline. +// Each node of this construct costs a lot and dominates the budget. +// Best to only do an if fast-path else block (so fast-path is inlined). +// This is irrespective of inlineExtraCallCost set in $GOROOT/src/cmd/compile/internal/gc/inl.go +// +// In decReaderSwitch methods below, we delegate all IO functions into their own methods. +// This allows for the inlining of the common path when z.bytes=true. +// Go 1.12+ supports inlining methods with up to 1 inlined function (or 2 if no other constructs). + +func (z *decReaderSwitch) numread() uint { + if z.bytes { + return z.rb.numread() + } else if z.bufio { + return z.bi.numread() + } else { + return z.ri.numread() + } +} +func (z *decReaderSwitch) track() { + if z.bytes { + z.rb.track() + } else if z.bufio { + z.bi.track() + } else { + z.ri.track() + } +} +func (z *decReaderSwitch) stopTrack() []byte { + if z.bytes { + return z.rb.stopTrack() + } else if z.bufio { + return z.bi.stopTrack() + } else { + return z.ri.stopTrack() + } +} + +// func (z *decReaderSwitch) unreadn1() { +// if z.bytes { +// z.rb.unreadn1() +// } else { +// z.unreadn1IO() +// } +// } +// func (z *decReaderSwitch) unreadn1IO() { +// if z.bufio { +// z.bi.unreadn1() +// } else { +// z.ri.unreadn1() +// } +// } + +func (z *decReaderSwitch) unreadn1() { + if z.bytes { + z.rb.unreadn1() + } else if z.bufio { + z.bi.unreadn1() + } else { + z.ri.unreadn1() // not inlined + } +} + +func (z *decReaderSwitch) readx(n uint) []byte { + if z.bytes { + return z.rb.readx(n) + } + return z.readxIO(n) +} +func (z *decReaderSwitch) readxIO(n uint) []byte { + if z.bufio { + return z.bi.readx(n) + } + return z.ri.readx(n) +} + +func (z *decReaderSwitch) readb(s []byte) { + if z.bytes { + z.rb.readb(s) + } else { + z.readbIO(s) + } +} + +//go:noinline - fallback for io, ensures z.bytes path is inlined +func (z *decReaderSwitch) readbIO(s []byte) { + if z.bufio { + z.bi.readb(s) + } else { + z.ri.readb(s) + } +} + +func (z *decReaderSwitch) readn1() uint8 { + if z.bytes { + return z.rb.readn1() + } + return z.readn1IO() +} +func (z *decReaderSwitch) readn1IO() uint8 { + if z.bufio { + return z.bi.readn1() + } + return z.ri.readn1() +} + +func (z *decReaderSwitch) skip(accept *bitset256) (token byte) { + if z.bytes { + return z.rb.skip(accept) + } + return z.skipIO(accept) +} +func (z *decReaderSwitch) skipIO(accept *bitset256) (token byte) { + if z.bufio { + return z.bi.skip(accept) + } + return z.ri.skip(accept) +} + +func (z *decReaderSwitch) readTo(in []byte, accept *bitset256) (out []byte) { + if z.bytes { + return z.rb.readToNoInput(accept) // z.rb.readTo(in, accept) + } + return z.readToIO(in, accept) +} + +//go:noinline - fallback for io, ensures z.bytes path is inlined +func (z *decReaderSwitch) readToIO(in []byte, accept *bitset256) (out []byte) { + if z.bufio { + return z.bi.readTo(in, accept) + } + return z.ri.readTo(in, accept) +} +func (z *decReaderSwitch) readUntil(in []byte, stop byte) (out []byte) { + if z.bytes { + return z.rb.readUntilNoInput(stop) + } + return z.readUntilIO(in, stop) +} + +func (z *decReaderSwitch) readUntilIO(in []byte, stop byte) (out []byte) { + if z.bufio { + return z.bi.readUntil(in, stop) + } + return z.ri.readUntil(in, stop) +} + +// Decoder reads and decodes an object from an input stream in a supported format. +// +// Decoder is NOT safe for concurrent use i.e. a Decoder cannot be used +// concurrently in multiple goroutines. +// +// However, as Decoder could be allocation heavy to initialize, a Reset method is provided +// so its state can be reused to decode new input streams repeatedly. +// This is the idiomatic way to use. +type Decoder struct { + panicHdl + // hopefully, reduce derefencing cost by laying the decReader inside the Decoder. + // Try to put things that go together to fit within a cache line (8 words). + + d decDriver + + // NOTE: Decoder shouldn't call it's read methods, + // as the handler MAY need to do some coordination. + r *decReaderSwitch + + // bi *bufioDecReader + // cache the mapTypeId and sliceTypeId for faster comparisons + mtid uintptr + stid uintptr + + hh Handle + h *BasicHandle + + // ---- cpu cache line boundary? + decReaderSwitch + + // ---- cpu cache line boundary? + n decNaked + + // cr containerStateRecv + err error + + depth int16 + maxdepth int16 + + _ [4]uint8 // padding + + is map[string]string // used for interning strings + + // ---- cpu cache line boundary? + b [decScratchByteArrayLen]byte // scratch buffer, used by Decoder and xxxEncDrivers + + // padding - false sharing help // modify 232 if Decoder struct changes. + // _ [cacheLineSize - 232%cacheLineSize]byte +} + +// NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader. +// +// For efficiency, Users are encouraged to configure ReaderBufferSize on the handle +// OR pass in a memory buffered reader (eg bufio.Reader, bytes.Buffer). +func NewDecoder(r io.Reader, h Handle) *Decoder { + d := newDecoder(h) + d.Reset(r) + return d +} + +// NewDecoderBytes returns a Decoder which efficiently decodes directly +// from a byte slice with zero copying. +func NewDecoderBytes(in []byte, h Handle) *Decoder { + d := newDecoder(h) + d.ResetBytes(in) + return d +} + +// var defaultDecNaked decNaked + +func newDecoder(h Handle) *Decoder { + d := &Decoder{h: basicHandle(h), err: errDecoderNotInitialized} + d.bytes = true + if useFinalizers { + runtime.SetFinalizer(d, (*Decoder).finalize) + // xdebugf(">>>> new(Decoder) with finalizer") + } + d.r = &d.decReaderSwitch + d.hh = h + d.be = h.isBinary() + // NOTE: do not initialize d.n here. It is lazily initialized in d.naked() + var jh *JsonHandle + jh, d.js = h.(*JsonHandle) + if d.js { + d.jsms = jh.MapKeyAsString + } + d.esep = d.hh.hasElemSeparators() + if d.h.InternString { + d.is = make(map[string]string, 32) + } + d.d = h.newDecDriver(d) + // d.cr, _ = d.d.(containerStateRecv) + return d +} + +func (d *Decoder) resetCommon() { + // d.r = &d.decReaderSwitch + d.d.reset() + d.err = nil + d.depth = 0 + d.maxdepth = d.h.MaxDepth + if d.maxdepth <= 0 { + d.maxdepth = decDefMaxDepth + } + // reset all things which were cached from the Handle, but could change + d.mtid, d.stid = 0, 0 + d.mtr, d.str = false, false + if d.h.MapType != nil { + d.mtid = rt2id(d.h.MapType) + d.mtr = fastpathAV.index(d.mtid) != -1 + } + if d.h.SliceType != nil { + d.stid = rt2id(d.h.SliceType) + d.str = fastpathAV.index(d.stid) != -1 + } +} + +// Reset the Decoder with a new Reader to decode from, +// clearing all state from last run(s). +func (d *Decoder) Reset(r io.Reader) { + if r == nil { + return + } + d.bytes = false + // d.typ = entryTypeUnset + if d.h.ReaderBufferSize > 0 { + if d.bi == nil { + d.bi = new(bufioDecReader) + } + d.bi.reset(r, d.h.ReaderBufferSize) + // d.r = d.bi + // d.typ = entryTypeBufio + d.bufio = true + } else { + // d.ri.x = &d.b + // d.s = d.sa[:0] + if d.ri == nil { + d.ri = new(ioDecReader) + } + d.ri.reset(r) + // d.r = d.ri + // d.typ = entryTypeIo + d.bufio = false + } + d.resetCommon() +} + +// ResetBytes resets the Decoder with a new []byte to decode from, +// clearing all state from last run(s). +func (d *Decoder) ResetBytes(in []byte) { + if in == nil { + return + } + d.bytes = true + d.bufio = false + // d.typ = entryTypeBytes + d.rb.reset(in) + // d.r = &d.rb + d.resetCommon() +} + +func (d *Decoder) naked() *decNaked { + return &d.n +} + +// Decode decodes the stream from reader and stores the result in the +// value pointed to by v. v cannot be a nil pointer. v can also be +// a reflect.Value of a pointer. +// +// Note that a pointer to a nil interface is not a nil pointer. +// If you do not know what type of stream it is, pass in a pointer to a nil interface. +// We will decode and store a value in that nil interface. +// +// Sample usages: +// +// // Decoding into a non-nil typed value +// var f float32 +// err = codec.NewDecoder(r, handle).Decode(&f) +// +// // Decoding into nil interface +// var v interface{} +// dec := codec.NewDecoder(r, handle) +// err = dec.Decode(&v) +// +// When decoding into a nil interface{}, we will decode into an appropriate value based +// on the contents of the stream: +// - Numbers are decoded as float64, int64 or uint64. +// - Other values are decoded appropriately depending on the type: +// bool, string, []byte, time.Time, etc +// - Extensions are decoded as RawExt (if no ext function registered for the tag) +// +// Configurations exist on the Handle to override defaults +// (e.g. for MapType, SliceType and how to decode raw bytes). +// +// When decoding into a non-nil interface{} value, the mode of encoding is based on the +// type of the value. When a value is seen: +// - If an extension is registered for it, call that extension function +// - If it implements BinaryUnmarshaler, call its UnmarshalBinary(data []byte) error +// - Else decode it based on its reflect.Kind +// +// There are some special rules when decoding into containers (slice/array/map/struct). +// Decode will typically use the stream contents to UPDATE the container i.e. the values +// in these containers will not be zero'ed before decoding. +// - A map can be decoded from a stream map, by updating matching keys. +// - A slice can be decoded from a stream array, +// by updating the first n elements, where n is length of the stream. +// - A slice can be decoded from a stream map, by decoding as if +// it contains a sequence of key-value pairs. +// - A struct can be decoded from a stream map, by updating matching fields. +// - A struct can be decoded from a stream array, +// by updating fields as they occur in the struct (by index). +// +// This in-place update maintains consistency in the decoding philosophy (i.e. we ALWAYS update +// in place by default). However, the consequence of this is that values in slices or maps +// which are not zero'ed before hand, will have part of the prior values in place after decode +// if the stream doesn't contain an update for those parts. +// +// This in-place update can be disabled by configuring the MapValueReset and SliceElementReset +// decode options available on every handle. +// +// Furthermore, when decoding a stream map or array with length of 0 into a nil map or slice, +// we reset the destination map or slice to a zero-length value. +// +// However, when decoding a stream nil, we reset the destination container +// to its "zero" value (e.g. nil for slice/map, etc). +// +// Note: we allow nil values in the stream anywhere except for map keys. +// A nil value in the encoded stream where a map key is expected is treated as an error. +func (d *Decoder) Decode(v interface{}) (err error) { + // tried to use closure, as runtime optimizes defer with no params. + // This seemed to be causing weird issues (like circular reference found, unexpected panic, etc). + // Also, see https://github.com/golang/go/issues/14939#issuecomment-417836139 + // defer func() { d.deferred(&err) }() + // { x, y := d, &err; defer func() { x.deferred(y) }() } + if d.err != nil { + return d.err + } + if recoverPanicToErr { + defer func() { + if x := recover(); x != nil { + panicValToErr(d, x, &d.err) + err = d.err + } + }() + } + + // defer d.deferred(&err) + d.mustDecode(v) + return +} + +// MustDecode is like Decode, but panics if unable to Decode. +// This provides insight to the code location that triggered the error. +func (d *Decoder) MustDecode(v interface{}) { + if d.err != nil { + panic(d.err) + } + d.mustDecode(v) +} + +// MustDecode is like Decode, but panics if unable to Decode. +// This provides insight to the code location that triggered the error. +func (d *Decoder) mustDecode(v interface{}) { + // TODO: Top-level: ensure that v is a pointer and not nil. + if d.d.TryDecodeAsNil() { + setZero(v) + return + } + if d.bi == nil { + d.decode(v) + return + } + + d.bi.calls++ + d.decode(v) + // xprintf.(">>>>>>>> >>>>>>>> num decFns: %v\n", d.cf.sn) + d.bi.calls-- + if !d.h.ExplicitRelease && d.bi.calls == 0 { + d.bi.release() + } +} + +// func (d *Decoder) deferred(err1 *error) { +// if recoverPanicToErr { +// if x := recover(); x != nil { +// panicValToErr(d, x, err1) +// panicValToErr(d, x, &d.err) +// } +// } +// } + +//go:noinline -- as it is run by finalizer +func (d *Decoder) finalize() { + // xdebugf("finalizing Decoder") + d.Release() +} + +// Release releases shared (pooled) resources. +// +// It is important to call Release() when done with a Decoder, so those resources +// are released instantly for use by subsequently created Decoders. +// +// By default, Release() is automatically called unless the option ExplicitRelease is set. +func (d *Decoder) Release() { + if d.bi != nil { + d.bi.release() + } + // d.decNakedPooler.end() +} + +// // this is not a smart swallow, as it allocates objects and does unnecessary work. +// func (d *Decoder) swallowViaHammer() { +// var blank interface{} +// d.decodeValueNoFn(reflect.ValueOf(&blank).Elem()) +// } + +func (d *Decoder) swallow() { + // smarter decode that just swallows the content + dd := d.d + if dd.TryDecodeAsNil() { + return + } + elemsep := d.esep + switch dd.ContainerType() { + case valueTypeMap: + containerLen := dd.ReadMapStart() + d.depthIncr() + hasLen := containerLen >= 0 + for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { + // if clenGtEqualZero {if j >= containerLen {break} } else if dd.CheckBreak() {break} + if elemsep { + dd.ReadMapElemKey() + } + d.swallow() + if elemsep { + dd.ReadMapElemValue() + } + d.swallow() + } + dd.ReadMapEnd() + d.depthDecr() + case valueTypeArray: + containerLen := dd.ReadArrayStart() + d.depthIncr() + hasLen := containerLen >= 0 + for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ { + if elemsep { + dd.ReadArrayElem() + } + d.swallow() + } + dd.ReadArrayEnd() + d.depthDecr() + case valueTypeBytes: + dd.DecodeBytes(d.b[:], true) + case valueTypeString: + dd.DecodeStringAsBytes() + default: + // these are all primitives, which we can get from decodeNaked + // if RawExt using Value, complete the processing. + n := d.naked() + dd.DecodeNaked() + if n.v == valueTypeExt && n.l == nil { + var v2 interface{} + d.decode(&v2) + } + } +} + +func setZero(iv interface{}) { + if iv == nil || definitelyNil(iv) { + return + } + var canDecode bool + switch v := iv.(type) { + case *string: + *v = "" + case *bool: + *v = false + case *int: + *v = 0 + case *int8: + *v = 0 + case *int16: + *v = 0 + case *int32: + *v = 0 + case *int64: + *v = 0 + case *uint: + *v = 0 + case *uint8: + *v = 0 + case *uint16: + *v = 0 + case *uint32: + *v = 0 + case *uint64: + *v = 0 + case *float32: + *v = 0 + case *float64: + *v = 0 + case *[]uint8: + *v = nil + case *Raw: + *v = nil + case *time.Time: + *v = time.Time{} + case reflect.Value: + if v, canDecode = isDecodeable(v); canDecode && v.CanSet() { + v.Set(reflect.Zero(v.Type())) + } // TODO: else drain if chan, clear if map, set all to nil if slice??? + default: + if !fastpathDecodeSetZeroTypeSwitch(iv) { + v := reflect.ValueOf(iv) + if v, canDecode = isDecodeable(v); canDecode && v.CanSet() { + v.Set(reflect.Zero(v.Type())) + } // TODO: else drain if chan, clear if map, set all to nil if slice??? + } + } +} + +func (d *Decoder) decode(iv interface{}) { + // a switch with only concrete types can be optimized. + // consequently, we deal with nil and interfaces outside the switch. + + if iv == nil { + d.errorstr(errstrCannotDecodeIntoNil) + return + } + + switch v := iv.(type) { + // case nil: + // case Selfer: + case reflect.Value: + v = d.ensureDecodeable(v) + d.decodeValue(v, nil, true) + + case *string: + *v = d.d.DecodeString() + case *bool: + *v = d.d.DecodeBool() + case *int: + *v = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) + case *int8: + *v = int8(chkOvf.IntV(d.d.DecodeInt64(), 8)) + case *int16: + *v = int16(chkOvf.IntV(d.d.DecodeInt64(), 16)) + case *int32: + *v = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) + case *int64: + *v = d.d.DecodeInt64() + case *uint: + *v = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) + case *uint8: + *v = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) + case *uint16: + *v = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16)) + case *uint32: + *v = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32)) + case *uint64: + *v = d.d.DecodeUint64() + case *float32: + f64 := d.d.DecodeFloat64() + if chkOvf.Float32(f64) { + d.errorf("float32 overflow: %v", f64) + } + *v = float32(f64) + case *float64: + *v = d.d.DecodeFloat64() + case *[]uint8: + *v = d.d.DecodeBytes(*v, false) + case []uint8: + b := d.d.DecodeBytes(v, false) + if !(len(b) > 0 && len(b) == len(v) && &b[0] == &v[0]) { + copy(v, b) + } + case *time.Time: + *v = d.d.DecodeTime() + case *Raw: + *v = d.rawBytes() + + case *interface{}: + d.decodeValue(reflect.ValueOf(iv).Elem(), nil, true) + // d.decodeValueNotNil(reflect.ValueOf(iv).Elem()) + + default: + if v, ok := iv.(Selfer); ok { + v.CodecDecodeSelf(d) + } else if !fastpathDecodeTypeSwitch(iv, d) { + v := reflect.ValueOf(iv) + v = d.ensureDecodeable(v) + d.decodeValue(v, nil, false) + // d.decodeValueFallback(v) + } + } +} + +func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn, chkAll bool) { + // If stream is not containing a nil value, then we can deref to the base + // non-pointer value, and decode into that. + var rvp reflect.Value + var rvpValid bool + if rv.Kind() == reflect.Ptr { + rvpValid = true + for { + if rv.IsNil() { + rv.Set(reflect.New(rv.Type().Elem())) + } + rvp = rv + rv = rv.Elem() + if rv.Kind() != reflect.Ptr { + break + } + } + } + + if fn == nil { + // always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer + fn = d.h.fn(rv.Type(), chkAll, true) // chkAll, chkAll) + } + if fn.i.addrD { + if rvpValid { + fn.fd(d, &fn.i, rvp) + } else if rv.CanAddr() { + fn.fd(d, &fn.i, rv.Addr()) + } else if !fn.i.addrF { + fn.fd(d, &fn.i, rv) + } else { + d.errorf("cannot decode into a non-pointer value") + } + } else { + fn.fd(d, &fn.i, rv) + } + // return rv +} + +func (d *Decoder) structFieldNotFound(index int, rvkencname string) { + // NOTE: rvkencname may be a stringView, so don't pass it to another function. + if d.h.ErrorIfNoField { + if index >= 0 { + d.errorf("no matching struct field found when decoding stream array at index %v", index) + return + } else if rvkencname != "" { + d.errorf("no matching struct field found when decoding stream map with key " + rvkencname) + return + } + } + d.swallow() +} + +func (d *Decoder) arrayCannotExpand(sliceLen, streamLen int) { + if d.h.ErrorIfNoArrayExpand { + d.errorf("cannot expand array len during decode from %v to %v", sliceLen, streamLen) + } +} + +func isDecodeable(rv reflect.Value) (rv2 reflect.Value, canDecode bool) { + switch rv.Kind() { + case reflect.Array: + return rv, rv.CanAddr() + case reflect.Ptr: + if !rv.IsNil() { + return rv.Elem(), true + } + case reflect.Slice, reflect.Chan, reflect.Map: + if !rv.IsNil() { + return rv, true + } + } + return +} + +func (d *Decoder) ensureDecodeable(rv reflect.Value) (rv2 reflect.Value) { + // decode can take any reflect.Value that is a inherently addressable i.e. + // - array + // - non-nil chan (we will SEND to it) + // - non-nil slice (we will set its elements) + // - non-nil map (we will put into it) + // - non-nil pointer (we can "update" it) + rv2, canDecode := isDecodeable(rv) + if canDecode { + return + } + if !rv.IsValid() { + d.errorstr(errstrCannotDecodeIntoNil) + return + } + if !rv.CanInterface() { + d.errorf("cannot decode into a value without an interface: %v", rv) + return + } + rvi := rv2i(rv) + rvk := rv.Kind() + d.errorf("cannot decode into value of kind: %v, type: %T, %v", rvk, rvi, rvi) + return +} + +func (d *Decoder) depthIncr() { + d.depth++ + if d.depth >= d.maxdepth { + panic(errMaxDepthExceeded) + } +} + +func (d *Decoder) depthDecr() { + d.depth-- +} + +// Possibly get an interned version of a string +// +// This should mostly be used for map keys, where the key type is string. +// This is because keys of a map/struct are typically reused across many objects. +func (d *Decoder) string(v []byte) (s string) { + if d.is == nil { + return string(v) // don't return stringView, as we need a real string here. + } + s, ok := d.is[string(v)] // no allocation here, per go implementation + if !ok { + s = string(v) // new allocation here + d.is[s] = s + } + return s +} + +// nextValueBytes returns the next value in the stream as a set of bytes. +func (d *Decoder) nextValueBytes() (bs []byte) { + d.d.uncacheRead() + d.r.track() + d.swallow() + bs = d.r.stopTrack() + return +} + +func (d *Decoder) rawBytes() []byte { + // ensure that this is not a view into the bytes + // i.e. make new copy always. + bs := d.nextValueBytes() + bs2 := make([]byte, len(bs)) + copy(bs2, bs) + return bs2 +} + +func (d *Decoder) wrapErr(v interface{}, err *error) { + *err = decodeError{codecError: codecError{name: d.hh.Name(), err: v}, pos: int(d.r.numread())} +} + +// NumBytesRead returns the number of bytes read +func (d *Decoder) NumBytesRead() int { + return int(d.r.numread()) +} + +// -------------------------------------------------- + +// decSliceHelper assists when decoding into a slice, from a map or an array in the stream. +// A slice can be set from a map or array in stream. This supports the MapBySlice interface. +type decSliceHelper struct { + d *Decoder + // ct valueType + array bool +} + +func (d *Decoder) decSliceHelperStart() (x decSliceHelper, clen int) { + dd := d.d + ctyp := dd.ContainerType() + switch ctyp { + case valueTypeArray: + x.array = true + clen = dd.ReadArrayStart() + case valueTypeMap: + clen = dd.ReadMapStart() * 2 + default: + d.errorf("only encoded map or array can be decoded into a slice (%d)", ctyp) + } + // x.ct = ctyp + x.d = d + return +} + +func (x decSliceHelper) End() { + if x.array { + x.d.d.ReadArrayEnd() + } else { + x.d.d.ReadMapEnd() + } +} + +func (x decSliceHelper) ElemContainerState(index int) { + if x.array { + x.d.d.ReadArrayElem() + } else if index%2 == 0 { + x.d.d.ReadMapElemKey() + } else { + x.d.d.ReadMapElemValue() + } +} + +func decByteSlice(r *decReaderSwitch, clen, maxInitLen int, bs []byte) (bsOut []byte) { + if clen == 0 { + return zeroByteSlice + } + if len(bs) == clen { + bsOut = bs + r.readb(bsOut) + } else if cap(bs) >= clen { + bsOut = bs[:clen] + r.readb(bsOut) + } else { + // bsOut = make([]byte, clen) + len2 := decInferLen(clen, maxInitLen, 1) + bsOut = make([]byte, len2) + r.readb(bsOut) + for len2 < clen { + len3 := decInferLen(clen-len2, maxInitLen, 1) + bs3 := bsOut + bsOut = make([]byte, len2+len3) + copy(bsOut, bs3) + r.readb(bsOut[len2:]) + len2 += len3 + } + } + return +} + +// func decByteSliceZeroCopy(r decReader, clen, maxInitLen int, bs []byte) (bsOut []byte) { +// if _, ok := r.(*bytesDecReader); ok && clen <= maxInitLen { +// return r.readx(clen) +// } +// return decByteSlice(r, clen, maxInitLen, bs) +// } + +func detachZeroCopyBytes(isBytesReader bool, dest []byte, in []byte) (out []byte) { + if xlen := len(in); xlen > 0 { + if isBytesReader || xlen <= scratchByteArrayLen { + if cap(dest) >= xlen { + out = dest[:xlen] + } else { + out = make([]byte, xlen) + } + copy(out, in) + return + } + } + return in +} + +// decInferLen will infer a sensible length, given the following: +// - clen: length wanted. +// - maxlen: max length to be returned. +// if <= 0, it is unset, and we infer it based on the unit size +// - unit: number of bytes for each element of the collection +func decInferLen(clen, maxlen, unit int) (rvlen int) { + // handle when maxlen is not set i.e. <= 0 + if clen <= 0 { + return + } + if unit == 0 { + return clen + } + if maxlen <= 0 { + // no maxlen defined. Use maximum of 256K memory, with a floor of 4K items. + // maxlen = 256 * 1024 / unit + // if maxlen < (4 * 1024) { + // maxlen = 4 * 1024 + // } + if unit < (256 / 4) { + maxlen = 256 * 1024 / unit + } else { + maxlen = 4 * 1024 + } + } + if clen > maxlen { + rvlen = maxlen + } else { + rvlen = clen + } + return +} + +func expandSliceRV(s reflect.Value, st reflect.Type, canChange bool, stElemSize, num, slen, scap int) ( + s2 reflect.Value, scap2 int, changed bool, err string) { + l1 := slen + num // new slice length + if l1 < slen { + err = errmsgExpandSliceOverflow + return + } + if l1 <= scap { + if s.CanSet() { + s.SetLen(l1) + } else if canChange { + s2 = s.Slice(0, l1) + scap2 = scap + changed = true + } else { + err = errmsgExpandSliceCannotChange + return + } + return + } + if !canChange { + err = errmsgExpandSliceCannotChange + return + } + scap2 = growCap(scap, stElemSize, num) + s2 = reflect.MakeSlice(st, l1, scap2) + changed = true + reflect.Copy(s2, s) + return +} + +func decReadFull(r io.Reader, bs []byte) (n uint, err error) { + var nn int + for n < uint(len(bs)) && err == nil { + nn, err = r.Read(bs[n:]) + if nn > 0 { + if err == io.EOF { + // leave EOF for next time + err = nil + } + n += uint(nn) + } + } + // xdebugf("decReadFull: len(bs): %v, n: %v, err: %v", len(bs), n, err) + // do not do this - it serves no purpose + // if n != len(bs) && err == io.EOF { err = io.ErrUnexpectedEOF } + return +} + +func decNakedReadRawBytes(dr decDriver, d *Decoder, n *decNaked, rawToString bool) { + if rawToString { + n.v = valueTypeString + n.s = string(dr.DecodeBytes(d.b[:], true)) + } else { + n.v = valueTypeBytes + n.l = dr.DecodeBytes(nil, false) + } +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/doc.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/doc.go new file mode 100644 index 00000000..325c6e1e --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/doc.go @@ -0,0 +1,239 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +/* +Package codec provides a High Performance, Feature-Rich Idiomatic +codec/encoding library for msgpack, json. + +Supported Serialization formats are: + + - msgpack: https://github.com/msgpack/msgpack + - json: http://json.org http://tools.ietf.org/html/rfc7159 + +For detailed usage information, read the primer at +http://ugorji.net/blog/go-codec-primer . + +The idiomatic Go support is as seen in other encoding packages in the +standard library (ie json, xml, gob, etc). + +Rich Feature Set includes: + + - Simple but extremely powerful and feature-rich API + - Excellent code coverage ( > 90% ) + - Very High Performance. + Our extensive benchmarks show us outperforming Gob, Json, Bson, etc by 2-4X. + - Lock-free (sans mutex) concurrency for scaling to 100's of cores + - In-place updates during decode, with option to zero value in maps and slices prior to decode + - Coerce types where appropriate + e.g. decode an int in the stream into a float, decode numbers from formatted strings, etc + - Corner Cases: + Overflows, nil maps/slices, nil values in streams are handled correctly + - Standard field renaming via tags + - Support for omitting empty fields during an encoding + - Encoding from any value and decoding into pointer to any value + (struct, slice, map, primitives, pointers, interface{}, etc) + - Extensions to support efficient encoding/decoding of any named types + - Support encoding.(Binary|Text)(M|Unm)arshaler interfaces + - Support IsZero() bool to determine if a value is a zero value. + Analogous to time.Time.IsZero() bool. + - Decoding without a schema (into a interface{}). + Includes Options to configure what specific map or slice type to use + when decoding an encoded list or map into a nil interface{} + - Mapping a non-interface type to an interface, so we can decode appropriately + into any interface type with a correctly configured non-interface value. + - Encode a struct as an array, and decode struct from an array in the data stream + - Option to encode struct keys as numbers (instead of strings) + (to support structured streams with fields encoded as numeric codes) + - Comprehensive support for anonymous fields + - Fast (no-reflection) encoding/decoding of common maps and slices + - Code-generation for faster performance. + - Support binary (e.g. messagepack) and text (e.g. json) formats + - Support indefinite-length formats to enable true streaming + (for formats which support it e.g. json) + - Support canonical encoding, where a value is ALWAYS encoded as same sequence of bytes. + This mostly applies to maps, where iteration order is non-deterministic. + - NIL in data stream decoded as zero value + - Never silently skip data when decoding. + User decides whether to return an error or silently skip data when keys or indexes + in the data stream do not map to fields in the struct. + - Detect and error when encoding a cyclic reference (instead of stack overflow shutdown) + - Encode/Decode from/to chan types (for iterative streaming support) + - Drop-in replacement for encoding/json. `json:` key in struct tag supported. + - Provides a RPC Server and Client Codec for net/rpc communication protocol. + - Handle unique idiosyncrasies of codecs e.g. + - For messagepack, configure how ambiguities in handling raw bytes are resolved + - For messagepack, provide rpc server/client codec to support + msgpack-rpc protocol defined at: + https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md + +## Extension Support + +Users can register a function to handle the encoding or decoding of their +custom types. + +There are no restrictions on what the custom type can be. Some examples: + +```go + + type BisSet []int + type BitSet64 uint64 + type UUID string + type MyStructWithUnexportedFields struct { a int; b bool; c []int; } + type GifImage struct { ... } + +``` + +As an illustration, MyStructWithUnexportedFields would normally be encoded +as an empty map because it has no exported fields, while UUID would be +encoded as a string. However, with extension support, you can encode any of +these however you like. + +## Custom Encoding and Decoding + +This package maintains symmetry in the encoding and decoding halfs. We +determine how to encode or decode by walking this decision tree + + - is type a codec.Selfer? + - is there an extension registered for the type? + - is format binary, and is type a encoding.BinaryMarshaler and BinaryUnmarshaler? + - is format specifically json, and is type a encoding/json.Marshaler and Unmarshaler? + - is format text-based, and type an encoding.TextMarshaler and TextUnmarshaler? + - else we use a pair of functions based on the "kind" of the type e.g. map, slice, int64, etc + +This symmetry is important to reduce chances of issues happening because the +encoding and decoding sides are out of sync e.g. decoded via very specific +encoding.TextUnmarshaler but encoded via kind-specific generalized mode. + +Consequently, if a type only defines one-half of the symmetry (e.g. it +implements UnmarshalJSON() but not MarshalJSON() ), then that type doesn't +satisfy the check and we will continue walking down the decision tree. + +## RPC + +RPC Client and Server Codecs are implemented, so the codecs can be used with +the standard net/rpc package. + +## Usage + +The Handle is SAFE for concurrent READ, but NOT SAFE for concurrent +modification. + +The Encoder and Decoder are NOT safe for concurrent use. + +Consequently, the usage model is basically: + + - Create and initialize the Handle before any use. + Once created, DO NOT modify it. + - Multiple Encoders or Decoders can now use the Handle concurrently. + They only read information off the Handle (never write). + - However, each Encoder or Decoder MUST not be used concurrently + - To re-use an Encoder/Decoder, call Reset(...) on it first. + This allows you use state maintained on the Encoder/Decoder. + +Sample usage model: + +```go + + // create and configure Handle + var ( + mh codec.MsgpackHandle + ) + + mh.MapType = reflect.TypeOf(map[string]interface{}(nil)) + + // configure extensions + // e.g. for msgpack, define functions and enable Time support for tag 1 + mh.SetExt(reflect.TypeOf(time.Time{}), 1, myExt) + + // create and use decoder/encoder + var ( + r io.Reader + w io.Writer + b []byte + h = &mh + ) + + dec = codec.NewDecoder(r, h) + dec = codec.NewDecoderBytes(b, h) + err = dec.Decode(&v) + + enc = codec.NewEncoder(w, h) + enc = codec.NewEncoderBytes(&b, h) + err = enc.Encode(v) + + //RPC Server + go func() { + for { + conn, err := listener.Accept() + rpcCodec := codec.GoRpc.ServerCodec(conn, h) + //OR rpcCodec := codec.MsgpackSpecRpc.ServerCodec(conn, h) + rpc.ServeCodec(rpcCodec) + } + }() + + //RPC Communication (client side) + conn, err = net.Dial("tcp", "localhost:5555") + rpcCodec := codec.GoRpc.ClientCodec(conn, h) + //OR rpcCodec := codec.MsgpackSpecRpc.ClientCodec(conn, h) + client := rpc.NewClientWithCodec(rpcCodec) + +``` + +## Running Tests + +To run tests, use the following: + +``` + + go test + +``` + +To run the full suite of tests, use the following: + +``` + + go test -tags alltests -run Suite + +``` + +You can run the tag 'safe' to run tests or build in safe mode. e.g. + +``` + + go test -tags safe -run Json + go test -tags "alltests safe" -run Suite + +``` + +## Running Benchmarks + +``` + + cd codec/bench + ./bench.sh -d + ./bench.sh -c + ./bench.sh -s + go test -bench . -benchmem -benchtime 1s + +``` + +Please see http://github.com/hashicorp/go-codec-bench . + +## Caveats + +Struct fields matching the following are ignored during encoding and +decoding + + - struct tag value set to - + - func, complex numbers, unsafe pointers + - unexported and not embedded + - unexported and embedded and not struct kind + - unexported and embedded pointers + +Every other field in a struct will be encoded/decoded. + +Embedded fields are encoded as if they exist in the top-level struct, with +some caveats. See Encode documentation. +*/ +package codec diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/encode.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/encode.go new file mode 100644 index 00000000..29c723e1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/encode.go @@ -0,0 +1,1812 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +import ( + "encoding" + "errors" + "fmt" + "io" + "reflect" + "runtime" + "sort" + "strconv" + "time" +) + +// defEncByteBufSize is the default size of []byte used +// for bufio buffer or []byte (when nil passed) +const defEncByteBufSize = 1 << 10 // 4:16, 6:64, 8:256, 10:1024 + +var errEncoderNotInitialized = errors.New("Encoder not initialized") + +/* + +// encWriter abstracts writing to a byte array or to an io.Writer. +// +// +// Deprecated: Use encWriterSwitch instead. +type encWriter interface { + writeb([]byte) + writestr(string) + writen1(byte) + writen2(byte, byte) + end() +} + +*/ + +// encDriver abstracts the actual codec (binc vs msgpack, etc) +type encDriver interface { + EncodeNil() + EncodeInt(i int64) + EncodeUint(i uint64) + EncodeBool(b bool) + EncodeFloat32(f float32) + EncodeFloat64(f float64) + // encodeExtPreamble(xtag byte, length int) + EncodeRawExt(re *RawExt, e *Encoder) + EncodeExt(v interface{}, xtag uint64, ext Ext, e *Encoder) + // Deprecated: use EncodeStringEnc instead + EncodeString(c charEncoding, v string) + // Deprecated: use EncodeStringBytesRaw instead + EncodeStringBytes(c charEncoding, v []byte) + EncodeStringEnc(c charEncoding, v string) // c cannot be cRAW + // EncodeSymbol(v string) + EncodeStringBytesRaw(v []byte) + EncodeTime(time.Time) + //encBignum(f *big.Int) + //encStringRunes(c charEncoding, v []rune) + WriteArrayStart(length int) + WriteArrayElem() + WriteArrayEnd() + WriteMapStart(length int) + WriteMapElemKey() + WriteMapElemValue() + WriteMapEnd() + + reset() + atEndOfEncode() +} + +type encDriverAsis interface { + EncodeAsis(v []byte) +} + +type encodeError struct { + codecError +} + +func (e encodeError) Error() string { + return fmt.Sprintf("%s encode error: %v", e.name, e.err) +} + +type encDriverNoopContainerWriter struct{} + +func (encDriverNoopContainerWriter) WriteArrayStart(length int) {} +func (encDriverNoopContainerWriter) WriteArrayElem() {} +func (encDriverNoopContainerWriter) WriteArrayEnd() {} +func (encDriverNoopContainerWriter) WriteMapStart(length int) {} +func (encDriverNoopContainerWriter) WriteMapElemKey() {} +func (encDriverNoopContainerWriter) WriteMapElemValue() {} +func (encDriverNoopContainerWriter) WriteMapEnd() {} +func (encDriverNoopContainerWriter) atEndOfEncode() {} + +type encDriverTrackContainerWriter struct { + c containerState +} + +func (e *encDriverTrackContainerWriter) WriteArrayStart(length int) { e.c = containerArrayStart } +func (e *encDriverTrackContainerWriter) WriteArrayElem() { e.c = containerArrayElem } +func (e *encDriverTrackContainerWriter) WriteArrayEnd() { e.c = containerArrayEnd } +func (e *encDriverTrackContainerWriter) WriteMapStart(length int) { e.c = containerMapStart } +func (e *encDriverTrackContainerWriter) WriteMapElemKey() { e.c = containerMapKey } +func (e *encDriverTrackContainerWriter) WriteMapElemValue() { e.c = containerMapValue } +func (e *encDriverTrackContainerWriter) WriteMapEnd() { e.c = containerMapEnd } +func (e *encDriverTrackContainerWriter) atEndOfEncode() {} + +// type ioEncWriterWriter interface { +// WriteByte(c byte) error +// WriteString(s string) (n int, err error) +// Write(p []byte) (n int, err error) +// } + +// EncodeOptions captures configuration options during encode. +type EncodeOptions struct { + // WriterBufferSize is the size of the buffer used when writing. + // + // if > 0, we use a smart buffer internally for performance purposes. + WriterBufferSize int + + // ChanRecvTimeout is the timeout used when selecting from a chan. + // + // Configuring this controls how we receive from a chan during the encoding process. + // - If ==0, we only consume the elements currently available in the chan. + // - if <0, we consume until the chan is closed. + // - If >0, we consume until this timeout. + ChanRecvTimeout time.Duration + + // StructToArray specifies to encode a struct as an array, and not as a map + StructToArray bool + + // Canonical representation means that encoding a value will always result in the same + // sequence of bytes. + // + // This only affects maps, as the iteration order for maps is random. + // + // The implementation MAY use the natural sort order for the map keys if possible: + // + // - If there is a natural sort order (ie for number, bool, string or []byte keys), + // then the map keys are first sorted in natural order and then written + // with corresponding map values to the strema. + // - If there is no natural sort order, then the map keys will first be + // encoded into []byte, and then sorted, + // before writing the sorted keys and the corresponding map values to the stream. + // + Canonical bool + + // CheckCircularRef controls whether we check for circular references + // and error fast during an encode. + // + // If enabled, an error is received if a pointer to a struct + // references itself either directly or through one of its fields (iteratively). + // + // This is opt-in, as there may be a performance hit to checking circular references. + CheckCircularRef bool + + // RecursiveEmptyCheck controls whether we descend into interfaces, structs and pointers + // when checking if a value is empty. + // + // Note that this may make OmitEmpty more expensive, as it incurs a lot more reflect calls. + RecursiveEmptyCheck bool + + // Raw controls whether we encode Raw values. + // This is a "dangerous" option and must be explicitly set. + // If set, we blindly encode Raw values as-is, without checking + // if they are a correct representation of a value in that format. + // If unset, we error out. + Raw bool + + // StringToRaw controls how strings are encoded. + // + // As a go string is just an (immutable) sequence of bytes, + // it can be encoded either as raw bytes or as a UTF string. + // + // By default, strings are encoded as UTF-8. + // but can be treated as []byte during an encode. + // + // Note that things which we know (by definition) to be UTF-8 + // are ALWAYS encoded as UTF-8 strings. + // These include encoding.TextMarshaler, time.Format calls, struct field names, etc. + StringToRaw bool + + // // AsSymbols defines what should be encoded as symbols. + // // + // // Encoding as symbols can reduce the encoded size significantly. + // // + // // However, during decoding, each string to be encoded as a symbol must + // // be checked to see if it has been seen before. Consequently, encoding time + // // will increase if using symbols, because string comparisons has a clear cost. + // // + // // Sample values: + // // AsSymbolNone + // // AsSymbolAll + // // AsSymbolMapStringKeys + // // AsSymbolMapStringKeysFlag | AsSymbolStructFieldNameFlag + // AsSymbols AsSymbolFlag +} + +// --------------------------------------------- + +/* + +type ioEncStringWriter interface { + WriteString(s string) (n int, err error) +} + +// ioEncWriter implements encWriter and can write to an io.Writer implementation +type ioEncWriter struct { + w io.Writer + ww io.Writer + bw io.ByteWriter + sw ioEncStringWriter + fw ioFlusher + b [8]byte +} + +func (z *ioEncWriter) reset(w io.Writer) { + z.w = w + var ok bool + if z.bw, ok = w.(io.ByteWriter); !ok { + z.bw = z + } + if z.sw, ok = w.(ioEncStringWriter); !ok { + z.sw = z + } + z.fw, _ = w.(ioFlusher) + z.ww = w +} + +func (z *ioEncWriter) WriteByte(b byte) (err error) { + z.b[0] = b + _, err = z.w.Write(z.b[:1]) + return +} + +func (z *ioEncWriter) WriteString(s string) (n int, err error) { + return z.w.Write(bytesView(s)) +} + +func (z *ioEncWriter) writeb(bs []byte) { + if _, err := z.ww.Write(bs); err != nil { + panic(err) + } +} + +func (z *ioEncWriter) writestr(s string) { + if _, err := z.sw.WriteString(s); err != nil { + panic(err) + } +} + +func (z *ioEncWriter) writen1(b byte) { + if err := z.bw.WriteByte(b); err != nil { + panic(err) + } +} + +func (z *ioEncWriter) writen2(b1, b2 byte) { + var err error + if err = z.bw.WriteByte(b1); err == nil { + if err = z.bw.WriteByte(b2); err == nil { + return + } + } + panic(err) +} + +// func (z *ioEncWriter) writen5(b1, b2, b3, b4, b5 byte) { +// z.b[0], z.b[1], z.b[2], z.b[3], z.b[4] = b1, b2, b3, b4, b5 +// if _, err := z.ww.Write(z.b[:5]); err != nil { +// panic(err) +// } +// } + +//go:noinline - so *encWriterSwitch.XXX has the bytesEncAppender.XXX inlined +func (z *ioEncWriter) end() { + if z.fw != nil { + if err := z.fw.Flush(); err != nil { + panic(err) + } + } +} + +*/ + +// --------------------------------------------- + +// bufioEncWriter +type bufioEncWriter struct { + buf []byte + w io.Writer + n int + sz int // buf size + + // Extensions can call Encode() within a current Encode() call. + // We need to know when the top level Encode() call returns, + // so we can decide whether to Release() or not. + calls uint16 // what depth in mustDecode are we in now. + + _ [6]uint8 // padding + + bytesBufPooler + + _ [1]uint64 // padding + // a int + // b [4]byte + // err +} + +func (z *bufioEncWriter) reset(w io.Writer, bufsize int) { + z.w = w + z.n = 0 + z.calls = 0 + if bufsize <= 0 { + bufsize = defEncByteBufSize + } + z.sz = bufsize + if cap(z.buf) >= bufsize { + z.buf = z.buf[:cap(z.buf)] + } else { + z.buf = z.bytesBufPooler.get(bufsize) + // z.buf = make([]byte, bufsize) + } +} + +func (z *bufioEncWriter) release() { + z.buf = nil + z.bytesBufPooler.end() +} + +//go:noinline - flush only called intermittently +func (z *bufioEncWriter) flushErr() (err error) { + n, err := z.w.Write(z.buf[:z.n]) + z.n -= n + if z.n > 0 && err == nil { + err = io.ErrShortWrite + } + if n > 0 && z.n > 0 { + copy(z.buf, z.buf[n:z.n+n]) + } + return err +} + +func (z *bufioEncWriter) flush() { + if err := z.flushErr(); err != nil { + panic(err) + } +} + +func (z *bufioEncWriter) writeb(s []byte) { +LOOP: + a := len(z.buf) - z.n + if len(s) > a { + z.n += copy(z.buf[z.n:], s[:a]) + s = s[a:] + z.flush() + goto LOOP + } + z.n += copy(z.buf[z.n:], s) +} + +func (z *bufioEncWriter) writestr(s string) { + // z.writeb(bytesView(s)) // inlined below +LOOP: + a := len(z.buf) - z.n + if len(s) > a { + z.n += copy(z.buf[z.n:], s[:a]) + s = s[a:] + z.flush() + goto LOOP + } + z.n += copy(z.buf[z.n:], s) +} + +func (z *bufioEncWriter) writen1(b1 byte) { + if 1 > len(z.buf)-z.n { + z.flush() + } + z.buf[z.n] = b1 + z.n++ +} + +func (z *bufioEncWriter) writen2(b1, b2 byte) { + if 2 > len(z.buf)-z.n { + z.flush() + } + z.buf[z.n+1] = b2 + z.buf[z.n] = b1 + z.n += 2 +} + +func (z *bufioEncWriter) endErr() (err error) { + if z.n > 0 { + err = z.flushErr() + } + return +} + +// --------------------------------------------- + +// bytesEncAppender implements encWriter and can write to an byte slice. +type bytesEncAppender struct { + b []byte + out *[]byte +} + +func (z *bytesEncAppender) writeb(s []byte) { + z.b = append(z.b, s...) +} +func (z *bytesEncAppender) writestr(s string) { + z.b = append(z.b, s...) +} +func (z *bytesEncAppender) writen1(b1 byte) { + z.b = append(z.b, b1) +} +func (z *bytesEncAppender) writen2(b1, b2 byte) { + z.b = append(z.b, b1, b2) +} +func (z *bytesEncAppender) endErr() error { + *(z.out) = z.b + return nil +} +func (z *bytesEncAppender) reset(in []byte, out *[]byte) { + z.b = in[:0] + z.out = out +} + +// --------------------------------------------- + +func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeRawExt(rv2i(rv).(*RawExt), e) +} + +func (e *Encoder) ext(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeExt(rv2i(rv), f.xfTag, f.xfFn, e) +} + +func (e *Encoder) selferMarshal(f *codecFnInfo, rv reflect.Value) { + rv2i(rv).(Selfer).CodecEncodeSelf(e) +} + +func (e *Encoder) binaryMarshal(f *codecFnInfo, rv reflect.Value) { + bs, fnerr := rv2i(rv).(encoding.BinaryMarshaler).MarshalBinary() + e.marshalRaw(bs, fnerr) +} + +func (e *Encoder) textMarshal(f *codecFnInfo, rv reflect.Value) { + bs, fnerr := rv2i(rv).(encoding.TextMarshaler).MarshalText() + e.marshalUtf8(bs, fnerr) +} + +func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) { + bs, fnerr := rv2i(rv).(jsonMarshaler).MarshalJSON() + e.marshalAsis(bs, fnerr) +} + +func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) { + e.rawBytes(rv2i(rv).(Raw)) +} + +func (e *Encoder) kInvalid(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeNil() +} + +func (e *Encoder) kErr(f *codecFnInfo, rv reflect.Value) { + e.errorf("unsupported kind %s, for %#v", rv.Kind(), rv) +} + +func (e *Encoder) kSlice(f *codecFnInfo, rv reflect.Value) { + ti := f.ti + ee := e.e + // array may be non-addressable, so we have to manage with care + // (don't call rv.Bytes, rv.Slice, etc). + // E.g. type struct S{B [2]byte}; + // Encode(S{}) will bomb on "panic: slice of unaddressable array". + if f.seq != seqTypeArray { + if rv.IsNil() { + ee.EncodeNil() + return + } + // If in this method, then there was no extension function defined. + // So it's okay to treat as []byte. + if ti.rtid == uint8SliceTypId { + ee.EncodeStringBytesRaw(rv.Bytes()) + return + } + } + if f.seq == seqTypeChan && ti.chandir&uint8(reflect.RecvDir) == 0 { + e.errorf("send-only channel cannot be encoded") + } + elemsep := e.esep + rtelem := ti.elem + rtelemIsByte := uint8TypId == rt2id(rtelem) // NOT rtelem.Kind() == reflect.Uint8 + var l int + // if a slice, array or chan of bytes, treat specially + if rtelemIsByte { + switch f.seq { + case seqTypeSlice: + ee.EncodeStringBytesRaw(rv.Bytes()) + case seqTypeArray: + l = rv.Len() + if rv.CanAddr() { + ee.EncodeStringBytesRaw(rv.Slice(0, l).Bytes()) + } else { + var bs []byte + if l <= cap(e.b) { + bs = e.b[:l] + } else { + bs = make([]byte, l) + } + reflect.Copy(reflect.ValueOf(bs), rv) + ee.EncodeStringBytesRaw(bs) + } + case seqTypeChan: + // do not use range, so that the number of elements encoded + // does not change, and encoding does not hang waiting on someone to close chan. + // for b := range rv2i(rv).(<-chan byte) { bs = append(bs, b) } + // ch := rv2i(rv).(<-chan byte) // fix error - that this is a chan byte, not a <-chan byte. + + if rv.IsNil() { + ee.EncodeNil() + break + } + bs := e.b[:0] + irv := rv2i(rv) + ch, ok := irv.(<-chan byte) + if !ok { + ch = irv.(chan byte) + } + + L1: + switch timeout := e.h.ChanRecvTimeout; { + case timeout == 0: // only consume available + for { + select { + case b := <-ch: + bs = append(bs, b) + default: + break L1 + } + } + case timeout > 0: // consume until timeout + tt := time.NewTimer(timeout) + for { + select { + case b := <-ch: + bs = append(bs, b) + case <-tt.C: + // close(tt.C) + break L1 + } + } + default: // consume until close + for b := range ch { + bs = append(bs, b) + } + } + + ee.EncodeStringBytesRaw(bs) + } + return + } + + // if chan, consume chan into a slice, and work off that slice. + if f.seq == seqTypeChan { + rvcs := reflect.Zero(reflect.SliceOf(rtelem)) + timeout := e.h.ChanRecvTimeout + if timeout < 0 { // consume until close + for { + recv, recvOk := rv.Recv() + if !recvOk { + break + } + rvcs = reflect.Append(rvcs, recv) + } + } else { + cases := make([]reflect.SelectCase, 2) + cases[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: rv} + if timeout == 0 { + cases[1] = reflect.SelectCase{Dir: reflect.SelectDefault} + } else { + tt := time.NewTimer(timeout) + cases[1] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tt.C)} + } + for { + chosen, recv, recvOk := reflect.Select(cases) + if chosen == 1 || !recvOk { + break + } + rvcs = reflect.Append(rvcs, recv) + } + } + rv = rvcs // TODO: ensure this doesn't mess up anywhere that rv of kind chan is expected + } + + l = rv.Len() + if ti.mbs { + if l%2 == 1 { + e.errorf("mapBySlice requires even slice length, but got %v", l) + return + } + ee.WriteMapStart(l / 2) + } else { + ee.WriteArrayStart(l) + } + + if l > 0 { + var fn *codecFn + for rtelem.Kind() == reflect.Ptr { + rtelem = rtelem.Elem() + } + // if kind is reflect.Interface, do not pre-determine the + // encoding type, because preEncodeValue may break it down to + // a concrete type and kInterface will bomb. + if rtelem.Kind() != reflect.Interface { + fn = e.h.fn(rtelem, true, true) + } + for j := 0; j < l; j++ { + if elemsep { + if ti.mbs { + if j%2 == 0 { + ee.WriteMapElemKey() + } else { + ee.WriteMapElemValue() + } + } else { + ee.WriteArrayElem() + } + } + e.encodeValue(rv.Index(j), fn, true) + } + } + + if ti.mbs { + ee.WriteMapEnd() + } else { + ee.WriteArrayEnd() + } +} + +func (e *Encoder) kStructNoOmitempty(f *codecFnInfo, rv reflect.Value) { + fti := f.ti + tisfi := fti.sfiSrc + toMap := !(fti.toArray || e.h.StructToArray) + if toMap { + tisfi = fti.sfiSort + } + + ee := e.e + + sfn := structFieldNode{v: rv, update: false} + if toMap { + ee.WriteMapStart(len(tisfi)) + if e.esep { + for _, si := range tisfi { + ee.WriteMapElemKey() + e.kStructFieldKey(fti.keyType, si.encNameAsciiAlphaNum, si.encName) + ee.WriteMapElemValue() + e.encodeValue(sfn.field(si), nil, true) + } + } else { + for _, si := range tisfi { + e.kStructFieldKey(fti.keyType, si.encNameAsciiAlphaNum, si.encName) + e.encodeValue(sfn.field(si), nil, true) + } + } + ee.WriteMapEnd() + } else { + ee.WriteArrayStart(len(tisfi)) + if e.esep { + for _, si := range tisfi { + ee.WriteArrayElem() + e.encodeValue(sfn.field(si), nil, true) + } + } else { + for _, si := range tisfi { + e.encodeValue(sfn.field(si), nil, true) + } + } + ee.WriteArrayEnd() + } +} + +func (e *Encoder) kStructFieldKey(keyType valueType, encNameAsciiAlphaNum bool, encName string) { + encStructFieldKey(encName, e.e, e.w, keyType, encNameAsciiAlphaNum, e.js) +} + +func (e *Encoder) kStruct(f *codecFnInfo, rv reflect.Value) { + fti := f.ti + elemsep := e.esep + tisfi := fti.sfiSrc + var newlen int + toMap := !(fti.toArray || e.h.StructToArray) + var mf map[string]interface{} + if f.ti.mf { + mf = rv2i(rv).(MissingFielder).CodecMissingFields() + toMap = true + newlen += len(mf) + } else if f.ti.mfp { + if rv.CanAddr() { + mf = rv2i(rv.Addr()).(MissingFielder).CodecMissingFields() + } else { + // make a new addressable value of same one, and use it + rv2 := reflect.New(rv.Type()) + rv2.Elem().Set(rv) + mf = rv2i(rv2).(MissingFielder).CodecMissingFields() + } + toMap = true + newlen += len(mf) + } + // if toMap, use the sorted array. If toArray, use unsorted array (to match sequence in struct) + if toMap { + tisfi = fti.sfiSort + } + newlen += len(tisfi) + ee := e.e + + // Use sync.Pool to reduce allocating slices unnecessarily. + // The cost of sync.Pool is less than the cost of new allocation. + // + // Each element of the array pools one of encStructPool(8|16|32|64). + // It allows the re-use of slices up to 64 in length. + // A performance cost of encoding structs was collecting + // which values were empty and should be omitted. + // We needed slices of reflect.Value and string to collect them. + // This shared pool reduces the amount of unnecessary creation we do. + // The cost is that of locking sometimes, but sync.Pool is efficient + // enough to reduce thread contention. + + // fmt.Printf(">>>>>>>>>>>>>> encode.kStruct: newlen: %d\n", newlen) + var spool sfiRvPooler + var fkvs = spool.get(newlen) + + var kv sfiRv + recur := e.h.RecursiveEmptyCheck + sfn := structFieldNode{v: rv, update: false} + newlen = 0 + for _, si := range tisfi { + // kv.r = si.field(rv, false) + kv.r = sfn.field(si) + if toMap { + if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) { + continue + } + kv.v = si // si.encName + } else { + // use the zero value. + // if a reference or struct, set to nil (so you do not output too much) + if si.omitEmpty() && isEmptyValue(kv.r, e.h.TypeInfos, recur, recur) { + switch kv.r.Kind() { + case reflect.Struct, reflect.Interface, reflect.Ptr, + reflect.Array, reflect.Map, reflect.Slice: + kv.r = reflect.Value{} //encode as nil + } + } + } + fkvs[newlen] = kv + newlen++ + } + fkvs = fkvs[:newlen] + + var mflen int + for k, v := range mf { + if k == "" { + delete(mf, k) + continue + } + if fti.infoFieldOmitempty && isEmptyValue(reflect.ValueOf(v), e.h.TypeInfos, recur, recur) { + delete(mf, k) + continue + } + mflen++ + } + + var j int + if toMap { + ee.WriteMapStart(newlen + mflen) + if elemsep { + for j = 0; j < len(fkvs); j++ { + kv = fkvs[j] + ee.WriteMapElemKey() + e.kStructFieldKey(fti.keyType, kv.v.encNameAsciiAlphaNum, kv.v.encName) + ee.WriteMapElemValue() + e.encodeValue(kv.r, nil, true) + } + } else { + for j = 0; j < len(fkvs); j++ { + kv = fkvs[j] + e.kStructFieldKey(fti.keyType, kv.v.encNameAsciiAlphaNum, kv.v.encName) + e.encodeValue(kv.r, nil, true) + } + } + // now, add the others + for k, v := range mf { + ee.WriteMapElemKey() + e.kStructFieldKey(fti.keyType, false, k) + ee.WriteMapElemValue() + e.encode(v) + } + ee.WriteMapEnd() + } else { + ee.WriteArrayStart(newlen) + if elemsep { + for j = 0; j < len(fkvs); j++ { + ee.WriteArrayElem() + e.encodeValue(fkvs[j].r, nil, true) + } + } else { + for j = 0; j < len(fkvs); j++ { + e.encodeValue(fkvs[j].r, nil, true) + } + } + ee.WriteArrayEnd() + } + + // do not use defer. Instead, use explicit pool return at end of function. + // defer has a cost we are trying to avoid. + // If there is a panic and these slices are not returned, it is ok. + spool.end() +} + +func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { + ee := e.e + if rv.IsNil() { + ee.EncodeNil() + return + } + + l := rv.Len() + ee.WriteMapStart(l) + if l == 0 { + ee.WriteMapEnd() + return + } + // var asSymbols bool + // determine the underlying key and val encFn's for the map. + // This eliminates some work which is done for each loop iteration i.e. + // rv.Type(), ref.ValueOf(rt).Pointer(), then check map/list for fn. + // + // However, if kind is reflect.Interface, do not pre-determine the + // encoding type, because preEncodeValue may break it down to + // a concrete type and kInterface will bomb. + var keyFn, valFn *codecFn + ti := f.ti + rtkey0 := ti.key + rtkey := rtkey0 + rtval0 := ti.elem + rtval := rtval0 + // rtkeyid := rt2id(rtkey0) + for rtval.Kind() == reflect.Ptr { + rtval = rtval.Elem() + } + if rtval.Kind() != reflect.Interface { + valFn = e.h.fn(rtval, true, true) + } + mks := rv.MapKeys() + + if e.h.Canonical { + e.kMapCanonical(rtkey, rv, mks, valFn) + ee.WriteMapEnd() + return + } + + var keyTypeIsString = stringTypId == rt2id(rtkey0) // rtkeyid + if !keyTypeIsString { + for rtkey.Kind() == reflect.Ptr { + rtkey = rtkey.Elem() + } + if rtkey.Kind() != reflect.Interface { + // rtkeyid = rt2id(rtkey) + keyFn = e.h.fn(rtkey, true, true) + } + } + + // for j, lmks := 0, len(mks); j < lmks; j++ { + for j := range mks { + if e.esep { + ee.WriteMapElemKey() + } + if keyTypeIsString { + if e.h.StringToRaw { + ee.EncodeStringBytesRaw(bytesView(mks[j].String())) + } else { + ee.EncodeStringEnc(cUTF8, mks[j].String()) + } + } else { + e.encodeValue(mks[j], keyFn, true) + } + if e.esep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mks[j]), valFn, true) + + } + ee.WriteMapEnd() +} + +func (e *Encoder) kMapCanonical(rtkey reflect.Type, rv reflect.Value, mks []reflect.Value, valFn *codecFn) { + ee := e.e + elemsep := e.esep + // we previously did out-of-band if an extension was registered. + // This is not necessary, as the natural kind is sufficient for ordering. + + switch rtkey.Kind() { + case reflect.Bool: + mksv := make([]boolRv, len(mks)) + for i, k := range mks { + v := &mksv[i] + v.r = k + v.v = k.Bool() + } + sort.Sort(boolRvSlice(mksv)) + for i := range mksv { + if elemsep { + ee.WriteMapElemKey() + } + ee.EncodeBool(mksv[i].v) + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) + } + case reflect.String: + mksv := make([]stringRv, len(mks)) + for i, k := range mks { + v := &mksv[i] + v.r = k + v.v = k.String() + } + sort.Sort(stringRvSlice(mksv)) + for i := range mksv { + if elemsep { + ee.WriteMapElemKey() + } + if e.h.StringToRaw { + ee.EncodeStringBytesRaw(bytesView(mksv[i].v)) + } else { + ee.EncodeStringEnc(cUTF8, mksv[i].v) + } + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) + } + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr: + mksv := make([]uintRv, len(mks)) + for i, k := range mks { + v := &mksv[i] + v.r = k + v.v = k.Uint() + } + sort.Sort(uintRvSlice(mksv)) + for i := range mksv { + if elemsep { + ee.WriteMapElemKey() + } + ee.EncodeUint(mksv[i].v) + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) + } + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + mksv := make([]intRv, len(mks)) + for i, k := range mks { + v := &mksv[i] + v.r = k + v.v = k.Int() + } + sort.Sort(intRvSlice(mksv)) + for i := range mksv { + if elemsep { + ee.WriteMapElemKey() + } + ee.EncodeInt(mksv[i].v) + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) + } + case reflect.Float32: + mksv := make([]floatRv, len(mks)) + for i, k := range mks { + v := &mksv[i] + v.r = k + v.v = k.Float() + } + sort.Sort(floatRvSlice(mksv)) + for i := range mksv { + if elemsep { + ee.WriteMapElemKey() + } + ee.EncodeFloat32(float32(mksv[i].v)) + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) + } + case reflect.Float64: + mksv := make([]floatRv, len(mks)) + for i, k := range mks { + v := &mksv[i] + v.r = k + v.v = k.Float() + } + sort.Sort(floatRvSlice(mksv)) + for i := range mksv { + if elemsep { + ee.WriteMapElemKey() + } + ee.EncodeFloat64(mksv[i].v) + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) + } + case reflect.Struct: + if rv.Type() == timeTyp { + mksv := make([]timeRv, len(mks)) + for i, k := range mks { + v := &mksv[i] + v.r = k + v.v = rv2i(k).(time.Time) + } + sort.Sort(timeRvSlice(mksv)) + for i := range mksv { + if elemsep { + ee.WriteMapElemKey() + } + ee.EncodeTime(mksv[i].v) + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksv[i].r), valFn, true) + } + break + } + fallthrough + default: + // out-of-band + // first encode each key to a []byte first, then sort them, then record + var mksv []byte = make([]byte, 0, len(mks)*16) // temporary byte slice for the encoding + e2 := NewEncoderBytes(&mksv, e.hh) + mksbv := make([]bytesRv, len(mks)) + for i, k := range mks { + v := &mksbv[i] + l := len(mksv) + e2.MustEncode(k) + v.r = k + v.v = mksv[l:] + } + sort.Sort(bytesRvSlice(mksbv)) + for j := range mksbv { + if elemsep { + ee.WriteMapElemKey() + } + e.asis(mksbv[j].v) + if elemsep { + ee.WriteMapElemValue() + } + e.encodeValue(rv.MapIndex(mksbv[j].r), valFn, true) + } + } +} + +// // -------------------------------------------------- + +type encWriterSwitch struct { + // wi *ioEncWriter + wb bytesEncAppender + wf *bufioEncWriter + // typ entryType + bytes bool // encoding to []byte + esep bool // whether it has elem separators + isas bool // whether e.as != nil + js bool // is json encoder? + be bool // is binary encoder? + _ [2]byte // padding + // _ [2]uint64 // padding + // _ uint64 // padding +} + +func (z *encWriterSwitch) writeb(s []byte) { + if z.bytes { + z.wb.writeb(s) + } else { + z.wf.writeb(s) + } +} +func (z *encWriterSwitch) writestr(s string) { + if z.bytes { + z.wb.writestr(s) + } else { + z.wf.writestr(s) + } +} +func (z *encWriterSwitch) writen1(b1 byte) { + if z.bytes { + z.wb.writen1(b1) + } else { + z.wf.writen1(b1) + } +} +func (z *encWriterSwitch) writen2(b1, b2 byte) { + if z.bytes { + z.wb.writen2(b1, b2) + } else { + z.wf.writen2(b1, b2) + } +} +func (z *encWriterSwitch) endErr() error { + if z.bytes { + return z.wb.endErr() + } + return z.wf.endErr() +} + +func (z *encWriterSwitch) end() { + if err := z.endErr(); err != nil { + panic(err) + } +} + +/* + +// ------------------------------------------ +func (z *encWriterSwitch) writeb(s []byte) { + switch z.typ { + case entryTypeBytes: + z.wb.writeb(s) + case entryTypeIo: + z.wi.writeb(s) + default: + z.wf.writeb(s) + } +} +func (z *encWriterSwitch) writestr(s string) { + switch z.typ { + case entryTypeBytes: + z.wb.writestr(s) + case entryTypeIo: + z.wi.writestr(s) + default: + z.wf.writestr(s) + } +} +func (z *encWriterSwitch) writen1(b1 byte) { + switch z.typ { + case entryTypeBytes: + z.wb.writen1(b1) + case entryTypeIo: + z.wi.writen1(b1) + default: + z.wf.writen1(b1) + } +} +func (z *encWriterSwitch) writen2(b1, b2 byte) { + switch z.typ { + case entryTypeBytes: + z.wb.writen2(b1, b2) + case entryTypeIo: + z.wi.writen2(b1, b2) + default: + z.wf.writen2(b1, b2) + } +} +func (z *encWriterSwitch) end() { + switch z.typ { + case entryTypeBytes: + z.wb.end() + case entryTypeIo: + z.wi.end() + default: + z.wf.end() + } +} + +// ------------------------------------------ +func (z *encWriterSwitch) writeb(s []byte) { + if z.bytes { + z.wb.writeb(s) + } else { + z.wi.writeb(s) + } +} +func (z *encWriterSwitch) writestr(s string) { + if z.bytes { + z.wb.writestr(s) + } else { + z.wi.writestr(s) + } +} +func (z *encWriterSwitch) writen1(b1 byte) { + if z.bytes { + z.wb.writen1(b1) + } else { + z.wi.writen1(b1) + } +} +func (z *encWriterSwitch) writen2(b1, b2 byte) { + if z.bytes { + z.wb.writen2(b1, b2) + } else { + z.wi.writen2(b1, b2) + } +} +func (z *encWriterSwitch) end() { + if z.bytes { + z.wb.end() + } else { + z.wi.end() + } +} + +*/ + +// Encoder writes an object to an output stream in a supported format. +// +// Encoder is NOT safe for concurrent use i.e. a Encoder cannot be used +// concurrently in multiple goroutines. +// +// However, as Encoder could be allocation heavy to initialize, a Reset method is provided +// so its state can be reused to decode new input streams repeatedly. +// This is the idiomatic way to use. +type Encoder struct { + panicHdl + // hopefully, reduce derefencing cost by laying the encWriter inside the Encoder + e encDriver + + // NOTE: Encoder shouldn't call it's write methods, + // as the handler MAY need to do some coordination. + w *encWriterSwitch + + // bw *bufio.Writer + as encDriverAsis + + err error + + h *BasicHandle + hh Handle + // ---- cpu cache line boundary? + 3 + encWriterSwitch + + ci set + + b [(5 * 8)]byte // for encoding chan or (non-addressable) [N]byte + + // ---- writable fields during execution --- *try* to keep in sep cache line + + // ---- cpu cache line boundary? + // b [scratchByteArrayLen]byte + // _ [cacheLineSize - scratchByteArrayLen]byte // padding + // b [cacheLineSize - (8 * 0)]byte // used for encoding a chan or (non-addressable) array of bytes +} + +// NewEncoder returns an Encoder for encoding into an io.Writer. +// +// For efficiency, Users are encouraged to configure WriterBufferSize on the handle +// OR pass in a memory buffered writer (eg bufio.Writer, bytes.Buffer). +func NewEncoder(w io.Writer, h Handle) *Encoder { + e := newEncoder(h) + e.Reset(w) + return e +} + +// NewEncoderBytes returns an encoder for encoding directly and efficiently +// into a byte slice, using zero-copying to temporary slices. +// +// It will potentially replace the output byte slice pointed to. +// After encoding, the out parameter contains the encoded contents. +func NewEncoderBytes(out *[]byte, h Handle) *Encoder { + e := newEncoder(h) + e.ResetBytes(out) + return e +} + +func newEncoder(h Handle) *Encoder { + e := &Encoder{h: basicHandle(h), err: errEncoderNotInitialized} + e.bytes = true + if useFinalizers { + runtime.SetFinalizer(e, (*Encoder).finalize) + // xdebugf(">>>> new(Encoder) with finalizer") + } + e.w = &e.encWriterSwitch + e.hh = h + e.esep = h.hasElemSeparators() + + return e +} + +func (e *Encoder) resetCommon() { + // e.w = &e.encWriterSwitch + if e.e == nil || e.hh.recreateEncDriver(e.e) { + e.e = e.hh.newEncDriver(e) + e.as, e.isas = e.e.(encDriverAsis) + // e.cr, _ = e.e.(containerStateRecv) + } + e.be = e.hh.isBinary() + _, e.js = e.hh.(*JsonHandle) + e.e.reset() + e.err = nil +} + +// Reset resets the Encoder with a new output stream. +// +// This accommodates using the state of the Encoder, +// where it has "cached" information about sub-engines. +func (e *Encoder) Reset(w io.Writer) { + if w == nil { + return + } + // var ok bool + e.bytes = false + if e.wf == nil { + e.wf = new(bufioEncWriter) + } + // e.typ = entryTypeUnset + // if e.h.WriterBufferSize > 0 { + // // bw := bufio.NewWriterSize(w, e.h.WriterBufferSize) + // // e.wi.bw = bw + // // e.wi.sw = bw + // // e.wi.fw = bw + // // e.wi.ww = bw + // if e.wf == nil { + // e.wf = new(bufioEncWriter) + // } + // e.wf.reset(w, e.h.WriterBufferSize) + // e.typ = entryTypeBufio + // } else { + // if e.wi == nil { + // e.wi = new(ioEncWriter) + // } + // e.wi.reset(w) + // e.typ = entryTypeIo + // } + e.wf.reset(w, e.h.WriterBufferSize) + // e.typ = entryTypeBufio + + // e.w = e.wi + e.resetCommon() +} + +// ResetBytes resets the Encoder with a new destination output []byte. +func (e *Encoder) ResetBytes(out *[]byte) { + if out == nil { + return + } + var in []byte = *out + if in == nil { + in = make([]byte, defEncByteBufSize) + } + e.bytes = true + // e.typ = entryTypeBytes + e.wb.reset(in, out) + // e.w = &e.wb + e.resetCommon() +} + +// Encode writes an object into a stream. +// +// Encoding can be configured via the struct tag for the fields. +// The key (in the struct tags) that we look at is configurable. +// +// By default, we look up the "codec" key in the struct field's tags, +// and fall bak to the "json" key if "codec" is absent. +// That key in struct field's tag value is the key name, +// followed by an optional comma and options. +// +// To set an option on all fields (e.g. omitempty on all fields), you +// can create a field called _struct, and set flags on it. The options +// which can be set on _struct are: +// - omitempty: so all fields are omitted if empty +// - toarray: so struct is encoded as an array +// - int: so struct key names are encoded as signed integers (instead of strings) +// - uint: so struct key names are encoded as unsigned integers (instead of strings) +// - float: so struct key names are encoded as floats (instead of strings) +// +// More details on these below. +// +// Struct values "usually" encode as maps. Each exported struct field is encoded unless: +// - the field's tag is "-", OR +// - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option. +// +// When encoding as a map, the first string in the tag (before the comma) +// is the map key string to use when encoding. +// ... +// This key is typically encoded as a string. +// However, there are instances where the encoded stream has mapping keys encoded as numbers. +// For example, some cbor streams have keys as integer codes in the stream, but they should map +// to fields in a structured object. Consequently, a struct is the natural representation in code. +// For these, configure the struct to encode/decode the keys as numbers (instead of string). +// This is done with the int,uint or float option on the _struct field (see above). +// +// However, struct values may encode as arrays. This happens when: +// - StructToArray Encode option is set, OR +// - the tag on the _struct field sets the "toarray" option +// +// Note that omitempty is ignored when encoding struct values as arrays, +// as an entry must be encoded for each field, to maintain its position. +// +// Values with types that implement MapBySlice are encoded as stream maps. +// +// The empty values (for omitempty option) are false, 0, any nil pointer +// or interface value, and any array, slice, map, or string of length zero. +// +// Anonymous fields are encoded inline except: +// - the struct tag specifies a replacement name (first value) +// - the field is of an interface type +// +// Examples: +// +// // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below. +// type MyStruct struct { +// _struct bool `codec:",omitempty"` //set omitempty for every field +// Field1 string `codec:"-"` //skip this field +// Field2 int `codec:"myName"` //Use key "myName" in encode stream +// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty. +// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty. +// io.Reader //use key "Reader". +// MyStruct `codec:"my1" //use key "my1". +// MyStruct //inline it +// ... +// } +// +// type MyStruct struct { +// _struct bool `codec:",toarray"` //encode struct as an array +// } +// +// type MyStruct struct { +// _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys +// Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1) +// Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2) +// } +// +// The mode of encoding is based on the type of the value. When a value is seen: +// - If a Selfer, call its CodecEncodeSelf method +// - If an extension is registered for it, call that extension function +// - If implements encoding.(Binary|Text|JSON)Marshaler, call Marshal(Binary|Text|JSON) method +// - Else encode it based on its reflect.Kind +// +// Note that struct field names and keys in map[string]XXX will be treated as symbols. +// Some formats support symbols (e.g. binc) and will properly encode the string +// only once in the stream, and use a tag to refer to it thereafter. +func (e *Encoder) Encode(v interface{}) (err error) { + // tried to use closure, as runtime optimizes defer with no params. + // This seemed to be causing weird issues (like circular reference found, unexpected panic, etc). + // Also, see https://github.com/golang/go/issues/14939#issuecomment-417836139 + // defer func() { e.deferred(&err) }() } + // { x, y := e, &err; defer func() { x.deferred(y) }() } + if e.err != nil { + return e.err + } + if recoverPanicToErr { + defer func() { + // if error occurred during encoding, return that error; + // else if error occurred on end'ing (i.e. during flush), return that error. + err = e.w.endErr() + x := recover() + if x == nil { + e.err = err + } else { + panicValToErr(e, x, &e.err) + err = e.err + } + }() + } + + // defer e.deferred(&err) + e.mustEncode(v) + return +} + +// MustEncode is like Encode, but panics if unable to Encode. +// This provides insight to the code location that triggered the error. +func (e *Encoder) MustEncode(v interface{}) { + if e.err != nil { + panic(e.err) + } + e.mustEncode(v) +} + +func (e *Encoder) mustEncode(v interface{}) { + if e.wf == nil { + e.encode(v) + e.e.atEndOfEncode() + e.w.end() + return + } + + if e.wf.buf == nil { + e.wf.buf = e.wf.bytesBufPooler.get(e.wf.sz) + } + e.wf.calls++ + + e.encode(v) + + e.wf.calls-- + + if e.wf.calls == 0 { + e.e.atEndOfEncode() + e.w.end() + if !e.h.ExplicitRelease { + e.wf.release() + } + } +} + +// func (e *Encoder) deferred(err1 *error) { +// e.w.end() +// if recoverPanicToErr { +// if x := recover(); x != nil { +// panicValToErr(e, x, err1) +// panicValToErr(e, x, &e.err) +// } +// } +// } + +//go:noinline -- as it is run by finalizer +func (e *Encoder) finalize() { + // xdebugf("finalizing Encoder") + e.Release() +} + +// Release releases shared (pooled) resources. +// +// It is important to call Release() when done with an Encoder, so those resources +// are released instantly for use by subsequently created Encoders. +func (e *Encoder) Release() { + if e.wf != nil { + e.wf.release() + } +} + +func (e *Encoder) encode(iv interface{}) { + // a switch with only concrete types can be optimized. + // consequently, we deal with nil and interfaces outside the switch. + + if iv == nil || definitelyNil(iv) { + e.e.EncodeNil() + return + } + + switch v := iv.(type) { + // case nil: + // case Selfer: + case Raw: + e.rawBytes(v) + case reflect.Value: + e.encodeValue(v, nil, true) + + case string: + if e.h.StringToRaw { + e.e.EncodeStringBytesRaw(bytesView(v)) + } else { + e.e.EncodeStringEnc(cUTF8, v) + } + case bool: + e.e.EncodeBool(v) + case int: + e.e.EncodeInt(int64(v)) + case int8: + e.e.EncodeInt(int64(v)) + case int16: + e.e.EncodeInt(int64(v)) + case int32: + e.e.EncodeInt(int64(v)) + case int64: + e.e.EncodeInt(v) + case uint: + e.e.EncodeUint(uint64(v)) + case uint8: + e.e.EncodeUint(uint64(v)) + case uint16: + e.e.EncodeUint(uint64(v)) + case uint32: + e.e.EncodeUint(uint64(v)) + case uint64: + e.e.EncodeUint(v) + case uintptr: + e.e.EncodeUint(uint64(v)) + case float32: + e.e.EncodeFloat32(v) + case float64: + e.e.EncodeFloat64(v) + case time.Time: + e.e.EncodeTime(v) + case []uint8: + e.e.EncodeStringBytesRaw(v) + + case *Raw: + e.rawBytes(*v) + + case *string: + if e.h.StringToRaw { + e.e.EncodeStringBytesRaw(bytesView(*v)) + } else { + e.e.EncodeStringEnc(cUTF8, *v) + } + case *bool: + e.e.EncodeBool(*v) + case *int: + e.e.EncodeInt(int64(*v)) + case *int8: + e.e.EncodeInt(int64(*v)) + case *int16: + e.e.EncodeInt(int64(*v)) + case *int32: + e.e.EncodeInt(int64(*v)) + case *int64: + e.e.EncodeInt(*v) + case *uint: + e.e.EncodeUint(uint64(*v)) + case *uint8: + e.e.EncodeUint(uint64(*v)) + case *uint16: + e.e.EncodeUint(uint64(*v)) + case *uint32: + e.e.EncodeUint(uint64(*v)) + case *uint64: + e.e.EncodeUint(*v) + case *uintptr: + e.e.EncodeUint(uint64(*v)) + case *float32: + e.e.EncodeFloat32(*v) + case *float64: + e.e.EncodeFloat64(*v) + case *time.Time: + e.e.EncodeTime(*v) + + case *[]uint8: + e.e.EncodeStringBytesRaw(*v) + + default: + if v, ok := iv.(Selfer); ok { + v.CodecEncodeSelf(e) + } else if !fastpathEncodeTypeSwitch(iv, e) { + // checkfastpath=true (not false), as underlying slice/map type may be fast-path + e.encodeValue(reflect.ValueOf(iv), nil, true) + } + } +} + +func (e *Encoder) encodeValue(rv reflect.Value, fn *codecFn, checkFastpath bool) { + // if a valid fn is passed, it MUST BE for the dereferenced type of rv + var sptr uintptr + var rvp reflect.Value + var rvpValid bool +TOP: + switch rv.Kind() { + case reflect.Ptr: + if rv.IsNil() { + e.e.EncodeNil() + return + } + rvpValid = true + rvp = rv + rv = rv.Elem() + if e.h.CheckCircularRef && rv.Kind() == reflect.Struct { + // TODO: Movable pointers will be an issue here. Future problem. + sptr = rv.UnsafeAddr() + break TOP + } + goto TOP + case reflect.Interface: + if rv.IsNil() { + e.e.EncodeNil() + return + } + rv = rv.Elem() + goto TOP + case reflect.Slice, reflect.Map: + if rv.IsNil() { + e.e.EncodeNil() + return + } + case reflect.Invalid, reflect.Func: + e.e.EncodeNil() + return + } + + if sptr != 0 && (&e.ci).add(sptr) { + e.errorf("circular reference found: # %d", sptr) + } + + if fn == nil { + rt := rv.Type() + // always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer + fn = e.h.fn(rt, checkFastpath, true) + } + if fn.i.addrE { + if rvpValid { + fn.fe(e, &fn.i, rvp) + } else if rv.CanAddr() { + fn.fe(e, &fn.i, rv.Addr()) + } else { + rv2 := reflect.New(rv.Type()) + rv2.Elem().Set(rv) + fn.fe(e, &fn.i, rv2) + } + } else { + fn.fe(e, &fn.i, rv) + } + if sptr != 0 { + (&e.ci).remove(sptr) + } +} + +// func (e *Encoder) marshal(bs []byte, fnerr error, asis bool, c charEncoding) { +// if fnerr != nil { +// panic(fnerr) +// } +// if bs == nil { +// e.e.EncodeNil() +// } else if asis { +// e.asis(bs) +// } else { +// e.e.EncodeStringBytesRaw(bs) +// } +// } + +func (e *Encoder) marshalUtf8(bs []byte, fnerr error) { + if fnerr != nil { + panic(fnerr) + } + if bs == nil { + e.e.EncodeNil() + } else { + e.e.EncodeStringEnc(cUTF8, stringView(bs)) + } +} + +func (e *Encoder) marshalAsis(bs []byte, fnerr error) { + if fnerr != nil { + panic(fnerr) + } + if bs == nil { + e.e.EncodeNil() + } else { + e.asis(bs) + } +} + +func (e *Encoder) marshalRaw(bs []byte, fnerr error) { + if fnerr != nil { + panic(fnerr) + } + if bs == nil { + e.e.EncodeNil() + } else { + e.e.EncodeStringBytesRaw(bs) + } +} + +func (e *Encoder) asis(v []byte) { + if e.isas { + e.as.EncodeAsis(v) + } else { + e.w.writeb(v) + } +} + +func (e *Encoder) rawBytes(vv Raw) { + v := []byte(vv) + if !e.h.Raw { + e.errorf("Raw values cannot be encoded: %v", v) + } + e.asis(v) +} + +func (e *Encoder) wrapErr(v interface{}, err *error) { + *err = encodeError{codecError{name: e.hh.Name(), err: v}} +} + +func encStructFieldKey(encName string, ee encDriver, w *encWriterSwitch, + keyType valueType, encNameAsciiAlphaNum bool, js bool) { + var m must + // use if-else-if, not switch (which compiles to binary-search) + // since keyType is typically valueTypeString, branch prediction is pretty good. + if keyType == valueTypeString { + if js && encNameAsciiAlphaNum { // keyType == valueTypeString + // w.writen1('"') + // w.writestr(encName) + // w.writen1('"') + // ---- + // w.writestr(`"` + encName + `"`) + // ---- + // do concat myself, so it is faster than the generic string concat + b := make([]byte, len(encName)+2) + copy(b[1:], encName) + b[0] = '"' + b[len(b)-1] = '"' + w.writeb(b) + } else { // keyType == valueTypeString + ee.EncodeStringEnc(cUTF8, encName) + } + } else if keyType == valueTypeInt { + ee.EncodeInt(m.Int(strconv.ParseInt(encName, 10, 64))) + } else if keyType == valueTypeUint { + ee.EncodeUint(m.Uint(strconv.ParseUint(encName, 10, 64))) + } else if keyType == valueTypeFloat { + ee.EncodeFloat64(m.Float(strconv.ParseFloat(encName, 64))) + } +} + +// func encStringAsRawBytesMaybe(ee encDriver, s string, stringToRaw bool) { +// if stringToRaw { +// ee.EncodeStringBytesRaw(bytesView(s)) +// } else { +// ee.EncodeStringEnc(cUTF8, s) +// } +// } diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/fast-path.not.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/fast-path.not.go new file mode 100644 index 00000000..93cb754a --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/fast-path.not.go @@ -0,0 +1,39 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +import "reflect" + +// fastpath was removed for safety reasons + +const fastpathEnabled = false + +func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { return false } +func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { return false } +func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { return false } +func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { return false } +func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool { return false } + +type fastpathT struct{} +type fastpathE struct { + rtid uintptr + rt reflect.Type + encfn func(*Encoder, *codecFnInfo, reflect.Value) + decfn func(*Decoder, *codecFnInfo, reflect.Value) +} +type fastpathA [0]fastpathE + +func (x fastpathA) index(rtid uintptr) int { return -1 } + +func (_ fastpathT) DecSliceUint8V(v []uint8, canChange bool, d *Decoder) (_ []uint8, changed bool) { + fn := d.h.fn(uint8SliceTyp, true, true) + d.kSlice(&fn.i, reflect.ValueOf(&v).Elem()) + return v, true +} + +var fastpathAV fastpathA +var fastpathTV fastpathT + +// ---- +// type TestMammoth2Wrapper struct{} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-array.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-array.go.tmpl new file mode 100644 index 00000000..790e914e --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-array.go.tmpl @@ -0,0 +1,78 @@ +{{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }} +{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}} +var {{var "c"}} bool {{/* // changed */}} +_ = {{var "c"}}{{end}} +if {{var "l"}} == 0 { + {{if isSlice }}if {{var "v"}} == nil { + {{var "v"}} = []{{ .Typ }}{} + {{var "c"}} = true + } else if len({{var "v"}}) != 0 { + {{var "v"}} = {{var "v"}}[:0] + {{var "c"}} = true + } {{else if isChan }}if {{var "v"}} == nil { + {{var "v"}} = make({{ .CTyp }}, 0) + {{var "c"}} = true + } {{end}} +} else { + {{var "hl"}} := {{var "l"}} > 0 + var {{var "rl"}} int + _ = {{var "rl"}} + {{if isSlice }} if {{var "hl"}} { + if {{var "l"}} > cap({{var "v"}}) { + {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) + if {{var "rl"}} <= cap({{var "v"}}) { + {{var "v"}} = {{var "v"}}[:{{var "rl"}}] + } else { + {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) + } + {{var "c"}} = true + } else if {{var "l"}} != len({{var "v"}}) { + {{var "v"}} = {{var "v"}}[:{{var "l"}}] + {{var "c"}} = true + } + } {{end}} + var {{var "j"}} int + // var {{var "dn"}} bool + for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { // bounds-check-elimination + {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil { + if {{var "hl"}} { + {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) + } else { + {{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}} + } + {{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}}) + {{var "c"}} = true + }{{end}} + {{var "h"}}.ElemContainerState({{var "j"}}) + {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */}} + {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }} + {{ decLineVar $x }} + {{var "v"}} <- {{ $x }} + // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this + {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */}} + var {{var "db"}} bool + if {{var "j"}} >= len({{var "v"}}) { + {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }}) + {{var "c"}} = true + {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true + {{end}} + } + if {{var "db"}} { + z.DecSwallow() + } else { + {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }} + } + {{end}} + } + {{if isSlice}} if {{var "j"}} < len({{var "v"}}) { + {{var "v"}} = {{var "v"}}[:{{var "j"}}] + {{var "c"}} = true + } else if {{var "j"}} == 0 && {{var "v"}} == nil { + {{var "v"}} = make([]{{ .Typ }}, 0) + {{var "c"}} = true + } {{end}} +} +{{var "h"}}.End() +{{if not isArray }}if {{var "c"}} { + *{{ .Varname }} = {{var "v"}} +}{{end}} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-map.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-map.go.tmpl new file mode 100644 index 00000000..8323b549 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-dec-map.go.tmpl @@ -0,0 +1,42 @@ +{{var "v"}} := *{{ .Varname }} +{{var "l"}} := r.ReadMapStart() +{{var "bh"}} := z.DecBasicHandle() +if {{var "v"}} == nil { + {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }}) + {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}}) + *{{ .Varname }} = {{var "v"}} +} +var {{var "mk"}} {{ .KTyp }} +var {{var "mv"}} {{ .Typ }} +var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool +if {{var "bh"}}.MapValueReset { + {{if decElemKindPtr}}{{var "mg"}} = true + {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } + {{else if not decElemKindImmutable}}{{var "mg"}} = true + {{end}} } +if {{var "l"}} != 0 { +{{var "hl"}} := {{var "l"}} > 0 + for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { + r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}} + {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} +{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} { + {{var "mk"}} = string({{var "bv"}}) + }{{ end }}{{if decElemKindPtr}} + {{var "ms"}} = true{{end}} + if {{var "mg"}} { + {{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}] + if {{var "mok"}} { + {{var "ms"}} = false + } {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}} + } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}} + r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}} + {{var "mdn"}} = false + {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }} + if {{var "mdn"}} { + if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} } + } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil { + {{var "v"}}[{{var "mk"}}] = {{var "mv"}} + } +} +} // else len==0: TODO: Should we clear map entries? +r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-enc-chan.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-enc-chan.go.tmpl new file mode 100644 index 00000000..4249588a --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-enc-chan.go.tmpl @@ -0,0 +1,27 @@ +{{.Label}}: +switch timeout{{.Sfx}} := z.EncBasicHandle().ChanRecvTimeout; { +case timeout{{.Sfx}} == 0: // only consume available + for { + select { + case b{{.Sfx}} := <-{{.Chan}}: + {{ .Slice }} = append({{.Slice}}, b{{.Sfx}}) + default: + break {{.Label}} + } + } +case timeout{{.Sfx}} > 0: // consume until timeout + tt{{.Sfx}} := time.NewTimer(timeout{{.Sfx}}) + for { + select { + case b{{.Sfx}} := <-{{.Chan}}: + {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) + case <-tt{{.Sfx}}.C: + // close(tt.C) + break {{.Label}} + } + } +default: // consume until close + for b{{.Sfx}} := range {{.Chan}} { + {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) + } +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.generated.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.generated.go new file mode 100644 index 00000000..2a7d1aab --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.generated.go @@ -0,0 +1,343 @@ +// comment this out // + build ignore + +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +// Code generated from gen-helper.go.tmpl - DO NOT EDIT. + +package codec + +import ( + "encoding" + "reflect" +) + +// GenVersion is the current version of codecgen. +const GenVersion = 10 + +// This file is used to generate helper code for codecgen. +// The values here i.e. genHelper(En|De)coder are not to be used directly by +// library users. They WILL change continuously and without notice. +// +// To help enforce this, we create an unexported type with exported members. +// The only way to get the type is via the one exported type that we control (somewhat). +// +// When static codecs are created for types, they will use this value +// to perform encoding or decoding of primitives or known slice or map types. + +// GenHelperEncoder is exported so that it can be used externally by codecgen. +// +// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. +func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) { + ge = genHelperEncoder{e: e} + ee = genHelperEncDriver{encDriver: e.e} + return +} + +// GenHelperDecoder is exported so that it can be used externally by codecgen. +// +// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. +func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) { + gd = genHelperDecoder{d: d} + dd = genHelperDecDriver{decDriver: d.d} + return +} + +type genHelperEncDriver struct { + encDriver +} + +func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {} +func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) { + encStructFieldKey(s, x.encDriver, nil, keyType, false, false) +} +func (x genHelperEncDriver) EncodeSymbol(s string) { + x.encDriver.EncodeStringEnc(cUTF8, s) +} + +type genHelperDecDriver struct { + decDriver + C checkOverflow +} + +func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {} +func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[decScratchByteArrayLen]byte) []byte { + return decStructFieldKey(x.decDriver, keyType, buf) +} +func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) { + return x.C.IntV(x.decDriver.DecodeInt64(), bitsize) +} +func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) { + return x.C.UintV(x.decDriver.DecodeUint64(), bitsize) +} +func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { + f = x.DecodeFloat64() + if chkOverflow32 && chkOvf.Float32(f) { + panicv.errorf("float32 overflow: %v", f) + } + return +} +func (x genHelperDecDriver) DecodeFloat32As64() (f float64) { + f = x.DecodeFloat64() + if chkOvf.Float32(f) { + panicv.errorf("float32 overflow: %v", f) + } + return +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +type genHelperEncoder struct { + M must + e *Encoder + F fastpathT +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +type genHelperDecoder struct { + C checkOverflow + d *Decoder + F fastpathT +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncBasicHandle() *BasicHandle { + return f.e.h +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncBinary() bool { + return f.e.be // f.e.hh.isBinaryEncoding() +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) IsJSONHandle() bool { + return f.e.js +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncFallback(iv interface{}) { + // println(">>>>>>>>> EncFallback") + // f.e.encodeI(iv, false, false) + f.e.encodeValue(reflect.ValueOf(iv), nil, false) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) { + bs, fnerr := iv.MarshalText() + f.e.marshalUtf8(bs, fnerr) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) { + bs, fnerr := iv.MarshalJSON() + f.e.marshalAsis(bs, fnerr) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) { + bs, fnerr := iv.MarshalBinary() + f.e.marshalRaw(bs, fnerr) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: builtin no longer supported - so we make this method a no-op, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperEncoder) TimeRtidIfBinc() (v uintptr) { return } + +// func (f genHelperEncoder) TimeRtidIfBinc() uintptr { +// if _, ok := f.e.hh.(*BincHandle); ok { +// return timeTypId +// } +// } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) I2Rtid(v interface{}) uintptr { + return i2rtid(v) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { + return f.e.h.getExt(rtid) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) { + f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) WriteStr(s string) { + f.e.w.writestr(s) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) BytesView(v string) []byte { return bytesView(v) } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperEncoder) HasExtensions() bool { + return len(f.e.h.extHandle) != 0 +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperEncoder) EncExt(v interface{}) (r bool) { + if xfFn := f.e.h.getExt(i2rtid(v)); xfFn != nil { + f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) + return true + } + return false +} + +// ---------------- DECODER FOLLOWS ----------------- + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecBasicHandle() *BasicHandle { + return f.d.h +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecBinary() bool { + return f.d.be // f.d.hh.isBinaryEncoding() +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecSwallow() { f.d.swallow() } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecScratchBuffer() []byte { + return f.d.b[:] +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte { + return &f.d.b +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) { + // println(">>>>>>>>> DecFallback") + rv := reflect.ValueOf(iv) + if chkPtr { + rv = f.d.ensureDecodeable(rv) + } + f.d.decodeValue(rv, nil, false) + // f.d.decodeValueFallback(rv) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) { + return f.d.decSliceHelperStart() +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) { + f.d.structFieldNotFound(index, name) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) { + f.d.arrayCannotExpand(sliceLen, streamLen) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { + fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes()) + if fnerr != nil { + panic(fnerr) + } +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { + // bs := f.dd.DecodeStringAsBytes() + // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. + fnerr := tm.UnmarshalJSON(f.d.nextValueBytes()) + if fnerr != nil { + panic(fnerr) + } +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { + fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true)) + if fnerr != nil { + panic(fnerr) + } +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: builtin no longer supported - so we make this method a no-op, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) TimeRtidIfBinc() (v uintptr) { return } + +// func (f genHelperDecoder) TimeRtidIfBinc() uintptr { +// // Note: builtin is no longer supported - so make this a no-op +// if _, ok := f.d.hh.(*BincHandle); ok { +// return timeTypId +// } +// return 0 +// } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) IsJSONHandle() bool { + return f.d.js +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) I2Rtid(v interface{}) uintptr { + return i2rtid(v) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { + return f.d.h.getExt(rtid) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) { + f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) HasExtensions() bool { + return len(f.d.h.extHandle) != 0 +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) DecExt(v interface{}) (r bool) { + if xfFn := f.d.h.getExt(i2rtid(v)); xfFn != nil { + f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) + return true + } + return false +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) { + return decInferLen(clen, maxlen, unit) +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: no longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) } diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.go.tmpl new file mode 100644 index 00000000..f5d0634e --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-helper.go.tmpl @@ -0,0 +1,308 @@ +// comment this out // + build ignore + +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +// Code generated from gen-helper.go.tmpl - DO NOT EDIT. + +package codec + +import ( + "encoding" + "reflect" +) + +// GenVersion is the current version of codecgen. +const GenVersion = {{ .Version }} + +// This file is used to generate helper code for codecgen. +// The values here i.e. genHelper(En|De)coder are not to be used directly by +// library users. They WILL change continuously and without notice. +// +// To help enforce this, we create an unexported type with exported members. +// The only way to get the type is via the one exported type that we control (somewhat). +// +// When static codecs are created for types, they will use this value +// to perform encoding or decoding of primitives or known slice or map types. + +// GenHelperEncoder is exported so that it can be used externally by codecgen. +// +// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. +func GenHelperEncoder(e *Encoder) (ge genHelperEncoder, ee genHelperEncDriver) { + ge = genHelperEncoder{e: e} + ee = genHelperEncDriver{encDriver: e.e} + return +} + +// GenHelperDecoder is exported so that it can be used externally by codecgen. +// +// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE. +func GenHelperDecoder(d *Decoder) (gd genHelperDecoder, dd genHelperDecDriver) { + gd = genHelperDecoder{d: d} + dd = genHelperDecDriver{decDriver: d.d} + return +} + +type genHelperEncDriver struct { + encDriver +} + +func (x genHelperEncDriver) EncodeBuiltin(rt uintptr, v interface{}) {} +func (x genHelperEncDriver) EncStructFieldKey(keyType valueType, s string) { + encStructFieldKey(s, x.encDriver, nil, keyType, false, false) +} +func (x genHelperEncDriver) EncodeSymbol(s string) { + x.encDriver.EncodeStringEnc(cUTF8, s) +} + +type genHelperDecDriver struct { + decDriver + C checkOverflow +} + +func (x genHelperDecDriver) DecodeBuiltin(rt uintptr, v interface{}) {} +func (x genHelperDecDriver) DecStructFieldKey(keyType valueType, buf *[decScratchByteArrayLen]byte) []byte { + return decStructFieldKey(x.decDriver, keyType, buf) +} +func (x genHelperDecDriver) DecodeInt(bitsize uint8) (i int64) { + return x.C.IntV(x.decDriver.DecodeInt64(), bitsize) +} +func (x genHelperDecDriver) DecodeUint(bitsize uint8) (ui uint64) { + return x.C.UintV(x.decDriver.DecodeUint64(), bitsize) +} +func (x genHelperDecDriver) DecodeFloat(chkOverflow32 bool) (f float64) { + f = x.DecodeFloat64() + if chkOverflow32 && chkOvf.Float32(f) { + panicv.errorf("float32 overflow: %v", f) + } + return +} +func (x genHelperDecDriver) DecodeFloat32As64() (f float64) { + f = x.DecodeFloat64() + if chkOvf.Float32(f) { + panicv.errorf("float32 overflow: %v", f) + } + return +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +type genHelperEncoder struct { + M must + e *Encoder + F fastpathT +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +type genHelperDecoder struct { + C checkOverflow + d *Decoder + F fastpathT +} + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncBasicHandle() *BasicHandle { + return f.e.h +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncBinary() bool { + return f.e.be // f.e.hh.isBinaryEncoding() +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) IsJSONHandle() bool { + return f.e.js +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncFallback(iv interface{}) { + // println(">>>>>>>>> EncFallback") + // f.e.encodeI(iv, false, false) + f.e.encodeValue(reflect.ValueOf(iv), nil, false) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncTextMarshal(iv encoding.TextMarshaler) { + bs, fnerr := iv.MarshalText() + f.e.marshalUtf8(bs, fnerr) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncJSONMarshal(iv jsonMarshaler) { + bs, fnerr := iv.MarshalJSON() + f.e.marshalAsis(bs, fnerr) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncBinaryMarshal(iv encoding.BinaryMarshaler) { + bs, fnerr := iv.MarshalBinary() + f.e.marshalRaw(bs, fnerr) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncRaw(iv Raw) { f.e.rawBytes(iv) } +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: builtin no longer supported - so we make this method a no-op, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperEncoder) TimeRtidIfBinc() (v uintptr) { return } +// func (f genHelperEncoder) TimeRtidIfBinc() uintptr { +// if _, ok := f.e.hh.(*BincHandle); ok { +// return timeTypId +// } +// } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) I2Rtid(v interface{}) uintptr { + return i2rtid(v) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { + return f.e.h.getExt(rtid) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) EncExtension(v interface{}, xfFn *extTypeTagFn) { + f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) WriteStr(s string) { + f.e.w.writestr(s) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperEncoder) BytesView(v string) []byte { return bytesView(v) } +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperEncoder) HasExtensions() bool { + return len(f.e.h.extHandle) != 0 +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperEncoder) EncExt(v interface{}) (r bool) { + if xfFn := f.e.h.getExt(i2rtid(v)); xfFn != nil { + f.e.e.EncodeExt(v, xfFn.tag, xfFn.ext, f.e) + return true + } + return false +} + +// ---------------- DECODER FOLLOWS ----------------- + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecBasicHandle() *BasicHandle { + return f.d.h +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecBinary() bool { + return f.d.be // f.d.hh.isBinaryEncoding() +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecSwallow() { f.d.swallow() } +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecScratchBuffer() []byte { + return f.d.b[:] +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecScratchArrayBuffer() *[decScratchByteArrayLen]byte { + return &f.d.b +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecFallback(iv interface{}, chkPtr bool) { + // println(">>>>>>>>> DecFallback") + rv := reflect.ValueOf(iv) + if chkPtr { + rv = f.d.ensureDecodeable(rv) + } + f.d.decodeValue(rv, nil, false) + // f.d.decodeValueFallback(rv) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecSliceHelperStart() (decSliceHelper, int) { + return f.d.decSliceHelperStart() +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecStructFieldNotFound(index int, name string) { + f.d.structFieldNotFound(index, name) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecArrayCannotExpand(sliceLen, streamLen int) { + f.d.arrayCannotExpand(sliceLen, streamLen) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecTextUnmarshal(tm encoding.TextUnmarshaler) { + fnerr := tm.UnmarshalText(f.d.d.DecodeStringAsBytes()) + if fnerr != nil { + panic(fnerr) + } +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecJSONUnmarshal(tm jsonUnmarshaler) { + // bs := f.dd.DecodeStringAsBytes() + // grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself. + fnerr := tm.UnmarshalJSON(f.d.nextValueBytes()) + if fnerr != nil { + panic(fnerr) + } +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecBinaryUnmarshal(bm encoding.BinaryUnmarshaler) { + fnerr := bm.UnmarshalBinary(f.d.d.DecodeBytes(nil, true)) + if fnerr != nil { + panic(fnerr) + } +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecRaw() []byte { return f.d.rawBytes() } +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: builtin no longer supported - so we make this method a no-op, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) TimeRtidIfBinc() (v uintptr) { return } +// func (f genHelperDecoder) TimeRtidIfBinc() uintptr { +// // Note: builtin is no longer supported - so make this a no-op +// if _, ok := f.d.hh.(*BincHandle); ok { +// return timeTypId +// } +// return 0 +// } + +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) IsJSONHandle() bool { + return f.d.js +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) I2Rtid(v interface{}) uintptr { + return i2rtid(v) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) Extension(rtid uintptr) (xfn *extTypeTagFn) { + return f.d.h.getExt(rtid) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecExtension(v interface{}, xfFn *extTypeTagFn) { + f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) HasExtensions() bool { + return len(f.d.h.extHandle) != 0 +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: No longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) DecExt(v interface{}) (r bool) { + if xfFn := f.d.h.getExt(i2rtid(v)); xfFn != nil { + f.d.d.DecodeExt(v, xfFn.tag, xfFn.ext) + return true + } + return false +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +func (f genHelperDecoder) DecInferLen(clen, maxlen, unit int) (rvlen int) { + return decInferLen(clen, maxlen, unit) +} +// FOR USE BY CODECGEN ONLY. IT *WILL* CHANGE WITHOUT NOTICE. *DO NOT USE* +// +// Deprecated: no longer used, +// but leave in-place so that old generated files continue to work without regeneration. +func (f genHelperDecoder) StringView(v []byte) string { return stringView(v) } + diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-internal.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-internal.go new file mode 100644 index 00000000..d3c51a53 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen-internal.go @@ -0,0 +1,284 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +import ( + "bytes" + "errors" + "go/format" + "io" + "io/ioutil" + "strings" + "sync" + "text/template" +) + +const genVersion = 10 + +func genInternalEncCommandAsString(s string, vname string) string { + switch s { + case "uint", "uint8", "uint16", "uint32", "uint64": + return "ee.EncodeUint(uint64(" + vname + "))" + case "int", "int8", "int16", "int32", "int64": + return "ee.EncodeInt(int64(" + vname + "))" + case "string": + return "if e.h.StringToRaw { ee.EncodeStringBytesRaw(bytesView(" + vname + ")) " + + "} else { ee.EncodeStringEnc(cUTF8, " + vname + ") }" + case "float32": + return "ee.EncodeFloat32(" + vname + ")" + case "float64": + return "ee.EncodeFloat64(" + vname + ")" + case "bool": + return "ee.EncodeBool(" + vname + ")" + // case "symbol": + // return "ee.EncodeSymbol(" + vname + ")" + default: + return "e.encode(" + vname + ")" + } +} + +func genInternalDecCommandAsString(s string) string { + switch s { + case "uint": + return "uint(chkOvf.UintV(dd.DecodeUint64(), uintBitsize))" + case "uint8": + return "uint8(chkOvf.UintV(dd.DecodeUint64(), 8))" + case "uint16": + return "uint16(chkOvf.UintV(dd.DecodeUint64(), 16))" + case "uint32": + return "uint32(chkOvf.UintV(dd.DecodeUint64(), 32))" + case "uint64": + return "dd.DecodeUint64()" + case "uintptr": + return "uintptr(chkOvf.UintV(dd.DecodeUint64(), uintBitsize))" + case "int": + return "int(chkOvf.IntV(dd.DecodeInt64(), intBitsize))" + case "int8": + return "int8(chkOvf.IntV(dd.DecodeInt64(), 8))" + case "int16": + return "int16(chkOvf.IntV(dd.DecodeInt64(), 16))" + case "int32": + return "int32(chkOvf.IntV(dd.DecodeInt64(), 32))" + case "int64": + return "dd.DecodeInt64()" + + case "string": + return "dd.DecodeString()" + case "float32": + return "float32(chkOvf.Float32V(dd.DecodeFloat64()))" + case "float64": + return "dd.DecodeFloat64()" + case "bool": + return "dd.DecodeBool()" + default: + panic(errors.New("gen internal: unknown type for decode: " + s)) + } +} + +func genInternalZeroValue(s string) string { + switch s { + case "interface{}", "interface {}": + return "nil" + case "bool": + return "false" + case "string": + return `""` + default: + return "0" + } +} + +var genInternalNonZeroValueIdx [5]uint64 +var genInternalNonZeroValueStrs = [2][5]string{ + {`"string-is-an-interface"`, "true", `"some-string"`, "11.1", "33"}, + {`"string-is-an-interface-2"`, "true", `"some-string-2"`, "22.2", "44"}, +} + +func genInternalNonZeroValue(s string) string { + switch s { + case "interface{}", "interface {}": + genInternalNonZeroValueIdx[0]++ + return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[0]%2][0] // return string, to remove ambiguity + case "bool": + genInternalNonZeroValueIdx[1]++ + return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[1]%2][1] + case "string": + genInternalNonZeroValueIdx[2]++ + return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[2]%2][2] + case "float32", "float64", "float", "double": + genInternalNonZeroValueIdx[3]++ + return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[3]%2][3] + default: + genInternalNonZeroValueIdx[4]++ + return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[4]%2][4] + } +} + +func genInternalSortType(s string, elem bool) string { + for _, v := range [...]string{"int", "uint", "float", "bool", "string"} { + if strings.HasPrefix(s, v) { + if elem { + if v == "int" || v == "uint" || v == "float" { + return v + "64" + } else { + return v + } + } + return v + "Slice" + } + } + panic("sorttype: unexpected type: " + s) +} + +type genV struct { + // genV is either a primitive (Primitive != "") or a map (MapKey != "") or a slice + MapKey string + Elem string + Primitive string + Size int +} + +type genInternal struct { + Version int + Values []genV +} + +func (x genInternal) FastpathLen() (l int) { + for _, v := range x.Values { + if v.Primitive == "" && !(v.MapKey == "" && v.Elem == "uint8") { + l++ + } + } + return +} + +// var genInternalMu sync.Mutex +var genInternalV = genInternal{Version: genVersion} +var genInternalTmplFuncs template.FuncMap +var genInternalOnce sync.Once + +func genInternalInit() { + types := [...]string{ + "interface{}", + "string", + "float32", + "float64", + "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "uintptr", + "int", + "int8", + "int16", + "int32", + "int64", + "bool", + } + // keep as slice, so it is in specific iteration order. + // Initial order was uint64, string, interface{}, int, int64 + mapvaltypes := [...]string{ + "interface{}", + "string", + "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "uintptr", + "int", + "int8", + "int16", + "int32", + "int64", + "float32", + "float64", + "bool", + } + wordSizeBytes := int(intBitsize) / 8 + + mapvaltypes2 := map[string]int{ + "interface{}": 2 * wordSizeBytes, + "string": 2 * wordSizeBytes, + "uint": 1 * wordSizeBytes, + "uint8": 1, + "uint16": 2, + "uint32": 4, + "uint64": 8, + "uintptr": 1 * wordSizeBytes, + "int": 1 * wordSizeBytes, + "int8": 1, + "int16": 2, + "int32": 4, + "int64": 8, + "float32": 4, + "float64": 8, + "bool": 1, + } + var gt = genInternal{Version: genVersion} + + // For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function + for _, s := range types { + gt.Values = append(gt.Values, genV{Primitive: s, Size: mapvaltypes2[s]}) + // if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already. + // gt.Values = append(gt.Values, genV{Elem: s, Size: mapvaltypes2[s]}) + // } + gt.Values = append(gt.Values, genV{Elem: s, Size: mapvaltypes2[s]}) + if _, ok := mapvaltypes2[s]; !ok { + gt.Values = append(gt.Values, genV{MapKey: s, Elem: s, Size: 2 * mapvaltypes2[s]}) + } + for _, ms := range mapvaltypes { + gt.Values = append(gt.Values, genV{MapKey: s, Elem: ms, Size: mapvaltypes2[s] + mapvaltypes2[ms]}) + } + } + + funcs := make(template.FuncMap) + // funcs["haspfx"] = strings.HasPrefix + funcs["encmd"] = genInternalEncCommandAsString + funcs["decmd"] = genInternalDecCommandAsString + funcs["zerocmd"] = genInternalZeroValue + funcs["nonzerocmd"] = genInternalNonZeroValue + funcs["hasprefix"] = strings.HasPrefix + funcs["sorttype"] = genInternalSortType + + genInternalV = gt + genInternalTmplFuncs = funcs +} + +// genInternalGoFile is used to generate source files from templates. +// It is run by the program author alone. +// Unfortunately, it has to be exported so that it can be called from a command line tool. +// *** DO NOT USE *** +func genInternalGoFile(r io.Reader, w io.Writer) (err error) { + genInternalOnce.Do(genInternalInit) + + gt := genInternalV + + t := template.New("").Funcs(genInternalTmplFuncs) + + tmplstr, err := ioutil.ReadAll(r) + if err != nil { + return + } + + if t, err = t.Parse(string(tmplstr)); err != nil { + return + } + + var out bytes.Buffer + err = t.Execute(&out, gt) + if err != nil { + return + } + + bout, err := format.Source(out.Bytes()) + if err != nil { + w.Write(out.Bytes()) // write out if error, so we can still see. + // w.Write(bout) // write out if error, as much as possible, so we can still see. + return + } + w.Write(bout) + return +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.generated.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.generated.go new file mode 100644 index 00000000..2178efd5 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.generated.go @@ -0,0 +1,165 @@ +//go:build codecgen.exec +// +build codecgen.exec + +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +// DO NOT EDIT. THIS FILE IS AUTO-GENERATED FROM gen-dec-(map|array).go.tmpl + +const genDecMapTmpl = ` +{{var "v"}} := *{{ .Varname }} +{{var "l"}} := r.ReadMapStart() +{{var "bh"}} := z.DecBasicHandle() +if {{var "v"}} == nil { + {{var "rl"}} := z.DecInferLen({{var "l"}}, {{var "bh"}}.MaxInitLen, {{ .Size }}) + {{var "v"}} = make(map[{{ .KTyp }}]{{ .Typ }}, {{var "rl"}}) + *{{ .Varname }} = {{var "v"}} +} +var {{var "mk"}} {{ .KTyp }} +var {{var "mv"}} {{ .Typ }} +var {{var "mg"}}, {{var "mdn"}} {{if decElemKindPtr}}, {{var "ms"}}, {{var "mok"}}{{end}} bool +if {{var "bh"}}.MapValueReset { + {{if decElemKindPtr}}{{var "mg"}} = true + {{else if decElemKindIntf}}if !{{var "bh"}}.InterfaceReset { {{var "mg"}} = true } + {{else if not decElemKindImmutable}}{{var "mg"}} = true + {{end}} } +if {{var "l"}} != 0 { +{{var "hl"}} := {{var "l"}} > 0 + for {{var "j"}} := 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { + r.ReadMapElemKey() {{/* z.DecSendContainerState(codecSelfer_containerMapKey{{ .Sfx }}) */}} + {{ $x := printf "%vmk%v" .TempVar .Rand }}{{ decLineVarK $x }} +{{ if eq .KTyp "interface{}" }}{{/* // special case if a byte array. */}}if {{var "bv"}}, {{var "bok"}} := {{var "mk"}}.([]byte); {{var "bok"}} { + {{var "mk"}} = string({{var "bv"}}) + }{{ end }}{{if decElemKindPtr}} + {{var "ms"}} = true{{end}} + if {{var "mg"}} { + {{if decElemKindPtr}}{{var "mv"}}, {{var "mok"}} = {{var "v"}}[{{var "mk"}}] + if {{var "mok"}} { + {{var "ms"}} = false + } {{else}}{{var "mv"}} = {{var "v"}}[{{var "mk"}}] {{end}} + } {{if not decElemKindImmutable}}else { {{var "mv"}} = {{decElemZero}} }{{end}} + r.ReadMapElemValue() {{/* z.DecSendContainerState(codecSelfer_containerMapValue{{ .Sfx }}) */}} + {{var "mdn"}} = false + {{ $x := printf "%vmv%v" .TempVar .Rand }}{{ $y := printf "%vmdn%v" .TempVar .Rand }}{{ decLineVar $x $y }} + if {{var "mdn"}} { + if {{ var "bh" }}.DeleteOnNilMapValue { delete({{var "v"}}, {{var "mk"}}) } else { {{var "v"}}[{{var "mk"}}] = {{decElemZero}} } + } else if {{if decElemKindPtr}} {{var "ms"}} && {{end}} {{var "v"}} != nil { + {{var "v"}}[{{var "mk"}}] = {{var "mv"}} + } +} +} // else len==0: TODO: Should we clear map entries? +r.ReadMapEnd() {{/* z.DecSendContainerState(codecSelfer_containerMapEnd{{ .Sfx }}) */}} +` + +const genDecListTmpl = ` +{{var "v"}} := {{if not isArray}}*{{end}}{{ .Varname }} +{{var "h"}}, {{var "l"}} := z.DecSliceHelperStart() {{/* // helper, containerLenS */}}{{if not isArray}} +var {{var "c"}} bool {{/* // changed */}} +_ = {{var "c"}}{{end}} +if {{var "l"}} == 0 { + {{if isSlice }}if {{var "v"}} == nil { + {{var "v"}} = []{{ .Typ }}{} + {{var "c"}} = true + } else if len({{var "v"}}) != 0 { + {{var "v"}} = {{var "v"}}[:0] + {{var "c"}} = true + } {{else if isChan }}if {{var "v"}} == nil { + {{var "v"}} = make({{ .CTyp }}, 0) + {{var "c"}} = true + } {{end}} +} else { + {{var "hl"}} := {{var "l"}} > 0 + var {{var "rl"}} int + _ = {{var "rl"}} + {{if isSlice }} if {{var "hl"}} { + if {{var "l"}} > cap({{var "v"}}) { + {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) + if {{var "rl"}} <= cap({{var "v"}}) { + {{var "v"}} = {{var "v"}}[:{{var "rl"}}] + } else { + {{var "v"}} = make([]{{ .Typ }}, {{var "rl"}}) + } + {{var "c"}} = true + } else if {{var "l"}} != len({{var "v"}}) { + {{var "v"}} = {{var "v"}}[:{{var "l"}}] + {{var "c"}} = true + } + } {{end}} + var {{var "j"}} int + // var {{var "dn"}} bool + for {{var "j"}} = 0; ({{var "hl"}} && {{var "j"}} < {{var "l"}}) || !({{var "hl"}} || r.CheckBreak()); {{var "j"}}++ { // bounds-check-elimination + {{if not isArray}} if {{var "j"}} == 0 && {{var "v"}} == nil { + if {{var "hl"}} { + {{var "rl"}} = z.DecInferLen({{var "l"}}, z.DecBasicHandle().MaxInitLen, {{ .Size }}) + } else { + {{var "rl"}} = {{if isSlice}}8{{else if isChan}}64{{end}} + } + {{var "v"}} = make({{if isSlice}}[]{{ .Typ }}{{else if isChan}}{{.CTyp}}{{end}}, {{var "rl"}}) + {{var "c"}} = true + }{{end}} + {{var "h"}}.ElemContainerState({{var "j"}}) + {{/* {{var "dn"}} = r.TryDecodeAsNil() */}}{{/* commented out, as decLineVar handles this already each time */}} + {{if isChan}}{{ $x := printf "%[1]vvcx%[2]v" .TempVar .Rand }}var {{$x}} {{ .Typ }} + {{ decLineVar $x }} + {{var "v"}} <- {{ $x }} + // println(">>>> sending ", {{ $x }}, " into ", {{var "v"}}) // TODO: remove this + {{else}}{{/* // if indefinite, etc, then expand the slice if necessary */}} + var {{var "db"}} bool + if {{var "j"}} >= len({{var "v"}}) { + {{if isSlice }} {{var "v"}} = append({{var "v"}}, {{ zero }}) + {{var "c"}} = true + {{else}} z.DecArrayCannotExpand(len(v), {{var "j"}}+1); {{var "db"}} = true + {{end}} + } + if {{var "db"}} { + z.DecSwallow() + } else { + {{ $x := printf "%[1]vv%[2]v[%[1]vj%[2]v]" .TempVar .Rand }}{{ decLineVar $x }} + } + {{end}} + } + {{if isSlice}} if {{var "j"}} < len({{var "v"}}) { + {{var "v"}} = {{var "v"}}[:{{var "j"}}] + {{var "c"}} = true + } else if {{var "j"}} == 0 && {{var "v"}} == nil { + {{var "v"}} = make([]{{ .Typ }}, 0) + {{var "c"}} = true + } {{end}} +} +{{var "h"}}.End() +{{if not isArray }}if {{var "c"}} { + *{{ .Varname }} = {{var "v"}} +}{{end}} +` + +const genEncChanTmpl = ` +{{.Label}}: +switch timeout{{.Sfx}} := z.EncBasicHandle().ChanRecvTimeout; { +case timeout{{.Sfx}} == 0: // only consume available + for { + select { + case b{{.Sfx}} := <-{{.Chan}}: + {{ .Slice }} = append({{.Slice}}, b{{.Sfx}}) + default: + break {{.Label}} + } + } +case timeout{{.Sfx}} > 0: // consume until timeout + tt{{.Sfx}} := time.NewTimer(timeout{{.Sfx}}) + for { + select { + case b{{.Sfx}} := <-{{.Chan}}: + {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) + case <-tt{{.Sfx}}.C: + // close(tt.C) + break {{.Label}} + } + } +default: // consume until close + for b{{.Sfx}} := range {{.Chan}} { + {{.Slice}} = append({{.Slice}}, b{{.Sfx}}) + } +} +` diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.go new file mode 100644 index 00000000..92e631ca --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/gen.go @@ -0,0 +1,1875 @@ +//go:build codecgen.exec +// +build codecgen.exec + +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +import ( + "encoding/base32" + "errors" + "fmt" + "io" + "math/rand" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "text/template" + "time" + "unicode" + "unicode/utf8" +) + +// --------------------------------------------------- +// codecgen supports the full cycle of reflection-based codec: +// - RawExt +// - Raw +// - Extensions +// - (Binary|Text|JSON)(Unm|M)arshal +// - generic by-kind +// +// This means that, for dynamic things, we MUST use reflection to at least get the reflect.Type. +// In those areas, we try to only do reflection or interface-conversion when NECESSARY: +// - Extensions, only if Extensions are configured. +// +// However, codecgen doesn't support the following: +// - Canonical option. (codecgen IGNORES it currently) +// This is just because it has not been implemented. +// - MissingFielder implementation. +// If a type implements MissingFielder, it is completely ignored by codecgen. +// +// During encode/decode, Selfer takes precedence. +// A type implementing Selfer will know how to encode/decode itself statically. +// +// The following field types are supported: +// +// array: [n]T +// slice: []T +// map: map[K]V +// primitive: [u]int[n], float(32|64), bool, string +// struct +// +// --------------------------------------------------- +// Note that a Selfer cannot call (e|d).(En|De)code on itself, +// as this will cause a circular reference, as (En|De)code will call Selfer methods. +// Any type that implements Selfer must implement completely and not fallback to (En|De)code. +// +// In addition, code in this file manages the generation of fast-path implementations of +// encode/decode of slices/maps of primitive keys/values. +// +// Users MUST re-generate their implementations whenever the code shape changes. +// The generated code will panic if it was generated with a version older than the supporting library. +// --------------------------------------------------- +// +// codec framework is very feature rich. +// When encoding or decoding into an interface, it depends on the runtime type of the interface. +// The type of the interface may be a named type, an extension, etc. +// Consequently, we fallback to runtime codec for encoding/decoding interfaces. +// In addition, we fallback for any value which cannot be guaranteed at runtime. +// This allows us support ANY value, including any named types, specifically those which +// do not implement our interfaces (e.g. Selfer). +// +// This explains some slowness compared to other code generation codecs (e.g. msgp). +// This reduction in speed is only seen when your refers to interfaces, +// e.g. type T struct { A interface{}; B []interface{}; C map[string]interface{} } +// +// codecgen will panic if the file was generated with an old version of the library in use. +// +// Note: +// +// It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil. +// This way, there isn't a function call overhead just to see that we should not enter a block of code. +// +// GenVersion is the current version of codecgen. +// +// NOTE: Increment this value each time codecgen changes fundamentally. +// Fundamental changes are: +// - helper methods change (signature change, new ones added, some removed, etc) +// - codecgen command line changes +// +// v1: Initial Version +// v2: +// v3: Changes for Kubernetes: +// +// changes in signature of some unpublished helper methods and codecgen cmdline arguments. +// +// v4: Removed separator support from (en|de)cDriver, and refactored codec(gen) +// v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections. +// v6: removed unsafe from gen, and now uses codecgen.exec tag +// v7: +// v8: current - we now maintain compatibility with old generated code. +// v9: skipped +// v10: modified encDriver and decDriver interfaces. Remove deprecated methods after Jan 1, 2019 +const ( + genCodecPkg = "codec1978" + genTempVarPfx = "yy" + genTopLevelVarName = "x" + + // ignore canBeNil parameter, and always set to true. + // This is because nil can appear anywhere, so we should always check. + genAnythingCanBeNil = true + + // if genUseOneFunctionForDecStructMap, make a single codecDecodeSelferFromMap function; + // else make codecDecodeSelferFromMap{LenPrefix,CheckBreak} so that conditionals + // are not executed a lot. + // + // From testing, it didn't make much difference in runtime, so keep as true (one function only) + genUseOneFunctionForDecStructMap = true +) + +type genStructMapStyle uint8 + +const ( + genStructMapStyleConsolidated genStructMapStyle = iota + genStructMapStyleLenPrefix + genStructMapStyleCheckBreak +) + +var ( + errGenAllTypesSamePkg = errors.New("All types must be in the same package") + errGenExpectArrayOrMap = errors.New("unexpected type. Expecting array/map/slice") + + // base64 requires 64 unique characters in Go 1.22+, which is not possible for Go identifiers. + genBase32enc = base32.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") + genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`) +) + +type genBuf struct { + buf []byte +} + +func (x *genBuf) s(s string) *genBuf { x.buf = append(x.buf, s...); return x } +func (x *genBuf) b(s []byte) *genBuf { x.buf = append(x.buf, s...); return x } +func (x *genBuf) v() string { return string(x.buf) } +func (x *genBuf) f(s string, args ...interface{}) { x.s(fmt.Sprintf(s, args...)) } +func (x *genBuf) reset() { + if x.buf != nil { + x.buf = x.buf[:0] + } +} + +// genRunner holds some state used during a Gen run. +type genRunner struct { + w io.Writer // output + c uint64 // counter used for generating varsfx + t []reflect.Type // list of types to run selfer on + + tc reflect.Type // currently running selfer on this type + te map[uintptr]bool // types for which the encoder has been created + td map[uintptr]bool // types for which the decoder has been created + cp string // codec import path + + im map[string]reflect.Type // imports to add + imn map[string]string // package names of imports to add + imc uint64 // counter for import numbers + + is map[reflect.Type]struct{} // types seen during import search + bp string // base PkgPath, for which we are generating for + + cpfx string // codec package prefix + + tm map[reflect.Type]struct{} // types for which enc/dec must be generated + ts []reflect.Type // types for which enc/dec must be generated + + xs string // top level variable/constant suffix + hn string // fn helper type name + + ti *TypeInfos + // rr *rand.Rand // random generator for file-specific types + + nx bool // no extensions +} + +// Gen will write a complete go file containing Selfer implementations for each +// type passed. All the types must be in the same package. +// +// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINUOUSLY WITHOUT NOTICE. +func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool, + ti *TypeInfos, typ ...reflect.Type) { + // All types passed to this method do not have a codec.Selfer method implemented directly. + // codecgen already checks the AST and skips any types that define the codec.Selfer methods. + // Consequently, there's no need to check and trim them if they implement codec.Selfer + + if len(typ) == 0 { + return + } + x := genRunner{ + w: w, + t: typ, + te: make(map[uintptr]bool), + td: make(map[uintptr]bool), + im: make(map[string]reflect.Type), + imn: make(map[string]string), + is: make(map[reflect.Type]struct{}), + tm: make(map[reflect.Type]struct{}), + ts: []reflect.Type{}, + bp: genImportPath(typ[0]), + xs: uid, + ti: ti, + nx: noExtensions, + } + if x.ti == nil { + x.ti = defTypeInfos + } + if x.xs == "" { + rr := rand.New(rand.NewSource(time.Now().UnixNano())) + x.xs = strconv.FormatInt(rr.Int63n(9999), 10) + } + + // gather imports first: + x.cp = genImportPath(reflect.TypeOf(x)) + x.imn[x.cp] = genCodecPkg + for _, t := range typ { + // fmt.Printf("###########: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name()) + if genImportPath(t) != x.bp { + panic(errGenAllTypesSamePkg) + } + x.genRefPkgs(t) + } + if buildTags != "" { + x.line("// +build " + buildTags) + x.line("") + } + x.line(` + +// Code generated by codecgen - DO NOT EDIT. + +`) + x.line("package " + pkgName) + x.line("") + x.line("import (") + if x.cp != x.bp { + x.cpfx = genCodecPkg + "." + x.linef("%s \"%s\"", genCodecPkg, x.cp) + } + // use a sorted set of im keys, so that we can get consistent output + imKeys := make([]string, 0, len(x.im)) + for k := range x.im { + imKeys = append(imKeys, k) + } + sort.Strings(imKeys) + for _, k := range imKeys { // for k, _ := range x.im { + if k == x.imn[k] { + x.linef("\"%s\"", k) + } else { + x.linef("%s \"%s\"", x.imn[k], k) + } + } + // add required packages + for _, k := range [...]string{"runtime", "errors", "strconv"} { // "reflect", "fmt" + if _, ok := x.im[k]; !ok { + x.line("\"" + k + "\"") + } + } + x.line(")") + x.line("") + + x.line("const (") + x.linef("// ----- content types ----") + x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8)) + x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW)) + x.linef("// ----- value types used ----") + for _, vt := range [...]valueType{ + valueTypeArray, valueTypeMap, valueTypeString, + valueTypeInt, valueTypeUint, valueTypeFloat} { + x.linef("codecSelferValueType%s%s = %v", vt.String(), x.xs, int64(vt)) + } + + x.linef("codecSelferBitsize%s = uint8(32 << (^uint(0) >> 63))", x.xs) + x.line(")") + x.line("var (") + x.line("errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + " = errors.New(`only encoded map or array can be decoded into a struct`)") + x.line(")") + x.line("") + + x.hn = "codecSelfer" + x.xs + x.line("type " + x.hn + " struct{}") + x.line("") + + x.varsfxreset() + x.line("func init() {") + x.linef("if %sGenVersion != %v {", x.cpfx, genVersion) + x.line("_, file, _, _ := runtime.Caller(0)") + x.outf(`panic("codecgen version mismatch: current: %v, need " + strconv.FormatInt(int64(%sGenVersion), 10) + ". Re-generate file: " + file)`, genVersion, x.cpfx) + // x.out(`panic(fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `) + // x.linef(`%v, %sGenVersion, file))`, genVersion, x.cpfx) + x.linef("}") + x.line("if false { var _ byte = 0; // reference the types, but skip this branch at build/run time") + // x.line("_ = strconv.ParseInt") + var n int + // for k, t := range x.im { + for _, k := range imKeys { + t := x.im[k] + x.linef("var v%v %s.%s", n, x.imn[k], t.Name()) + n++ + } + if n > 0 { + x.out("_") + for i := 1; i < n; i++ { + x.out(", _") + } + x.out(" = v0") + for i := 1; i < n; i++ { + x.outf(", v%v", i) + } + } + x.line("} ") // close if false + x.line("}") // close init + x.line("") + + // generate rest of type info + for _, t := range typ { + x.tc = t + x.selfer(true) + x.selfer(false) + } + + for _, t := range x.ts { + rtid := rt2id(t) + // generate enc functions for all these slice/map types. + x.varsfxreset() + x.linef("func (x %s) enc%s(v %s%s, e *%sEncoder) {", x.hn, x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), x.cpfx) + x.genRequiredMethodVars(true) + switch t.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + x.encListFallback("v", t) + case reflect.Map: + x.encMapFallback("v", t) + default: + panic(errGenExpectArrayOrMap) + } + x.line("}") + x.line("") + + // generate dec functions for all these slice/map types. + x.varsfxreset() + x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx) + x.genRequiredMethodVars(false) + switch t.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + x.decListFallback("v", rtid, t) + case reflect.Map: + x.decMapFallback("v", rtid, t) + default: + panic(errGenExpectArrayOrMap) + } + x.line("}") + x.line("") + } + + x.line("") +} + +func (x *genRunner) checkForSelfer(t reflect.Type, varname string) bool { + // return varname != genTopLevelVarName && t != x.tc + // the only time we checkForSelfer is if we are not at the TOP of the generated code. + return varname != genTopLevelVarName +} + +func (x *genRunner) arr2str(t reflect.Type, s string) string { + if t.Kind() == reflect.Array { + return s + } + return "" +} + +func (x *genRunner) genRequiredMethodVars(encode bool) { + x.line("var h " + x.hn) + if encode { + x.line("z, r := " + x.cpfx + "GenHelperEncoder(e)") + } else { + x.line("z, r := " + x.cpfx + "GenHelperDecoder(d)") + } + x.line("_, _, _ = h, z, r") +} + +func (x *genRunner) genRefPkgs(t reflect.Type) { + if _, ok := x.is[t]; ok { + return + } + x.is[t] = struct{}{} + tpkg, tname := genImportPath(t), t.Name() + if tpkg != "" && tpkg != x.bp && tpkg != x.cp && tname != "" && tname[0] >= 'A' && tname[0] <= 'Z' { + if _, ok := x.im[tpkg]; !ok { + x.im[tpkg] = t + if idx := strings.LastIndex(tpkg, "/"); idx < 0 { + x.imn[tpkg] = tpkg + } else { + x.imc++ + x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + genGoIdentifier(tpkg[idx+1:], false) + } + } + } + switch t.Kind() { + case reflect.Array, reflect.Slice, reflect.Ptr, reflect.Chan: + x.genRefPkgs(t.Elem()) + case reflect.Map: + x.genRefPkgs(t.Elem()) + x.genRefPkgs(t.Key()) + case reflect.Struct: + for i := 0; i < t.NumField(); i++ { + if fname := t.Field(i).Name; fname != "" && fname[0] >= 'A' && fname[0] <= 'Z' { + x.genRefPkgs(t.Field(i).Type) + } + } + } +} + +func (x *genRunner) varsfx() string { + x.c++ + return strconv.FormatUint(x.c, 10) +} + +func (x *genRunner) varsfxreset() { + x.c = 0 +} + +func (x *genRunner) out(s string) { + _, err := io.WriteString(x.w, s) + if err != nil { + panic(err) + } +} + +func (x *genRunner) outf(s string, params ...interface{}) { + _, err := fmt.Fprintf(x.w, s, params...) + if err != nil { + panic(err) + } +} + +func (x *genRunner) line(s string) { + x.out(s) + if len(s) == 0 || s[len(s)-1] != '\n' { + x.out("\n") + } +} + +func (x *genRunner) linef(s string, params ...interface{}) { + x.outf(s, params...) + if len(s) == 0 || s[len(s)-1] != '\n' { + x.out("\n") + } +} + +func (x *genRunner) genTypeName(t reflect.Type) (n string) { + // defer func() { fmt.Printf(">>>> ####: genTypeName: t: %v, name: '%s'\n", t, n) }() + + // if the type has a PkgPath, which doesn't match the current package, + // then include it. + // We cannot depend on t.String() because it includes current package, + // or t.PkgPath because it includes full import path, + // + var ptrPfx string + for t.Kind() == reflect.Ptr { + ptrPfx += "*" + t = t.Elem() + } + if tn := t.Name(); tn != "" { + return ptrPfx + x.genTypeNamePrim(t) + } + switch t.Kind() { + case reflect.Map: + return ptrPfx + "map[" + x.genTypeName(t.Key()) + "]" + x.genTypeName(t.Elem()) + case reflect.Slice: + return ptrPfx + "[]" + x.genTypeName(t.Elem()) + case reflect.Array: + return ptrPfx + "[" + strconv.FormatInt(int64(t.Len()), 10) + "]" + x.genTypeName(t.Elem()) + case reflect.Chan: + return ptrPfx + t.ChanDir().String() + " " + x.genTypeName(t.Elem()) + default: + if t == intfTyp { + return ptrPfx + "interface{}" + } else { + return ptrPfx + x.genTypeNamePrim(t) + } + } +} + +func (x *genRunner) genTypeNamePrim(t reflect.Type) (n string) { + if t.Name() == "" { + return t.String() + } else if genImportPath(t) == "" || genImportPath(t) == genImportPath(x.tc) { + return t.Name() + } else { + return x.imn[genImportPath(t)] + "." + t.Name() + // return t.String() // best way to get the package name inclusive + } +} + +func (x *genRunner) genZeroValueR(t reflect.Type) string { + // if t is a named type, w + switch t.Kind() { + case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func, + reflect.Slice, reflect.Map, reflect.Invalid: + return "nil" + case reflect.Bool: + return "false" + case reflect.String: + return `""` + case reflect.Struct, reflect.Array: + return x.genTypeName(t) + "{}" + default: // all numbers + return "0" + } +} + +func (x *genRunner) genMethodNameT(t reflect.Type) (s string) { + return genMethodNameT(t, x.tc) +} + +func (x *genRunner) selfer(encode bool) { + t := x.tc + t0 := t + // always make decode use a pointer receiver, + // and structs/arrays always use a ptr receiver (encode|decode) + isptr := !encode || t.Kind() == reflect.Array || (t.Kind() == reflect.Struct && t != timeTyp) + x.varsfxreset() + + fnSigPfx := "func (" + genTopLevelVarName + " " + if isptr { + fnSigPfx += "*" + } + fnSigPfx += x.genTypeName(t) + x.out(fnSigPfx) + + if isptr { + t = reflect.PtrTo(t) + } + if encode { + x.line(") CodecEncodeSelf(e *" + x.cpfx + "Encoder) {") + x.genRequiredMethodVars(true) + x.encVar(genTopLevelVarName, t) + } else { + x.line(") CodecDecodeSelf(d *" + x.cpfx + "Decoder) {") + x.genRequiredMethodVars(false) + // do not use decVar, as there is no need to check TryDecodeAsNil + // or way to elegantly handle that, and also setting it to a + // non-nil value doesn't affect the pointer passed. + // x.decVar(genTopLevelVarName, t, false) + x.dec(genTopLevelVarName, t0, true) + } + x.line("}") + x.line("") + + if encode || t0.Kind() != reflect.Struct { + return + } + + // write is containerMap + if genUseOneFunctionForDecStructMap { + x.out(fnSigPfx) + x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {") + x.genRequiredMethodVars(false) + x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleConsolidated) + x.line("}") + x.line("") + } else { + x.out(fnSigPfx) + x.line(") codecDecodeSelfFromMapLenPrefix(l int, d *" + x.cpfx + "Decoder) {") + x.genRequiredMethodVars(false) + x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleLenPrefix) + x.line("}") + x.line("") + + x.out(fnSigPfx) + x.line(") codecDecodeSelfFromMapCheckBreak(l int, d *" + x.cpfx + "Decoder) {") + x.genRequiredMethodVars(false) + x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0, genStructMapStyleCheckBreak) + x.line("}") + x.line("") + } + + // write containerArray + x.out(fnSigPfx) + x.line(") codecDecodeSelfFromArray(l int, d *" + x.cpfx + "Decoder) {") + x.genRequiredMethodVars(false) + x.decStructArray(genTopLevelVarName, "l", "return", rt2id(t0), t0) + x.line("}") + x.line("") + +} + +// used for chan, array, slice, map +func (x *genRunner) xtraSM(varname string, t reflect.Type, encode, isptr bool) { + var ptrPfx, addrPfx string + if isptr { + ptrPfx = "*" + } else { + addrPfx = "&" + } + if encode { + x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), ptrPfx, x.genTypeName(t), varname) + } else { + x.linef("h.dec%s((*%s)(%s%s), d)", x.genMethodNameT(t), x.genTypeName(t), addrPfx, varname) + } + x.registerXtraT(t) +} + +func (x *genRunner) registerXtraT(t reflect.Type) { + // recursively register the types + if _, ok := x.tm[t]; ok { + return + } + var tkey reflect.Type + switch t.Kind() { + case reflect.Chan, reflect.Slice, reflect.Array: + case reflect.Map: + tkey = t.Key() + default: + return + } + x.tm[t] = struct{}{} + x.ts = append(x.ts, t) + // check if this refers to any xtra types eg. a slice of array: add the array + x.registerXtraT(t.Elem()) + if tkey != nil { + x.registerXtraT(tkey) + } +} + +// encVar will encode a variable. +// The parameter, t, is the reflect.Type of the variable itself +func (x *genRunner) encVar(varname string, t reflect.Type) { + // fmt.Printf(">>>>>> varname: %s, t: %v\n", varname, t) + var checkNil bool + switch t.Kind() { + case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan: + checkNil = true + } + if checkNil { + x.linef("if %s == nil { r.EncodeNil() } else { ", varname) + } + + switch t.Kind() { + case reflect.Ptr: + telem := t.Elem() + tek := telem.Kind() + if tek == reflect.Array || (tek == reflect.Struct && telem != timeTyp) { + x.enc(varname, genNonPtr(t)) + break + } + i := x.varsfx() + x.line(genTempVarPfx + i + " := *" + varname) + x.enc(genTempVarPfx+i, genNonPtr(t)) + case reflect.Struct, reflect.Array: + if t == timeTyp { + x.enc(varname, t) + break + } + i := x.varsfx() + x.line(genTempVarPfx + i + " := &" + varname) + x.enc(genTempVarPfx+i, t) + default: + x.enc(varname, t) + } + + if checkNil { + x.line("}") + } + +} + +// enc will encode a variable (varname) of type t, where t represents T. +// if t is !time.Time and t is of kind reflect.Struct or reflect.Array, varname is of type *T +// (to prevent copying), +// else t is of type T +func (x *genRunner) enc(varname string, t reflect.Type) { + rtid := rt2id(t) + ti2 := x.ti.get(rtid, t) + // We call CodecEncodeSelf if one of the following are honored: + // - the type already implements Selfer, call that + // - the type has a Selfer implementation just created, use that + // - the type is in the list of the ones we will generate for, but it is not currently being generated + + mi := x.varsfx() + // tptr := reflect.PtrTo(t) + tk := t.Kind() + if x.checkForSelfer(t, varname) { + if tk == reflect.Array || (tk == reflect.Struct && rtid != timeTypId) { // varname is of type *T + // if tptr.Implements(selferTyp) || t.Implements(selferTyp) { + if ti2.isFlag(typeInfoFlagIsZeroerPtr) || ti2.isFlag(typeInfoFlagIsZeroer) { + x.line(varname + ".CodecEncodeSelf(e)") + return + } + } else { // varname is of type T + if ti2.cs { // t.Implements(selferTyp) { + x.line(varname + ".CodecEncodeSelf(e)") + return + } else if ti2.csp { // tptr.Implements(selferTyp) { + x.linef("%ssf%s := &%s", genTempVarPfx, mi, varname) + x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi) + return + } + } + + if _, ok := x.te[rtid]; ok { + x.line(varname + ".CodecEncodeSelf(e)") + return + } + } + + inlist := false + for _, t0 := range x.t { + if t == t0 { + inlist = true + if x.checkForSelfer(t, varname) { + x.line(varname + ".CodecEncodeSelf(e)") + return + } + break + } + } + + var rtidAdded bool + if t == x.tc { + x.te[rtid] = true + rtidAdded = true + } + + // check if + // - type is time.Time, RawExt, Raw + // - the type implements (Text|JSON|Binary)(Unm|M)arshal + + x.line("if false {") //start if block + defer func() { x.line("}") }() //end if block + + if t == timeTyp { + x.linef("} else if !z.EncBasicHandle().TimeNotBuiltin { r.EncodeTime(%s)", varname) + // return + } + if t == rawTyp { + x.linef("} else { z.EncRaw(%s)", varname) + return + } + if t == rawExtTyp { + x.linef("} else { r.EncodeRawExt(%s, e)", varname) + return + } + // only check for extensions if the type is named, and has a packagePath. + var arrayOrStruct = tk == reflect.Array || tk == reflect.Struct // meaning varname if of type *T + if !x.nx && genImportPath(t) != "" && t.Name() != "" { + yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi) + x.linef("} else if %s := z.Extension(z.I2Rtid(%s)); %s != nil { z.EncExtension(%s, %s) ", yy, varname, yy, varname, yy) + } + if arrayOrStruct { // varname is of type *T + if ti2.bm || ti2.bmp { // t.Implements(binaryMarshalerTyp) || tptr.Implements(binaryMarshalerTyp) { + x.linef("} else if z.EncBinary() { z.EncBinaryMarshal(%v) ", varname) + } + if ti2.jm || ti2.jmp { // t.Implements(jsonMarshalerTyp) || tptr.Implements(jsonMarshalerTyp) { + x.linef("} else if !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", varname) + } else if ti2.tm || ti2.tmp { // t.Implements(textMarshalerTyp) || tptr.Implements(textMarshalerTyp) { + x.linef("} else if !z.EncBinary() { z.EncTextMarshal(%v) ", varname) + } + } else { // varname is of type T + if ti2.bm { // t.Implements(binaryMarshalerTyp) { + x.linef("} else if z.EncBinary() { z.EncBinaryMarshal(%v) ", varname) + } else if ti2.bmp { // tptr.Implements(binaryMarshalerTyp) { + x.linef("} else if z.EncBinary() { z.EncBinaryMarshal(&%v) ", varname) + } + if ti2.jm { // t.Implements(jsonMarshalerTyp) { + x.linef("} else if !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", varname) + } else if ti2.jmp { // tptr.Implements(jsonMarshalerTyp) { + x.linef("} else if !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(&%v) ", varname) + } else if ti2.tm { // t.Implements(textMarshalerTyp) { + x.linef("} else if !z.EncBinary() { z.EncTextMarshal(%v) ", varname) + } else if ti2.tmp { // tptr.Implements(textMarshalerTyp) { + x.linef("} else if !z.EncBinary() { z.EncTextMarshal(&%v) ", varname) + } + } + x.line("} else {") + + switch t.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + x.line("r.EncodeInt(int64(" + varname + "))") + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + x.line("r.EncodeUint(uint64(" + varname + "))") + case reflect.Float32: + x.line("r.EncodeFloat32(float32(" + varname + "))") + case reflect.Float64: + x.line("r.EncodeFloat64(float64(" + varname + "))") + case reflect.Bool: + x.line("r.EncodeBool(bool(" + varname + "))") + case reflect.String: + x.linef("if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw(z.BytesView(string(%s))) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, string(%s)) }", varname, x.xs, varname) + case reflect.Chan: + x.xtraSM(varname, t, true, false) + // x.encListFallback(varname, rtid, t) + case reflect.Array: + x.xtraSM(varname, t, true, true) + case reflect.Slice: + // if nil, call dedicated function + // if a []uint8, call dedicated function + // if a known fastpath slice, call dedicated function + // else write encode function in-line. + // - if elements are primitives or Selfers, call dedicated function on each member. + // - else call Encoder.encode(XXX) on it. + if rtid == uint8SliceTypId { + x.line("r.EncodeStringBytesRaw([]byte(" + varname + "))") + } else if fastpathAV.index(rtid) != -1 { + g := x.newGenV(t) + x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)") + } else { + x.xtraSM(varname, t, true, false) + // x.encListFallback(varname, rtid, t) + } + case reflect.Map: + // if nil, call dedicated function + // if a known fastpath map, call dedicated function + // else write encode function in-line. + // - if elements are primitives or Selfers, call dedicated function on each member. + // - else call Encoder.encode(XXX) on it. + // x.line("if " + varname + " == nil { \nr.EncodeNil()\n } else { ") + if fastpathAV.index(rtid) != -1 { + g := x.newGenV(t) + x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", e)") + } else { + x.xtraSM(varname, t, true, false) + // x.encMapFallback(varname, rtid, t) + } + case reflect.Struct: + if !inlist { + delete(x.te, rtid) + x.line("z.EncFallback(" + varname + ")") + break + } + x.encStruct(varname, rtid, t) + default: + if rtidAdded { + delete(x.te, rtid) + } + x.line("z.EncFallback(" + varname + ")") + } +} + +func (x *genRunner) encZero(t reflect.Type) { + switch t.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + x.line("r.EncodeInt(0)") + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + x.line("r.EncodeUint(0)") + case reflect.Float32: + x.line("r.EncodeFloat32(0)") + case reflect.Float64: + x.line("r.EncodeFloat64(0)") + case reflect.Bool: + x.line("r.EncodeBool(false)") + case reflect.String: + x.linef(`if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw([]byte{}) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, "") }`, x.xs) + default: + x.line("r.EncodeNil()") + } +} + +func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) { + // smartly check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc. + // also, for maps/slices/arrays, check if len ! 0 (not if == zero value) + varname2 := varname + "." + t2.Name + switch t2.Type.Kind() { + case reflect.Struct: + rtid2 := rt2id(t2.Type) + ti2 := x.ti.get(rtid2, t2.Type) + // fmt.Printf(">>>> structfield: omitempty: type: %s, field: %s\n", t2.Type.Name(), t2.Name) + if ti2.rtid == timeTypId { + buf.s("!(").s(varname2).s(".IsZero())") + break + } + if ti2.isFlag(typeInfoFlagIsZeroerPtr) || ti2.isFlag(typeInfoFlagIsZeroer) { + buf.s("!(").s(varname2).s(".IsZero())") + break + } + if ti2.isFlag(typeInfoFlagComparable) { + buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type)) + break + } + // buf.s("(") + buf.s("false") + for i, n := 0, t2.Type.NumField(); i < n; i++ { + f := t2.Type.Field(i) + if f.PkgPath != "" { // unexported + continue + } + buf.s(" || ") + x.encOmitEmptyLine(f, varname2, buf) + } + //buf.s(")") + case reflect.Bool: + buf.s(varname2) + case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan: + buf.s("len(").s(varname2).s(") != 0") + default: + buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type)) + } +} + +func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) { + // Use knowledge from structfieldinfo (mbs, encodable fields. Ignore omitempty. ) + // replicate code in kStruct i.e. for each field, deref type to non-pointer, and call x.enc on it + + // if t === type currently running selfer on, do for all + ti := x.ti.get(rtid, t) + i := x.varsfx() + sepVarname := genTempVarPfx + "sep" + i + numfieldsvar := genTempVarPfx + "q" + i + ti2arrayvar := genTempVarPfx + "r" + i + struct2arrvar := genTempVarPfx + "2arr" + i + + x.line(sepVarname + " := !z.EncBinary()") + x.linef("%s := z.EncBasicHandle().StructToArray", struct2arrvar) + x.linef("_, _ = %s, %s", sepVarname, struct2arrvar) + x.linef("const %s bool = %v // struct tag has 'toArray'", ti2arrayvar, ti.toArray) + + tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing. + + // var nn int + // due to omitEmpty, we need to calculate the + // number of non-empty things we write out first. + // This is required as we need to pre-determine the size of the container, + // to support length-prefixing. + if ti.anyOmitEmpty { + x.linef("var %s = [%v]bool{ // should field at this index be written?", numfieldsvar, len(tisfi)) + + for j, si := range tisfi { + _ = j + if !si.omitEmpty() { + // x.linef("%s[%v] = true // %s", numfieldsvar, j, si.fieldName) + x.linef("true, // %s", si.fieldName) + // nn++ + continue + } + var t2 reflect.StructField + var omitline genBuf + { + t2typ := t + varname3 := varname + // go through the loop, record the t2 field explicitly, + // and gather the omit line if embedded in pointers. + for ij, ix := range si.is { + if uint8(ij) == si.nis { + break + } + for t2typ.Kind() == reflect.Ptr { + t2typ = t2typ.Elem() + } + t2 = t2typ.Field(int(ix)) + t2typ = t2.Type + varname3 = varname3 + "." + t2.Name + // do not include actual field in the omit line. + // that is done subsequently (right after - below). + if uint8(ij+1) < si.nis && t2typ.Kind() == reflect.Ptr { + omitline.s(varname3).s(" != nil && ") + } + } + } + x.encOmitEmptyLine(t2, varname, &omitline) + x.linef("%s, // %s", omitline.v(), si.fieldName) + } + x.line("}") + x.linef("_ = %s", numfieldsvar) + } + // x.linef("var %snn%s int", genTempVarPfx, i) + x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray { + x.linef("r.WriteArrayStart(%d)", len(tisfi)) + x.linef("} else {") // if not ti.toArray + if ti.anyOmitEmpty { + // nn = 0 + // x.linef("var %snn%s = %v", genTempVarPfx, i, nn) + x.linef("var %snn%s int", genTempVarPfx, i) + x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i) + x.linef("r.WriteMapStart(%snn%s)", genTempVarPfx, i) + x.linef("%snn%s = %v", genTempVarPfx, i, 0) + } else { + x.linef("r.WriteMapStart(%d)", len(tisfi)) + } + x.line("}") // close if not StructToArray + + for j, si := range tisfi { + i := x.varsfx() + isNilVarName := genTempVarPfx + "n" + i + var labelUsed bool + var t2 reflect.StructField + { + t2typ := t + varname3 := varname + for ij, ix := range si.is { + if uint8(ij) == si.nis { + break + } + for t2typ.Kind() == reflect.Ptr { + t2typ = t2typ.Elem() + } + t2 = t2typ.Field(int(ix)) + t2typ = t2.Type + varname3 = varname3 + "." + t2.Name + if t2typ.Kind() == reflect.Ptr { + if !labelUsed { + x.line("var " + isNilVarName + " bool") + } + x.line("if " + varname3 + " == nil { " + isNilVarName + " = true ") + x.line("goto LABEL" + i) + x.line("}") + labelUsed = true + // "varname3 = new(" + x.genTypeName(t3.Elem()) + ") }") + } + } + // t2 = t.FieldByIndex(si.is) + } + if labelUsed { + x.line("LABEL" + i + ":") + } + // if the type of the field is a Selfer, or one of the ones + + x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray + if labelUsed { + x.linef("if %s { r.WriteArrayElem(); r.EncodeNil() } else { ", isNilVarName) + } + x.line("r.WriteArrayElem()") + if si.omitEmpty() { + x.linef("if %s[%v] {", numfieldsvar, j) + } + x.encVar(varname+"."+t2.Name, t2.Type) + if si.omitEmpty() { + x.linef("} else {") + x.encZero(t2.Type) + x.linef("}") + } + if labelUsed { + x.line("}") + } + + x.linef("} else {") // if not ti.toArray + + if si.omitEmpty() { + x.linef("if %s[%v] {", numfieldsvar, j) + } + x.line("r.WriteMapElemKey()") + + // emulate EncStructFieldKey + switch ti.keyType { + case valueTypeInt: + x.linef("r.EncodeInt(z.M.Int(strconv.ParseInt(`%s`, 10, 64)))", si.encName) + case valueTypeUint: + x.linef("r.EncodeUint(z.M.Uint(strconv.ParseUint(`%s`, 10, 64)))", si.encName) + case valueTypeFloat: + x.linef("r.EncodeFloat64(z.M.Float(strconv.ParseFloat(`%s`, 64)))", si.encName) + default: // string + if si.encNameAsciiAlphaNum { + x.linef(`if z.IsJSONHandle() { z.WriteStr("\"%s\"") } else { `, si.encName) + } + x.linef("r.EncodeStringEnc(codecSelferCcUTF8%s, `%s`)", x.xs, si.encName) + if si.encNameAsciiAlphaNum { + x.linef("}") + } + } + // x.linef("r.EncStructFieldKey(codecSelferValueType%s%s, `%s`)", ti.keyType.String(), x.xs, si.encName) + x.line("r.WriteMapElemValue()") + if labelUsed { + x.line("if " + isNilVarName + " { r.EncodeNil() } else { ") + x.encVar(varname+"."+t2.Name, t2.Type) + x.line("}") + } else { + x.encVar(varname+"."+t2.Name, t2.Type) + } + if si.omitEmpty() { + x.line("}") + } + x.linef("} ") // end if/else ti.toArray + } + x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray { + x.line("r.WriteArrayEnd()") + x.line("} else {") + x.line("r.WriteMapEnd()") + x.line("}") + +} + +func (x *genRunner) encListFallback(varname string, t reflect.Type) { + elemBytes := t.Elem().Kind() == reflect.Uint8 + if t.AssignableTo(uint8SliceTyp) { + x.linef("r.EncodeStringBytesRaw([]byte(%s))", varname) + return + } + if t.Kind() == reflect.Array && elemBytes { + x.linef("r.EncodeStringBytesRaw(((*[%d]byte)(%s))[:])", t.Len(), varname) + return + } + i := x.varsfx() + if t.Kind() == reflect.Chan { + type ts struct { + Label, Chan, Slice, Sfx string + } + tm, err := template.New("").Parse(genEncChanTmpl) + if err != nil { + panic(err) + } + x.linef("if %s == nil { r.EncodeNil() } else { ", varname) + x.linef("var sch%s []%s", i, x.genTypeName(t.Elem())) + err = tm.Execute(x.w, &ts{"Lsch" + i, varname, "sch" + i, i}) + if err != nil { + panic(err) + } + // x.linef("%s = sch%s", varname, i) + if elemBytes { + x.linef("r.EncodeStringBytesRaw([]byte(%s))", "sch"+i) + x.line("}") + return + } + varname = "sch" + i + } + + x.line("r.WriteArrayStart(len(" + varname + "))") + x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname) + x.line("r.WriteArrayElem()") + + x.encVar(genTempVarPfx+"v"+i, t.Elem()) + x.line("}") + x.line("r.WriteArrayEnd()") + if t.Kind() == reflect.Chan { + x.line("}") + } +} + +func (x *genRunner) encMapFallback(varname string, t reflect.Type) { + // TODO: expand this to handle canonical. + i := x.varsfx() + x.line("r.WriteMapStart(len(" + varname + "))") + x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname) + x.line("r.WriteMapElemKey()") + x.encVar(genTempVarPfx+"k"+i, t.Key()) + x.line("r.WriteMapElemValue()") + x.encVar(genTempVarPfx+"v"+i, t.Elem()) + x.line("}") + x.line("r.WriteMapEnd()") +} + +func (x *genRunner) decVarInitPtr(varname, nilvar string, t reflect.Type, si *structFieldInfo, + newbuf, nilbuf *genBuf) (t2 reflect.StructField) { + //we must accommodate anonymous fields, where the embedded field is a nil pointer in the value. + // t2 = t.FieldByIndex(si.is) + t2typ := t + varname3 := varname + t2kind := t2typ.Kind() + var nilbufed bool + if si != nil { + for ij, ix := range si.is { + if uint8(ij) == si.nis { + break + } + for t2typ.Kind() == reflect.Ptr { + t2typ = t2typ.Elem() + } + t2 = t2typ.Field(int(ix)) + t2typ = t2.Type + varname3 = varname3 + "." + t2.Name + t2kind = t2typ.Kind() + if t2kind != reflect.Ptr { + continue + } + if newbuf != nil { + newbuf.f("if %s == nil { %s = new(%s) }\n", varname3, varname3, x.genTypeName(t2typ.Elem())) + } + if nilbuf != nil { + if !nilbufed { + nilbuf.s("if true") + nilbufed = true + } + nilbuf.s(" && ").s(varname3).s(" != nil") + } + } + } + // if t2typ.Kind() == reflect.Ptr { + // varname3 = varname3 + t2.Name + // } + if nilbuf != nil { + if nilbufed { + nilbuf.s(" { ") + } + if nilvar != "" { + nilbuf.s(nilvar).s(" = true") + } else if tk := t2typ.Kind(); tk == reflect.Ptr { + if strings.IndexByte(varname3, '.') != -1 || strings.IndexByte(varname3, '[') != -1 { + nilbuf.s(varname3).s(" = nil") + } else { + nilbuf.s("*").s(varname3).s(" = ").s(x.genZeroValueR(t2typ.Elem())) + } + } else { + nilbuf.s(varname3).s(" = ").s(x.genZeroValueR(t2typ)) + } + if nilbufed { + nilbuf.s("}") + } + } + return t2 +} + +// decVar takes a variable called varname, of type t +func (x *genRunner) decVarMain(varname, rand string, t reflect.Type, checkNotNil bool) { + // We only encode as nil if a nillable value. + // This removes some of the wasted checks for TryDecodeAsNil. + // We need to think about this more, to see what happens if omitempty, etc + // cause a nil value to be stored when something is expected. + // This could happen when decoding from a struct encoded as an array. + // For that, decVar should be called with canNil=true, to force true as its value. + var varname2 string + if t.Kind() != reflect.Ptr { + if t.PkgPath() != "" || !x.decTryAssignPrimitive(varname, t, false) { + x.dec(varname, t, false) + } + } else { + if checkNotNil { + x.linef("if %s == nil { %s = new(%s) }", varname, varname, x.genTypeName(t.Elem())) + } + // Ensure we set underlying ptr to a non-nil value (so we can deref to it later). + // There's a chance of a **T in here which is nil. + var ptrPfx string + for t = t.Elem(); t.Kind() == reflect.Ptr; t = t.Elem() { + ptrPfx += "*" + if checkNotNil { + x.linef("if %s%s == nil { %s%s = new(%s)}", + ptrPfx, varname, ptrPfx, varname, x.genTypeName(t)) + } + } + // Should we create temp var if a slice/map indexing? No. dec(...) can now handle it. + + if ptrPfx == "" { + x.dec(varname, t, true) + } else { + varname2 = genTempVarPfx + "z" + rand + x.line(varname2 + " := " + ptrPfx + varname) + x.dec(varname2, t, true) + } + } +} + +// decVar takes a variable called varname, of type t +func (x *genRunner) decVar(varname, nilvar string, t reflect.Type, canBeNil, checkNotNil bool) { + i := x.varsfx() + + // We only encode as nil if a nillable value. + // This removes some of the wasted checks for TryDecodeAsNil. + // We need to think about this more, to see what happens if omitempty, etc + // cause a nil value to be stored when something is expected. + // This could happen when decoding from a struct encoded as an array. + // For that, decVar should be called with canNil=true, to force true as its value. + + if !canBeNil { + canBeNil = genAnythingCanBeNil || !genIsImmutable(t) + } + + if canBeNil { + var buf genBuf + x.decVarInitPtr(varname, nilvar, t, nil, nil, &buf) + x.linef("if r.TryDecodeAsNil() { %s } else {", buf.buf) + } else { + x.line("// cannot be nil") + } + + x.decVarMain(varname, i, t, checkNotNil) + + if canBeNil { + x.line("} ") + } +} + +// dec will decode a variable (varname) of type t or ptrTo(t) if isptr==true. +// t is always a basetype (i.e. not of kind reflect.Ptr). +func (x *genRunner) dec(varname string, t reflect.Type, isptr bool) { + // assumptions: + // - the varname is to a pointer already. No need to take address of it + // - t is always a baseType T (not a *T, etc). + rtid := rt2id(t) + ti2 := x.ti.get(rtid, t) + // tptr := reflect.PtrTo(t) + if x.checkForSelfer(t, varname) { + if ti2.cs || ti2.csp { // t.Implements(selferTyp) || tptr.Implements(selferTyp) { + x.line(varname + ".CodecDecodeSelf(d)") + return + } + if _, ok := x.td[rtid]; ok { + x.line(varname + ".CodecDecodeSelf(d)") + return + } + } + + inlist := false + for _, t0 := range x.t { + if t == t0 { + inlist = true + if x.checkForSelfer(t, varname) { + x.line(varname + ".CodecDecodeSelf(d)") + return + } + break + } + } + + var rtidAdded bool + if t == x.tc { + x.td[rtid] = true + rtidAdded = true + } + + // check if + // - type is time.Time, Raw, RawExt + // - the type implements (Text|JSON|Binary)(Unm|M)arshal + + mi := x.varsfx() + // x.linef("%sm%s := z.DecBinary()", genTempVarPfx, mi) + // x.linef("_ = %sm%s", genTempVarPfx, mi) + x.line("if false {") //start if block + defer func() { x.line("}") }() //end if block + + var ptrPfx, addrPfx string + if isptr { + ptrPfx = "*" + } else { + addrPfx = "&" + } + if t == timeTyp { + x.linef("} else if !z.DecBasicHandle().TimeNotBuiltin { %s%v = r.DecodeTime()", ptrPfx, varname) + // return + } + if t == rawTyp { + x.linef("} else { %s%v = z.DecRaw()", ptrPfx, varname) + return + } + + if t == rawExtTyp { + x.linef("} else { r.DecodeExt(%s%v, 0, nil)", addrPfx, varname) + return + } + + // only check for extensions if the type is named, and has a packagePath. + if !x.nx && genImportPath(t) != "" && t.Name() != "" { + // first check if extensions are configued, before doing the interface conversion + // x.linef("} else if z.HasExtensions() && z.DecExt(%s) {", varname) + yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi) + x.linef("} else if %s := z.Extension(z.I2Rtid(%s)); %s != nil { z.DecExtension(%s, %s) ", yy, varname, yy, varname, yy) + } + + if ti2.bu || ti2.bup { // t.Implements(binaryUnmarshalerTyp) || tptr.Implements(binaryUnmarshalerTyp) { + x.linef("} else if z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", addrPfx, varname) + } + if ti2.ju || ti2.jup { // t.Implements(jsonUnmarshalerTyp) || tptr.Implements(jsonUnmarshalerTyp) { + x.linef("} else if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", addrPfx, varname) + } else if ti2.tu || ti2.tup { // t.Implements(textUnmarshalerTyp) || tptr.Implements(textUnmarshalerTyp) { + x.linef("} else if !z.DecBinary() { z.DecTextUnmarshal(%s%v)", addrPfx, varname) + } + + x.line("} else {") + + if x.decTryAssignPrimitive(varname, t, isptr) { + return + } + + switch t.Kind() { + case reflect.Array, reflect.Chan: + x.xtraSM(varname, t, false, isptr) + case reflect.Slice: + // if a []uint8, call dedicated function + // if a known fastpath slice, call dedicated function + // else write encode function in-line. + // - if elements are primitives or Selfers, call dedicated function on each member. + // - else call Encoder.encode(XXX) on it. + if rtid == uint8SliceTypId { + x.linef("%s%s = r.DecodeBytes(%s(%s[]byte)(%s), false)", + ptrPfx, varname, ptrPfx, ptrPfx, varname) + } else if fastpathAV.index(rtid) != -1 { + g := x.newGenV(t) + x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname) + } else { + x.xtraSM(varname, t, false, isptr) + // x.decListFallback(varname, rtid, false, t) + } + case reflect.Map: + // if a known fastpath map, call dedicated function + // else write encode function in-line. + // - if elements are primitives or Selfers, call dedicated function on each member. + // - else call Encoder.encode(XXX) on it. + if fastpathAV.index(rtid) != -1 { + g := x.newGenV(t) + x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname) + } else { + x.xtraSM(varname, t, false, isptr) + // x.decMapFallback(varname, rtid, t) + } + case reflect.Struct: + if inlist { + // no need to create temp variable if isptr, or x.F or x[F] + if isptr || strings.IndexByte(varname, '.') != -1 || strings.IndexByte(varname, '[') != -1 { + x.decStruct(varname, rtid, t) + } else { + varname2 := genTempVarPfx + "j" + mi + x.line(varname2 + " := &" + varname) + x.decStruct(varname2, rtid, t) + } + } else { + // delete(x.td, rtid) + x.line("z.DecFallback(" + addrPfx + varname + ", false)") + } + default: + if rtidAdded { + delete(x.te, rtid) + } + x.line("z.DecFallback(" + addrPfx + varname + ", true)") + } +} + +func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type, isptr bool) (done bool) { + // This should only be used for exact primitives (ie un-named types). + // Named types may be implementations of Selfer, Unmarshaler, etc. + // They should be handled by dec(...) + + var ptr string + if isptr { + ptr = "*" + } + switch t.Kind() { + case reflect.Int: + x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs) + case reflect.Int8: + x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 8))", ptr, varname, x.genTypeName(t)) + case reflect.Int16: + x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 16))", ptr, varname, x.genTypeName(t)) + case reflect.Int32: + x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 32))", ptr, varname, x.genTypeName(t)) + case reflect.Int64: + x.linef("%s%s = (%s)(r.DecodeInt64())", ptr, varname, x.genTypeName(t)) + + case reflect.Uint: + x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs) + case reflect.Uint8: + x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 8))", ptr, varname, x.genTypeName(t)) + case reflect.Uint16: + x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 16))", ptr, varname, x.genTypeName(t)) + case reflect.Uint32: + x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 32))", ptr, varname, x.genTypeName(t)) + case reflect.Uint64: + x.linef("%s%s = (%s)(r.DecodeUint64())", ptr, varname, x.genTypeName(t)) + case reflect.Uintptr: + x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs) + + case reflect.Float32: + x.linef("%s%s = (%s)(r.DecodeFloat32As64())", ptr, varname, x.genTypeName(t)) + case reflect.Float64: + x.linef("%s%s = (%s)(r.DecodeFloat64())", ptr, varname, x.genTypeName(t)) + + case reflect.Bool: + x.linef("%s%s = (%s)(r.DecodeBool())", ptr, varname, x.genTypeName(t)) + case reflect.String: + x.linef("%s%s = (%s)(r.DecodeString())", ptr, varname, x.genTypeName(t)) + default: + return false + } + return true +} + +func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) { + if t.AssignableTo(uint8SliceTyp) { + x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false)") + return + } + if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 { + x.linef("r.DecodeBytes( ((*[%d]byte)(%s))[:], true)", t.Len(), varname) + return + } + type tstruc struct { + TempVar string + Rand string + Varname string + CTyp string + Typ string + Immutable bool + Size int + } + telem := t.Elem() + ts := tstruc{genTempVarPfx, x.varsfx(), varname, x.genTypeName(t), x.genTypeName(telem), genIsImmutable(telem), int(telem.Size())} + + funcs := make(template.FuncMap) + + funcs["decLineVar"] = func(varname string) string { + x.decVar(varname, "", telem, false, true) + return "" + } + funcs["var"] = func(s string) string { + return ts.TempVar + s + ts.Rand + } + funcs["zero"] = func() string { + return x.genZeroValueR(telem) + } + funcs["isArray"] = func() bool { + return t.Kind() == reflect.Array + } + funcs["isSlice"] = func() bool { + return t.Kind() == reflect.Slice + } + funcs["isChan"] = func() bool { + return t.Kind() == reflect.Chan + } + tm, err := template.New("").Funcs(funcs).Parse(genDecListTmpl) + if err != nil { + panic(err) + } + if err = tm.Execute(x.w, &ts); err != nil { + panic(err) + } +} + +func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) { + type tstruc struct { + TempVar string + Sfx string + Rand string + Varname string + KTyp string + Typ string + Size int + } + telem := t.Elem() + tkey := t.Key() + ts := tstruc{ + genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey), + x.genTypeName(telem), int(telem.Size() + tkey.Size()), + } + + funcs := make(template.FuncMap) + funcs["decElemZero"] = func() string { + return x.genZeroValueR(telem) + } + funcs["decElemKindImmutable"] = func() bool { + return genIsImmutable(telem) + } + funcs["decElemKindPtr"] = func() bool { + return telem.Kind() == reflect.Ptr + } + funcs["decElemKindIntf"] = func() bool { + return telem.Kind() == reflect.Interface + } + funcs["decLineVarK"] = func(varname string) string { + x.decVar(varname, "", tkey, false, true) + return "" + } + funcs["decLineVar"] = func(varname, decodedNilVarname string) string { + x.decVar(varname, decodedNilVarname, telem, false, true) + return "" + } + funcs["var"] = func(s string) string { + return ts.TempVar + s + ts.Rand + } + + tm, err := template.New("").Funcs(funcs).Parse(genDecMapTmpl) + if err != nil { + panic(err) + } + if err = tm.Execute(x.w, &ts); err != nil { + panic(err) + } +} + +func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintptr, t reflect.Type) { + ti := x.ti.get(rtid, t) + tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing. + x.line("switch (" + kName + ") {") + var newbuf, nilbuf genBuf + for _, si := range tisfi { + x.line("case \"" + si.encName + "\":") + newbuf.reset() + nilbuf.reset() + t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf) + x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf) + x.decVarMain(varname+"."+t2.Name, x.varsfx(), t2.Type, false) + x.line("}") + } + x.line("default:") + // pass the slice here, so that the string will not escape, and maybe save allocation + x.line("z.DecStructFieldNotFound(-1, " + kName + ")") + x.line("} // end switch " + kName) +} + +func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) { + tpfx := genTempVarPfx + ti := x.ti.get(rtid, t) + i := x.varsfx() + kName := tpfx + "s" + i + + switch style { + case genStructMapStyleLenPrefix: + x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i) + case genStructMapStyleCheckBreak: + x.linef("for %sj%s := 0; !r.CheckBreak(); %sj%s++ {", tpfx, i, tpfx, i) + default: // 0, otherwise. + x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length + x.linef("for %sj%s := 0; ; %sj%s++ {", tpfx, i, tpfx, i) + x.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname) + x.line("} else { if r.CheckBreak() { break }; }") + } + x.line("r.ReadMapElemKey()") + + // emulate decstructfieldkey + switch ti.keyType { + case valueTypeInt: + x.linef("%s := z.StringView(strconv.AppendInt(z.DecScratchArrayBuffer()[:0], r.DecodeInt64(), 10))", kName) + case valueTypeUint: + x.linef("%s := z.StringView(strconv.AppendUint(z.DecScratchArrayBuffer()[:0], r.DecodeUint64(), 10))", kName) + case valueTypeFloat: + x.linef("%s := z.StringView(strconv.AppendFloat(z.DecScratchArrayBuffer()[:0], r.DecodeFloat64(), 'f', -1, 64))", kName) + default: // string + x.linef("%s := z.StringView(r.DecodeStringAsBytes())", kName) + } + // x.linef("%s := z.StringView(r.DecStructFieldKey(codecSelferValueType%s%s, z.DecScratchArrayBuffer()))", kName, ti.keyType.String(), x.xs) + + x.line("r.ReadMapElemValue()") + x.decStructMapSwitch(kName, varname, rtid, t) + + x.line("} // end for " + tpfx + "j" + i) + x.line("r.ReadMapEnd()") +} + +func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) { + tpfx := genTempVarPfx + i := x.varsfx() + ti := x.ti.get(rtid, t) + tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing. + x.linef("var %sj%s int", tpfx, i) + x.linef("var %sb%s bool", tpfx, i) // break + x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length + var newbuf, nilbuf genBuf + for _, si := range tisfi { + x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }", + tpfx, i, tpfx, i, tpfx, i, + tpfx, i, lenvarname, tpfx, i) + x.linef("if %sb%s { r.ReadArrayEnd(); %s }", tpfx, i, breakString) + x.line("r.ReadArrayElem()") + newbuf.reset() + nilbuf.reset() + t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf) + x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf) + x.decVarMain(varname+"."+t2.Name, x.varsfx(), t2.Type, false) + x.line("}") + } + // read remaining values and throw away. + x.line("for {") + x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }", + tpfx, i, tpfx, i, tpfx, i, + tpfx, i, lenvarname, tpfx, i) + x.linef("if %sb%s { break }", tpfx, i) + x.line("r.ReadArrayElem()") + x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i) + x.line("}") + x.line("r.ReadArrayEnd()") +} + +func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) { + // varname MUST be a ptr, or a struct field or a slice element. + i := x.varsfx() + x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i) + x.linef("if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs) + x.line(genTempVarPfx + "l" + i + " := r.ReadMapStart()") + x.linef("if %sl%s == 0 {", genTempVarPfx, i) + x.line("r.ReadMapEnd()") + if genUseOneFunctionForDecStructMap { + x.line("} else { ") + x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i) + } else { + x.line("} else if " + genTempVarPfx + "l" + i + " > 0 { ") + x.line(varname + ".codecDecodeSelfFromMapLenPrefix(" + genTempVarPfx + "l" + i + ", d)") + x.line("} else {") + x.line(varname + ".codecDecodeSelfFromMapCheckBreak(" + genTempVarPfx + "l" + i + ", d)") + } + x.line("}") + + // else if container is array + x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs) + x.line(genTempVarPfx + "l" + i + " := r.ReadArrayStart()") + x.linef("if %sl%s == 0 {", genTempVarPfx, i) + x.line("r.ReadArrayEnd()") + x.line("} else { ") + x.linef("%s.codecDecodeSelfFromArray(%sl%s, d)", varname, genTempVarPfx, i) + x.line("}") + // else panic + x.line("} else { ") + x.line("panic(errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + ")") + x.line("} ") +} + +// -------- + +func (x *genRunner) newGenV(t reflect.Type) (v genV) { + switch t.Kind() { + case reflect.Slice, reflect.Array: + te := t.Elem() + v.Elem = x.genTypeName(te) + v.Size = int(te.Size()) + case reflect.Map: + te, tk := t.Elem(), t.Key() + v.Elem = x.genTypeName(te) + v.MapKey = x.genTypeName(tk) + v.Size = int(te.Size() + tk.Size()) + default: + panic("unexpected type for newGenV. Requires map or slice type") + } + return +} + +func (x *genV) MethodNamePfx(prefix string, prim bool) string { + var name []byte + if prefix != "" { + name = append(name, prefix...) + } + if prim { + name = append(name, genTitleCaseName(x.Primitive)...) + } else { + if x.MapKey == "" { + name = append(name, "Slice"...) + } else { + name = append(name, "Map"...) + name = append(name, genTitleCaseName(x.MapKey)...) + } + name = append(name, genTitleCaseName(x.Elem)...) + } + return string(name) + +} + +// genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise. +// +// This handles the misbehaviour that occurs when 1.5-style vendoring is enabled, +// where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped. +// We strip it here. +func genImportPath(t reflect.Type) (s string) { + s = t.PkgPath() + s = genStripVendor(s) + return +} + +// A go identifier is (letter|_)[letter|number|_]* +func genGoIdentifier(s string, checkFirstChar bool) string { + b := make([]byte, 0, len(s)) + t := make([]byte, 4) + var n int + for i, r := range s { + if checkFirstChar && i == 0 && !unicode.IsLetter(r) { + b = append(b, '_') + } + // r must be unicode_letter, unicode_digit or _ + if unicode.IsLetter(r) || unicode.IsDigit(r) { + n = utf8.EncodeRune(t, r) + b = append(b, t[:n]...) + } else { + b = append(b, '_') + } + } + return string(b) +} + +func genNonPtr(t reflect.Type) reflect.Type { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t +} + +func genTitleCaseName(s string) string { + switch s { + case "interface{}", "interface {}": + return "Intf" + default: + return strings.ToUpper(s[0:1]) + s[1:] + } +} + +func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) { + var ptrPfx string + for t.Kind() == reflect.Ptr { + ptrPfx += "Ptrto" + t = t.Elem() + } + tstr := t.String() + if tn := t.Name(); tn != "" { + if tRef != nil && genImportPath(t) == genImportPath(tRef) { + return ptrPfx + tn + } else { + if genQNameRegex.MatchString(tstr) { + return ptrPfx + strings.Replace(tstr, ".", "_", 1000) + } else { + return ptrPfx + genCustomTypeName(tstr) + } + } + } + switch t.Kind() { + case reflect.Map: + return ptrPfx + "Map" + genMethodNameT(t.Key(), tRef) + genMethodNameT(t.Elem(), tRef) + case reflect.Slice: + return ptrPfx + "Slice" + genMethodNameT(t.Elem(), tRef) + case reflect.Array: + return ptrPfx + "Array" + strconv.FormatInt(int64(t.Len()), 10) + genMethodNameT(t.Elem(), tRef) + case reflect.Chan: + var cx string + switch t.ChanDir() { + case reflect.SendDir: + cx = "ChanSend" + case reflect.RecvDir: + cx = "ChanRecv" + default: + cx = "Chan" + } + return ptrPfx + cx + genMethodNameT(t.Elem(), tRef) + default: + if t == intfTyp { + return ptrPfx + "Interface" + } else { + if tRef != nil && genImportPath(t) == genImportPath(tRef) { + if t.Name() != "" { + return ptrPfx + t.Name() + } else { + return ptrPfx + genCustomTypeName(tstr) + } + } else { + // best way to get the package name inclusive + // return ptrPfx + strings.Replace(tstr, ".", "_", 1000) + // return ptrPfx + genBase32enc.EncodeToString([]byte(tstr)) + if t.Name() != "" && genQNameRegex.MatchString(tstr) { + return ptrPfx + strings.Replace(tstr, ".", "_", 1000) + } else { + return ptrPfx + genCustomTypeName(tstr) + } + } + } + } +} + +// genCustomNameForType base32encodes the t.String() value in such a way +// that it can be used within a function name. +func genCustomTypeName(tstr string) string { + len2 := genBase32enc.EncodedLen(len(tstr)) + bufx := make([]byte, len2) + genBase32enc.Encode(bufx, []byte(tstr)) + for i := len2 - 1; i >= 0; i-- { + if bufx[i] == '=' { + len2-- + } else { + break + } + } + return string(bufx[:len2]) +} + +func genIsImmutable(t reflect.Type) (v bool) { + return isImmutableKind(t.Kind()) +} + +func genStripVendor(s string) string { + // HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later. + // if s contains /vendor/ OR startsWith vendor/, then return everything after it. + const vendorStart = "vendor/" + const vendorInline = "/vendor/" + if i := strings.LastIndex(s, vendorInline); i >= 0 { + s = s[i+len(vendorInline):] + } else if strings.HasPrefix(s, vendorStart) { + s = s[len(vendorStart):] + } + return s +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper.go new file mode 100644 index 00000000..9c0ed16a --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper.go @@ -0,0 +1,2926 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +// Contains code shared by both encode and decode. + +// Some shared ideas around encoding/decoding +// ------------------------------------------ +// +// If an interface{} is passed, we first do a type assertion to see if it is +// a primitive type or a map/slice of primitive types, and use a fastpath to handle it. +// +// If we start with a reflect.Value, we are already in reflect.Value land and +// will try to grab the function for the underlying Type and directly call that function. +// This is more performant than calling reflect.Value.Interface(). +// +// This still helps us bypass many layers of reflection, and give best performance. +// +// Containers +// ------------ +// Containers in the stream are either associative arrays (key-value pairs) or +// regular arrays (indexed by incrementing integers). +// +// Some streams support indefinite-length containers, and use a breaking +// byte-sequence to denote that the container has come to an end. +// +// Some streams also are text-based, and use explicit separators to denote the +// end/beginning of different values. +// +// During encode, we use a high-level condition to determine how to iterate through +// the container. That decision is based on whether the container is text-based (with +// separators) or binary (without separators). If binary, we do not even call the +// encoding of separators. +// +// During decode, we use a different high-level condition to determine how to iterate +// through the containers. That decision is based on whether the stream contained +// a length prefix, or if it used explicit breaks. If length-prefixed, we assume that +// it has to be binary, and we do not even try to read separators. +// +// Philosophy +// ------------ +// On decode, this codec will update containers appropriately: +// - If struct, update fields from stream into fields of struct. +// If field in stream not found in struct, handle appropriately (based on option). +// If a struct field has no corresponding value in the stream, leave it AS IS. +// If nil in stream, set value to nil/zero value. +// - If map, update map from stream. +// If the stream value is NIL, set the map to nil. +// - if slice, try to update up to length of array in stream. +// if container len is less than stream array length, +// and container cannot be expanded, handled (based on option). +// This means you can decode 4-element stream array into 1-element array. +// +// ------------------------------------ +// On encode, user can specify omitEmpty. This means that the value will be omitted +// if the zero value. The problem may occur during decode, where omitted values do not affect +// the value being decoded into. This means that if decoding into a struct with an +// int field with current value=5, and the field is omitted in the stream, then after +// decoding, the value will still be 5 (not 0). +// omitEmpty only works if you guarantee that you always decode into zero-values. +// +// ------------------------------------ +// We could have truncated a map to remove keys not available in the stream, +// or set values in the struct which are not in the stream to their zero values. +// We decided against it because there is no efficient way to do it. +// We may introduce it as an option later. +// However, that will require enabling it for both runtime and code generation modes. +// +// To support truncate, we need to do 2 passes over the container: +// map +// - first collect all keys (e.g. in k1) +// - for each key in stream, mark k1 that the key should not be removed +// - after updating map, do second pass and call delete for all keys in k1 which are not marked +// struct: +// - for each field, track the *typeInfo s1 +// - iterate through all s1, and for each one not marked, set value to zero +// - this involves checking the possible anonymous fields which are nil ptrs. +// too much work. +// +// ------------------------------------------ +// Error Handling is done within the library using panic. +// +// This way, the code doesn't have to keep checking if an error has happened, +// and we don't have to keep sending the error value along with each call +// or storing it in the En|Decoder and checking it constantly along the way. +// +// The disadvantage is that small functions which use panics cannot be inlined. +// The code accounts for that by only using panics behind an interface; +// since interface calls cannot be inlined, this is irrelevant. +// +// We considered storing the error is En|Decoder. +// - once it has its err field set, it cannot be used again. +// - panicing will be optional, controlled by const flag. +// - code should always check error first and return early. +// We eventually decided against it as it makes the code clumsier to always +// check for these error conditions. + +import ( + "bytes" + "encoding" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +const ( + scratchByteArrayLen = 32 + // initCollectionCap = 16 // 32 is defensive. 16 is preferred. + + // Support encoding.(Binary|Text)(Unm|M)arshaler. + // This constant flag will enable or disable it. + supportMarshalInterfaces = true + + // for debugging, set this to false, to catch panic traces. + // Note that this will always cause rpc tests to fail, since they need io.EOF sent via panic. + recoverPanicToErr = true + + // arrayCacheLen is the length of the cache used in encoder or decoder for + // allowing zero-alloc initialization. + // arrayCacheLen = 8 + + // size of the cacheline: defaulting to value for archs: amd64, arm64, 386 + // should use "runtime/internal/sys".CacheLineSize, but that is not exposed. + cacheLineSize = 64 + + wordSizeBits = 32 << (^uint(0) >> 63) // strconv.IntSize + wordSize = wordSizeBits / 8 + + // so structFieldInfo fits into 8 bytes + maxLevelsEmbedding = 14 + + // useFinalizers=true configures finalizers to release pool'ed resources + // acquired by Encoder/Decoder during their GC. + // + // Note that calling SetFinalizer is always expensive, + // as code must be run on the systemstack even for SetFinalizer(t, nil). + // + // We document that folks SHOULD call Release() when done, or they can + // explicitly call SetFinalizer themselves e.g. + // runtime.SetFinalizer(e, (*Encoder).Release) + // runtime.SetFinalizer(d, (*Decoder).Release) + useFinalizers = false +) + +var oneByteArr [1]byte +var zeroByteSlice = oneByteArr[:0:0] + +var codecgen bool + +var refBitset bitset256 +var pool pooler +var panicv panicHdl + +func init() { + pool.init() + + refBitset.set(byte(reflect.Map)) + refBitset.set(byte(reflect.Ptr)) + refBitset.set(byte(reflect.Func)) + refBitset.set(byte(reflect.Chan)) +} + +type clsErr struct { + closed bool // is it closed? + errClosed error // error on closing +} + +// type entryType uint8 + +// const ( +// entryTypeBytes entryType = iota // make this 0, so a comparison is cheap +// entryTypeIo +// entryTypeBufio +// entryTypeUnset = 255 +// ) + +type charEncoding uint8 + +const ( + _ charEncoding = iota // make 0 unset + cUTF8 + cUTF16LE + cUTF16BE + cUTF32LE + cUTF32BE + // Deprecated: not a true char encoding value + cRAW charEncoding = 255 +) + +// valueType is the stream type +type valueType uint8 + +const ( + valueTypeUnset valueType = iota + valueTypeNil + valueTypeInt + valueTypeUint + valueTypeFloat + valueTypeBool + valueTypeString + valueTypeSymbol + valueTypeBytes + valueTypeMap + valueTypeArray + valueTypeTime + valueTypeExt + + // valueTypeInvalid = 0xff +) + +var valueTypeStrings = [...]string{ + "Unset", + "Nil", + "Int", + "Uint", + "Float", + "Bool", + "String", + "Symbol", + "Bytes", + "Map", + "Array", + "Timestamp", + "Ext", +} + +func (x valueType) String() string { + if int(x) < len(valueTypeStrings) { + return valueTypeStrings[x] + } + return strconv.FormatInt(int64(x), 10) +} + +type seqType uint8 + +const ( + _ seqType = iota + seqTypeArray + seqTypeSlice + seqTypeChan +) + +// note that containerMapStart and containerArraySend are not sent. +// This is because the ReadXXXStart and EncodeXXXStart already does these. +type containerState uint8 + +const ( + _ containerState = iota + + containerMapStart // slot left open, since Driver method already covers it + containerMapKey + containerMapValue + containerMapEnd + containerArrayStart // slot left open, since Driver methods already cover it + containerArrayElem + containerArrayEnd +) + +// // sfiIdx used for tracking where a (field/enc)Name is seen in a []*structFieldInfo +// type sfiIdx struct { +// name string +// index int +// } + +// do not recurse if a containing type refers to an embedded type +// which refers back to its containing type (via a pointer). +// The second time this back-reference happens, break out, +// so as not to cause an infinite loop. +const rgetMaxRecursion = 2 + +// Anecdotally, we believe most types have <= 12 fields. +// - even Java's PMD rules set TooManyFields threshold to 15. +// However, go has embedded fields, which should be regarded as +// top level, allowing structs to possibly double or triple. +// In addition, we don't want to keep creating transient arrays, +// especially for the sfi index tracking, and the evtypes tracking. +// +// So - try to keep typeInfoLoadArray within 2K bytes +const ( + typeInfoLoadArraySfisLen = 16 + typeInfoLoadArraySfiidxLen = 8 * 112 + typeInfoLoadArrayEtypesLen = 12 + typeInfoLoadArrayBLen = 8 * 4 +) + +type typeInfoLoad struct { + // fNames []string + // encNames []string + etypes []uintptr + sfis []structFieldInfo +} + +type typeInfoLoadArray struct { + // fNames [typeInfoLoadArrayLen]string + // encNames [typeInfoLoadArrayLen]string + sfis [typeInfoLoadArraySfisLen]structFieldInfo + sfiidx [typeInfoLoadArraySfiidxLen]byte + etypes [typeInfoLoadArrayEtypesLen]uintptr + b [typeInfoLoadArrayBLen]byte // scratch - used for struct field names +} + +// mirror json.Marshaler and json.Unmarshaler here, +// so we don't import the encoding/json package + +type jsonMarshaler interface { + MarshalJSON() ([]byte, error) +} +type jsonUnmarshaler interface { + UnmarshalJSON([]byte) error +} + +type isZeroer interface { + IsZero() bool +} + +type codecError struct { + name string + err interface{} +} + +func (e codecError) Cause() error { + switch xerr := e.err.(type) { + case nil: + return nil + case error: + return xerr + case string: + return errors.New(xerr) + case fmt.Stringer: + return errors.New(xerr.String()) + default: + return fmt.Errorf("%v", e.err) + } +} + +func (e codecError) Error() string { + return fmt.Sprintf("%s error: %v", e.name, e.err) +} + +// type byteAccepter func(byte) bool + +var ( + bigen = binary.BigEndian + structInfoFieldName = "_struct" + + mapStrIntfTyp = reflect.TypeOf(map[string]interface{}(nil)) + mapIntfIntfTyp = reflect.TypeOf(map[interface{}]interface{}(nil)) + intfSliceTyp = reflect.TypeOf([]interface{}(nil)) + intfTyp = intfSliceTyp.Elem() + + reflectValTyp = reflect.TypeOf((*reflect.Value)(nil)).Elem() + + stringTyp = reflect.TypeOf("") + timeTyp = reflect.TypeOf(time.Time{}) + rawExtTyp = reflect.TypeOf(RawExt{}) + rawTyp = reflect.TypeOf(Raw{}) + uintptrTyp = reflect.TypeOf(uintptr(0)) + uint8Typ = reflect.TypeOf(uint8(0)) + uint8SliceTyp = reflect.TypeOf([]uint8(nil)) + uintTyp = reflect.TypeOf(uint(0)) + intTyp = reflect.TypeOf(int(0)) + + mapBySliceTyp = reflect.TypeOf((*MapBySlice)(nil)).Elem() + + binaryMarshalerTyp = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem() + binaryUnmarshalerTyp = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem() + + textMarshalerTyp = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() + textUnmarshalerTyp = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + + jsonMarshalerTyp = reflect.TypeOf((*jsonMarshaler)(nil)).Elem() + jsonUnmarshalerTyp = reflect.TypeOf((*jsonUnmarshaler)(nil)).Elem() + + selferTyp = reflect.TypeOf((*Selfer)(nil)).Elem() + missingFielderTyp = reflect.TypeOf((*MissingFielder)(nil)).Elem() + iszeroTyp = reflect.TypeOf((*isZeroer)(nil)).Elem() + + uint8TypId = rt2id(uint8Typ) + uint8SliceTypId = rt2id(uint8SliceTyp) + rawExtTypId = rt2id(rawExtTyp) + rawTypId = rt2id(rawTyp) + intfTypId = rt2id(intfTyp) + timeTypId = rt2id(timeTyp) + stringTypId = rt2id(stringTyp) + + mapStrIntfTypId = rt2id(mapStrIntfTyp) + mapIntfIntfTypId = rt2id(mapIntfIntfTyp) + intfSliceTypId = rt2id(intfSliceTyp) + // mapBySliceTypId = rt2id(mapBySliceTyp) + + intBitsize = uint8(intTyp.Bits()) + uintBitsize = uint8(uintTyp.Bits()) + + // bsAll0x00 = []byte{0, 0, 0, 0, 0, 0, 0, 0} + bsAll0xff = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + + chkOvf checkOverflow + + errNoFieldNameToStructFieldInfo = errors.New("no field name passed to parseStructFieldInfo") +) + +var defTypeInfos = NewTypeInfos([]string{"codec", "json"}) + +var immutableKindsSet = [32]bool{ + // reflect.Invalid: , + reflect.Bool: true, + reflect.Int: true, + reflect.Int8: true, + reflect.Int16: true, + reflect.Int32: true, + reflect.Int64: true, + reflect.Uint: true, + reflect.Uint8: true, + reflect.Uint16: true, + reflect.Uint32: true, + reflect.Uint64: true, + reflect.Uintptr: true, + reflect.Float32: true, + reflect.Float64: true, + reflect.Complex64: true, + reflect.Complex128: true, + // reflect.Array + // reflect.Chan + // reflect.Func: true, + // reflect.Interface + // reflect.Map + // reflect.Ptr + // reflect.Slice + reflect.String: true, + reflect.Struct: true, + // reflect.UnsafePointer +} + +// Selfer defines methods by which a value can encode or decode itself. +// +// Any type which implements Selfer will be able to encode or decode itself. +// Consequently, during (en|de)code, this takes precedence over +// (text|binary)(M|Unm)arshal or extension support. +// +// By definition, it is not allowed for a Selfer to directly call Encode or Decode on itself. +// If that is done, Encode/Decode will rightfully fail with a Stack Overflow style error. +// For example, the snippet below will cause such an error. +// +// type testSelferRecur struct{} +// func (s *testSelferRecur) CodecEncodeSelf(e *Encoder) { e.MustEncode(s) } +// func (s *testSelferRecur) CodecDecodeSelf(d *Decoder) { d.MustDecode(s) } +// +// Note: *the first set of bytes of any value MUST NOT represent nil in the format*. +// This is because, during each decode, we first check the the next set of bytes +// represent nil, and if so, we just set the value to nil. +type Selfer interface { + CodecEncodeSelf(*Encoder) + CodecDecodeSelf(*Decoder) +} + +// MissingFielder defines the interface allowing structs to internally decode or encode +// values which do not map to struct fields. +// +// We expect that this interface is bound to a pointer type (so the mutation function works). +// +// A use-case is if a version of a type unexports a field, but you want compatibility between +// both versions during encoding and decoding. +// +// Note that the interface is completely ignored during codecgen. +type MissingFielder interface { + // CodecMissingField is called to set a missing field and value pair. + // + // It returns true if the missing field was set on the struct. + CodecMissingField(field []byte, value interface{}) bool + + // CodecMissingFields returns the set of fields which are not struct fields + CodecMissingFields() map[string]interface{} +} + +// MapBySlice is a tag interface that denotes wrapped slice should encode as a map in the stream. +// The slice contains a sequence of key-value pairs. +// This affords storing a map in a specific sequence in the stream. +// +// Example usage: +// +// type T1 []string // or []int or []Point or any other "slice" type +// func (_ T1) MapBySlice{} // T1 now implements MapBySlice, and will be encoded as a map +// type T2 struct { KeyValues T1 } +// +// var kvs = []string{"one", "1", "two", "2", "three", "3"} +// var v2 = T2{ KeyValues: T1(kvs) } +// // v2 will be encoded like the map: {"KeyValues": {"one": "1", "two": "2", "three": "3"} } +// +// The support of MapBySlice affords the following: +// - A slice type which implements MapBySlice will be encoded as a map +// - A slice can be decoded from a map in the stream +// - It MUST be a slice type (not a pointer receiver) that implements MapBySlice +type MapBySlice interface { + MapBySlice() +} + +// BasicHandle encapsulates the common options and extension functions. +// +// Deprecated: DO NOT USE DIRECTLY. EXPORTED FOR GODOC BENEFIT. WILL BE REMOVED. +type BasicHandle struct { + // BasicHandle is always a part of a different type. + // It doesn't have to fit into it own cache lines. + + // TypeInfos is used to get the type info for any type. + // + // If not configured, the default TypeInfos is used, which uses struct tag keys: codec, json + TypeInfos *TypeInfos + + // Note: BasicHandle is not comparable, due to these slices here (extHandle, intf2impls). + // If *[]T is used instead, this becomes comparable, at the cost of extra indirection. + // Thses slices are used all the time, so keep as slices (not pointers). + + extHandle + + intf2impls + + inited uint32 + _ uint32 // padding + + // ---- cache line + + RPCOptions + + // TimeNotBuiltin configures whether time.Time should be treated as a builtin type. + // + // All Handlers should know how to encode/decode time.Time as part of the core + // format specification, or as a standard extension defined by the format. + // + // However, users can elect to handle time.Time as a custom extension, or via the + // standard library's encoding.Binary(M|Unm)arshaler or Text(M|Unm)arshaler interface. + // To elect this behavior, users can set TimeNotBuiltin=true. + // Note: Setting TimeNotBuiltin=true can be used to enable the legacy behavior + // (for Cbor and Msgpack), where time.Time was not a builtin supported type. + TimeNotBuiltin bool + + // ExplicitRelease configures whether Release() is implicitly called after an encode or + // decode call. + // + // If you will hold onto an Encoder or Decoder for re-use, by calling Reset(...) + // on it or calling (Must)Encode repeatedly into a given []byte or io.Writer, + // then you do not want it to be implicitly closed after each Encode/Decode call. + // Doing so will unnecessarily return resources to the shared pool, only for you to + // grab them right after again to do another Encode/Decode call. + // + // Instead, you configure ExplicitRelease=true, and you explicitly call Release() when + // you are truly done. + // + // As an alternative, you can explicitly set a finalizer - so its resources + // are returned to the shared pool before it is garbage-collected. Do it as below: + // runtime.SetFinalizer(e, (*Encoder).Release) + // runtime.SetFinalizer(d, (*Decoder).Release) + ExplicitRelease bool + + be bool // is handle a binary encoding? + js bool // is handle javascript handler? + n byte // first letter of handle name + _ uint16 // padding + + // ---- cache line + + DecodeOptions + + // ---- cache line + + EncodeOptions + + // noBuiltInTypeChecker + + rtidFns atomicRtidFnSlice + mu sync.Mutex + // r []uintptr // rtids mapped to s above +} + +// basicHandle returns an initialized BasicHandle from the Handle. +func basicHandle(hh Handle) (x *BasicHandle) { + x = hh.getBasicHandle() + // ** We need to simulate once.Do, to ensure no data race within the block. + // ** Consequently, below would not work. + // if atomic.CompareAndSwapUint32(&x.inited, 0, 1) { + // x.be = hh.isBinary() + // _, x.js = hh.(*JsonHandle) + // x.n = hh.Name()[0] + // } + + // simulate once.Do using our own stored flag and mutex as a CompareAndSwap + // is not sufficient, since a race condition can occur within init(Handle) function. + // init is made noinline, so that this function can be inlined by its caller. + if atomic.LoadUint32(&x.inited) == 0 { + x.init(hh) + } + return +} + +//go:noinline +func (x *BasicHandle) init(hh Handle) { + // make it uninlineable, as it is called at most once + x.mu.Lock() + if x.inited == 0 { + x.be = hh.isBinary() + _, x.js = hh.(*JsonHandle) + x.n = hh.Name()[0] + atomic.StoreUint32(&x.inited, 1) + } + x.mu.Unlock() +} + +func (x *BasicHandle) getBasicHandle() *BasicHandle { + return x +} + +func (x *BasicHandle) getTypeInfo(rtid uintptr, rt reflect.Type) (pti *typeInfo) { + if x.TypeInfos == nil { + return defTypeInfos.get(rtid, rt) + } + return x.TypeInfos.get(rtid, rt) +} + +func findFn(s []codecRtidFn, rtid uintptr) (i uint, fn *codecFn) { + // binary search. adapted from sort/search.go. + // Note: we use goto (instead of for loop) so this can be inlined. + + // h, i, j := 0, 0, len(s) + var h uint // var h, i uint + var j = uint(len(s)) +LOOP: + if i < j { + h = i + (j-i)/2 + if s[h].rtid < rtid { + i = h + 1 + } else { + j = h + } + goto LOOP + } + if i < uint(len(s)) && s[i].rtid == rtid { + fn = s[i].fn + } + return +} + +func (x *BasicHandle) fn(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (fn *codecFn) { + rtid := rt2id(rt) + sp := x.rtidFns.load() + if sp != nil { + if _, fn = findFn(sp, rtid); fn != nil { + // xdebugf("<<<< %c: found fn for %v in rtidfns of size: %v", c.n, rt, len(sp)) + return + } + } + c := x + // xdebugf("#### for %c: load fn for %v in rtidfns of size: %v", c.n, rt, len(sp)) + fn = new(codecFn) + fi := &(fn.i) + ti := c.getTypeInfo(rtid, rt) + fi.ti = ti + + rk := reflect.Kind(ti.kind) + + if checkCodecSelfer && (ti.cs || ti.csp) { + fn.fe = (*Encoder).selferMarshal + fn.fd = (*Decoder).selferUnmarshal + fi.addrF = true + fi.addrD = ti.csp + fi.addrE = ti.csp + } else if rtid == timeTypId && !c.TimeNotBuiltin { + fn.fe = (*Encoder).kTime + fn.fd = (*Decoder).kTime + } else if rtid == rawTypId { + fn.fe = (*Encoder).raw + fn.fd = (*Decoder).raw + } else if rtid == rawExtTypId { + fn.fe = (*Encoder).rawExt + fn.fd = (*Decoder).rawExt + fi.addrF = true + fi.addrD = true + fi.addrE = true + } else if xfFn := c.getExt(rtid); xfFn != nil { + fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext + fn.fe = (*Encoder).ext + fn.fd = (*Decoder).ext + fi.addrF = true + fi.addrD = true + if rk == reflect.Struct || rk == reflect.Array { + fi.addrE = true + } + } else if supportMarshalInterfaces && c.be && (ti.bm || ti.bmp) && (ti.bu || ti.bup) { + fn.fe = (*Encoder).binaryMarshal + fn.fd = (*Decoder).binaryUnmarshal + fi.addrF = true + fi.addrD = ti.bup + fi.addrE = ti.bmp + } else if supportMarshalInterfaces && !c.be && c.js && (ti.jm || ti.jmp) && (ti.ju || ti.jup) { + //If JSON, we should check JSONMarshal before textMarshal + fn.fe = (*Encoder).jsonMarshal + fn.fd = (*Decoder).jsonUnmarshal + fi.addrF = true + fi.addrD = ti.jup + fi.addrE = ti.jmp + } else if supportMarshalInterfaces && !c.be && (ti.tm || ti.tmp) && (ti.tu || ti.tup) { + fn.fe = (*Encoder).textMarshal + fn.fd = (*Decoder).textUnmarshal + fi.addrF = true + fi.addrD = ti.tup + fi.addrE = ti.tmp + } else { + if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) { + if ti.pkgpath == "" { // un-named slice or map + if idx := fastpathAV.index(rtid); idx != -1 { + fn.fe = fastpathAV[idx].encfn + fn.fd = fastpathAV[idx].decfn + fi.addrD = true + fi.addrF = false + } + } else { + // use mapping for underlying type if there + var rtu reflect.Type + if rk == reflect.Map { + rtu = reflect.MapOf(ti.key, ti.elem) + } else { + rtu = reflect.SliceOf(ti.elem) + } + rtuid := rt2id(rtu) + if idx := fastpathAV.index(rtuid); idx != -1 { + xfnf := fastpathAV[idx].encfn + xrt := fastpathAV[idx].rt + fn.fe = func(e *Encoder, xf *codecFnInfo, xrv reflect.Value) { + xfnf(e, xf, xrv.Convert(xrt)) + } + fi.addrD = true + fi.addrF = false // meaning it can be an address(ptr) or a value + xfnf2 := fastpathAV[idx].decfn + fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) { + if xrv.Kind() == reflect.Ptr { + xfnf2(d, xf, xrv.Convert(reflect.PtrTo(xrt))) + } else { + xfnf2(d, xf, xrv.Convert(xrt)) + } + } + } + } + } + if fn.fe == nil && fn.fd == nil { + switch rk { + case reflect.Bool: + fn.fe = (*Encoder).kBool + fn.fd = (*Decoder).kBool + case reflect.String: + fn.fe = (*Encoder).kString + fn.fd = (*Decoder).kString + case reflect.Int: + fn.fd = (*Decoder).kInt + fn.fe = (*Encoder).kInt + case reflect.Int8: + fn.fe = (*Encoder).kInt8 + fn.fd = (*Decoder).kInt8 + case reflect.Int16: + fn.fe = (*Encoder).kInt16 + fn.fd = (*Decoder).kInt16 + case reflect.Int32: + fn.fe = (*Encoder).kInt32 + fn.fd = (*Decoder).kInt32 + case reflect.Int64: + fn.fe = (*Encoder).kInt64 + fn.fd = (*Decoder).kInt64 + case reflect.Uint: + fn.fd = (*Decoder).kUint + fn.fe = (*Encoder).kUint + case reflect.Uint8: + fn.fe = (*Encoder).kUint8 + fn.fd = (*Decoder).kUint8 + case reflect.Uint16: + fn.fe = (*Encoder).kUint16 + fn.fd = (*Decoder).kUint16 + case reflect.Uint32: + fn.fe = (*Encoder).kUint32 + fn.fd = (*Decoder).kUint32 + case reflect.Uint64: + fn.fe = (*Encoder).kUint64 + fn.fd = (*Decoder).kUint64 + case reflect.Uintptr: + fn.fe = (*Encoder).kUintptr + fn.fd = (*Decoder).kUintptr + case reflect.Float32: + fn.fe = (*Encoder).kFloat32 + fn.fd = (*Decoder).kFloat32 + case reflect.Float64: + fn.fe = (*Encoder).kFloat64 + fn.fd = (*Decoder).kFloat64 + case reflect.Invalid: + fn.fe = (*Encoder).kInvalid + fn.fd = (*Decoder).kErr + case reflect.Chan: + fi.seq = seqTypeChan + fn.fe = (*Encoder).kSlice + fn.fd = (*Decoder).kSlice + case reflect.Slice: + fi.seq = seqTypeSlice + fn.fe = (*Encoder).kSlice + fn.fd = (*Decoder).kSlice + case reflect.Array: + fi.seq = seqTypeArray + fn.fe = (*Encoder).kSlice + fi.addrF = false + fi.addrD = false + rt2 := reflect.SliceOf(ti.elem) + fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) { + d.h.fn(rt2, true, false).fd(d, xf, xrv.Slice(0, xrv.Len())) + } + // fn.fd = (*Decoder).kArray + case reflect.Struct: + if ti.anyOmitEmpty || ti.mf || ti.mfp { + fn.fe = (*Encoder).kStruct + } else { + fn.fe = (*Encoder).kStructNoOmitempty + } + fn.fd = (*Decoder).kStruct + case reflect.Map: + fn.fe = (*Encoder).kMap + fn.fd = (*Decoder).kMap + case reflect.Interface: + // encode: reflect.Interface are handled already by preEncodeValue + fn.fd = (*Decoder).kInterface + fn.fe = (*Encoder).kErr + default: + // reflect.Ptr and reflect.Interface are handled already by preEncodeValue + fn.fe = (*Encoder).kErr + fn.fd = (*Decoder).kErr + } + } + } + + c.mu.Lock() + var sp2 []codecRtidFn + sp = c.rtidFns.load() + if sp == nil { + sp2 = []codecRtidFn{{rtid, fn}} + c.rtidFns.store(sp2) + // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2)) + // xdebugf(">>>> loading stored rtidfns of size: %v", len(c.rtidFns.load())) + } else { + idx, fn2 := findFn(sp, rtid) + if fn2 == nil { + sp2 = make([]codecRtidFn, len(sp)+1) + copy(sp2, sp[:idx]) + copy(sp2[idx+1:], sp[idx:]) + sp2[idx] = codecRtidFn{rtid, fn} + c.rtidFns.store(sp2) + // xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2)) + + } + } + c.mu.Unlock() + return +} + +// Handle defines a specific encoding format. It also stores any runtime state +// used during an Encoding or Decoding session e.g. stored state about Types, etc. +// +// Once a handle is configured, it can be shared across multiple Encoders and Decoders. +// +// Note that a Handle is NOT safe for concurrent modification. +// Consequently, do not modify it after it is configured if shared among +// multiple Encoders and Decoders in different goroutines. +// +// Consequently, the typical usage model is that a Handle is pre-configured +// before first time use, and not modified while in use. +// Such a pre-configured Handle is safe for concurrent access. +type Handle interface { + Name() string + // return the basic handle. It may not have been inited. + // Prefer to use basicHandle() helper function that ensures it has been inited. + getBasicHandle() *BasicHandle + recreateEncDriver(encDriver) bool + newEncDriver(w *Encoder) encDriver + newDecDriver(r *Decoder) decDriver + isBinary() bool + hasElemSeparators() bool + // IsBuiltinType(rtid uintptr) bool +} + +// Raw represents raw formatted bytes. +// We "blindly" store it during encode and retrieve the raw bytes during decode. +// Note: it is dangerous during encode, so we may gate the behaviour +// behind an Encode flag which must be explicitly set. +type Raw []byte + +// RawExt represents raw unprocessed extension data. +// Some codecs will decode extension data as a *RawExt +// if there is no registered extension for the tag. +// +// Only one of Data or Value is nil. +// If Data is nil, then the content of the RawExt is in the Value. +type RawExt struct { + Tag uint64 + // Data is the []byte which represents the raw ext. If nil, ext is exposed in Value. + // Data is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of types + Data []byte + // Value represents the extension, if Data is nil. + // Value is used by codecs (e.g. cbor, json) which leverage the format to do + // custom serialization of the types. + Value interface{} +} + +// BytesExt handles custom (de)serialization of types to/from []byte. +// It is used by codecs (e.g. binc, msgpack, simple) which do custom serialization of the types. +type BytesExt interface { + // WriteExt converts a value to a []byte. + // + // Note: v is a pointer iff the registered extension type is a struct or array kind. + WriteExt(v interface{}) []byte + + // ReadExt updates a value from a []byte. + // + // Note: dst is always a pointer kind to the registered extension type. + ReadExt(dst interface{}, src []byte) +} + +// InterfaceExt handles custom (de)serialization of types to/from another interface{} value. +// The Encoder or Decoder will then handle the further (de)serialization of that known type. +// +// It is used by codecs (e.g. cbor, json) which use the format to do custom serialization of types. +type InterfaceExt interface { + // ConvertExt converts a value into a simpler interface for easy encoding + // e.g. convert time.Time to int64. + // + // Note: v is a pointer iff the registered extension type is a struct or array kind. + ConvertExt(v interface{}) interface{} + + // UpdateExt updates a value from a simpler interface for easy decoding + // e.g. convert int64 to time.Time. + // + // Note: dst is always a pointer kind to the registered extension type. + UpdateExt(dst interface{}, src interface{}) +} + +// Ext handles custom (de)serialization of custom types / extensions. +type Ext interface { + BytesExt + InterfaceExt +} + +// addExtWrapper is a wrapper implementation to support former AddExt exported method. +type addExtWrapper struct { + encFn func(reflect.Value) ([]byte, error) + decFn func(reflect.Value, []byte) error +} + +func (x addExtWrapper) WriteExt(v interface{}) []byte { + bs, err := x.encFn(reflect.ValueOf(v)) + if err != nil { + panic(err) + } + return bs +} + +func (x addExtWrapper) ReadExt(v interface{}, bs []byte) { + if err := x.decFn(reflect.ValueOf(v), bs); err != nil { + panic(err) + } +} + +func (x addExtWrapper) ConvertExt(v interface{}) interface{} { + return x.WriteExt(v) +} + +func (x addExtWrapper) UpdateExt(dest interface{}, v interface{}) { + x.ReadExt(dest, v.([]byte)) +} + +type extWrapper struct { + BytesExt + InterfaceExt +} + +type bytesExtFailer struct{} + +func (bytesExtFailer) WriteExt(v interface{}) []byte { + panicv.errorstr("BytesExt.WriteExt is not supported") + return nil +} +func (bytesExtFailer) ReadExt(v interface{}, bs []byte) { + panicv.errorstr("BytesExt.ReadExt is not supported") +} + +type interfaceExtFailer struct{} + +func (interfaceExtFailer) ConvertExt(v interface{}) interface{} { + panicv.errorstr("InterfaceExt.ConvertExt is not supported") + return nil +} +func (interfaceExtFailer) UpdateExt(dest interface{}, v interface{}) { + panicv.errorstr("InterfaceExt.UpdateExt is not supported") +} + +type binaryEncodingType struct{} + +func (binaryEncodingType) isBinary() bool { return true } + +type textEncodingType struct{} + +func (textEncodingType) isBinary() bool { return false } + +// noBuiltInTypes is embedded into many types which do not support builtins +// e.g. msgpack, simple, cbor. + +// type noBuiltInTypeChecker struct{} +// func (noBuiltInTypeChecker) IsBuiltinType(rt uintptr) bool { return false } +// type noBuiltInTypes struct{ noBuiltInTypeChecker } + +type noBuiltInTypes struct{} + +func (noBuiltInTypes) EncodeBuiltin(rt uintptr, v interface{}) {} +func (noBuiltInTypes) DecodeBuiltin(rt uintptr, v interface{}) {} + +// type noStreamingCodec struct{} +// func (noStreamingCodec) CheckBreak() bool { return false } +// func (noStreamingCodec) hasElemSeparators() bool { return false } + +type noElemSeparators struct{} + +func (noElemSeparators) hasElemSeparators() (v bool) { return } +func (noElemSeparators) recreateEncDriver(e encDriver) (v bool) { return } + +// bigenHelper. +// Users must already slice the x completely, because we will not reslice. +type bigenHelper struct { + x []byte // must be correctly sliced to appropriate len. slicing is a cost. + w *encWriterSwitch +} + +func (z bigenHelper) writeUint16(v uint16) { + bigen.PutUint16(z.x, v) + z.w.writeb(z.x) +} + +func (z bigenHelper) writeUint32(v uint32) { + bigen.PutUint32(z.x, v) + z.w.writeb(z.x) +} + +func (z bigenHelper) writeUint64(v uint64) { + bigen.PutUint64(z.x, v) + z.w.writeb(z.x) +} + +type extTypeTagFn struct { + rtid uintptr + rtidptr uintptr + rt reflect.Type + tag uint64 + ext Ext + _padding [1]uint64 // padding +} + +type extHandle []extTypeTagFn + +// AddExt registes an encode and decode function for a reflect.Type. +// To deregister an Ext, call AddExt with nil encfn and/or nil decfn. +// +// Deprecated: Use SetBytesExt or SetInterfaceExt on the Handle instead. +func (o *extHandle) AddExt(rt reflect.Type, tag byte, + encfn func(reflect.Value) ([]byte, error), + decfn func(reflect.Value, []byte) error) (err error) { + if encfn == nil || decfn == nil { + return o.SetExt(rt, uint64(tag), nil) + } + return o.SetExt(rt, uint64(tag), addExtWrapper{encfn, decfn}) +} + +// SetExt will set the extension for a tag and reflect.Type. +// Note that the type must be a named type, and specifically not a pointer or Interface. +// An error is returned if that is not honored. +// To Deregister an ext, call SetExt with nil Ext. +// +// Deprecated: Use SetBytesExt or SetInterfaceExt on the Handle instead. +func (o *extHandle) SetExt(rt reflect.Type, tag uint64, ext Ext) (err error) { + // o is a pointer, because we may need to initialize it + rk := rt.Kind() + for rk == reflect.Ptr { + rt = rt.Elem() + rk = rt.Kind() + } + + if rt.PkgPath() == "" || rk == reflect.Interface { // || rk == reflect.Ptr { + return fmt.Errorf("codec.Handle.SetExt: Takes named type, not a pointer or interface: %v", rt) + } + + rtid := rt2id(rt) + switch rtid { + case timeTypId, rawTypId, rawExtTypId: + // all natively supported type, so cannot have an extension + return // TODO: should we silently ignore, or return an error??? + } + o2 := *o + for i := range o2 { + v := &o2[i] + if v.rtid == rtid { + v.tag, v.ext = tag, ext + return + } + } + rtidptr := rt2id(reflect.PtrTo(rt)) + *o = append(o2, extTypeTagFn{rtid, rtidptr, rt, tag, ext, [1]uint64{}}) + return +} + +func (o extHandle) getExt(rtid uintptr) (v *extTypeTagFn) { + for i := range o { + v = &o[i] + if v.rtid == rtid || v.rtidptr == rtid { + return + } + } + return nil +} + +func (o extHandle) getExtForTag(tag uint64) (v *extTypeTagFn) { + for i := range o { + v = &o[i] + if v.tag == tag { + return + } + } + return nil +} + +type intf2impl struct { + rtid uintptr // for intf + impl reflect.Type + // _ [1]uint64 // padding // not-needed, as *intf2impl is never returned. +} + +type intf2impls []intf2impl + +// Intf2Impl maps an interface to an implementing type. +// This allows us support infering the concrete type +// and populating it when passed an interface. +// e.g. var v io.Reader can be decoded as a bytes.Buffer, etc. +// +// Passing a nil impl will clear the mapping. +func (o *intf2impls) Intf2Impl(intf, impl reflect.Type) (err error) { + if impl != nil && !impl.Implements(intf) { + return fmt.Errorf("Intf2Impl: %v does not implement %v", impl, intf) + } + rtid := rt2id(intf) + o2 := *o + for i := range o2 { + v := &o2[i] + if v.rtid == rtid { + v.impl = impl + return + } + } + *o = append(o2, intf2impl{rtid, impl}) + return +} + +func (o intf2impls) intf2impl(rtid uintptr) (rv reflect.Value) { + for i := range o { + v := &o[i] + if v.rtid == rtid { + if v.impl == nil { + return + } + if v.impl.Kind() == reflect.Ptr { + return reflect.New(v.impl.Elem()) + } + return reflect.New(v.impl).Elem() + } + } + return +} + +type structFieldInfoFlag uint8 + +const ( + _ structFieldInfoFlag = 1 << iota + structFieldInfoFlagReady + structFieldInfoFlagOmitEmpty +) + +func (x *structFieldInfoFlag) flagSet(f structFieldInfoFlag) { + *x = *x | f +} + +func (x *structFieldInfoFlag) flagClr(f structFieldInfoFlag) { + *x = *x &^ f +} + +func (x structFieldInfoFlag) flagGet(f structFieldInfoFlag) bool { + return x&f != 0 +} + +func (x structFieldInfoFlag) omitEmpty() bool { + return x.flagGet(structFieldInfoFlagOmitEmpty) +} + +func (x structFieldInfoFlag) ready() bool { + return x.flagGet(structFieldInfoFlagReady) +} + +type structFieldInfo struct { + encName string // encode name + fieldName string // field name + + is [maxLevelsEmbedding]uint16 // (recursive/embedded) field index in struct + nis uint8 // num levels of embedding. if 1, then it's not embedded. + + encNameAsciiAlphaNum bool // the encName only contains ascii alphabet and numbers + structFieldInfoFlag + _ [1]byte // padding +} + +func (si *structFieldInfo) setToZeroValue(v reflect.Value) { + if v, valid := si.field(v, false); valid { + v.Set(reflect.Zero(v.Type())) + } +} + +// rv returns the field of the struct. +// If anonymous, it returns an Invalid +func (si *structFieldInfo) field(v reflect.Value, update bool) (rv2 reflect.Value, valid bool) { + // replicate FieldByIndex + for i, x := range si.is { + if uint8(i) == si.nis { + break + } + if v, valid = baseStructRv(v, update); !valid { + return + } + v = v.Field(int(x)) + } + + return v, true +} + +// func (si *structFieldInfo) fieldval(v reflect.Value, update bool) reflect.Value { +// v, _ = si.field(v, update) +// return v +// } + +func parseStructInfo(stag string) (toArray, omitEmpty bool, keytype valueType) { + keytype = valueTypeString // default + if stag == "" { + return + } + for i, s := range strings.Split(stag, ",") { + if i == 0 { + } else { + switch s { + case "omitempty": + omitEmpty = true + case "toarray": + toArray = true + case "int": + keytype = valueTypeInt + case "uint": + keytype = valueTypeUint + case "float": + keytype = valueTypeFloat + // case "bool": + // keytype = valueTypeBool + case "string": + keytype = valueTypeString + } + } + } + return +} + +func (si *structFieldInfo) parseTag(stag string) { + // if fname == "" { + // panic(errNoFieldNameToStructFieldInfo) + // } + + if stag == "" { + return + } + for i, s := range strings.Split(stag, ",") { + if i == 0 { + if s != "" { + si.encName = s + } + } else { + switch s { + case "omitempty": + si.flagSet(structFieldInfoFlagOmitEmpty) + // si.omitEmpty = true + // case "toarray": + // si.toArray = true + } + } + } +} + +type sfiSortedByEncName []*structFieldInfo + +func (p sfiSortedByEncName) Len() int { return len(p) } +func (p sfiSortedByEncName) Less(i, j int) bool { return p[uint(i)].encName < p[uint(j)].encName } +func (p sfiSortedByEncName) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +const structFieldNodeNumToCache = 4 + +type structFieldNodeCache struct { + rv [structFieldNodeNumToCache]reflect.Value + idx [structFieldNodeNumToCache]uint32 + num uint8 +} + +func (x *structFieldNodeCache) get(key uint32) (fv reflect.Value, valid bool) { + for i, k := range &x.idx { + if uint8(i) == x.num { + return // break + } + if key == k { + return x.rv[i], true + } + } + return +} + +func (x *structFieldNodeCache) tryAdd(fv reflect.Value, key uint32) { + if x.num < structFieldNodeNumToCache { + x.rv[x.num] = fv + x.idx[x.num] = key + x.num++ + return + } +} + +type structFieldNode struct { + v reflect.Value + cache2 structFieldNodeCache + cache3 structFieldNodeCache + update bool +} + +func (x *structFieldNode) field(si *structFieldInfo) (fv reflect.Value) { + // return si.fieldval(x.v, x.update) + // Note: we only cache if nis=2 or nis=3 i.e. up to 2 levels of embedding + // This mostly saves us time on the repeated calls to v.Elem, v.Field, etc. + var valid bool + switch si.nis { + case 1: + fv = x.v.Field(int(si.is[0])) + case 2: + if fv, valid = x.cache2.get(uint32(si.is[0])); valid { + fv = fv.Field(int(si.is[1])) + return + } + fv = x.v.Field(int(si.is[0])) + if fv, valid = baseStructRv(fv, x.update); !valid { + return + } + x.cache2.tryAdd(fv, uint32(si.is[0])) + fv = fv.Field(int(si.is[1])) + case 3: + var key uint32 = uint32(si.is[0])<<16 | uint32(si.is[1]) + if fv, valid = x.cache3.get(key); valid { + fv = fv.Field(int(si.is[2])) + return + } + fv = x.v.Field(int(si.is[0])) + if fv, valid = baseStructRv(fv, x.update); !valid { + return + } + fv = fv.Field(int(si.is[1])) + if fv, valid = baseStructRv(fv, x.update); !valid { + return + } + x.cache3.tryAdd(fv, key) + fv = fv.Field(int(si.is[2])) + default: + fv, _ = si.field(x.v, x.update) + } + return +} + +func baseStructRv(v reflect.Value, update bool) (v2 reflect.Value, valid bool) { + for v.Kind() == reflect.Ptr { + if v.IsNil() { + if !update { + return + } + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + return v, true +} + +type typeInfoFlag uint8 + +const ( + typeInfoFlagComparable = 1 << iota + typeInfoFlagIsZeroer + typeInfoFlagIsZeroerPtr +) + +// typeInfo keeps information about each (non-ptr) type referenced in the encode/decode sequence. +// +// During an encode/decode sequence, we work as below: +// - If base is a built in type, en/decode base value +// - If base is registered as an extension, en/decode base value +// - If type is binary(M/Unm)arshaler, call Binary(M/Unm)arshal method +// - If type is text(M/Unm)arshaler, call Text(M/Unm)arshal method +// - Else decode appropriately based on the reflect.Kind +type typeInfo struct { + rt reflect.Type + elem reflect.Type + pkgpath string + + rtid uintptr + // rv0 reflect.Value // saved zero value, used if immutableKind + + numMeth uint16 // number of methods + kind uint8 + chandir uint8 + + anyOmitEmpty bool // true if a struct, and any of the fields are tagged "omitempty" + toArray bool // whether this (struct) type should be encoded as an array + keyType valueType // if struct, how is the field name stored in a stream? default is string + mbs bool // base type (T or *T) is a MapBySlice + + // ---- cpu cache line boundary? + sfiSort []*structFieldInfo // sorted. Used when enc/dec struct to map. + sfiSrc []*structFieldInfo // unsorted. Used when enc/dec struct to array. + + key reflect.Type + + // ---- cpu cache line boundary? + // sfis []structFieldInfo // all sfi, in src order, as created. + sfiNamesSort []byte // all names, with indexes into the sfiSort + + // format of marshal type fields below: [btj][mu]p? OR csp? + + bm bool // T is a binaryMarshaler + bmp bool // *T is a binaryMarshaler + bu bool // T is a binaryUnmarshaler + bup bool // *T is a binaryUnmarshaler + tm bool // T is a textMarshaler + tmp bool // *T is a textMarshaler + tu bool // T is a textUnmarshaler + tup bool // *T is a textUnmarshaler + + jm bool // T is a jsonMarshaler + jmp bool // *T is a jsonMarshaler + ju bool // T is a jsonUnmarshaler + jup bool // *T is a jsonUnmarshaler + cs bool // T is a Selfer + csp bool // *T is a Selfer + mf bool // T is a MissingFielder + mfp bool // *T is a MissingFielder + + // other flags, with individual bits representing if set. + flags typeInfoFlag + infoFieldOmitempty bool + + _ [6]byte // padding + _ [2]uint64 // padding +} + +func (ti *typeInfo) isFlag(f typeInfoFlag) bool { + return ti.flags&f != 0 +} + +func (ti *typeInfo) indexForEncName(name []byte) (index int16) { + var sn []byte + if len(name)+2 <= 32 { + var buf [32]byte // should not escape to heap + sn = buf[:len(name)+2] + } else { + sn = make([]byte, len(name)+2) + } + copy(sn[1:], name) + sn[0], sn[len(sn)-1] = tiSep2(name), 0xff + j := bytes.Index(ti.sfiNamesSort, sn) + if j < 0 { + return -1 + } + index = int16(uint16(ti.sfiNamesSort[j+len(sn)+1]) | uint16(ti.sfiNamesSort[j+len(sn)])<<8) + return +} + +type rtid2ti struct { + rtid uintptr + ti *typeInfo +} + +// TypeInfos caches typeInfo for each type on first inspection. +// +// It is configured with a set of tag keys, which are used to get +// configuration for the type. +type TypeInfos struct { + // infos: formerly map[uintptr]*typeInfo, now *[]rtid2ti, 2 words expected + infos atomicTypeInfoSlice + mu sync.Mutex + tags []string + _ [2]uint64 // padding +} + +// NewTypeInfos creates a TypeInfos given a set of struct tags keys. +// +// This allows users customize the struct tag keys which contain configuration +// of their types. +func NewTypeInfos(tags []string) *TypeInfos { + return &TypeInfos{tags: tags} +} + +func (x *TypeInfos) structTag(t reflect.StructTag) (s string) { + // check for tags: codec, json, in that order. + // this allows seamless support for many configured structs. + for _, x := range x.tags { + s = t.Get(x) + if s != "" { + return s + } + } + return +} + +func findTypeInfo(s []rtid2ti, rtid uintptr) (i uint, ti *typeInfo) { + // binary search. adapted from sort/search.go. + // Note: we use goto (instead of for loop) so this can be inlined. + + // if sp == nil { + // return -1, nil + // } + // s := *sp + + // h, i, j := 0, 0, len(s) + var h uint // var h, i uint + var j = uint(len(s)) +LOOP: + if i < j { + h = i + (j-i)/2 + if s[h].rtid < rtid { + i = h + 1 + } else { + j = h + } + goto LOOP + } + if i < uint(len(s)) && s[i].rtid == rtid { + ti = s[i].ti + } + return +} + +func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) { + sp := x.infos.load() + if sp != nil { + _, pti = findTypeInfo(sp, rtid) + if pti != nil { + return + } + } + + rk := rt.Kind() + + if rk == reflect.Ptr { // || (rk == reflect.Interface && rtid != intfTypId) { + panicv.errorf("invalid kind passed to TypeInfos.get: %v - %v", rk, rt) + } + + // do not hold lock while computing this. + // it may lead to duplication, but that's ok. + ti := typeInfo{ + rt: rt, + rtid: rtid, + kind: uint8(rk), + pkgpath: rt.PkgPath(), + keyType: valueTypeString, // default it - so it's never 0 + } + // ti.rv0 = reflect.Zero(rt) + + // ti.comparable = rt.Comparable() + ti.numMeth = uint16(rt.NumMethod()) + + ti.bm, ti.bmp = implIntf(rt, binaryMarshalerTyp) + ti.bu, ti.bup = implIntf(rt, binaryUnmarshalerTyp) + ti.tm, ti.tmp = implIntf(rt, textMarshalerTyp) + ti.tu, ti.tup = implIntf(rt, textUnmarshalerTyp) + ti.jm, ti.jmp = implIntf(rt, jsonMarshalerTyp) + ti.ju, ti.jup = implIntf(rt, jsonUnmarshalerTyp) + ti.cs, ti.csp = implIntf(rt, selferTyp) + ti.mf, ti.mfp = implIntf(rt, missingFielderTyp) + + b1, b2 := implIntf(rt, iszeroTyp) + if b1 { + ti.flags |= typeInfoFlagIsZeroer + } + if b2 { + ti.flags |= typeInfoFlagIsZeroerPtr + } + if rt.Comparable() { + ti.flags |= typeInfoFlagComparable + } + + switch rk { + case reflect.Struct: + var omitEmpty bool + if f, ok := rt.FieldByName(structInfoFieldName); ok { + ti.toArray, omitEmpty, ti.keyType = parseStructInfo(x.structTag(f.Tag)) + ti.infoFieldOmitempty = omitEmpty + } else { + ti.keyType = valueTypeString + } + pp, pi := &pool.tiload, pool.tiload.Get() // pool.tiLoad() + pv := pi.(*typeInfoLoadArray) + pv.etypes[0] = ti.rtid + // vv := typeInfoLoad{pv.fNames[:0], pv.encNames[:0], pv.etypes[:1], pv.sfis[:0]} + vv := typeInfoLoad{pv.etypes[:1], pv.sfis[:0]} + x.rget(rt, rtid, omitEmpty, nil, &vv) + // ti.sfis = vv.sfis + ti.sfiSrc, ti.sfiSort, ti.sfiNamesSort, ti.anyOmitEmpty = rgetResolveSFI(rt, vv.sfis, pv) + pp.Put(pi) + case reflect.Map: + ti.elem = rt.Elem() + ti.key = rt.Key() + case reflect.Slice: + ti.mbs, _ = implIntf(rt, mapBySliceTyp) + ti.elem = rt.Elem() + case reflect.Chan: + ti.elem = rt.Elem() + ti.chandir = uint8(rt.ChanDir()) + case reflect.Array, reflect.Ptr: + ti.elem = rt.Elem() + } + // sfi = sfiSrc + + x.mu.Lock() + sp = x.infos.load() + var sp2 []rtid2ti + if sp == nil { + pti = &ti + sp2 = []rtid2ti{{rtid, pti}} + x.infos.store(sp2) + } else { + var idx uint + idx, pti = findTypeInfo(sp, rtid) + if pti == nil { + pti = &ti + sp2 = make([]rtid2ti, len(sp)+1) + copy(sp2, sp[:idx]) + copy(sp2[idx+1:], sp[idx:]) + sp2[idx] = rtid2ti{rtid, pti} + x.infos.store(sp2) + } + } + x.mu.Unlock() + return +} + +func (x *TypeInfos) rget(rt reflect.Type, rtid uintptr, omitEmpty bool, + indexstack []uint16, pv *typeInfoLoad) { + // Read up fields and store how to access the value. + // + // It uses go's rules for message selectors, + // which say that the field with the shallowest depth is selected. + // + // Note: we consciously use slices, not a map, to simulate a set. + // Typically, types have < 16 fields, + // and iteration using equals is faster than maps there + flen := rt.NumField() + if flen > (1< %v fields are not supported - has %v fields", + (1<= 0; i-- { // bounds-check elimination + b := si.encName[i] + if (b >= '0' && b <= '9') || (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') { + continue + } + si.encNameAsciiAlphaNum = false + break + } + si.fieldName = f.Name + si.flagSet(structFieldInfoFlagReady) + + // pv.encNames = append(pv.encNames, si.encName) + + // si.ikind = int(f.Type.Kind()) + if len(indexstack) > maxLevelsEmbedding-1 { + panicv.errorf("codec: only supports up to %v depth of embedding - type has %v depth", + maxLevelsEmbedding-1, len(indexstack)) + } + si.nis = uint8(len(indexstack)) + 1 + copy(si.is[:], indexstack) + si.is[len(indexstack)] = j + + if omitEmpty { + si.flagSet(structFieldInfoFlagOmitEmpty) + } + pv.sfis = append(pv.sfis, si) + } +} + +func tiSep(name string) uint8 { + // (xn[0]%64) // (between 192-255 - outside ascii BMP) + // return 0xfe - (name[0] & 63) + // return 0xfe - (name[0] & 63) - uint8(len(name)) + // return 0xfe - (name[0] & 63) - uint8(len(name)&63) + // return ((0xfe - (name[0] & 63)) & 0xf8) | (uint8(len(name) & 0x07)) + return 0xfe - (name[0] & 63) - uint8(len(name)&63) +} + +func tiSep2(name []byte) uint8 { + return 0xfe - (name[0] & 63) - uint8(len(name)&63) +} + +// resolves the struct field info got from a call to rget. +// Returns a trimmed, unsorted and sorted []*structFieldInfo. +func rgetResolveSFI(rt reflect.Type, x []structFieldInfo, pv *typeInfoLoadArray) ( + y, z []*structFieldInfo, ss []byte, anyOmitEmpty bool) { + sa := pv.sfiidx[:0] + sn := pv.b[:] + n := len(x) + + var xn string + var ui uint16 + var sep byte + + for i := range x { + ui = uint16(i) + xn = x[i].encName // fieldName or encName? use encName for now. + if len(xn)+2 > cap(pv.b) { + sn = make([]byte, len(xn)+2) + } else { + sn = sn[:len(xn)+2] + } + // use a custom sep, so that misses are less frequent, + // since the sep (first char in search) is as unique as first char in field name. + sep = tiSep(xn) + sn[0], sn[len(sn)-1] = sep, 0xff + copy(sn[1:], xn) + j := bytes.Index(sa, sn) + if j == -1 { + sa = append(sa, sep) + sa = append(sa, xn...) + sa = append(sa, 0xff, byte(ui>>8), byte(ui)) + } else { + index := uint16(sa[j+len(sn)+1]) | uint16(sa[j+len(sn)])<<8 + // one of them must be reset to nil, + // and the index updated appropriately to the other one + if x[i].nis == x[index].nis { + } else if x[i].nis < x[index].nis { + sa[j+len(sn)], sa[j+len(sn)+1] = byte(ui>>8), byte(ui) + if x[index].ready() { + x[index].flagClr(structFieldInfoFlagReady) + n-- + } + } else { + if x[i].ready() { + x[i].flagClr(structFieldInfoFlagReady) + n-- + } + } + } + + } + var w []structFieldInfo + sharingArray := len(x) <= typeInfoLoadArraySfisLen // sharing array with typeInfoLoadArray + if sharingArray { + w = make([]structFieldInfo, n) + } + + // remove all the nils (non-ready) + y = make([]*structFieldInfo, n) + n = 0 + var sslen int + for i := range x { + if !x[i].ready() { + continue + } + if !anyOmitEmpty && x[i].omitEmpty() { + anyOmitEmpty = true + } + if sharingArray { + w[n] = x[i] + y[n] = &w[n] + } else { + y[n] = &x[i] + } + sslen = sslen + len(x[i].encName) + 4 + n++ + } + if n != len(y) { + panicv.errorf("failure reading struct %v - expecting %d of %d valid fields, got %d", + rt, len(y), len(x), n) + } + + z = make([]*structFieldInfo, len(y)) + copy(z, y) + sort.Sort(sfiSortedByEncName(z)) + + sharingArray = len(sa) <= typeInfoLoadArraySfiidxLen + if sharingArray { + ss = make([]byte, 0, sslen) + } else { + ss = sa[:0] // reuse the newly made sa array if necessary + } + for i := range z { + xn = z[i].encName + sep = tiSep(xn) + ui = uint16(i) + ss = append(ss, sep) + ss = append(ss, xn...) + ss = append(ss, 0xff, byte(ui>>8), byte(ui)) + } + return +} + +func implIntf(rt, iTyp reflect.Type) (base bool, indir bool) { + return rt.Implements(iTyp), reflect.PtrTo(rt).Implements(iTyp) +} + +// isEmptyStruct is only called from isEmptyValue, and checks if a struct is empty: +// - does it implement IsZero() bool +// - is it comparable, and can i compare directly using == +// - if checkStruct, then walk through the encodable fields +// and check if they are empty or not. +func isEmptyStruct(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool { + // v is a struct kind - no need to check again. + // We only check isZero on a struct kind, to reduce the amount of times + // that we lookup the rtid and typeInfo for each type as we walk the tree. + + vt := v.Type() + rtid := rt2id(vt) + if tinfos == nil { + tinfos = defTypeInfos + } + ti := tinfos.get(rtid, vt) + if ti.rtid == timeTypId { + return rv2i(v).(time.Time).IsZero() + } + if ti.isFlag(typeInfoFlagIsZeroerPtr) && v.CanAddr() { + return rv2i(v.Addr()).(isZeroer).IsZero() + } + if ti.isFlag(typeInfoFlagIsZeroer) { + return rv2i(v).(isZeroer).IsZero() + } + if ti.isFlag(typeInfoFlagComparable) { + return rv2i(v) == rv2i(reflect.Zero(vt)) + } + if !checkStruct { + return false + } + // We only care about what we can encode/decode, + // so that is what we use to check omitEmpty. + for _, si := range ti.sfiSrc { + sfv, valid := si.field(v, false) + if valid && !isEmptyValue(sfv, tinfos, deref, checkStruct) { + return false + } + } + return true +} + +// func roundFloat(x float64) float64 { +// t := math.Trunc(x) +// if math.Abs(x-t) >= 0.5 { +// return t + math.Copysign(1, x) +// } +// return t +// } + +func panicToErr(h errDecorator, err *error) { + // Note: This method MUST be called directly from defer i.e. defer panicToErr ... + // else it seems the recover is not fully handled + if recoverPanicToErr { + if x := recover(); x != nil { + // fmt.Printf("panic'ing with: %v\n", x) + // debug.PrintStack() + panicValToErr(h, x, err) + } + } +} + +func panicValToErr(h errDecorator, v interface{}, err *error) { + switch xerr := v.(type) { + case nil: + case error: + switch xerr { + case nil: + case io.EOF, io.ErrUnexpectedEOF, errEncoderNotInitialized, errDecoderNotInitialized: + // treat as special (bubble up) + *err = xerr + default: + h.wrapErr(xerr, err) + } + case string: + if xerr != "" { + h.wrapErr(xerr, err) + } + case fmt.Stringer: + if xerr != nil { + h.wrapErr(xerr, err) + } + default: + h.wrapErr(v, err) + } +} + +func isImmutableKind(k reflect.Kind) (v bool) { + // return immutableKindsSet[k] + // since we know reflect.Kind is in range 0..31, then use the k%32 == k constraint + return immutableKindsSet[k%reflect.Kind(len(immutableKindsSet))] // bounds-check-elimination +} + +// ---- + +type codecFnInfo struct { + ti *typeInfo + xfFn Ext + xfTag uint64 + seq seqType + addrD bool + addrF bool // if addrD, this says whether decode function can take a value or a ptr + addrE bool +} + +// codecFn encapsulates the captured variables and the encode function. +// This way, we only do some calculations one times, and pass to the +// code block that should be called (encapsulated in a function) +// instead of executing the checks every time. +type codecFn struct { + i codecFnInfo + fe func(*Encoder, *codecFnInfo, reflect.Value) + fd func(*Decoder, *codecFnInfo, reflect.Value) + _ [1]uint64 // padding +} + +type codecRtidFn struct { + rtid uintptr + fn *codecFn +} + +// ---- + +// these "checkOverflow" functions must be inlinable, and not call anybody. +// Overflow means that the value cannot be represented without wrapping/overflow. +// Overflow=false does not mean that the value can be represented without losing precision +// (especially for floating point). + +type checkOverflow struct{} + +// func (checkOverflow) Float16(f float64) (overflow bool) { +// panicv.errorf("unimplemented") +// if f < 0 { +// f = -f +// } +// return math.MaxFloat32 < f && f <= math.MaxFloat64 +// } + +func (checkOverflow) Float32(v float64) (overflow bool) { + if v < 0 { + v = -v + } + return math.MaxFloat32 < v && v <= math.MaxFloat64 +} +func (checkOverflow) Uint(v uint64, bitsize uint8) (overflow bool) { + if bitsize == 0 || bitsize >= 64 || v == 0 { + return + } + if trunc := (v << (64 - bitsize)) >> (64 - bitsize); v != trunc { + overflow = true + } + return +} +func (checkOverflow) Int(v int64, bitsize uint8) (overflow bool) { + if bitsize == 0 || bitsize >= 64 || v == 0 { + return + } + if trunc := (v << (64 - bitsize)) >> (64 - bitsize); v != trunc { + overflow = true + } + return +} +func (checkOverflow) SignedInt(v uint64) (overflow bool) { + //e.g. -127 to 128 for int8 + pos := (v >> 63) == 0 + ui2 := v & 0x7fffffffffffffff + if pos { + if ui2 > math.MaxInt64 { + overflow = true + } + } else { + if ui2 > math.MaxInt64-1 { + overflow = true + } + } + return +} + +func (x checkOverflow) Float32V(v float64) float64 { + if x.Float32(v) { + panicv.errorf("float32 overflow: %v", v) + } + return v +} +func (x checkOverflow) UintV(v uint64, bitsize uint8) uint64 { + if x.Uint(v, bitsize) { + panicv.errorf("uint64 overflow: %v", v) + } + return v +} +func (x checkOverflow) IntV(v int64, bitsize uint8) int64 { + if x.Int(v, bitsize) { + panicv.errorf("int64 overflow: %v", v) + } + return v +} +func (x checkOverflow) SignedIntV(v uint64) int64 { + if x.SignedInt(v) { + panicv.errorf("uint64 to int64 overflow: %v", v) + } + return int64(v) +} + +// ------------------ SORT ----------------- + +func isNaN(f float64) bool { return f != f } + +// ----------------------- + +type ioFlusher interface { + Flush() error +} + +type ioPeeker interface { + Peek(int) ([]byte, error) +} + +type ioBuffered interface { + Buffered() int +} + +// ----------------------- + +type intSlice []int64 +type uintSlice []uint64 + +// type uintptrSlice []uintptr +type floatSlice []float64 +type boolSlice []bool +type stringSlice []string + +// type bytesSlice [][]byte + +func (p intSlice) Len() int { return len(p) } +func (p intSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } +func (p intSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p uintSlice) Len() int { return len(p) } +func (p uintSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } +func (p uintSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +// func (p uintptrSlice) Len() int { return len(p) } +// func (p uintptrSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } +// func (p uintptrSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p floatSlice) Len() int { return len(p) } +func (p floatSlice) Less(i, j int) bool { + return p[uint(i)] < p[uint(j)] || isNaN(p[uint(i)]) && !isNaN(p[uint(j)]) +} +func (p floatSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p stringSlice) Len() int { return len(p) } +func (p stringSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } +func (p stringSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +// func (p bytesSlice) Len() int { return len(p) } +// func (p bytesSlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)], p[uint(j)]) == -1 } +// func (p bytesSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p boolSlice) Len() int { return len(p) } +func (p boolSlice) Less(i, j int) bool { return !p[uint(i)] && p[uint(j)] } +func (p boolSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +// --------------------- + +type sfiRv struct { + v *structFieldInfo + r reflect.Value +} + +type intRv struct { + v int64 + r reflect.Value +} +type intRvSlice []intRv +type uintRv struct { + v uint64 + r reflect.Value +} +type uintRvSlice []uintRv +type floatRv struct { + v float64 + r reflect.Value +} +type floatRvSlice []floatRv +type boolRv struct { + v bool + r reflect.Value +} +type boolRvSlice []boolRv +type stringRv struct { + v string + r reflect.Value +} +type stringRvSlice []stringRv +type bytesRv struct { + v []byte + r reflect.Value +} +type bytesRvSlice []bytesRv +type timeRv struct { + v time.Time + r reflect.Value +} +type timeRvSlice []timeRv + +func (p intRvSlice) Len() int { return len(p) } +func (p intRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } +func (p intRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p uintRvSlice) Len() int { return len(p) } +func (p uintRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } +func (p uintRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p floatRvSlice) Len() int { return len(p) } +func (p floatRvSlice) Less(i, j int) bool { + return p[uint(i)].v < p[uint(j)].v || isNaN(p[uint(i)].v) && !isNaN(p[uint(j)].v) +} +func (p floatRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p stringRvSlice) Len() int { return len(p) } +func (p stringRvSlice) Less(i, j int) bool { return p[uint(i)].v < p[uint(j)].v } +func (p stringRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p bytesRvSlice) Len() int { return len(p) } +func (p bytesRvSlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)].v, p[uint(j)].v) == -1 } +func (p bytesRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p boolRvSlice) Len() int { return len(p) } +func (p boolRvSlice) Less(i, j int) bool { return !p[uint(i)].v && p[uint(j)].v } +func (p boolRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +func (p timeRvSlice) Len() int { return len(p) } +func (p timeRvSlice) Less(i, j int) bool { return p[uint(i)].v.Before(p[uint(j)].v) } +func (p timeRvSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +// ----------------- + +type bytesI struct { + v []byte + i interface{} +} + +type bytesISlice []bytesI + +func (p bytesISlice) Len() int { return len(p) } +func (p bytesISlice) Less(i, j int) bool { return bytes.Compare(p[uint(i)].v, p[uint(j)].v) == -1 } +func (p bytesISlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } + +// ----------------- + +type set []uintptr + +func (s *set) add(v uintptr) (exists bool) { + // e.ci is always nil, or len >= 1 + x := *s + if x == nil { + x = make([]uintptr, 1, 8) + x[0] = v + *s = x + return + } + // typically, length will be 1. make this perform. + if len(x) == 1 { + if j := x[0]; j == 0 { + x[0] = v + } else if j == v { + exists = true + } else { + x = append(x, v) + *s = x + } + return + } + // check if it exists + for _, j := range x { + if j == v { + exists = true + return + } + } + // try to replace a "deleted" slot + for i, j := range x { + if j == 0 { + x[i] = v + return + } + } + // if unable to replace deleted slot, just append it. + x = append(x, v) + *s = x + return +} + +func (s *set) remove(v uintptr) (exists bool) { + x := *s + if len(x) == 0 { + return + } + if len(x) == 1 { + if x[0] == v { + x[0] = 0 + } + return + } + for i, j := range x { + if j == v { + exists = true + x[i] = 0 // set it to 0, as way to delete it. + // copy(x[i:], x[i+1:]) + // x = x[:len(x)-1] + return + } + } + return +} + +// ------ + +// bitset types are better than [256]bool, because they permit the whole +// bitset array being on a single cache line and use less memory. +// +// Also, since pos is a byte (0-255), there's no bounds checks on indexing (cheap). +// +// We previously had bitset128 [16]byte, and bitset32 [4]byte, but those introduces +// bounds checking, so we discarded them, and everyone uses bitset256. +// +// given x > 0 and n > 0 and x is exactly 2^n, then pos/x === pos>>n AND pos%x === pos&(x-1). +// consequently, pos/32 === pos>>5, pos/16 === pos>>4, pos/8 === pos>>3, pos%8 == pos&7 + +type bitset256 [32]byte + +func (x *bitset256) isset(pos byte) bool { + return x[pos>>3]&(1<<(pos&7)) != 0 +} + +// func (x *bitset256) issetv(pos byte) byte { +// return x[pos>>3] & (1 << (pos & 7)) +// } + +func (x *bitset256) set(pos byte) { + x[pos>>3] |= (1 << (pos & 7)) +} + +// func (x *bitset256) unset(pos byte) { +// x[pos>>3] &^= (1 << (pos & 7)) +// } + +// type bit2set256 [64]byte + +// func (x *bit2set256) set(pos byte, v1, v2 bool) { +// var pos2 uint8 = (pos & 3) << 1 // returning 0, 2, 4 or 6 +// if v1 { +// x[pos>>2] |= 1 << (pos2 + 1) +// } +// if v2 { +// x[pos>>2] |= 1 << pos2 +// } +// } +// func (x *bit2set256) get(pos byte) uint8 { +// var pos2 uint8 = (pos & 3) << 1 // returning 0, 2, 4 or 6 +// return x[pos>>2] << (6 - pos2) >> 6 // 11000000 -> 00000011 +// } + +// ------------ + +type pooler struct { + // function-scoped pooled resources + tiload sync.Pool // for type info loading + sfiRv8, sfiRv16, sfiRv32, sfiRv64, sfiRv128 sync.Pool // for struct encoding + + // lifetime-scoped pooled resources + // dn sync.Pool // for decNaked + buf1k, buf2k, buf4k, buf8k, buf16k, buf32k, buf64k sync.Pool // for [N]byte +} + +func (p *pooler) init() { + p.tiload.New = func() interface{} { return new(typeInfoLoadArray) } + + p.sfiRv8.New = func() interface{} { return new([8]sfiRv) } + p.sfiRv16.New = func() interface{} { return new([16]sfiRv) } + p.sfiRv32.New = func() interface{} { return new([32]sfiRv) } + p.sfiRv64.New = func() interface{} { return new([64]sfiRv) } + p.sfiRv128.New = func() interface{} { return new([128]sfiRv) } + + // p.dn.New = func() interface{} { x := new(decNaked); x.init(); return x } + + p.buf1k.New = func() interface{} { return new([1 * 1024]byte) } + p.buf2k.New = func() interface{} { return new([2 * 1024]byte) } + p.buf4k.New = func() interface{} { return new([4 * 1024]byte) } + p.buf8k.New = func() interface{} { return new([8 * 1024]byte) } + p.buf16k.New = func() interface{} { return new([16 * 1024]byte) } + p.buf32k.New = func() interface{} { return new([32 * 1024]byte) } + p.buf64k.New = func() interface{} { return new([64 * 1024]byte) } + +} + +// func (p *pooler) sfiRv8() (sp *sync.Pool, v interface{}) { +// return &p.strRv8, p.strRv8.Get() +// } +// func (p *pooler) sfiRv16() (sp *sync.Pool, v interface{}) { +// return &p.strRv16, p.strRv16.Get() +// } +// func (p *pooler) sfiRv32() (sp *sync.Pool, v interface{}) { +// return &p.strRv32, p.strRv32.Get() +// } +// func (p *pooler) sfiRv64() (sp *sync.Pool, v interface{}) { +// return &p.strRv64, p.strRv64.Get() +// } +// func (p *pooler) sfiRv128() (sp *sync.Pool, v interface{}) { +// return &p.strRv128, p.strRv128.Get() +// } + +// func (p *pooler) bytes1k() (sp *sync.Pool, v interface{}) { +// return &p.buf1k, p.buf1k.Get() +// } +// func (p *pooler) bytes2k() (sp *sync.Pool, v interface{}) { +// return &p.buf2k, p.buf2k.Get() +// } +// func (p *pooler) bytes4k() (sp *sync.Pool, v interface{}) { +// return &p.buf4k, p.buf4k.Get() +// } +// func (p *pooler) bytes8k() (sp *sync.Pool, v interface{}) { +// return &p.buf8k, p.buf8k.Get() +// } +// func (p *pooler) bytes16k() (sp *sync.Pool, v interface{}) { +// return &p.buf16k, p.buf16k.Get() +// } +// func (p *pooler) bytes32k() (sp *sync.Pool, v interface{}) { +// return &p.buf32k, p.buf32k.Get() +// } +// func (p *pooler) bytes64k() (sp *sync.Pool, v interface{}) { +// return &p.buf64k, p.buf64k.Get() +// } + +// func (p *pooler) tiLoad() (sp *sync.Pool, v interface{}) { +// return &p.tiload, p.tiload.Get() +// } + +// func (p *pooler) decNaked() (sp *sync.Pool, v interface{}) { +// return &p.dn, p.dn.Get() +// } + +// func (p *pooler) decNaked() (v *decNaked, f func(*decNaked) ) { +// sp := &(p.dn) +// vv := sp.Get() +// return vv.(*decNaked), func(x *decNaked) { sp.Put(vv) } +// } +// func (p *pooler) decNakedGet() (v interface{}) { +// return p.dn.Get() +// } +// func (p *pooler) tiLoadGet() (v interface{}) { +// return p.tiload.Get() +// } +// func (p *pooler) decNakedPut(v interface{}) { +// p.dn.Put(v) +// } +// func (p *pooler) tiLoadPut(v interface{}) { +// p.tiload.Put(v) +// } + +// ---------------------------------------------------- + +type panicHdl struct{} + +func (panicHdl) errorv(err error) { + if err != nil { + panic(err) + } +} + +func (panicHdl) errorstr(message string) { + if message != "" { + panic(message) + } +} + +func (panicHdl) errorf(format string, params ...interface{}) { + if format == "" { + } else if len(params) == 0 { + panic(format) + } else { + panic(fmt.Sprintf(format, params...)) + } +} + +// ---------------------------------------------------- + +type errDecorator interface { + wrapErr(in interface{}, out *error) +} + +type errDecoratorDef struct{} + +func (errDecoratorDef) wrapErr(v interface{}, e *error) { *e = fmt.Errorf("%v", v) } + +// ---------------------------------------------------- + +type must struct{} + +func (must) String(s string, err error) string { + if err != nil { + panicv.errorv(err) + } + return s +} +func (must) Int(s int64, err error) int64 { + if err != nil { + panicv.errorv(err) + } + return s +} +func (must) Uint(s uint64, err error) uint64 { + if err != nil { + panicv.errorv(err) + } + return s +} +func (must) Float(s float64, err error) float64 { + if err != nil { + panicv.errorv(err) + } + return s +} + +// ------------------- + +type bytesBufPooler struct { + pool *sync.Pool + poolbuf interface{} +} + +func (z *bytesBufPooler) end() { + if z.pool != nil { + z.pool.Put(z.poolbuf) + z.pool, z.poolbuf = nil, nil + } +} + +func (z *bytesBufPooler) get(bufsize int) (buf []byte) { + // ensure an end is called first (if necessary) + if z.pool != nil { + z.pool.Put(z.poolbuf) + z.pool, z.poolbuf = nil, nil + } + + if bufsize <= 1*1024 { + z.pool, z.poolbuf = &pool.buf1k, pool.buf1k.Get() // pool.bytes1k() + buf = z.poolbuf.(*[1 * 1024]byte)[:] + } else if bufsize <= 2*1024 { + z.pool, z.poolbuf = &pool.buf2k, pool.buf2k.Get() // pool.bytes2k() + buf = z.poolbuf.(*[2 * 1024]byte)[:] + } else if bufsize <= 4*1024 { + z.pool, z.poolbuf = &pool.buf4k, pool.buf4k.Get() // pool.bytes4k() + buf = z.poolbuf.(*[4 * 1024]byte)[:] + } else if bufsize <= 8*1024 { + z.pool, z.poolbuf = &pool.buf8k, pool.buf8k.Get() // pool.bytes8k() + buf = z.poolbuf.(*[8 * 1024]byte)[:] + } else if bufsize <= 16*1024 { + z.pool, z.poolbuf = &pool.buf16k, pool.buf16k.Get() // pool.bytes16k() + buf = z.poolbuf.(*[16 * 1024]byte)[:] + } else if bufsize <= 32*1024 { + z.pool, z.poolbuf = &pool.buf32k, pool.buf32k.Get() // pool.bytes32k() + buf = z.poolbuf.(*[32 * 1024]byte)[:] + } else { + z.pool, z.poolbuf = &pool.buf64k, pool.buf64k.Get() // pool.bytes64k() + buf = z.poolbuf.(*[64 * 1024]byte)[:] + } + return +} + +// ---------------- + +type sfiRvPooler struct { + pool *sync.Pool + poolv interface{} +} + +func (z *sfiRvPooler) end() { + if z.pool != nil { + z.pool.Put(z.poolv) + z.pool, z.poolv = nil, nil + } +} + +func (z *sfiRvPooler) get(newlen int) (fkvs []sfiRv) { + if newlen < 0 { // bounds-check-elimination + // cannot happen // here for bounds-check-elimination + } else if newlen <= 8 { + z.pool, z.poolv = &pool.sfiRv8, pool.sfiRv8.Get() // pool.sfiRv8() + fkvs = z.poolv.(*[8]sfiRv)[:newlen] + } else if newlen <= 16 { + z.pool, z.poolv = &pool.sfiRv16, pool.sfiRv16.Get() // pool.sfiRv16() + fkvs = z.poolv.(*[16]sfiRv)[:newlen] + } else if newlen <= 32 { + z.pool, z.poolv = &pool.sfiRv32, pool.sfiRv32.Get() // pool.sfiRv32() + fkvs = z.poolv.(*[32]sfiRv)[:newlen] + } else if newlen <= 64 { + z.pool, z.poolv = &pool.sfiRv64, pool.sfiRv64.Get() // pool.sfiRv64() + fkvs = z.poolv.(*[64]sfiRv)[:newlen] + } else if newlen <= 128 { + z.pool, z.poolv = &pool.sfiRv128, pool.sfiRv128.Get() // pool.sfiRv128() + fkvs = z.poolv.(*[128]sfiRv)[:newlen] + } else { + fkvs = make([]sfiRv, newlen) + } + return +} + +// safe-mod optimizations + +const safeMode = true + +// stringView returns a view of the []byte as a string. +// In unsafe mode, it doesn't incur allocation and copying caused by conversion. +// In regular safe mode, it is an allocation and copy. +// +// Usage: Always maintain a reference to v while result of this call is in use, +// +// and call keepAlive4BytesView(v) at point where done with view. +func stringView(v []byte) string { + return string(v) +} + +// bytesView returns a view of the string as a []byte. +// In unsafe mode, it doesn't incur allocation and copying caused by conversion. +// In regular safe mode, it is an allocation and copy. +// +// Usage: Always maintain a reference to v while result of this call is in use, +// +// and call keepAlive4BytesView(v) at point where done with view. +func bytesView(v string) []byte { + return []byte(v) +} + +func definitelyNil(v interface{}) bool { + // this is a best-effort option. + // We just return false, so we don't unnecessarily incur the cost of reflection this early. + return false +} + +func rv2i(rv reflect.Value) interface{} { + return rv.Interface() +} + +func rt2id(rt reflect.Type) uintptr { + return reflect.ValueOf(rt).Pointer() +} + +func i2rtid(i interface{}) uintptr { + return reflect.ValueOf(reflect.TypeOf(i)).Pointer() +} + +// -------------------------- + +func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool { + switch v.Kind() { + case reflect.Invalid: + return true + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + if deref { + if v.IsNil() { + return true + } + return isEmptyValue(v.Elem(), tinfos, deref, checkStruct) + } + return v.IsNil() + case reflect.Struct: + return isEmptyStruct(v, tinfos, deref, checkStruct) + } + return false +} + +// -------------------------- +type atomicClsErr struct { + v atomic.Value +} + +func (x *atomicClsErr) load() (e clsErr) { + if i := x.v.Load(); i != nil { + e = i.(clsErr) + } + return +} + +func (x *atomicClsErr) store(p clsErr) { + x.v.Store(p) +} + +// -------------------------- +type atomicTypeInfoSlice struct { // expected to be 2 words + v atomic.Value +} + +func (x *atomicTypeInfoSlice) load() (e []rtid2ti) { + if i := x.v.Load(); i != nil { + e = i.([]rtid2ti) + } + return +} + +func (x *atomicTypeInfoSlice) store(p []rtid2ti) { + x.v.Store(p) +} + +// -------------------------- +type atomicRtidFnSlice struct { // expected to be 2 words + v atomic.Value +} + +func (x *atomicRtidFnSlice) load() (e []codecRtidFn) { + if i := x.v.Load(); i != nil { + e = i.([]codecRtidFn) + } + return +} + +func (x *atomicRtidFnSlice) store(p []codecRtidFn) { + x.v.Store(p) +} + +// -------------------------- +func (n *decNaked) ru() reflect.Value { + return reflect.ValueOf(&n.u).Elem() +} +func (n *decNaked) ri() reflect.Value { + return reflect.ValueOf(&n.i).Elem() +} +func (n *decNaked) rf() reflect.Value { + return reflect.ValueOf(&n.f).Elem() +} +func (n *decNaked) rl() reflect.Value { + return reflect.ValueOf(&n.l).Elem() +} +func (n *decNaked) rs() reflect.Value { + return reflect.ValueOf(&n.s).Elem() +} +func (n *decNaked) rt() reflect.Value { + return reflect.ValueOf(&n.t).Elem() +} +func (n *decNaked) rb() reflect.Value { + return reflect.ValueOf(&n.b).Elem() +} + +// -------------------------- +func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) { + rv.SetBytes(d.rawBytes()) +} + +func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) { + rv.SetString(d.d.DecodeString()) +} + +func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) { + rv.SetBool(d.d.DecodeBool()) +} + +func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) { + rv.Set(reflect.ValueOf(d.d.DecodeTime())) +} + +func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) { + fv := d.d.DecodeFloat64() + if chkOvf.Float32(fv) { + d.errorf("float32 overflow: %v", fv) + } + rv.SetFloat(fv) +} + +func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) { + rv.SetFloat(d.d.DecodeFloat64()) +} + +func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) { + rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) +} + +func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) { + rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 8)) +} + +func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) { + rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 16)) +} + +func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) { + rv.SetInt(chkOvf.IntV(d.d.DecodeInt64(), 32)) +} + +func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) { + rv.SetInt(d.d.DecodeInt64()) +} + +func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) { + rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) +} + +func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) { + rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) +} + +func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) { + rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 8)) +} + +func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) { + rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 16)) +} + +func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) { + rv.SetUint(chkOvf.UintV(d.d.DecodeUint64(), 32)) +} + +func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) { + rv.SetUint(d.d.DecodeUint64()) +} + +// ---------------- + +func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeBool(rv.Bool()) +} + +func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeTime(rv2i(rv).(time.Time)) +} + +func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) { + s := rv.String() + if e.h.StringToRaw { + e.e.EncodeStringBytesRaw(bytesView(s)) + } else { + e.e.EncodeStringEnc(cUTF8, s) + } +} + +func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeFloat64(rv.Float()) +} + +func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeFloat32(float32(rv.Float())) +} + +func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeInt(rv.Int()) +} + +func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeInt(rv.Int()) +} + +func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeInt(rv.Int()) +} + +func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeInt(rv.Int()) +} + +func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeInt(rv.Int()) +} + +func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeUint(rv.Uint()) +} + +func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeUint(rv.Uint()) +} + +func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeUint(rv.Uint()) +} + +func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeUint(rv.Uint()) +} + +func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeUint(rv.Uint()) +} + +func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) { + e.e.EncodeUint(rv.Uint()) +} + +func makeMapReflect(t reflect.Type, size int) reflect.Value { + if size < 0 { + return reflect.MakeMapWithSize(t, 4) + } + return reflect.MakeMapWithSize(t, size) +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper_internal.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper_internal.go new file mode 100644 index 00000000..4f5eb843 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/helper_internal.go @@ -0,0 +1,89 @@ +// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +// All non-std package dependencies live in this file, +// so porting to different environment is easy (just update functions). + +func pruneSignExt(v []byte, pos bool) (n int) { + if len(v) < 2 { + } else if pos && v[0] == 0 { + for ; v[n] == 0 && n+1 < len(v) && (v[n+1]&(1<<7) == 0); n++ { + } + } else if !pos && v[0] == 0xff { + for ; v[n] == 0xff && n+1 < len(v) && (v[n+1]&(1<<7) != 0); n++ { + } + } + return +} + +// GrowCap will return a new capacity for a slice, given the following: +// - oldCap: current capacity +// - unit: in-memory size of an element +// - num: number of elements to add +func growCap(oldCap, unit, num int) (newCap int) { + // appendslice logic (if cap < 1024, *2, else *1.25): + // leads to many copy calls, especially when copying bytes. + // bytes.Buffer model (2*cap + n): much better for bytes. + // smarter way is to take the byte-size of the appended element(type) into account + + // maintain 3 thresholds: + // t1: if cap <= t1, newcap = 2x + // t2: if cap <= t2, newcap = 1.75x + // t3: if cap <= t3, newcap = 1.5x + // else newcap = 1.25x + // + // t1, t2, t3 >= 1024 always. + // i.e. if unit size >= 16, then always do 2x or 1.25x (ie t1, t2, t3 are all same) + // + // With this, appending for bytes increase by: + // 100% up to 4K + // 75% up to 8K + // 50% up to 16K + // 25% beyond that + + // unit can be 0 e.g. for struct{}{}; handle that appropriately + var t1, t2, t3 int // thresholds + if unit <= 1 { + t1, t2, t3 = 4*1024, 8*1024, 16*1024 + } else if unit < 16 { + t3 = 16 / unit * 1024 + t1 = t3 * 1 / 4 + t2 = t3 * 2 / 4 + } else { + t1, t2, t3 = 1024, 1024, 1024 + } + + var x int // temporary variable + + // x is multiplier here: one of 5, 6, 7 or 8; incr of 25%, 50%, 75% or 100% respectively + if oldCap <= t1 { // [0,t1] + x = 8 + } else if oldCap > t3 { // (t3,infinity] + x = 5 + } else if oldCap <= t2 { // (t1,t2] + x = 7 + } else { // (t2,t3] + x = 6 + } + newCap = x * oldCap / 4 + + if num > 0 { + newCap += num + } + + // ensure newCap is a multiple of 64 (if it is > 64) or 16. + if newCap > 64 { + if x = newCap % 64; x != 0 { + x = newCap / 64 + newCap = 64 * (x + 1) + } + } else { + if x = newCap % 16; x != 0 { + x = newCap / 16 + newCap = 16 * (x + 1) + } + } + return +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/json.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/json.go new file mode 100644 index 00000000..5fc375f9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/json.go @@ -0,0 +1,1491 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +// By default, this json support uses base64 encoding for bytes, because you cannot +// store and read any arbitrary string in json (only unicode). +// However, the user can configre how to encode/decode bytes. +// +// This library specifically supports UTF-8 for encoding and decoding only. +// +// Note that the library will happily encode/decode things which are not valid +// json e.g. a map[int64]string. We do it for consistency. With valid json, +// we will encode and decode appropriately. +// Users can specify their map type if necessary to force it. +// +// Note: +// - we cannot use strconv.Quote and strconv.Unquote because json quotes/unquotes differently. +// We implement it here. + +// Top-level methods of json(End|Dec)Driver (which are implementations of (en|de)cDriver +// MUST not call one-another. + +import ( + "bytes" + "encoding/base64" + "math" + "reflect" + "strconv" + "time" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +//-------------------------------- + +var jsonLiterals = [...]byte{ + '"', 't', 'r', 'u', 'e', '"', + '"', 'f', 'a', 'l', 's', 'e', '"', + '"', 'n', 'u', 'l', 'l', '"', +} + +const ( + jsonLitTrueQ = 0 + jsonLitTrue = 1 + jsonLitFalseQ = 6 + jsonLitFalse = 7 + // jsonLitNullQ = 13 + jsonLitNull = 14 +) + +var ( + jsonLiteral4True = jsonLiterals[jsonLitTrue+1 : jsonLitTrue+4] + jsonLiteral4False = jsonLiterals[jsonLitFalse+1 : jsonLitFalse+5] + jsonLiteral4Null = jsonLiterals[jsonLitNull+1 : jsonLitNull+4] +) + +const ( + jsonU4Chk2 = '0' + jsonU4Chk1 = 'a' - 10 + jsonU4Chk0 = 'A' - 10 + + jsonScratchArrayLen = 64 +) + +const ( + // If !jsonValidateSymbols, decoding will be faster, by skipping some checks: + // - If we see first character of null, false or true, + // do not validate subsequent characters. + // - e.g. if we see a n, assume null and skip next 3 characters, + // and do not validate they are ull. + // P.S. Do not expect a significant decoding boost from this. + jsonValidateSymbols = true + + jsonSpacesOrTabsLen = 128 + + jsonAlwaysReturnInternString = false +) + +var ( + // jsonTabs and jsonSpaces are used as caches for indents + jsonTabs, jsonSpaces [jsonSpacesOrTabsLen]byte + + jsonCharHtmlSafeSet bitset256 + jsonCharSafeSet bitset256 + jsonCharWhitespaceSet bitset256 + jsonNumSet bitset256 +) + +func init() { + var i byte + for i = 0; i < jsonSpacesOrTabsLen; i++ { + jsonSpaces[i] = ' ' + jsonTabs[i] = '\t' + } + + // populate the safe values as true: note: ASCII control characters are (0-31) + // jsonCharSafeSet: all true except (0-31) " \ + // jsonCharHtmlSafeSet: all true except (0-31) " \ < > & + for i = 32; i < utf8.RuneSelf; i++ { + switch i { + case '"', '\\': + case '<', '>', '&': + jsonCharSafeSet.set(i) // = true + default: + jsonCharSafeSet.set(i) + jsonCharHtmlSafeSet.set(i) + } + } + for i = 0; i <= utf8.RuneSelf; i++ { + switch i { + case ' ', '\t', '\r', '\n': + jsonCharWhitespaceSet.set(i) + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '.', '+', '-': + jsonNumSet.set(i) + } + } +} + +// ---------------- + +type jsonEncDriverTypical struct { + jsonEncDriver +} + +func (e *jsonEncDriverTypical) typical() {} + +func (e *jsonEncDriverTypical) WriteArrayStart(length int) { + e.w.writen1('[') + e.c = containerArrayStart +} + +func (e *jsonEncDriverTypical) WriteArrayElem() { + if e.c != containerArrayStart { + e.w.writen1(',') + } + e.c = containerArrayElem +} + +func (e *jsonEncDriverTypical) WriteArrayEnd() { + e.w.writen1(']') + e.c = containerArrayEnd +} + +func (e *jsonEncDriverTypical) WriteMapStart(length int) { + e.w.writen1('{') + e.c = containerMapStart +} + +func (e *jsonEncDriverTypical) WriteMapElemKey() { + if e.c != containerMapStart { + e.w.writen1(',') + } + e.c = containerMapKey +} + +func (e *jsonEncDriverTypical) WriteMapElemValue() { + e.w.writen1(':') + e.c = containerMapValue +} + +func (e *jsonEncDriverTypical) WriteMapEnd() { + e.w.writen1('}') + e.c = containerMapEnd +} + +func (e *jsonEncDriverTypical) EncodeBool(b bool) { + if b { + e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4]) + } else { + e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5]) + } +} + +func (e *jsonEncDriverTypical) EncodeFloat64(f float64) { + fmt, prec := jsonFloatStrconvFmtPrec(f) + e.w.writeb(strconv.AppendFloat(e.b[:0], f, fmt, prec, 64)) +} + +func (e *jsonEncDriverTypical) EncodeInt(v int64) { + e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) +} + +func (e *jsonEncDriverTypical) EncodeUint(v uint64) { + e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) +} + +func (e *jsonEncDriverTypical) EncodeFloat32(f float32) { + e.EncodeFloat64(float64(f)) +} + +// func (e *jsonEncDriverTypical) atEndOfEncode() { +// if e.tw { +// e.w.writen1(' ') +// } +// } + +// ---------------- + +type jsonEncDriverGeneric struct { + jsonEncDriver + // ds string // indent string + di int8 // indent per + d bool // indenting? + dt bool // indent using tabs + dl uint16 // indent level + ks bool // map key as string + is byte // integer as string + _ byte // padding + _ [2]uint64 // padding +} + +// indent is done as below: +// - newline and indent are added before each mapKey or arrayElem +// - newline and indent are added before each ending, +// except there was no entry (so we can have {} or []) + +func (e *jsonEncDriverGeneric) reset() { + e.jsonEncDriver.reset() + e.d, e.dt, e.dl, e.di = false, false, 0, 0 + if e.h.Indent > 0 { + e.d = true + e.di = int8(e.h.Indent) + } else if e.h.Indent < 0 { + e.d = true + e.dt = true + e.di = int8(-e.h.Indent) + } + e.ks = e.h.MapKeyAsString + e.is = e.h.IntegerAsString +} + +func (e *jsonEncDriverGeneric) WriteArrayStart(length int) { + if e.d { + e.dl++ + } + e.w.writen1('[') + e.c = containerArrayStart +} + +func (e *jsonEncDriverGeneric) WriteArrayElem() { + if e.c != containerArrayStart { + e.w.writen1(',') + } + if e.d { + e.writeIndent() + } + e.c = containerArrayElem +} + +func (e *jsonEncDriverGeneric) WriteArrayEnd() { + if e.d { + e.dl-- + if e.c != containerArrayStart { + e.writeIndent() + } + } + e.w.writen1(']') + e.c = containerArrayEnd +} + +func (e *jsonEncDriverGeneric) WriteMapStart(length int) { + if e.d { + e.dl++ + } + e.w.writen1('{') + e.c = containerMapStart +} + +func (e *jsonEncDriverGeneric) WriteMapElemKey() { + if e.c != containerMapStart { + e.w.writen1(',') + } + if e.d { + e.writeIndent() + } + e.c = containerMapKey +} + +func (e *jsonEncDriverGeneric) WriteMapElemValue() { + if e.d { + e.w.writen2(':', ' ') + } else { + e.w.writen1(':') + } + e.c = containerMapValue +} + +func (e *jsonEncDriverGeneric) WriteMapEnd() { + if e.d { + e.dl-- + if e.c != containerMapStart { + e.writeIndent() + } + } + e.w.writen1('}') + e.c = containerMapEnd +} + +func (e *jsonEncDriverGeneric) writeIndent() { + e.w.writen1('\n') + x := int(e.di) * int(e.dl) + if e.dt { + for x > jsonSpacesOrTabsLen { + e.w.writeb(jsonTabs[:]) + x -= jsonSpacesOrTabsLen + } + e.w.writeb(jsonTabs[:x]) + } else { + for x > jsonSpacesOrTabsLen { + e.w.writeb(jsonSpaces[:]) + x -= jsonSpacesOrTabsLen + } + e.w.writeb(jsonSpaces[:x]) + } +} + +func (e *jsonEncDriverGeneric) EncodeBool(b bool) { + if e.ks && e.c == containerMapKey { + if b { + e.w.writeb(jsonLiterals[jsonLitTrueQ : jsonLitTrueQ+6]) + } else { + e.w.writeb(jsonLiterals[jsonLitFalseQ : jsonLitFalseQ+7]) + } + } else { + if b { + e.w.writeb(jsonLiterals[jsonLitTrue : jsonLitTrue+4]) + } else { + e.w.writeb(jsonLiterals[jsonLitFalse : jsonLitFalse+5]) + } + } +} + +func (e *jsonEncDriverGeneric) EncodeFloat64(f float64) { + // instead of using 'g', specify whether to use 'e' or 'f' + fmt, prec := jsonFloatStrconvFmtPrec(f) + + var blen int + if e.ks && e.c == containerMapKey { + blen = 2 + len(strconv.AppendFloat(e.b[1:1], f, fmt, prec, 64)) + e.b[0] = '"' + e.b[blen-1] = '"' + } else { + blen = len(strconv.AppendFloat(e.b[:0], f, fmt, prec, 64)) + } + e.w.writeb(e.b[:blen]) +} + +func (e *jsonEncDriverGeneric) EncodeInt(v int64) { + x := e.is + if x == 'A' || x == 'L' && (v > 1<<53 || v < -(1<<53)) || (e.ks && e.c == containerMapKey) { + blen := 2 + len(strconv.AppendInt(e.b[1:1], v, 10)) + e.b[0] = '"' + e.b[blen-1] = '"' + e.w.writeb(e.b[:blen]) + return + } + e.w.writeb(strconv.AppendInt(e.b[:0], v, 10)) +} + +func (e *jsonEncDriverGeneric) EncodeUint(v uint64) { + x := e.is + if x == 'A' || x == 'L' && v > 1<<53 || (e.ks && e.c == containerMapKey) { + blen := 2 + len(strconv.AppendUint(e.b[1:1], v, 10)) + e.b[0] = '"' + e.b[blen-1] = '"' + e.w.writeb(e.b[:blen]) + return + } + e.w.writeb(strconv.AppendUint(e.b[:0], v, 10)) +} + +func (e *jsonEncDriverGeneric) EncodeFloat32(f float32) { + // e.encodeFloat(float64(f), 32) + // always encode all floats as IEEE 64-bit floating point. + // It also ensures that we can decode in full precision even if into a float32, + // as what is written is always to float64 precision. + e.EncodeFloat64(float64(f)) +} + +// func (e *jsonEncDriverGeneric) atEndOfEncode() { +// if e.tw { +// if e.d { +// e.w.writen1('\n') +// } else { +// e.w.writen1(' ') +// } +// } +// } + +// -------------------- + +type jsonEncDriver struct { + noBuiltInTypes + e *Encoder + h *JsonHandle + w *encWriterSwitch + se extWrapper + // ---- cpu cache line boundary? + bs []byte // scratch + // ---- cpu cache line boundary? + // scratch: encode time, etc. + // include scratch buffer and padding, but leave space for containerstate + b [jsonScratchArrayLen + 8 + 8 - 1]byte + c containerState + // _ [2]uint64 // padding +} + +func (e *jsonEncDriver) EncodeNil() { + // We always encode nil as just null (never in quotes) + // This allows us to easily decode if a nil in the json stream + // ie if initial token is n. + e.w.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4]) + + // if e.h.MapKeyAsString && e.c == containerMapKey { + // e.w.writeb(jsonLiterals[jsonLitNullQ : jsonLitNullQ+6]) + // } else { + // e.w.writeb(jsonLiterals[jsonLitNull : jsonLitNull+4]) + // } +} + +func (e *jsonEncDriver) EncodeTime(t time.Time) { + // Do NOT use MarshalJSON, as it allocates internally. + // instead, we call AppendFormat directly, using our scratch buffer (e.b) + if t.IsZero() { + e.EncodeNil() + } else { + e.b[0] = '"' + b := t.AppendFormat(e.b[1:1], time.RFC3339Nano) + e.b[len(b)+1] = '"' + e.w.writeb(e.b[:len(b)+2]) + } + // v, err := t.MarshalJSON(); if err != nil { e.e.error(err) } e.w.writeb(v) +} + +func (e *jsonEncDriver) EncodeExt(rv interface{}, xtag uint64, ext Ext, en *Encoder) { + if v := ext.ConvertExt(rv); v == nil { + e.EncodeNil() + } else { + en.encode(v) + } +} + +func (e *jsonEncDriver) EncodeRawExt(re *RawExt, en *Encoder) { + // only encodes re.Value (never re.Data) + if re.Value == nil { + e.EncodeNil() + } else { + en.encode(re.Value) + } +} + +func (e *jsonEncDriver) EncodeString(c charEncoding, v string) { + e.quoteStr(v) +} + +func (e *jsonEncDriver) EncodeStringEnc(c charEncoding, v string) { + e.quoteStr(v) +} + +func (e *jsonEncDriver) EncodeStringBytes(c charEncoding, v []byte) { + // if encoding raw bytes and RawBytesExt is configured, use it to encode + if v == nil { + e.EncodeNil() + return + } + if c == cRAW { + if e.se.InterfaceExt != nil { + e.EncodeExt(v, 0, &e.se, e.e) + return + } + + slen := base64.StdEncoding.EncodedLen(len(v)) + 2 + if cap(e.bs) >= slen { + e.bs = e.bs[:slen] + } else { + e.bs = make([]byte, slen) + } + e.bs[0] = '"' + base64.StdEncoding.Encode(e.bs[1:], v) + e.bs[slen-1] = '"' + e.w.writeb(e.bs) + } else { + e.quoteStr(stringView(v)) + } +} + +func (e *jsonEncDriver) EncodeStringBytesRaw(v []byte) { + // if encoding raw bytes and RawBytesExt is configured, use it to encode + if v == nil { + e.EncodeNil() + return + } + if e.se.InterfaceExt != nil { + e.EncodeExt(v, 0, &e.se, e.e) + return + } + + slen := base64.StdEncoding.EncodedLen(len(v)) + 2 + if cap(e.bs) >= slen { + e.bs = e.bs[:slen] + } else { + e.bs = make([]byte, slen) + } + e.bs[0] = '"' + base64.StdEncoding.Encode(e.bs[1:], v) + e.bs[slen-1] = '"' + e.w.writeb(e.bs) +} + +func (e *jsonEncDriver) EncodeAsis(v []byte) { + e.w.writeb(v) +} + +func (e *jsonEncDriver) quoteStr(s string) { + // adapted from std pkg encoding/json + const hex = "0123456789abcdef" + w := e.w + htmlasis := e.h.HTMLCharsAsIs + w.writen1('"') + var start int + for i, slen := 0, len(s); i < slen; { + // encode all bytes < 0x20 (except \r, \n). + // also encode < > & to prevent security holes when served to some browsers. + if b := s[i]; b < utf8.RuneSelf { + // if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { + // if (htmlasis && jsonCharSafeSet.isset(b)) || jsonCharHtmlSafeSet.isset(b) { + if jsonCharHtmlSafeSet.isset(b) || (htmlasis && jsonCharSafeSet.isset(b)) { + i++ + continue + } + if start < i { + w.writestr(s[start:i]) + } + switch b { + case '\\', '"': + w.writen2('\\', b) + case '\n': + w.writen2('\\', 'n') + case '\r': + w.writen2('\\', 'r') + case '\b': + w.writen2('\\', 'b') + case '\f': + w.writen2('\\', 'f') + case '\t': + w.writen2('\\', 't') + default: + w.writestr(`\u00`) + w.writen2(hex[b>>4], hex[b&0xF]) + } + i++ + start = i + continue + } + c, size := utf8.DecodeRuneInString(s[i:]) + if c == utf8.RuneError && size == 1 { + if start < i { + w.writestr(s[start:i]) + } + w.writestr(`\ufffd`) + i += size + start = i + continue + } + // U+2028 is LINE SEPARATOR. U+2029 is PARAGRAPH SEPARATOR. + // Both technically valid JSON, but bomb on JSONP, so fix here unconditionally. + if c == '\u2028' || c == '\u2029' { + if start < i { + w.writestr(s[start:i]) + } + w.writestr(`\u202`) + w.writen1(hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + if start < len(s) { + w.writestr(s[start:]) + } + w.writen1('"') +} + +func (e *jsonEncDriver) atEndOfEncode() { + // if e.c == 0 { // scalar written, output space + // e.w.writen1(' ') + // } else if e.h.TermWhitespace { // container written, output new-line + // e.w.writen1('\n') + // } + if e.h.TermWhitespace { + if e.c == 0 { // scalar written, output space + e.w.writen1(' ') + } else { // container written, output new-line + e.w.writen1('\n') + } + } + + // e.c = 0 +} + +type jsonDecDriver struct { + noBuiltInTypes + d *Decoder + h *JsonHandle + r *decReaderSwitch + se extWrapper + + // ---- writable fields during execution --- *try* to keep in sep cache line + + c containerState + // tok is used to store the token read right after skipWhiteSpace. + tok uint8 + fnull bool // found null from appendStringAsBytes + bs []byte // scratch. Initialized from b. Used for parsing strings or numbers. + bstr [8]byte // scratch used for string \UXXX parsing + // ---- cpu cache line boundary? + b [jsonScratchArrayLen]byte // scratch 1, used for parsing strings or numbers or time.Time + b2 [jsonScratchArrayLen]byte // scratch 2, used only for readUntil, decNumBytes + + // _ [3]uint64 // padding + // n jsonNum +} + +// func jsonIsWS(b byte) bool { +// // return b == ' ' || b == '\t' || b == '\r' || b == '\n' +// return jsonCharWhitespaceSet.isset(b) +// } + +func (d *jsonDecDriver) uncacheRead() { + if d.tok != 0 { + d.r.unreadn1() + d.tok = 0 + } +} + +func (d *jsonDecDriver) ReadMapStart() int { + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + const xc uint8 = '{' + if d.tok != xc { + d.d.errorf("read map - expect char '%c' but got char '%c'", xc, d.tok) + } + d.tok = 0 + d.c = containerMapStart + return -1 +} + +func (d *jsonDecDriver) ReadArrayStart() int { + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + const xc uint8 = '[' + if d.tok != xc { + d.d.errorf("read array - expect char '%c' but got char '%c'", xc, d.tok) + } + d.tok = 0 + d.c = containerArrayStart + return -1 +} + +func (d *jsonDecDriver) CheckBreak() bool { + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + return d.tok == '}' || d.tok == ']' +} + +// For the ReadXXX methods below, we could just delegate to helper functions +// readContainerState(c containerState, xc uint8, check bool) +// - ReadArrayElem would become: +// readContainerState(containerArrayElem, ',', d.c != containerArrayStart) +// +// However, until mid-stack inlining comes in go1.11 which supports inlining of +// one-liners, we explicitly write them all 5 out to elide the extra func call. +// +// TODO: For Go 1.11, if inlined, consider consolidating these. + +func (d *jsonDecDriver) ReadArrayElem() { + const xc uint8 = ',' + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + if d.c != containerArrayStart { + if d.tok != xc { + d.d.errorf("read array element - expect char '%c' but got char '%c'", xc, d.tok) + } + d.tok = 0 + } + d.c = containerArrayElem +} + +func (d *jsonDecDriver) ReadArrayEnd() { + const xc uint8 = ']' + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + if d.tok != xc { + d.d.errorf("read array end - expect char '%c' but got char '%c'", xc, d.tok) + } + d.tok = 0 + d.c = containerArrayEnd +} + +func (d *jsonDecDriver) ReadMapElemKey() { + const xc uint8 = ',' + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + if d.c != containerMapStart { + if d.tok != xc { + d.d.errorf("read map key - expect char '%c' but got char '%c'", xc, d.tok) + } + d.tok = 0 + } + d.c = containerMapKey +} + +func (d *jsonDecDriver) ReadMapElemValue() { + const xc uint8 = ':' + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + if d.tok != xc { + d.d.errorf("read map value - expect char '%c' but got char '%c'", xc, d.tok) + } + d.tok = 0 + d.c = containerMapValue +} + +func (d *jsonDecDriver) ReadMapEnd() { + const xc uint8 = '}' + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + if d.tok != xc { + d.d.errorf("read map end - expect char '%c' but got char '%c'", xc, d.tok) + } + d.tok = 0 + d.c = containerMapEnd +} + +// func (d *jsonDecDriver) readLit(length, fromIdx uint8) { +// // length here is always less than 8 (literals are: null, true, false) +// bs := d.r.readx(int(length)) +// d.tok = 0 +// if jsonValidateSymbols && !bytes.Equal(bs, jsonLiterals[fromIdx:fromIdx+length]) { +// d.d.errorf("expecting %s: got %s", jsonLiterals[fromIdx:fromIdx+length], bs) +// } +// } + +func (d *jsonDecDriver) readLit4True() { + bs := d.r.readx(3) + d.tok = 0 + if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4True) { + d.d.errorf("expecting %s: got %s", jsonLiteral4True, bs) + } +} + +func (d *jsonDecDriver) readLit4False() { + bs := d.r.readx(4) + d.tok = 0 + if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4False) { + d.d.errorf("expecting %s: got %s", jsonLiteral4False, bs) + } +} + +func (d *jsonDecDriver) readLit4Null() { + bs := d.r.readx(3) + d.tok = 0 + if jsonValidateSymbols && !bytes.Equal(bs, jsonLiteral4Null) { + d.d.errorf("expecting %s: got %s", jsonLiteral4Null, bs) + } +} + +func (d *jsonDecDriver) TryDecodeAsNil() bool { + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + // we shouldn't try to see if "null" was here, right? + // only the plain string: `null` denotes a nil (ie not quotes) + if d.tok == 'n' { + d.readLit4Null() + return true + } + return false +} + +func (d *jsonDecDriver) DecodeBool() (v bool) { + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + fquot := d.c == containerMapKey && d.tok == '"' + if fquot { + d.tok = d.r.readn1() + } + switch d.tok { + case 'f': + d.readLit4False() + // v = false + case 't': + d.readLit4True() + v = true + default: + d.d.errorf("decode bool: got first char %c", d.tok) + // v = false // "unreachable" + } + if fquot { + d.r.readn1() + } + return +} + +func (d *jsonDecDriver) DecodeTime() (t time.Time) { + // read string, and pass the string into json.unmarshal + d.appendStringAsBytes() + if d.fnull { + return + } + t, err := time.Parse(time.RFC3339, stringView(d.bs)) + if err != nil { + d.d.errorv(err) + } + return +} + +func (d *jsonDecDriver) ContainerType() (vt valueType) { + // check container type by checking the first char + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + + // optimize this, so we don't do 4 checks but do one computation. + // return jsonContainerSet[d.tok] + + // ContainerType is mostly called for Map and Array, + // so this conditional is good enough (max 2 checks typically) + if b := d.tok; b == '{' { + return valueTypeMap + } else if b == '[' { + return valueTypeArray + } else if b == 'n' { + return valueTypeNil + } else if b == '"' { + return valueTypeString + } + return valueTypeUnset +} + +func (d *jsonDecDriver) decNumBytes() (bs []byte) { + // stores num bytes in d.bs + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + if d.tok == '"' { + bs = d.r.readUntil(d.b2[:0], '"') + bs = bs[:len(bs)-1] + } else { + d.r.unreadn1() + bs = d.r.readTo(d.bs[:0], &jsonNumSet) + } + d.tok = 0 + return bs +} + +func (d *jsonDecDriver) DecodeUint64() (u uint64) { + bs := d.decNumBytes() + if len(bs) == 0 { + return + } + n, neg, badsyntax, overflow := jsonParseInteger(bs) + if overflow { + d.d.errorf("overflow parsing unsigned integer: %s", bs) + } else if neg { + d.d.errorf("minus found parsing unsigned integer: %s", bs) + } else if badsyntax { + // fallback: try to decode as float, and cast + n = d.decUint64ViaFloat(stringView(bs)) + } + return n +} + +func (d *jsonDecDriver) DecodeInt64() (i int64) { + const cutoff = uint64(1 << uint(64-1)) + bs := d.decNumBytes() + if len(bs) == 0 { + return + } + n, neg, badsyntax, overflow := jsonParseInteger(bs) + if overflow { + d.d.errorf("overflow parsing integer: %s", bs) + } else if badsyntax { + // d.d.errorf("invalid syntax for integer: %s", bs) + // fallback: try to decode as float, and cast + if neg { + n = d.decUint64ViaFloat(stringView(bs[1:])) + } else { + n = d.decUint64ViaFloat(stringView(bs)) + } + } + if neg { + if n > cutoff { + d.d.errorf("overflow parsing integer: %s", bs) + } + i = -(int64(n)) + } else { + if n >= cutoff { + d.d.errorf("overflow parsing integer: %s", bs) + } + i = int64(n) + } + return +} + +func (d *jsonDecDriver) decUint64ViaFloat(s string) (u uint64) { + if len(s) == 0 { + return + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + d.d.errorf("invalid syntax for integer: %s", s) + // d.d.errorv(err) + } + fi, ff := math.Modf(f) + if ff > 0 { + d.d.errorf("fractional part found parsing integer: %s", s) + } else if fi > float64(math.MaxUint64) { + d.d.errorf("overflow parsing integer: %s", s) + } + return uint64(fi) +} + +func (d *jsonDecDriver) DecodeFloat64() (f float64) { + bs := d.decNumBytes() + if len(bs) == 0 { + return + } + f, err := strconv.ParseFloat(stringView(bs), 64) + if err != nil { + d.d.errorv(err) + } + return +} + +func (d *jsonDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { + if ext == nil { + re := rv.(*RawExt) + re.Tag = xtag + d.d.decode(&re.Value) + } else { + var v interface{} + d.d.decode(&v) + ext.UpdateExt(rv, v) + } + return +} + +func (d *jsonDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { + // if decoding into raw bytes, and the RawBytesExt is configured, use it to decode. + if d.se.InterfaceExt != nil { + bsOut = bs + d.DecodeExt(&bsOut, 0, &d.se) + return + } + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + // check if an "array" of uint8's (see ContainerType for how to infer if an array) + if d.tok == '[' { + bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) + return + } + d.appendStringAsBytes() + // base64 encodes []byte{} as "", and we encode nil []byte as null. + // Consequently, base64 should decode null as a nil []byte, and "" as an empty []byte{}. + // appendStringAsBytes returns a zero-len slice for both, so as not to reset d.bs. + // However, it sets a fnull field to true, so we can check if a null was found. + if len(d.bs) == 0 { + if d.fnull { + return nil + } + return []byte{} + } + bs0 := d.bs + slen := base64.StdEncoding.DecodedLen(len(bs0)) + if slen <= cap(bs) { + bsOut = bs[:slen] + } else if zerocopy && slen <= cap(d.b2) { + bsOut = d.b2[:slen] + } else { + bsOut = make([]byte, slen) + } + slen2, err := base64.StdEncoding.Decode(bsOut, bs0) + if err != nil { + d.d.errorf("error decoding base64 binary '%s': %v", bs0, err) + return nil + } + if slen != slen2 { + bsOut = bsOut[:slen2] + } + return +} + +func (d *jsonDecDriver) DecodeString() (s string) { + d.appendStringAsBytes() + return d.bsToString() +} + +func (d *jsonDecDriver) DecodeStringAsBytes() (s []byte) { + d.appendStringAsBytes() + return d.bs +} + +func (d *jsonDecDriver) appendStringAsBytes() { + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + + d.fnull = false + if d.tok != '"' { + // d.d.errorf("expect char '%c' but got char '%c'", '"', d.tok) + // handle non-string scalar: null, true, false or a number + switch d.tok { + case 'n': + d.readLit4Null() + d.bs = d.bs[:0] + d.fnull = true + case 'f': + d.readLit4False() + d.bs = d.bs[:5] + copy(d.bs, "false") + case 't': + d.readLit4True() + d.bs = d.bs[:4] + copy(d.bs, "true") + default: + // try to parse a valid number + bs := d.decNumBytes() + if len(bs) <= cap(d.bs) { + d.bs = d.bs[:len(bs)] + } else { + d.bs = make([]byte, len(bs)) + } + copy(d.bs, bs) + } + return + } + + d.tok = 0 + r := d.r + var cs = r.readUntil(d.b2[:0], '"') + var cslen = uint(len(cs)) + var c uint8 + v := d.bs[:0] + // append on each byte seen can be expensive, so we just + // keep track of where we last read a contiguous set of + // non-special bytes (using cursor variable), + // and when we see a special byte + // e.g. end-of-slice, " or \, + // we will append the full range into the v slice before proceeding + var i, cursor uint + for { + if i == cslen { + v = append(v, cs[cursor:]...) + cs = r.readUntil(d.b2[:0], '"') + cslen = uint(len(cs)) + i, cursor = 0, 0 + } + c = cs[i] + if c == '"' { + v = append(v, cs[cursor:i]...) + break + } + if c != '\\' { + i++ + continue + } + v = append(v, cs[cursor:i]...) + i++ + c = cs[i] + switch c { + case '"', '\\', '/', '\'': + v = append(v, c) + case 'b': + v = append(v, '\b') + case 'f': + v = append(v, '\f') + case 'n': + v = append(v, '\n') + case 'r': + v = append(v, '\r') + case 't': + v = append(v, '\t') + case 'u': + var r rune + var rr uint32 + if cslen < i+4 { + d.d.errorf("need at least 4 more bytes for unicode sequence") + } + var j uint + for _, c = range cs[i+1 : i+5] { // bounds-check-elimination + // best to use explicit if-else + // - not a table, etc which involve memory loads, array lookup with bounds checks, etc + if c >= '0' && c <= '9' { + rr = rr*16 + uint32(c-jsonU4Chk2) + } else if c >= 'a' && c <= 'f' { + rr = rr*16 + uint32(c-jsonU4Chk1) + } else if c >= 'A' && c <= 'F' { + rr = rr*16 + uint32(c-jsonU4Chk0) + } else { + r = unicode.ReplacementChar + i += 4 + goto encode_rune + } + } + r = rune(rr) + i += 4 + if utf16.IsSurrogate(r) { + if len(cs) >= int(i+6) { + var cx = cs[i+1:][:6:6] // [:6] affords bounds-check-elimination + if cx[0] == '\\' && cx[1] == 'u' { + i += 2 + var rr1 uint32 + for j = 2; j < 6; j++ { + c = cx[j] + if c >= '0' && c <= '9' { + rr = rr*16 + uint32(c-jsonU4Chk2) + } else if c >= 'a' && c <= 'f' { + rr = rr*16 + uint32(c-jsonU4Chk1) + } else if c >= 'A' && c <= 'F' { + rr = rr*16 + uint32(c-jsonU4Chk0) + } else { + r = unicode.ReplacementChar + i += 4 + goto encode_rune + } + } + r = utf16.DecodeRune(r, rune(rr1)) + i += 4 + goto encode_rune + } + } + r = unicode.ReplacementChar + } + encode_rune: + w2 := utf8.EncodeRune(d.bstr[:], r) + v = append(v, d.bstr[:w2]...) + default: + d.d.errorf("unsupported escaped value: %c", c) + } + i++ + cursor = i + } + d.bs = v +} + +func (d *jsonDecDriver) nakedNum(z *decNaked, bs []byte) (err error) { + const cutoff = uint64(1 << uint(64-1)) + + var n uint64 + var neg, badsyntax, overflow bool + + if len(bs) == 0 { + if d.h.PreferFloat { + z.v = valueTypeFloat + z.f = 0 + } else if d.h.SignedInteger { + z.v = valueTypeInt + z.i = 0 + } else { + z.v = valueTypeUint + z.u = 0 + } + return + } + if d.h.PreferFloat { + goto F + } + n, neg, badsyntax, overflow = jsonParseInteger(bs) + if badsyntax || overflow { + goto F + } + if neg { + if n > cutoff { + goto F + } + z.v = valueTypeInt + z.i = -(int64(n)) + } else if d.h.SignedInteger { + if n >= cutoff { + goto F + } + z.v = valueTypeInt + z.i = int64(n) + } else { + z.v = valueTypeUint + z.u = n + } + return +F: + z.v = valueTypeFloat + z.f, err = strconv.ParseFloat(stringView(bs), 64) + return +} + +func (d *jsonDecDriver) bsToString() string { + // if x := d.s.sc; x != nil && x.so && x.st == '}' { // map key + if jsonAlwaysReturnInternString || d.c == containerMapKey { + return d.d.string(d.bs) + } + return string(d.bs) +} + +func (d *jsonDecDriver) DecodeNaked() { + z := d.d.naked() + // var decodeFurther bool + + if d.tok == 0 { + d.tok = d.r.skip(&jsonCharWhitespaceSet) + } + switch d.tok { + case 'n': + d.readLit4Null() + z.v = valueTypeNil + case 'f': + d.readLit4False() + z.v = valueTypeBool + z.b = false + case 't': + d.readLit4True() + z.v = valueTypeBool + z.b = true + case '{': + z.v = valueTypeMap // don't consume. kInterfaceNaked will call ReadMapStart + case '[': + z.v = valueTypeArray // don't consume. kInterfaceNaked will call ReadArrayStart + case '"': + // if a string, and MapKeyAsString, then try to decode it as a nil, bool or number first + d.appendStringAsBytes() + if len(d.bs) > 0 && d.c == containerMapKey && d.h.MapKeyAsString { + switch stringView(d.bs) { + case "null": + z.v = valueTypeNil + case "true": + z.v = valueTypeBool + z.b = true + case "false": + z.v = valueTypeBool + z.b = false + default: + // check if a number: float, int or uint + if err := d.nakedNum(z, d.bs); err != nil { + z.v = valueTypeString + z.s = d.bsToString() + } + } + } else { + z.v = valueTypeString + z.s = d.bsToString() + } + default: // number + bs := d.decNumBytes() + if len(bs) == 0 { + d.d.errorf("decode number from empty string") + return + } + if err := d.nakedNum(z, bs); err != nil { + d.d.errorf("decode number from %s: %v", bs, err) + return + } + } + // if decodeFurther { + // d.s.sc.retryRead() + // } +} + +//---------------------- + +// JsonHandle is a handle for JSON encoding format. +// +// Json is comprehensively supported: +// - decodes numbers into interface{} as int, uint or float64 +// based on how the number looks and some config parameters e.g. PreferFloat, SignedInt, etc. +// - decode integers from float formatted numbers e.g. 1.27e+8 +// - decode any json value (numbers, bool, etc) from quoted strings +// - configurable way to encode/decode []byte . +// by default, encodes and decodes []byte using base64 Std Encoding +// - UTF-8 support for encoding and decoding +// +// It has better performance than the json library in the standard library, +// by leveraging the performance improvements of the codec library. +// +// In addition, it doesn't read more bytes than necessary during a decode, which allows +// reading multiple values from a stream containing json and non-json content. +// For example, a user can read a json value, then a cbor value, then a msgpack value, +// all from the same stream in sequence. +// +// Note that, when decoding quoted strings, invalid UTF-8 or invalid UTF-16 surrogate pairs are +// not treated as an error. Instead, they are replaced by the Unicode replacement character U+FFFD. +type JsonHandle struct { + textEncodingType + BasicHandle + + // Indent indicates how a value is encoded. + // - If positive, indent by that number of spaces. + // - If negative, indent by that number of tabs. + Indent int8 + + // IntegerAsString controls how integers (signed and unsigned) are encoded. + // + // Per the JSON Spec, JSON numbers are 64-bit floating point numbers. + // Consequently, integers > 2^53 cannot be represented as a JSON number without losing precision. + // This can be mitigated by configuring how to encode integers. + // + // IntegerAsString interpretes the following values: + // - if 'L', then encode integers > 2^53 as a json string. + // - if 'A', then encode all integers as a json string + // containing the exact integer representation as a decimal. + // - else encode all integers as a json number (default) + IntegerAsString byte + + // HTMLCharsAsIs controls how to encode some special characters to html: < > & + // + // By default, we encode them as \uXXX + // to prevent security holes when served from some browsers. + HTMLCharsAsIs bool + + // PreferFloat says that we will default to decoding a number as a float. + // If not set, we will examine the characters of the number and decode as an + // integer type if it doesn't have any of the characters [.eE]. + PreferFloat bool + + // TermWhitespace says that we add a whitespace character + // at the end of an encoding. + // + // The whitespace is important, especially if using numbers in a context + // where multiple items are written to a stream. + TermWhitespace bool + + // MapKeyAsString says to encode all map keys as strings. + // + // Use this to enforce strict json output. + // The only caveat is that nil value is ALWAYS written as null (never as "null") + MapKeyAsString bool + + // _ [2]byte // padding + + // Note: below, we store hardly-used items e.g. RawBytesExt is cached in the (en|de)cDriver. + + // RawBytesExt, if configured, is used to encode and decode raw bytes in a custom way. + // If not configured, raw bytes are encoded to/from base64 text. + RawBytesExt InterfaceExt + + _ [2]uint64 // padding +} + +// Name returns the name of the handle: json +func (h *JsonHandle) Name() string { return "json" } +func (h *JsonHandle) hasElemSeparators() bool { return true } +func (h *JsonHandle) typical() bool { + return h.Indent == 0 && !h.MapKeyAsString && h.IntegerAsString != 'A' && h.IntegerAsString != 'L' +} + +type jsonTypical interface { + typical() +} + +func (h *JsonHandle) recreateEncDriver(ed encDriver) (v bool) { + _, v = ed.(jsonTypical) + return v != h.typical() +} + +// SetInterfaceExt sets an extension +func (h *JsonHandle) SetInterfaceExt(rt reflect.Type, tag uint64, ext InterfaceExt) (err error) { + return h.SetExt(rt, tag, &extWrapper{bytesExtFailer{}, ext}) +} + +func (h *JsonHandle) newEncDriver(e *Encoder) (ee encDriver) { + var hd *jsonEncDriver + if h.typical() { + var v jsonEncDriverTypical + ee = &v + hd = &v.jsonEncDriver + } else { + var v jsonEncDriverGeneric + ee = &v + hd = &v.jsonEncDriver + } + hd.e, hd.h, hd.bs = e, h, hd.b[:0] + hd.se.BytesExt = bytesExtFailer{} + ee.reset() + return +} + +func (h *JsonHandle) newDecDriver(d *Decoder) decDriver { + // d := jsonDecDriver{r: r.(*bytesDecReader), h: h} + hd := jsonDecDriver{d: d, h: h} + hd.se.BytesExt = bytesExtFailer{} + hd.bs = hd.b[:0] + hd.reset() + return &hd +} + +func (e *jsonEncDriver) reset() { + e.w = e.e.w + e.se.InterfaceExt = e.h.RawBytesExt + if e.bs != nil { + e.bs = e.bs[:0] + } + e.c = 0 +} + +func (d *jsonDecDriver) reset() { + d.r = d.d.r + d.se.InterfaceExt = d.h.RawBytesExt + if d.bs != nil { + d.bs = d.bs[:0] + } + d.c, d.tok = 0, 0 + // d.n.reset() +} + +func jsonFloatStrconvFmtPrec(f float64) (fmt byte, prec int) { + prec = -1 + var abs = math.Abs(f) + if abs != 0 && (abs < 1e-6 || abs >= 1e21) { + fmt = 'e' + } else { + fmt = 'f' + // set prec to 1 iff mod is 0. + // better than using jsonIsFloatBytesB2 to check if a . or E in the float bytes. + // this ensures that every float has an e or .0 in it. + if abs <= 1 { + if abs == 0 || abs == 1 { + prec = 1 + } + } else if _, mod := math.Modf(abs); mod == 0 { + prec = 1 + } + } + return +} + +// custom-fitted version of strconv.Parse(Ui|I)nt. +// Also ensures we don't have to search for .eE to determine if a float or not. +// Note: s CANNOT be a zero-length slice. +func jsonParseInteger(s []byte) (n uint64, neg, badSyntax, overflow bool) { + const maxUint64 = (1<<64 - 1) + const cutoff = maxUint64/10 + 1 + + if len(s) == 0 { // bounds-check-elimination + // treat empty string as zero value + // badSyntax = true + return + } + switch s[0] { + case '+': + s = s[1:] + case '-': + s = s[1:] + neg = true + } + for _, c := range s { + if c < '0' || c > '9' { + badSyntax = true + return + } + // unsigned integers don't overflow well on multiplication, so check cutoff here + // e.g. (maxUint64-5)*10 doesn't overflow well ... + if n >= cutoff { + overflow = true + return + } + n *= 10 + n1 := n + uint64(c-'0') + if n1 < n || n1 > maxUint64 { + overflow = true + return + } + n = n1 + } + return +} + +var _ decDriver = (*jsonDecDriver)(nil) +var _ encDriver = (*jsonEncDriverGeneric)(nil) +var _ encDriver = (*jsonEncDriverTypical)(nil) +var _ jsonTypical = (*jsonEncDriverTypical)(nil) diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth-test.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth-test.go.tmpl new file mode 100644 index 00000000..c598cc73 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth-test.go.tmpl @@ -0,0 +1,154 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +// Code generated from mammoth-test.go.tmpl - DO NOT EDIT. + +package codec + +import "testing" +import "fmt" +import "reflect" + +// TestMammoth has all the different paths optimized in fast-path +// It has all the primitives, slices and maps. +// +// For each of those types, it has a pointer and a non-pointer field. + +func init() { _ = fmt.Printf } // so we can include fmt as needed + +type TestMammoth struct { + +{{range .Values }}{{if .Primitive }}{{/* +*/}}{{ .MethodNamePfx "F" true }} {{ .Primitive }} +{{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }} +{{end}}{{end}} + +{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* +*/}}{{ .MethodNamePfx "F" false }} []{{ .Elem }} +{{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }} +{{end}}{{end}}{{end}} + +{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* +*/}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }} +{{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }} +{{end}}{{end}}{{end}} + +} + +{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* +*/}} type {{ .MethodNamePfx "typMbs" false }} []{{ .Elem }} +func (_ {{ .MethodNamePfx "typMbs" false }}) MapBySlice() { } +{{end}}{{end}}{{end}} + +{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* +*/}} type {{ .MethodNamePfx "typMap" false }} map[{{ .MapKey }}]{{ .Elem }} +{{end}}{{end}}{{end}} + +func doTestMammothSlices(t *testing.T, h Handle) { +{{range $i, $e := .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* +*/}} + var v{{$i}}va [8]{{ .Elem }} + for _, v := range [][]{{ .Elem }}{ nil, {}, { {{ nonzerocmd .Elem }}, {{ zerocmd .Elem }}, {{ zerocmd .Elem }}, {{ nonzerocmd .Elem }} } } { {{/* + // fmt.Printf(">>>> running mammoth slice v{{$i}}: %v\n", v) + // - encode value to some []byte + // - decode into a length-wise-equal []byte + // - check if equal to initial slice + // - encode ptr to the value + // - check if encode bytes are same + // - decode into ptrs to: nil, then 1-elem slice, equal-length, then large len slice + // - decode into non-addressable slice of equal length, then larger len + // - for each decode, compare elem-by-elem to the original slice + // - + // - rinse and repeat for a MapBySlice version + // - + */}} + var v{{$i}}v1, v{{$i}}v2 []{{ .Elem }} + v{{$i}}v1 = v + bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-slice-v{{$i}}") + if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) } + testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}") + if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) } + testUnmarshalErr(reflect.ValueOf(v{{$i}}v2), bs{{$i}}, h, t, "dec-slice-v{{$i}}-noaddr") // non-addressable value + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-noaddr") + // ... + bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-slice-v{{$i}}-p") + v{{$i}}v2 = nil + testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p") + v{{$i}}va = [8]{{ .Elem }}{} // clear the array + v{{$i}}v2 = v{{$i}}va[:1:1] + testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-1") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-1") + v{{$i}}va = [8]{{ .Elem }}{} // clear the array + v{{$i}}v2 = v{{$i}}va[:len(v{{$i}}v1):len(v{{$i}}v1)] + testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-len") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-len") + v{{$i}}va = [8]{{ .Elem }}{} // clear the array + v{{$i}}v2 = v{{$i}}va[:] + testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-cap") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-slice-v{{$i}}-p-cap") + if len(v{{$i}}v1) > 1 { + v{{$i}}va = [8]{{ .Elem }}{} // clear the array + testUnmarshalErr((&v{{$i}}va)[:len(v{{$i}}v1)], bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-len-noaddr") + testDeepEqualErr(v{{$i}}v1, v{{$i}}va[:len(v{{$i}}v1)], t, "equal-slice-v{{$i}}-p-len-noaddr") + v{{$i}}va = [8]{{ .Elem }}{} // clear the array + testUnmarshalErr((&v{{$i}}va)[:], bs{{$i}}, h, t, "dec-slice-v{{$i}}-p-cap-noaddr") + testDeepEqualErr(v{{$i}}v1, v{{$i}}va[:len(v{{$i}}v1)], t, "equal-slice-v{{$i}}-p-cap-noaddr") + } + // ... + var v{{$i}}v3, v{{$i}}v4 {{ .MethodNamePfx "typMbs" false }} + v{{$i}}v2 = nil + if v != nil { v{{$i}}v2 = make([]{{ .Elem }}, len(v)) } + v{{$i}}v3 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v1) + v{{$i}}v4 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v2) + bs{{$i}} = testMarshalErr(v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom") + testUnmarshalErr(v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom") + testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom") + bs{{$i}} = testMarshalErr(&v{{$i}}v3, h, t, "enc-slice-v{{$i}}-custom-p") + v{{$i}}v2 = nil + v{{$i}}v4 = {{ .MethodNamePfx "typMbs" false }}(v{{$i}}v2) + testUnmarshalErr(&v{{$i}}v4, bs{{$i}}, h, t, "dec-slice-v{{$i}}-custom-p") + testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-slice-v{{$i}}-custom-p") + } +{{end}}{{end}}{{end}} +} + +func doTestMammothMaps(t *testing.T, h Handle) { +{{range $i, $e := .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* +*/}} + for _, v := range []map[{{ .MapKey }}]{{ .Elem }}{ nil, {}, { {{ nonzerocmd .MapKey }}:{{ zerocmd .Elem }} {{if ne "bool" .MapKey}}, {{ nonzerocmd .MapKey }}:{{ nonzerocmd .Elem }} {{end}} } } { + // fmt.Printf(">>>> running mammoth map v{{$i}}: %v\n", v) + var v{{$i}}v1, v{{$i}}v2 map[{{ .MapKey }}]{{ .Elem }} + v{{$i}}v1 = v + bs{{$i}} := testMarshalErr(v{{$i}}v1, h, t, "enc-map-v{{$i}}") + if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map + testUnmarshalErr(v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}") + if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map + testUnmarshalErr(reflect.ValueOf(v{{$i}}v2), bs{{$i}}, h, t, "dec-map-v{{$i}}-noaddr") // decode into non-addressable map value + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-noaddr") + if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map + testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-len") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-p-len") + bs{{$i}} = testMarshalErr(&v{{$i}}v1, h, t, "enc-map-v{{$i}}-p") + v{{$i}}v2 = nil + testUnmarshalErr(&v{{$i}}v2, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-nil") + testDeepEqualErr(v{{$i}}v1, v{{$i}}v2, t, "equal-map-v{{$i}}-p-nil") + // ... + if v == nil { v{{$i}}v2 = nil } else { v{{$i}}v2 = make(map[{{ .MapKey }}]{{ .Elem }}, len(v)) } // reset map + var v{{$i}}v3, v{{$i}}v4 {{ .MethodNamePfx "typMap" false }} + v{{$i}}v3 = {{ .MethodNamePfx "typMap" false }}(v{{$i}}v1) + v{{$i}}v4 = {{ .MethodNamePfx "typMap" false }}(v{{$i}}v2) + bs{{$i}} = testMarshalErr(v{{$i}}v3, h, t, "enc-map-v{{$i}}-custom") + testUnmarshalErr(v{{$i}}v4, bs{{$i}}, h, t, "dec-map-v{{$i}}-p-len") + testDeepEqualErr(v{{$i}}v3, v{{$i}}v4, t, "equal-map-v{{$i}}-p-len") + } +{{end}}{{end}}{{end}} + +} + +func doTestMammothMapsAndSlices(t *testing.T, h Handle) { + doTestMammothSlices(t, h) + doTestMammothMaps(t, h) +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth2-test.go.tmpl b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth2-test.go.tmpl new file mode 100644 index 00000000..3b546f3e --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/mammoth2-test.go.tmpl @@ -0,0 +1,92 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +// Code generated from mammoth2-test.go.tmpl - DO NOT EDIT. + +package codec + +// Increase codecoverage by covering all the codecgen paths, in fast-path and gen-helper.go.... +// +// Add: +// - test file for creating a mammoth generated file as _mammoth_generated.go +// - generate a second mammoth files in a different file: mammoth2_generated_test.go +// - mammoth-test.go.tmpl will do this +// - run codecgen on it, into mammoth2_codecgen_generated_test.go (no build tags) +// - as part of TestMammoth, run it also +// - this will cover all the codecgen, gen-helper, etc in one full run +// - check in mammoth* files into github also +// - then +// +// Now, add some types: +// - some that implement BinaryMarshal, TextMarshal, JSONMarshal, and one that implements none of it +// - create a wrapper type that includes TestMammoth2, with it in slices, and maps, and the custom types +// - this wrapper object is what we work encode/decode (so that the codecgen methods are called) + + +// import "encoding/binary" +import "fmt" + +type TestMammoth2 struct { + +{{range .Values }}{{if .Primitive }}{{/* +*/}}{{ .MethodNamePfx "F" true }} {{ .Primitive }} +{{ .MethodNamePfx "Fptr" true }} *{{ .Primitive }} +{{end}}{{end}} + +{{range .Values }}{{if not .Primitive }}{{if not .MapKey }}{{/* +*/}}{{ .MethodNamePfx "F" false }} []{{ .Elem }} +{{ .MethodNamePfx "Fptr" false }} *[]{{ .Elem }} +{{end}}{{end}}{{end}} + +{{range .Values }}{{if not .Primitive }}{{if .MapKey }}{{/* +*/}}{{ .MethodNamePfx "F" false }} map[{{ .MapKey }}]{{ .Elem }} +{{ .MethodNamePfx "Fptr" false }} *map[{{ .MapKey }}]{{ .Elem }} +{{end}}{{end}}{{end}} + +} + +// ----------- + +type testMammoth2Binary uint64 +func (x testMammoth2Binary) MarshalBinary() (data []byte, err error) { +data = make([]byte, 8) +bigen.PutUint64(data, uint64(x)) +return +} +func (x *testMammoth2Binary) UnmarshalBinary(data []byte) (err error) { +*x = testMammoth2Binary(bigen.Uint64(data)) +return +} + +type testMammoth2Text uint64 +func (x testMammoth2Text) MarshalText() (data []byte, err error) { +data = []byte(fmt.Sprintf("%b", uint64(x))) +return +} +func (x *testMammoth2Text) UnmarshalText(data []byte) (err error) { +_, err = fmt.Sscanf(string(data), "%b", (*uint64)(x)) +return +} + +type testMammoth2Json uint64 +func (x testMammoth2Json) MarshalJSON() (data []byte, err error) { +data = []byte(fmt.Sprintf("%v", uint64(x))) +return +} +func (x *testMammoth2Json) UnmarshalJSON(data []byte) (err error) { +_, err = fmt.Sscanf(string(data), "%v", (*uint64)(x)) +return +} + +type testMammoth2Basic [4]uint64 + +type TestMammoth2Wrapper struct { + V TestMammoth2 + T testMammoth2Text + B testMammoth2Binary + J testMammoth2Json + C testMammoth2Basic + M map[testMammoth2Basic]TestMammoth2 + L []TestMammoth2 + A [4]int64 +} diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/msgpack.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/msgpack.go new file mode 100644 index 00000000..99c8a13f --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/msgpack.go @@ -0,0 +1,1150 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +/* +MSGPACK + +Msgpack-c implementation powers the c, c++, python, ruby, etc libraries. +We need to maintain compatibility with it and how it encodes integer values +without caring about the type. + +For compatibility with behaviour of msgpack-c reference implementation: + - Go intX (>0) and uintX + IS ENCODED AS + msgpack +ve fixnum, unsigned + - Go intX (<0) + IS ENCODED AS + msgpack -ve fixnum, signed +*/ + +package codec + +import ( + "fmt" + "io" + "math" + "net/rpc" + "reflect" + "time" +) + +const ( + mpPosFixNumMin byte = 0x00 + mpPosFixNumMax byte = 0x7f + mpFixMapMin byte = 0x80 + mpFixMapMax byte = 0x8f + mpFixArrayMin byte = 0x90 + mpFixArrayMax byte = 0x9f + mpFixStrMin byte = 0xa0 + mpFixStrMax byte = 0xbf + mpNil byte = 0xc0 + _ byte = 0xc1 + mpFalse byte = 0xc2 + mpTrue byte = 0xc3 + mpFloat byte = 0xca + mpDouble byte = 0xcb + mpUint8 byte = 0xcc + mpUint16 byte = 0xcd + mpUint32 byte = 0xce + mpUint64 byte = 0xcf + mpInt8 byte = 0xd0 + mpInt16 byte = 0xd1 + mpInt32 byte = 0xd2 + mpInt64 byte = 0xd3 + + // extensions below + mpBin8 byte = 0xc4 + mpBin16 byte = 0xc5 + mpBin32 byte = 0xc6 + mpExt8 byte = 0xc7 + mpExt16 byte = 0xc8 + mpExt32 byte = 0xc9 + mpFixExt1 byte = 0xd4 + mpFixExt2 byte = 0xd5 + mpFixExt4 byte = 0xd6 + mpFixExt8 byte = 0xd7 + mpFixExt16 byte = 0xd8 + + mpStr8 byte = 0xd9 // new + mpStr16 byte = 0xda + mpStr32 byte = 0xdb + + mpArray16 byte = 0xdc + mpArray32 byte = 0xdd + + mpMap16 byte = 0xde + mpMap32 byte = 0xdf + + mpNegFixNumMin byte = 0xe0 + mpNegFixNumMax byte = 0xff +) + +var mpTimeExtTag int8 = -1 +var mpTimeExtTagU = uint8(mpTimeExtTag) + +// var mpdesc = map[byte]string{ +// mpPosFixNumMin: "PosFixNumMin", +// mpPosFixNumMax: "PosFixNumMax", +// mpFixMapMin: "FixMapMin", +// mpFixMapMax: "FixMapMax", +// mpFixArrayMin: "FixArrayMin", +// mpFixArrayMax: "FixArrayMax", +// mpFixStrMin: "FixStrMin", +// mpFixStrMax: "FixStrMax", +// mpNil: "Nil", +// mpFalse: "False", +// mpTrue: "True", +// mpFloat: "Float", +// mpDouble: "Double", +// mpUint8: "Uint8", +// mpUint16: "Uint16", +// mpUint32: "Uint32", +// mpUint64: "Uint64", +// mpInt8: "Int8", +// mpInt16: "Int16", +// mpInt32: "Int32", +// mpInt64: "Int64", +// mpBin8: "Bin8", +// mpBin16: "Bin16", +// mpBin32: "Bin32", +// mpExt8: "Ext8", +// mpExt16: "Ext16", +// mpExt32: "Ext32", +// mpFixExt1: "FixExt1", +// mpFixExt2: "FixExt2", +// mpFixExt4: "FixExt4", +// mpFixExt8: "FixExt8", +// mpFixExt16: "FixExt16", +// mpStr8: "Str8", +// mpStr16: "Str16", +// mpStr32: "Str32", +// mpArray16: "Array16", +// mpArray32: "Array32", +// mpMap16: "Map16", +// mpMap32: "Map32", +// mpNegFixNumMin: "NegFixNumMin", +// mpNegFixNumMax: "NegFixNumMax", +// } + +func mpdesc(bd byte) string { + switch bd { + case mpNil: + return "nil" + case mpFalse: + return "false" + case mpTrue: + return "true" + case mpFloat, mpDouble: + return "float" + case mpUint8, mpUint16, mpUint32, mpUint64: + return "uint" + case mpInt8, mpInt16, mpInt32, mpInt64: + return "int" + default: + switch { + case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax: + return "int" + case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax: + return "int" + case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax: + return "string|bytes" + case bd == mpBin8, bd == mpBin16, bd == mpBin32: + return "bytes" + case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: + return "array" + case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax: + return "map" + case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32: + return "ext" + default: + return "unknown" + } + } +} + +// MsgpackSpecRpcMultiArgs is a special type which signifies to the MsgpackSpecRpcCodec +// that the backend RPC service takes multiple arguments, which have been arranged +// in sequence in the slice. +// +// The Codec then passes it AS-IS to the rpc service (without wrapping it in an +// array of 1 element). +type MsgpackSpecRpcMultiArgs []interface{} + +// A MsgpackContainer type specifies the different types of msgpackContainers. +type msgpackContainerType struct { + fixCutoff uint8 + bFixMin, b8, b16, b32 byte + // hasFixMin, has8, has8Always bool +} + +var ( + msgpackContainerRawLegacy = msgpackContainerType{ + 32, mpFixStrMin, 0, mpStr16, mpStr32, + } + msgpackContainerStr = msgpackContainerType{ + 32, mpFixStrMin, mpStr8, mpStr16, mpStr32, // true, true, false, + } + msgpackContainerBin = msgpackContainerType{ + 0, 0, mpBin8, mpBin16, mpBin32, // false, true, true, + } + msgpackContainerList = msgpackContainerType{ + 16, mpFixArrayMin, 0, mpArray16, mpArray32, // true, false, false, + } + msgpackContainerMap = msgpackContainerType{ + 16, mpFixMapMin, 0, mpMap16, mpMap32, // true, false, false, + } +) + +//--------------------------------------------- + +type msgpackEncDriver struct { + noBuiltInTypes + encDriverNoopContainerWriter + // encNoSeparator + e *Encoder + w *encWriterSwitch + h *MsgpackHandle + x [8]byte + // _ [3]uint64 // padding +} + +func (e *msgpackEncDriver) EncodeNil() { + e.w.writen1(mpNil) +} + +func (e *msgpackEncDriver) EncodeInt(i int64) { + if e.h.PositiveIntUnsigned && i >= 0 { + e.EncodeUint(uint64(i)) + } else if i > math.MaxInt8 { + if i <= math.MaxInt16 { + e.w.writen1(mpInt16) + bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i)) + } else if i <= math.MaxInt32 { + e.w.writen1(mpInt32) + bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i)) + } else { + e.w.writen1(mpInt64) + bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i)) + } + } else if i >= -32 { + if e.h.NoFixedNum { + e.w.writen2(mpInt8, byte(i)) + } else { + e.w.writen1(byte(i)) + } + } else if i >= math.MinInt8 { + e.w.writen2(mpInt8, byte(i)) + } else if i >= math.MinInt16 { + e.w.writen1(mpInt16) + bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i)) + } else if i >= math.MinInt32 { + e.w.writen1(mpInt32) + bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i)) + } else { + e.w.writen1(mpInt64) + bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i)) + } +} + +func (e *msgpackEncDriver) EncodeUint(i uint64) { + if i <= math.MaxInt8 { + if e.h.NoFixedNum { + e.w.writen2(mpUint8, byte(i)) + } else { + e.w.writen1(byte(i)) + } + } else if i <= math.MaxUint8 { + e.w.writen2(mpUint8, byte(i)) + } else if i <= math.MaxUint16 { + e.w.writen1(mpUint16) + bigenHelper{e.x[:2], e.w}.writeUint16(uint16(i)) + } else if i <= math.MaxUint32 { + e.w.writen1(mpUint32) + bigenHelper{e.x[:4], e.w}.writeUint32(uint32(i)) + } else { + e.w.writen1(mpUint64) + bigenHelper{e.x[:8], e.w}.writeUint64(uint64(i)) + } +} + +func (e *msgpackEncDriver) EncodeBool(b bool) { + if b { + e.w.writen1(mpTrue) + } else { + e.w.writen1(mpFalse) + } +} + +func (e *msgpackEncDriver) EncodeFloat32(f float32) { + e.w.writen1(mpFloat) + bigenHelper{e.x[:4], e.w}.writeUint32(math.Float32bits(f)) +} + +func (e *msgpackEncDriver) EncodeFloat64(f float64) { + e.w.writen1(mpDouble) + bigenHelper{e.x[:8], e.w}.writeUint64(math.Float64bits(f)) +} + +func (e *msgpackEncDriver) EncodeTime(t time.Time) { + // use the MarshalBinary format if requested + if e.h.TimeNotBuiltin { + bin, err := t.MarshalBinary() + if err != nil { + return + } + e.EncodeStringBytesRaw(bin) + return + } + if t.IsZero() { + e.EncodeNil() + return + } + t = t.UTC() + sec, nsec := t.Unix(), uint64(t.Nanosecond()) + var data64 uint64 + var l = 4 + if sec >= 0 && sec>>34 == 0 { + data64 = (nsec << 34) | uint64(sec) + if data64&0xffffffff00000000 != 0 { + l = 8 + } + } else { + l = 12 + } + if e.h.WriteExt { + e.encodeExtPreamble(mpTimeExtTagU, l) + } else { + e.writeContainerLen(msgpackContainerRawLegacy, l) + } + switch l { + case 4: + bigenHelper{e.x[:4], e.w}.writeUint32(uint32(data64)) + case 8: + bigenHelper{e.x[:8], e.w}.writeUint64(data64) + case 12: + bigenHelper{e.x[:4], e.w}.writeUint32(uint32(nsec)) + bigenHelper{e.x[:8], e.w}.writeUint64(uint64(sec)) + } +} + +func (e *msgpackEncDriver) EncodeExt(v interface{}, xtag uint64, ext Ext, _ *Encoder) { + bs := ext.WriteExt(v) + if bs == nil { + e.EncodeNil() + return + } + if e.h.WriteExt { + e.encodeExtPreamble(uint8(xtag), len(bs)) + e.w.writeb(bs) + } else { + e.EncodeStringBytesRaw(bs) + } +} + +func (e *msgpackEncDriver) EncodeRawExt(re *RawExt, _ *Encoder) { + e.encodeExtPreamble(uint8(re.Tag), len(re.Data)) + e.w.writeb(re.Data) +} + +func (e *msgpackEncDriver) encodeExtPreamble(xtag byte, l int) { + if l == 1 { + e.w.writen2(mpFixExt1, xtag) + } else if l == 2 { + e.w.writen2(mpFixExt2, xtag) + } else if l == 4 { + e.w.writen2(mpFixExt4, xtag) + } else if l == 8 { + e.w.writen2(mpFixExt8, xtag) + } else if l == 16 { + e.w.writen2(mpFixExt16, xtag) + } else if l < 256 { + e.w.writen2(mpExt8, byte(l)) + e.w.writen1(xtag) + } else if l < 65536 { + e.w.writen1(mpExt16) + bigenHelper{e.x[:2], e.w}.writeUint16(uint16(l)) + e.w.writen1(xtag) + } else { + e.w.writen1(mpExt32) + bigenHelper{e.x[:4], e.w}.writeUint32(uint32(l)) + e.w.writen1(xtag) + } +} + +func (e *msgpackEncDriver) WriteArrayStart(length int) { + e.writeContainerLen(msgpackContainerList, length) +} + +func (e *msgpackEncDriver) WriteMapStart(length int) { + e.writeContainerLen(msgpackContainerMap, length) +} + +func (e *msgpackEncDriver) EncodeString(c charEncoding, s string) { + slen := len(s) + if c == cRAW && e.h.WriteExt { + e.writeContainerLen(msgpackContainerBin, slen) + } else { + e.writeContainerLen(msgpackContainerRawLegacy, slen) + } + if slen > 0 { + e.w.writestr(s) + } +} + +func (e *msgpackEncDriver) EncodeStringEnc(c charEncoding, s string) { + slen := len(s) + if e.h.WriteExt { + e.writeContainerLen(msgpackContainerStr, slen) + } else { + e.writeContainerLen(msgpackContainerRawLegacy, slen) + } + if slen > 0 { + e.w.writestr(s) + } +} + +func (e *msgpackEncDriver) EncodeStringBytes(c charEncoding, bs []byte) { + if bs == nil { + e.EncodeNil() + return + } + slen := len(bs) + if c == cRAW && e.h.WriteExt { + e.writeContainerLen(msgpackContainerBin, slen) + } else { + e.writeContainerLen(msgpackContainerRawLegacy, slen) + } + if slen > 0 { + e.w.writeb(bs) + } +} + +func (e *msgpackEncDriver) EncodeStringBytesRaw(bs []byte) { + if bs == nil { + e.EncodeNil() + return + } + slen := len(bs) + if e.h.WriteExt { + e.writeContainerLen(msgpackContainerBin, slen) + } else { + e.writeContainerLen(msgpackContainerRawLegacy, slen) + } + if slen > 0 { + e.w.writeb(bs) + } +} + +func (e *msgpackEncDriver) writeContainerLen(ct msgpackContainerType, l int) { + if ct.fixCutoff > 0 && l < int(ct.fixCutoff) { + e.w.writen1(ct.bFixMin | byte(l)) + } else if ct.b8 > 0 && l < 256 { + e.w.writen2(ct.b8, uint8(l)) + } else if l < 65536 { + e.w.writen1(ct.b16) + bigenHelper{e.x[:2], e.w}.writeUint16(uint16(l)) + } else { + e.w.writen1(ct.b32) + bigenHelper{e.x[:4], e.w}.writeUint32(uint32(l)) + } +} + +//--------------------------------------------- + +type msgpackDecDriver struct { + d *Decoder + r *decReaderSwitch + h *MsgpackHandle + // b [scratchByteArrayLen]byte + bd byte + bdRead bool + br bool // bytes reader + noBuiltInTypes + // noStreamingCodec + // decNoSeparator + decDriverNoopContainerReader + // _ [3]uint64 // padding +} + +// Note: This returns either a primitive (int, bool, etc) for non-containers, +// or a containerType, or a specific type denoting nil or extension. +// It is called when a nil interface{} is passed, leaving it up to the DecDriver +// to introspect the stream and decide how best to decode. +// It deciphers the value by looking at the stream first. +func (d *msgpackDecDriver) DecodeNaked() { + if !d.bdRead { + d.readNextBd() + } + bd := d.bd + n := d.d.naked() + var decodeFurther bool + + switch bd { + case mpNil: + n.v = valueTypeNil + d.bdRead = false + case mpFalse: + n.v = valueTypeBool + n.b = false + case mpTrue: + n.v = valueTypeBool + n.b = true + + case mpFloat: + n.v = valueTypeFloat + n.f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4)))) + case mpDouble: + n.v = valueTypeFloat + n.f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) + + case mpUint8: + n.v = valueTypeUint + n.u = uint64(d.r.readn1()) + case mpUint16: + n.v = valueTypeUint + n.u = uint64(bigen.Uint16(d.r.readx(2))) + case mpUint32: + n.v = valueTypeUint + n.u = uint64(bigen.Uint32(d.r.readx(4))) + case mpUint64: + n.v = valueTypeUint + n.u = uint64(bigen.Uint64(d.r.readx(8))) + + case mpInt8: + n.v = valueTypeInt + n.i = int64(int8(d.r.readn1())) + case mpInt16: + n.v = valueTypeInt + n.i = int64(int16(bigen.Uint16(d.r.readx(2)))) + case mpInt32: + n.v = valueTypeInt + n.i = int64(int32(bigen.Uint32(d.r.readx(4)))) + case mpInt64: + n.v = valueTypeInt + n.i = int64(int64(bigen.Uint64(d.r.readx(8)))) + + default: + switch { + case bd >= mpPosFixNumMin && bd <= mpPosFixNumMax: + // positive fixnum (always signed) + n.v = valueTypeInt + n.i = int64(int8(bd)) + case bd >= mpNegFixNumMin && bd <= mpNegFixNumMax: + // negative fixnum + n.v = valueTypeInt + n.i = int64(int8(bd)) + case bd == mpStr8, bd == mpStr16, bd == mpStr32, bd >= mpFixStrMin && bd <= mpFixStrMax: + if d.h.WriteExt || d.h.RawToString { + n.v = valueTypeString + n.s = d.DecodeString() + } else { + n.v = valueTypeBytes + n.l = d.DecodeBytes(nil, false) + } + case bd == mpBin8, bd == mpBin16, bd == mpBin32: + decNakedReadRawBytes(d, d.d, n, d.h.RawToString) + case bd == mpArray16, bd == mpArray32, bd >= mpFixArrayMin && bd <= mpFixArrayMax: + n.v = valueTypeArray + decodeFurther = true + case bd == mpMap16, bd == mpMap32, bd >= mpFixMapMin && bd <= mpFixMapMax: + n.v = valueTypeMap + decodeFurther = true + case bd >= mpFixExt1 && bd <= mpFixExt16, bd >= mpExt8 && bd <= mpExt32: + n.v = valueTypeExt + clen := d.readExtLen() + n.u = uint64(d.r.readn1()) + if n.u == uint64(mpTimeExtTagU) { + n.v = valueTypeTime + n.t = d.decodeTime(clen) + } else if d.br { + n.l = d.r.readx(uint(clen)) + } else { + n.l = decByteSlice(d.r, clen, d.d.h.MaxInitLen, d.d.b[:]) + } + default: + d.d.errorf("cannot infer value: %s: Ox%x/%d/%s", msgBadDesc, bd, bd, mpdesc(bd)) + } + } + if !decodeFurther { + d.bdRead = false + } + if n.v == valueTypeUint && d.h.SignedInteger { + n.v = valueTypeInt + n.i = int64(n.u) + } +} + +// int can be decoded from msgpack type: intXXX or uintXXX +func (d *msgpackDecDriver) DecodeInt64() (i int64) { + if !d.bdRead { + d.readNextBd() + } + switch d.bd { + case mpUint8: + i = int64(uint64(d.r.readn1())) + case mpUint16: + i = int64(uint64(bigen.Uint16(d.r.readx(2)))) + case mpUint32: + i = int64(uint64(bigen.Uint32(d.r.readx(4)))) + case mpUint64: + i = int64(bigen.Uint64(d.r.readx(8))) + case mpInt8: + i = int64(int8(d.r.readn1())) + case mpInt16: + i = int64(int16(bigen.Uint16(d.r.readx(2)))) + case mpInt32: + i = int64(int32(bigen.Uint32(d.r.readx(4)))) + case mpInt64: + i = int64(bigen.Uint64(d.r.readx(8))) + default: + switch { + case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax: + i = int64(int8(d.bd)) + case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: + i = int64(int8(d.bd)) + default: + d.d.errorf("cannot decode signed integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd)) + return + } + } + d.bdRead = false + return +} + +// uint can be decoded from msgpack type: intXXX or uintXXX +func (d *msgpackDecDriver) DecodeUint64() (ui uint64) { + if !d.bdRead { + d.readNextBd() + } + switch d.bd { + case mpUint8: + ui = uint64(d.r.readn1()) + case mpUint16: + ui = uint64(bigen.Uint16(d.r.readx(2))) + case mpUint32: + ui = uint64(bigen.Uint32(d.r.readx(4))) + case mpUint64: + ui = bigen.Uint64(d.r.readx(8)) + case mpInt8: + if i := int64(int8(d.r.readn1())); i >= 0 { + ui = uint64(i) + } else { + d.d.errorf("assigning negative signed value: %v, to unsigned type", i) + return + } + case mpInt16: + if i := int64(int16(bigen.Uint16(d.r.readx(2)))); i >= 0 { + ui = uint64(i) + } else { + d.d.errorf("assigning negative signed value: %v, to unsigned type", i) + return + } + case mpInt32: + if i := int64(int32(bigen.Uint32(d.r.readx(4)))); i >= 0 { + ui = uint64(i) + } else { + d.d.errorf("assigning negative signed value: %v, to unsigned type", i) + return + } + case mpInt64: + if i := int64(bigen.Uint64(d.r.readx(8))); i >= 0 { + ui = uint64(i) + } else { + d.d.errorf("assigning negative signed value: %v, to unsigned type", i) + return + } + default: + switch { + case d.bd >= mpPosFixNumMin && d.bd <= mpPosFixNumMax: + ui = uint64(d.bd) + case d.bd >= mpNegFixNumMin && d.bd <= mpNegFixNumMax: + d.d.errorf("assigning negative signed value: %v, to unsigned type", int(d.bd)) + return + default: + d.d.errorf("cannot decode unsigned integer: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd)) + return + } + } + d.bdRead = false + return +} + +// float can either be decoded from msgpack type: float, double or intX +func (d *msgpackDecDriver) DecodeFloat64() (f float64) { + if !d.bdRead { + d.readNextBd() + } + if d.bd == mpFloat { + f = float64(math.Float32frombits(bigen.Uint32(d.r.readx(4)))) + } else if d.bd == mpDouble { + f = math.Float64frombits(bigen.Uint64(d.r.readx(8))) + } else { + f = float64(d.DecodeInt64()) + } + d.bdRead = false + return +} + +// bool can be decoded from bool, fixnum 0 or 1. +func (d *msgpackDecDriver) DecodeBool() (b bool) { + if !d.bdRead { + d.readNextBd() + } + if d.bd == mpFalse || d.bd == 0 { + // b = false + } else if d.bd == mpTrue || d.bd == 1 { + b = true + } else { + d.d.errorf("cannot decode bool: %s: %x/%s", msgBadDesc, d.bd, mpdesc(d.bd)) + return + } + d.bdRead = false + return +} + +func (d *msgpackDecDriver) DecodeBytes(bs []byte, zerocopy bool) (bsOut []byte) { + if !d.bdRead { + d.readNextBd() + } + + bd := d.bd + var clen int + if bd == mpNil { + d.bdRead = false + return + } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { + clen = d.readContainerLen(msgpackContainerBin) // binary + } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) { + clen = d.readContainerLen(msgpackContainerStr) // string/raw + } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) { + // check if an "array" of uint8's + if zerocopy && len(bs) == 0 { + bs = d.d.b[:] + } + bsOut, _ = fastpathTV.DecSliceUint8V(bs, true, d.d) + return + } else { + d.d.errorf("invalid byte descriptor for decoding bytes, got: 0x%x", d.bd) + return + } + + d.bdRead = false + if zerocopy { + if d.br { + return d.r.readx(uint(clen)) + } else if len(bs) == 0 { + bs = d.d.b[:] + } + } + return decByteSlice(d.r, clen, d.h.MaxInitLen, bs) +} + +func (d *msgpackDecDriver) DecodeString() (s string) { + return string(d.DecodeBytes(d.d.b[:], true)) +} + +func (d *msgpackDecDriver) DecodeStringAsBytes() (s []byte) { + return d.DecodeBytes(d.d.b[:], true) +} + +func (d *msgpackDecDriver) readNextBd() { + d.bd = d.r.readn1() + d.bdRead = true +} + +func (d *msgpackDecDriver) uncacheRead() { + if d.bdRead { + d.r.unreadn1() + d.bdRead = false + } +} + +func (d *msgpackDecDriver) ContainerType() (vt valueType) { + if !d.bdRead { + d.readNextBd() + } + bd := d.bd + // if bd == mpNil { + // // nil + // } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { + // // binary + // } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) { + // // string/raw + // } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) { + // // array + // } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) { + // // map + // } + if bd == mpNil { + return valueTypeNil + } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { + return valueTypeBytes + } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) { + if d.h.WriteExt || d.h.RawToString { // UTF-8 string (new spec) + return valueTypeString + } + return valueTypeBytes // raw (old spec) + } else if bd == mpArray16 || bd == mpArray32 || (bd >= mpFixArrayMin && bd <= mpFixArrayMax) { + return valueTypeArray + } else if bd == mpMap16 || bd == mpMap32 || (bd >= mpFixMapMin && bd <= mpFixMapMax) { + return valueTypeMap + } + // else { + // d.d.errorf("isContainerType: unsupported parameter: %v", vt) + // } + return valueTypeUnset +} + +func (d *msgpackDecDriver) TryDecodeAsNil() (v bool) { + if !d.bdRead { + d.readNextBd() + } + if d.bd == mpNil { + d.bdRead = false + return true + } + return +} + +func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int) { + bd := d.bd + if bd == mpNil { + clen = -1 // to represent nil + } else if bd == ct.b8 { + clen = int(d.r.readn1()) + } else if bd == ct.b16 { + clen = int(bigen.Uint16(d.r.readx(2))) + } else if bd == ct.b32 { + clen = int(bigen.Uint32(d.r.readx(4))) + } else if (ct.bFixMin & bd) == ct.bFixMin { + clen = int(ct.bFixMin ^ bd) + } else { + d.d.errorf("cannot read container length: %s: hex: %x, decimal: %d", msgBadDesc, bd, bd) + return + } + d.bdRead = false + return +} + +func (d *msgpackDecDriver) ReadMapStart() int { + if !d.bdRead { + d.readNextBd() + } + return d.readContainerLen(msgpackContainerMap) +} + +func (d *msgpackDecDriver) ReadArrayStart() int { + if !d.bdRead { + d.readNextBd() + } + return d.readContainerLen(msgpackContainerList) +} + +func (d *msgpackDecDriver) readExtLen() (clen int) { + switch d.bd { + case mpNil: + clen = -1 // to represent nil + case mpFixExt1: + clen = 1 + case mpFixExt2: + clen = 2 + case mpFixExt4: + clen = 4 + case mpFixExt8: + clen = 8 + case mpFixExt16: + clen = 16 + case mpExt8: + clen = int(d.r.readn1()) + case mpExt16: + clen = int(bigen.Uint16(d.r.readx(2))) + case mpExt32: + clen = int(bigen.Uint32(d.r.readx(4))) + default: + d.d.errorf("decoding ext bytes: found unexpected byte: %x", d.bd) + return + } + return +} + +func (d *msgpackDecDriver) DecodeTime() (t time.Time) { + // decode time from string bytes or ext + if !d.bdRead { + d.readNextBd() + } + bd := d.bd + var clen int + if bd == mpNil { + d.bdRead = false + return + } else if bd == mpBin8 || bd == mpBin16 || bd == mpBin32 { + clen = d.readContainerLen(msgpackContainerBin) // binary + } else if bd == mpStr8 || bd == mpStr16 || bd == mpStr32 || (bd >= mpFixStrMin && bd <= mpFixStrMax) { + clen = d.readContainerLen(msgpackContainerStr) // string/raw + } else { + // expect to see mpFixExt4,-1 OR mpFixExt8,-1 OR mpExt8,12,-1 + d.bdRead = false + b2 := d.r.readn1() + if d.bd == mpFixExt4 && b2 == mpTimeExtTagU { + clen = 4 + } else if d.bd == mpFixExt8 && b2 == mpTimeExtTagU { + clen = 8 + } else if d.bd == mpExt8 && b2 == 12 && d.r.readn1() == mpTimeExtTagU { + clen = 12 + } else { + d.d.errorf("invalid stream for decoding time as extension: got 0x%x, 0x%x", d.bd, b2) + return + } + } + return d.decodeTime(clen) +} + +func (d *msgpackDecDriver) decodeTime(clen int) (t time.Time) { + bs := d.r.readx(uint(clen)) + + // Decode as a binary marshalled string for compatibility with other versions of go-msgpack. + // time.Time should always be encoded as 16 bytes or fewer in the binary marshalling format, + // so will always fit within the 32 byte max for fixed strings + if d.bd >= mpFixStrMin && d.bd <= mpFixStrMax { + err := t.UnmarshalBinary(bs) + if err == nil { + return + } + // fallthrough on failure + } + + d.bdRead = false + switch clen { + case 4: + t = time.Unix(int64(bigen.Uint32(bs)), 0).UTC() + case 8: + tv := bigen.Uint64(bs) + t = time.Unix(int64(tv&0x00000003ffffffff), int64(tv>>34)).UTC() + case 12: + nsec := bigen.Uint32(bs[:4]) + sec := bigen.Uint64(bs[4:]) + t = time.Unix(int64(sec), int64(nsec)).UTC() + default: + d.d.errorf("invalid bytes for decoding time - expecting string or 4, 8, or 12 bytes, got %d", clen) + } + return +} + +func (d *msgpackDecDriver) DecodeExt(rv interface{}, xtag uint64, ext Ext) (realxtag uint64) { + if xtag > 0xff { + d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag) + return + } + realxtag1, xbs := d.decodeExtV(ext != nil, uint8(xtag)) + realxtag = uint64(realxtag1) + if ext == nil { + re := rv.(*RawExt) + re.Tag = realxtag + re.Data = detachZeroCopyBytes(d.br, re.Data, xbs) + } else { + ext.ReadExt(rv, xbs) + } + return +} + +func (d *msgpackDecDriver) decodeExtV(verifyTag bool, tag byte) (xtag byte, xbs []byte) { + if !d.bdRead { + d.readNextBd() + } + xbd := d.bd + if xbd == mpBin8 || xbd == mpBin16 || xbd == mpBin32 { + xbs = d.DecodeBytes(nil, true) + } else if xbd == mpStr8 || xbd == mpStr16 || xbd == mpStr32 || + (xbd >= mpFixStrMin && xbd <= mpFixStrMax) { + xbs = d.DecodeStringAsBytes() + } else { + clen := d.readExtLen() + xtag = d.r.readn1() + if verifyTag && xtag != tag { + d.d.errorf("wrong extension tag - got %b, expecting %v", xtag, tag) + return + } + if d.br { + xbs = d.r.readx(uint(clen)) + } else { + xbs = decByteSlice(d.r, clen, d.d.h.MaxInitLen, d.d.b[:]) + } + } + d.bdRead = false + return +} + +//-------------------------------------------------- + +// MsgpackHandle is a Handle for the Msgpack Schema-Free Encoding Format. +type MsgpackHandle struct { + BasicHandle + + // NoFixedNum says to output all signed integers as 2-bytes, never as 1-byte fixednum. + NoFixedNum bool + + // WriteExt controls whether the new spec is honored. + // + // With WriteExt=true, we can encode configured extensions with extension tags + // and encode string/[]byte/extensions in a way compatible with the new spec + // but incompatible with the old spec. + // + // For compatibility with the old spec, set WriteExt=false. + // + // With WriteExt=false: + // configured extensions are serialized as raw bytes (not msgpack extensions). + // reserved byte descriptors like Str8 and those enabling the new msgpack Binary type + // are not encoded. + WriteExt bool + + // PositiveIntUnsigned says to encode positive integers as unsigned. + PositiveIntUnsigned bool + + binaryEncodingType + noElemSeparators + + // _ [1]uint64 // padding +} + +// Name returns the name of the handle: msgpack +func (h *MsgpackHandle) Name() string { return "msgpack" } + +// SetBytesExt sets an extension +func (h *MsgpackHandle) SetBytesExt(rt reflect.Type, tag uint64, ext BytesExt) (err error) { + return h.SetExt(rt, tag, &extWrapper{ext, interfaceExtFailer{}}) +} + +func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver { + return &msgpackEncDriver{e: e, w: e.w, h: h} +} + +func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver { + return &msgpackDecDriver{d: d, h: h, r: d.r, br: d.bytes} +} + +func (e *msgpackEncDriver) reset() { + e.w = e.e.w +} + +func (d *msgpackDecDriver) reset() { + d.r, d.br = d.d.r, d.d.bytes + d.bd, d.bdRead = 0, false +} + +//-------------------------------------------------- + +type msgpackSpecRpcCodec struct { + rpcCodec +} + +// /////////////// Spec RPC Codec /////////////////// +func (c *msgpackSpecRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error { + // WriteRequest can write to both a Go service, and other services that do + // not abide by the 1 argument rule of a Go service. + // We discriminate based on if the body is a MsgpackSpecRpcMultiArgs + var bodyArr []interface{} + if m, ok := body.(MsgpackSpecRpcMultiArgs); ok { + bodyArr = ([]interface{})(m) + } else { + bodyArr = []interface{}{body} + } + r2 := []interface{}{0, uint32(r.Seq), r.ServiceMethod, bodyArr} + return c.write(r2, nil, false) +} + +func (c *msgpackSpecRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { + var moe interface{} + if r.Error != "" { + moe = r.Error + } + if moe != nil && body != nil { + body = nil + } + r2 := []interface{}{1, uint32(r.Seq), moe, body} + return c.write(r2, nil, false) +} + +func (c *msgpackSpecRpcCodec) ReadResponseHeader(r *rpc.Response) error { + return c.parseCustomHeader(1, &r.Seq, &r.Error) +} + +func (c *msgpackSpecRpcCodec) ReadRequestHeader(r *rpc.Request) error { + return c.parseCustomHeader(0, &r.Seq, &r.ServiceMethod) +} + +func (c *msgpackSpecRpcCodec) ReadRequestBody(body interface{}) error { + if body == nil { // read and discard + return c.read(nil) + } + bodyArr := []interface{}{body} + return c.read(&bodyArr) +} + +func (c *msgpackSpecRpcCodec) parseCustomHeader(expectTypeByte byte, msgid *uint64, methodOrError *string) (err error) { + if cls := c.cls.load(); cls.closed { + return io.EOF + } + + // We read the response header by hand + // so that the body can be decoded on its own from the stream at a later time. + + const fia byte = 0x94 //four item array descriptor value + // Not sure why the panic of EOF is swallowed above. + // if bs1 := c.dec.r.readn1(); bs1 != fia { + // err = fmt.Errorf("Unexpected value for array descriptor: Expecting %v. Received %v", fia, bs1) + // return + // } + var ba [1]byte + var n int + for { + n, err = c.r.Read(ba[:]) + if err != nil { + return + } + if n == 1 { + break + } + } + + var b = ba[0] + if b != fia { + err = fmt.Errorf("not array - %s %x/%s", msgBadDesc, b, mpdesc(b)) + } else { + err = c.read(&b) + if err == nil { + if b != expectTypeByte { + err = fmt.Errorf("%s - expecting %v but got %x/%s", + msgBadDesc, expectTypeByte, b, mpdesc(b)) + } else { + err = c.read(msgid) + if err == nil { + err = c.read(methodOrError) + } + } + } + } + return +} + +//-------------------------------------------------- + +// msgpackSpecRpc is the implementation of Rpc that uses custom communication protocol +// as defined in the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md +type msgpackSpecRpc struct{} + +// MsgpackSpecRpc implements Rpc using the communication protocol defined in +// the msgpack spec at https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md . +// +// See GoRpc documentation, for information on buffering for better performance. +var MsgpackSpecRpc msgpackSpecRpc + +func (x msgpackSpecRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { + return &msgpackSpecRpcCodec{newRPCCodec(conn, h)} +} + +func (x msgpackSpecRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec { + return &msgpackSpecRpcCodec{newRPCCodec(conn, h)} +} + +var _ decDriver = (*msgpackDecDriver)(nil) +var _ encDriver = (*msgpackEncDriver)(nil) diff --git a/vendor/github.com/hashicorp/go-msgpack/v2/codec/rpc.go b/vendor/github.com/hashicorp/go-msgpack/v2/codec/rpc.go new file mode 100644 index 00000000..3fa9f547 --- /dev/null +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/rpc.go @@ -0,0 +1,227 @@ +// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. +// Use of this source code is governed by a MIT license found in the LICENSE file. + +package codec + +import ( + "bufio" + "errors" + "io" + "net/rpc" +) + +var errRpcJsonNeedsTermWhitespace = errors.New("rpc requires JsonHandle with TermWhitespace=true") + +// Rpc provides a rpc Server or Client Codec for rpc communication. +type Rpc interface { + ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec + ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec +} + +// RPCOptions holds options specific to rpc functionality +type RPCOptions struct { + // RPCNoBuffer configures whether we attempt to buffer reads and writes during RPC calls. + // + // Set RPCNoBuffer=true to turn buffering off. + // Buffering can still be done if buffered connections are passed in, or + // buffering is configured on the handle. + RPCNoBuffer bool +} + +// rpcCodec defines the struct members and common methods. +type rpcCodec struct { + c io.Closer + r io.Reader + w io.Writer + f ioFlusher + + dec *Decoder + enc *Encoder + // bw *bufio.Writer + // br *bufio.Reader + h Handle + + cls atomicClsErr +} + +func newRPCCodec(conn io.ReadWriteCloser, h Handle) rpcCodec { + // return newRPCCodec2(bufio.NewReader(conn), bufio.NewWriter(conn), conn, h) + return newRPCCodec2(conn, conn, conn, h) +} + +func newRPCCodec2(r io.Reader, w io.Writer, c io.Closer, h Handle) rpcCodec { + // defensive: ensure that jsonH has TermWhitespace turned on. + if jsonH, ok := h.(*JsonHandle); ok && !jsonH.TermWhitespace { + panic(errRpcJsonNeedsTermWhitespace) + } + // always ensure that we use a flusher, and always flush what was written to the connection. + // we lose nothing by using a buffered writer internally. + f, ok := w.(ioFlusher) + bh := basicHandle(h) + if !bh.RPCNoBuffer { + if bh.WriterBufferSize <= 0 { + if !ok { + bw := bufio.NewWriter(w) + f, w = bw, bw + } + } + if bh.ReaderBufferSize <= 0 { + if _, ok = w.(ioPeeker); !ok { + if _, ok = w.(ioBuffered); !ok { + br := bufio.NewReader(r) + r = br + } + } + } + } + return rpcCodec{ + c: c, + w: w, + r: r, + f: f, + h: h, + enc: NewEncoder(w, h), + dec: NewDecoder(r, h), + } +} + +func (c *rpcCodec) write(obj1, obj2 interface{}, writeObj2 bool) (err error) { + if c.c != nil { + cls := c.cls.load() + if cls.closed { + return cls.errClosed + } + } + err = c.enc.Encode(obj1) + if err == nil { + if writeObj2 { + err = c.enc.Encode(obj2) + } + // if err == nil && c.f != nil { + // err = c.f.Flush() + // } + } + if c.f != nil { + if err == nil { + err = c.f.Flush() + } else { + _ = c.f.Flush() // swallow flush error, so we maintain prior error on write + } + } + return +} + +func (c *rpcCodec) swallow(err *error) { + defer panicToErr(c.dec, err) + c.dec.swallow() +} + +func (c *rpcCodec) read(obj interface{}) (err error) { + if c.c != nil { + cls := c.cls.load() + if cls.closed { + return cls.errClosed + } + } + //If nil is passed in, we should read and discard + if obj == nil { + // var obj2 interface{} + // return c.dec.Decode(&obj2) + c.swallow(&err) + return + } + return c.dec.Decode(obj) +} + +func (c *rpcCodec) Close() error { + if c.c == nil { + return nil + } + cls := c.cls.load() + if cls.closed { + return cls.errClosed + } + cls.errClosed = c.c.Close() + cls.closed = true + c.cls.store(cls) + return cls.errClosed +} + +func (c *rpcCodec) ReadResponseBody(body interface{}) error { + return c.read(body) +} + +// ------------------------------------- + +type goRpcCodec struct { + rpcCodec +} + +func (c *goRpcCodec) WriteRequest(r *rpc.Request, body interface{}) error { + return c.write(r, body, true) +} + +func (c *goRpcCodec) WriteResponse(r *rpc.Response, body interface{}) error { + return c.write(r, body, true) +} + +func (c *goRpcCodec) ReadResponseHeader(r *rpc.Response) error { + return c.read(r) +} + +func (c *goRpcCodec) ReadRequestHeader(r *rpc.Request) error { + return c.read(r) +} + +func (c *goRpcCodec) ReadRequestBody(body interface{}) error { + return c.read(body) +} + +// ------------------------------------- + +// goRpc is the implementation of Rpc that uses the communication protocol +// as defined in net/rpc package. +type goRpc struct{} + +// GoRpc implements Rpc using the communication protocol defined in net/rpc package. +// +// Note: network connection (from net.Dial, of type io.ReadWriteCloser) is not buffered. +// +// For performance, you should configure WriterBufferSize and ReaderBufferSize on the handle. +// This ensures we use an adequate buffer during reading and writing. +// If not configured, we will internally initialize and use a buffer during reads and writes. +// This can be turned off via the RPCNoBuffer option on the Handle. +// +// var handle codec.JsonHandle +// handle.RPCNoBuffer = true // turns off attempt by rpc module to initialize a buffer +// +// Example 1: one way of configuring buffering explicitly: +// +// var handle codec.JsonHandle // codec handle +// handle.ReaderBufferSize = 1024 +// handle.WriterBufferSize = 1024 +// var conn io.ReadWriteCloser // connection got from a socket +// var serverCodec = GoRpc.ServerCodec(conn, handle) +// var clientCodec = GoRpc.ClientCodec(conn, handle) +// +// Example 2: you can also explicitly create a buffered connection yourself, +// and not worry about configuring the buffer sizes in the Handle. +// +// var handle codec.Handle // codec handle +// var conn io.ReadWriteCloser // connection got from a socket +// var bufconn = struct { // bufconn here is a buffered io.ReadWriteCloser +// io.Closer +// *bufio.Reader +// *bufio.Writer +// }{conn, bufio.NewReader(conn), bufio.NewWriter(conn)} +// var serverCodec = GoRpc.ServerCodec(bufconn, handle) +// var clientCodec = GoRpc.ClientCodec(bufconn, handle) +var GoRpc goRpc + +func (x goRpc) ServerCodec(conn io.ReadWriteCloser, h Handle) rpc.ServerCodec { + return &goRpcCodec{newRPCCodec(conn, h)} +} + +func (x goRpc) ClientCodec(conn io.ReadWriteCloser, h Handle) rpc.ClientCodec { + return &goRpcCodec{newRPCCodec(conn, h)} +} diff --git a/vendor/github.com/hashicorp/go-msgpack/codec/msgpack_test.py b/vendor/github.com/hashicorp/go-msgpack/v2/codec/test.py similarity index 64% rename from vendor/github.com/hashicorp/go-msgpack/codec/msgpack_test.py rename to vendor/github.com/hashicorp/go-msgpack/v2/codec/test.py index e933838c..8418fee4 100644 --- a/vendor/github.com/hashicorp/go-msgpack/codec/msgpack_test.py +++ b/vendor/github.com/hashicorp/go-msgpack/v2/codec/test.py @@ -4,6 +4,13 @@ # A Test calls this internally to create the golden files # So it can process them (so we don't have to checkin the files). +# Ensure msgpack-python is installed first, using: +# sudo apt-get install python-dev +# sudo apt-get install python-pip +# pip install --user msgpack-python msgpack-rpc-python + +# Ensure all "string" keys are utf strings (else encoded as bytes) + import msgpack, msgpackrpc, sys, os, threading def get_test_data_list(): @@ -21,54 +28,59 @@ def get_test_data_list(): -3232.0, -6464646464.0, 3232.0, + 6464.0, 6464646464.0, False, True, + u"null", None, - "someday", - "", - "bytestring", + u"some&day>some 0 @@ -80,17 +92,17 @@ def doRpcServer(port, stopTimeSec): server.start() def doRpcClientToPythonSvc(port): - address = msgpackrpc.Address('localhost', port) + address = msgpackrpc.Address('127.0.0.1', port) client = msgpackrpc.Client(address, unpack_encoding='utf-8') - print client.call("Echo123", "A1", "B2", "C3") - print client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}) + print(client.call("Echo123", "A1", "B2", "C3")) + print(client.call("EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})) def doRpcClientToGoSvc(port): # print ">>>> port: ", port, " <<<<<" - address = msgpackrpc.Address('localhost', port) + address = msgpackrpc.Address('127.0.0.1', port) client = msgpackrpc.Client(address, unpack_encoding='utf-8') - print client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"]) - print client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"}) + print(client.call("TestRpcInt.Echo123", ["A1", "B2", "C3"])) + print(client.call("TestRpcInt.EchoStruct", {"A" :"Aa", "B":"Bb", "C":"Cc"})) def doMain(args): if len(args) == 2 and args[0] == "testdata": @@ -102,7 +114,7 @@ def doMain(args): elif len(args) == 2 and args[0] == "rpc-client-go-service": doRpcClientToGoSvc(int(args[1])) else: - print("Usage: msgpack_test.py " + + print("Usage: test.py " + "[testdata|rpc-server|rpc-client-python-service|rpc-client-go-service] ...") if __name__ == "__main__": diff --git a/vendor/github.com/hashicorp/golang-lru/v2/2q.go b/vendor/github.com/hashicorp/golang-lru/v2/2q.go index 5e00d9a7..8c95252b 100644 --- a/vendor/github.com/hashicorp/golang-lru/v2/2q.go +++ b/vendor/github.com/hashicorp/golang-lru/v2/2q.go @@ -30,8 +30,10 @@ const ( // head. The ARCCache is similar, but does not require setting any // parameters. type TwoQueueCache[K comparable, V any] struct { - size int - recentSize int + size int + recentSize int + recentRatio float64 + ghostRatio float64 recent simplelru.LRUCache[K, V] frequent simplelru.LRUCache[K, V] @@ -80,6 +82,8 @@ func New2QParams[K comparable, V any](size int, recentRatio, ghostRatio float64) c := &TwoQueueCache[K, V]{ size: size, recentSize: recentSize, + recentRatio: recentRatio, + ghostRatio: ghostRatio, recent: recent, frequent: frequent, recentEvict: recentEvict, @@ -171,6 +175,34 @@ func (c *TwoQueueCache[K, V]) Len() int { return c.recent.Len() + c.frequent.Len() } +// Resize changes the cache size. +func (c *TwoQueueCache[K, V]) Resize(size int) (evicted int) { + c.lock.Lock() + defer c.lock.Unlock() + + // Recalculate the sub-sizes + recentSize := int(float64(size) * c.recentRatio) + evictSize := int(float64(size) * c.ghostRatio) + c.size = size + c.recentSize = recentSize + + // ensureSpace + diff := c.recent.Len() + c.frequent.Len() - size + if diff < 0 { + diff = 0 + } + for i := 0; i < diff; i++ { + c.ensureSpace(true) + } + + // Reallocate the LRUs + c.recent.Resize(size) + c.frequent.Resize(size) + c.recentEvict.Resize(evictSize) + + return diff +} + // Keys returns a slice of the keys in the cache. // The frequently used keys are first in the returned slice. func (c *TwoQueueCache[K, V]) Keys() []K { diff --git a/vendor/github.com/hashicorp/raft-boltdb/v2/LICENSE b/vendor/github.com/hashicorp/raft-boltdb/v2/LICENSE index f0e5c79e..65d3bade 100644 --- a/vendor/github.com/hashicorp/raft-boltdb/v2/LICENSE +++ b/vendor/github.com/hashicorp/raft-boltdb/v2/LICENSE @@ -1,3 +1,5 @@ +Copyright (c) 2015 HashiCorp, Inc. + Mozilla Public License, version 2.0 1. Definitions diff --git a/vendor/github.com/hashicorp/raft-boltdb/v2/bolt_store.go b/vendor/github.com/hashicorp/raft-boltdb/v2/bolt_store.go index 5414b294..54e3fa6c 100644 --- a/vendor/github.com/hashicorp/raft-boltdb/v2/bolt_store.go +++ b/vendor/github.com/hashicorp/raft-boltdb/v2/bolt_store.go @@ -6,7 +6,7 @@ import ( "os" "time" - metrics "github.com/armon/go-metrics" + "github.com/armon/go-metrics" v1 "github.com/boltdb/bolt" "github.com/hashicorp/raft" "go.etcd.io/bbolt" @@ -36,6 +36,8 @@ type BoltStore struct { // The path to the Bolt database file path string + + msgpackUseNewTimeFormat bool } // Options contains all the configuration used to open the Bbolt @@ -51,6 +53,12 @@ type Options struct { // write to the log. This is unsafe, so it should be used // with caution. NoSync bool + + // MsgpackUseNewTimeFormat when set to true, force the underlying msgpack + // codec to use the new format of time.Time when encoding (used in + // go-msgpack v1.1.5 by default). Decoding is not affected, as all + // go-msgpack v2.1.0+ decoders know how to decode both formats. + MsgpackUseNewTimeFormat bool } // readOnly returns true if the contained bolt options say to open @@ -76,8 +84,9 @@ func New(options Options) (*BoltStore, error) { // Create the new store store := &BoltStore{ - conn: handle, - path: options.Path, + conn: handle, + path: options.Path, + msgpackUseNewTimeFormat: options.MsgpackUseNewTimeFormat, } // If the store was opened read-only, don't try and create buckets @@ -188,7 +197,7 @@ func (b *BoltStore) StoreLogs(logs []*raft.Log) error { batchSize := 0 for _, log := range logs { key := uint64ToBytes(log.Index) - val, err := encodeMsgPack(log) + val, err := encodeMsgPack(log, b.msgpackUseNewTimeFormat) if err != nil { return err } diff --git a/vendor/github.com/hashicorp/raft-boltdb/v2/util.go b/vendor/github.com/hashicorp/raft-boltdb/v2/util.go index 68dd786b..28f7dfcd 100644 --- a/vendor/github.com/hashicorp/raft-boltdb/v2/util.go +++ b/vendor/github.com/hashicorp/raft-boltdb/v2/util.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/binary" - "github.com/hashicorp/go-msgpack/codec" + "github.com/hashicorp/go-msgpack/v2/codec" ) // Decode reverses the encode operation on a byte slice input @@ -16,9 +16,13 @@ func decodeMsgPack(buf []byte, out interface{}) error { } // Encode writes an encoded object to a new bytes buffer -func encodeMsgPack(in interface{}) (*bytes.Buffer, error) { +func encodeMsgPack(in interface{}, useNewTimeFormat bool) (*bytes.Buffer, error) { buf := bytes.NewBuffer(nil) - hd := codec.MsgpackHandle{} + hd := codec.MsgpackHandle{ + BasicHandle: codec.BasicHandle{ + TimeNotBuiltin: !useNewTimeFormat, + }, + } enc := codec.NewEncoder(buf, &hd) err := enc.Encode(in) return buf, err diff --git a/vendor/github.com/hashicorp/raft/CHANGELOG.md b/vendor/github.com/hashicorp/raft/CHANGELOG.md index b190ba86..d77609f7 100644 --- a/vendor/github.com/hashicorp/raft/CHANGELOG.md +++ b/vendor/github.com/hashicorp/raft/CHANGELOG.md @@ -1,12 +1,40 @@ # UNRELEASED +# 1.6.0 (November 15th, 2023) + +CHANGES + +* Upgrade hashicorp/go-msgpack to v2, with go.mod upgraded from v0.5.5 to v2.1.1. [GH-577](https://github.com/hashicorp/raft/pull/577) + + go-msgpack v2.1.1 is by default binary compatible with v0.5.5 ("non-builtin" encoding of `time.Time`), but can decode messages produced by v1.1.5 as well ("builtin" encoding of `time.Time`). + + However, if users of this libary overrode the version of go-msgpack (especially to v1), this **could break** compatibility if raft nodes are running a mix of versions. + + This compatibility can be configured at runtime in Raft using `NetworkTransportConfig.MsgpackUseNewTimeFormat` -- the default is `false`, which maintains compatibility with `go-msgpack` v0.5.5, but if set to `true`, will be compatible with `go-msgpack` v1.1.5. + +IMPROVEMENTS + +* Push to notify channel when shutting down. [GH-567](https://github.com/hashicorp/raft/pull/567) +* Add CommitIndex API [GH-560](https://github.com/hashicorp/raft/pull/560) +* Document some Apply error cases better [GH-561](https://github.com/hashicorp/raft/pull/561) + +BUG FIXES + +* Race with `candidateFromLeadershipTransfer` [GH-570](https://github.com/hashicorp/raft/pull/570) + + +# 1.5.0 (April 21st, 2023) + +IMPROVEMENTS +* Fixed a performance anomaly related to pipelining RPCs that caused large increases in commit latency under high write throughput. Default behavior has changed. For more information see #541. + # 1.4.0 (March 17th, 2023) FEATURES -* Support log stores with a montonically increasing index. Implementing a log store with the `MonotonicLogStore` interface where `IsMonotonic()` returns true will allow Raft to clear all previous logs on user restores of Raft snapshots. +* Support log stores with a monotonically increasing index. Implementing a log store with the `MonotonicLogStore` interface where `IsMonotonic()` returns true will allow Raft to clear all previous logs on user restores of Raft snapshots. BUG FIXES -* Restoring a snapshot with the raft-wal log store caused a panic due to index gap that is created during snapshot restores. +* Restoring a snapshot with the raft-wal log store caused a panic due to index gap that is created during snapshot restores. # 1.3.0 (April 22nd, 2021) diff --git a/vendor/github.com/hashicorp/raft/README.md b/vendor/github.com/hashicorp/raft/README.md index fef24795..ded5bd02 100644 --- a/vendor/github.com/hashicorp/raft/README.md +++ b/vendor/github.com/hashicorp/raft/README.md @@ -34,7 +34,8 @@ and `StableStore`. ## Community Contributed Examples -[Raft gRPC Example](https://github.com/Jille/raft-grpc-example) - Utilizing the Raft repository with gRPC +- [Raft gRPC Example](https://github.com/Jille/raft-grpc-example) - Utilizing the Raft repository with gRPC +- [Raft-based KV-store Example](https://github.com/otoolep/hraftd) - Uses Hashicorp Raft to build a distributed key-value store ## Tagged Releases diff --git a/vendor/github.com/hashicorp/raft/api.go b/vendor/github.com/hashicorp/raft/api.go index 23077dc3..01f573ce 100644 --- a/vendor/github.com/hashicorp/raft/api.go +++ b/vendor/github.com/hashicorp/raft/api.go @@ -134,7 +134,7 @@ type Raft struct { // candidate because the leader tries to transfer leadership. This flag is // used in RequestVoteRequest to express that a leadership transfer is going // on. - candidateFromLeadershipTransfer bool + candidateFromLeadershipTransfer atomic.Bool // Stores our local server ID, used to avoid sending RPCs to ourself localID ServerID @@ -788,12 +788,23 @@ func (r *Raft) LeaderWithID() (ServerAddress, ServerID) { // An optional timeout can be provided to limit the amount of time we wait // for the command to be started. This must be run on the leader or it // will fail. +// +// If the node discovers it is no longer the leader while applying the command, +// it will return ErrLeadershipLost. There is no way to guarantee whether the +// write succeeded or failed in this case. For example, if the leader is +// partitioned it can't know if a quorum of followers wrote the log to disk. If +// at least one did, it may survive into the next leader's term. +// +// If a user snapshot is restored while the command is in-flight, an +// ErrAbortedByRestore is returned. In this case the write effectively failed +// since its effects will not be present in the FSM after the restore. func (r *Raft) Apply(cmd []byte, timeout time.Duration) ApplyFuture { return r.ApplyLog(Log{Data: cmd}, timeout) } // ApplyLog performs Apply but takes in a Log directly. The only values -// currently taken from the submitted Log are Data and Extensions. +// currently taken from the submitted Log are Data and Extensions. See +// Apply for details on error cases. func (r *Raft) ApplyLog(log Log, timeout time.Duration) ApplyFuture { metrics.IncrCounter([]string{"raft", "apply"}, 1) @@ -1194,6 +1205,13 @@ func (r *Raft) LastIndex() uint64 { return r.getLastIndex() } +// CommitIndex returns the committed index. +// This API maybe helpful for server to implement the read index optimization +// as described in the Raft paper. +func (r *Raft) CommitIndex() uint64 { + return r.getCommitIndex() +} + // AppliedIndex returns the last index applied to the FSM. This is generally // lagging behind the last index, especially for indexes that are persisted but // have not yet been considered committed by the leader. NOTE - this reflects diff --git a/vendor/github.com/hashicorp/raft/file_snapshot.go b/vendor/github.com/hashicorp/raft/file_snapshot.go index ae8aad3c..25ace6c3 100644 --- a/vendor/github.com/hashicorp/raft/file_snapshot.go +++ b/vendor/github.com/hashicorp/raft/file_snapshot.go @@ -99,7 +99,7 @@ func NewFileSnapshotStoreWithLogger(base string, retain int, logger hclog.Logger // Ensure our path exists path := filepath.Join(base, snapPath) - if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { + if err := os.MkdirAll(path, 0o755); err != nil && !os.IsExist(err) { return nil, fmt.Errorf("snapshot path not accessible: %v", err) } @@ -170,7 +170,7 @@ func (f *FileSnapshotStore) Create(version SnapshotVersion, index, term uint64, f.logger.Info("creating new snapshot", "path", path) // Make the directory - if err := os.MkdirAll(path, 0755); err != nil { + if err := os.MkdirAll(path, 0o755); err != nil { f.logger.Error("failed to make snapshot directly", "error", err) return nil, err } diff --git a/vendor/github.com/hashicorp/raft/net_transport.go b/vendor/github.com/hashicorp/raft/net_transport.go index bf78a481..bc34285e 100644 --- a/vendor/github.com/hashicorp/raft/net_transport.go +++ b/vendor/github.com/hashicorp/raft/net_transport.go @@ -14,9 +14,9 @@ import ( "sync" "time" - metrics "github.com/armon/go-metrics" + "github.com/armon/go-metrics" "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-msgpack/codec" + "github.com/hashicorp/go-msgpack/v2/codec" ) const ( @@ -106,6 +106,8 @@ type NetworkTransport struct { timeout time.Duration TimeoutScale int + + msgpackUseNewTimeFormat bool } // NetworkTransportConfig encapsulates configuration for the network transport layer. @@ -157,6 +159,12 @@ type NetworkTransportConfig struct { // Timeout is used to apply I/O deadlines. For InstallSnapshot, we multiply // the timeout by (SnapshotSize / TimeoutScale). Timeout time.Duration + + // MsgpackUseNewTimeFormat when set to true, force the underlying msgpack + // codec to use the new format of time.Time when encoding (used in + // go-msgpack v1.1.5 by default). Decoding is not affected, as all + // go-msgpack v2.1.0+ decoders know how to decode both formats. + MsgpackUseNewTimeFormat bool } // ServerAddressProvider is a target address to which we invoke an RPC when establishing a connection @@ -214,16 +222,17 @@ func NewNetworkTransportWithConfig( maxInFlight = DefaultMaxRPCsInFlight } trans := &NetworkTransport{ - connPool: make(map[ServerAddress][]*netConn), - consumeCh: make(chan RPC), - logger: config.Logger, - maxPool: config.MaxPool, - maxInFlight: maxInFlight, - shutdownCh: make(chan struct{}), - stream: config.Stream, - timeout: config.Timeout, - TimeoutScale: DefaultTimeoutScale, - serverAddressProvider: config.ServerAddressProvider, + connPool: make(map[ServerAddress][]*netConn), + consumeCh: make(chan RPC), + logger: config.Logger, + maxPool: config.MaxPool, + maxInFlight: maxInFlight, + shutdownCh: make(chan struct{}), + stream: config.Stream, + timeout: config.Timeout, + TimeoutScale: DefaultTimeoutScale, + serverAddressProvider: config.ServerAddressProvider, + msgpackUseNewTimeFormat: config.MsgpackUseNewTimeFormat, } // Create the connection context and then start our listener. @@ -407,7 +416,11 @@ func (n *NetworkTransport) getConn(target ServerAddress) (*netConn, error) { w: bufio.NewWriterSize(conn, connSendBufferSize), } - netConn.enc = codec.NewEncoder(netConn.w, &codec.MsgpackHandle{}) + netConn.enc = codec.NewEncoder(netConn.w, &codec.MsgpackHandle{ + BasicHandle: codec.BasicHandle{ + TimeNotBuiltin: !n.msgpackUseNewTimeFormat, + }, + }) // Done return netConn, nil @@ -586,7 +599,11 @@ func (n *NetworkTransport) handleConn(connCtx context.Context, conn net.Conn) { r := bufio.NewReaderSize(conn, connReceiveBufferSize) w := bufio.NewWriter(conn) dec := codec.NewDecoder(r, &codec.MsgpackHandle{}) - enc := codec.NewEncoder(w, &codec.MsgpackHandle{}) + enc := codec.NewEncoder(w, &codec.MsgpackHandle{ + BasicHandle: codec.BasicHandle{ + TimeNotBuiltin: !n.msgpackUseNewTimeFormat, + }, + }) for { select { diff --git a/vendor/github.com/hashicorp/raft/raft.go b/vendor/github.com/hashicorp/raft/raft.go index be674344..28c11283 100644 --- a/vendor/github.com/hashicorp/raft/raft.go +++ b/vendor/github.com/hashicorp/raft/raft.go @@ -293,7 +293,7 @@ func (r *Raft) runCandidate() { // which will make other servers vote even though they have a leader already. // It is important to reset that flag, because this priviledge could be abused // otherwise. - defer func() { r.candidateFromLeadershipTransfer = false }() + defer func() { r.candidateFromLeadershipTransfer.Store(false) }() electionTimeout := r.config().ElectionTimeout electionTimer := randomTimeout(electionTimeout) @@ -434,6 +434,11 @@ func (r *Raft) runLeader() { select { case notify <- true: case <-r.shutdownCh: + // make sure push to the notify channel ( if given ) + select { + case notify <- true: + default: + } } } @@ -687,8 +692,21 @@ func (r *Raft) leaderLoop() { case err := <-doneCh: if err != nil { r.logger.Debug(err.Error()) + future.respond(err) + } else { + // Wait for up to ElectionTimeout before flagging the + // leadership transfer as done and unblocking applies in + // the leaderLoop. + select { + case <-time.After(r.config().ElectionTimeout): + err := fmt.Errorf("leadership transfer timeout") + r.logger.Debug(err.Error()) + future.respond(err) + case <-leftLeaderLoop: + r.logger.Debug("lost leadership during transfer (expected)") + future.respond(nil) + } } - future.respond(err) } }() @@ -735,7 +753,7 @@ func (r *Raft) leaderLoop() { start := time.Now() var groupReady []*list.Element - var groupFutures = make(map[uint64]*logFuture) + groupFutures := make(map[uint64]*logFuture) var lastIdxInGroup uint64 // Pull all inflight logs that are committed off the queue. @@ -784,7 +802,6 @@ func (r *Raft) leaderLoop() { if v.quorumSize == 0 { // Just dispatched, start the verification r.verifyLeader(v) - } else if v.votes < v.quorumSize { // Early return, means there must be a new leader r.logger.Warn("new leader elected, stepping down") @@ -1391,7 +1408,7 @@ func (r *Raft) appendEntries(rpc RPC, a *AppendEntriesRequest) { // Increase the term if we see a newer one, also transition to follower // if we ever get an appendEntries call - if a.Term > r.getCurrentTerm() || (r.getState() != Follower && !r.candidateFromLeadershipTransfer) { + if a.Term > r.getCurrentTerm() || (r.getState() != Follower && !r.candidateFromLeadershipTransfer.Load()) { // Ensure transition to follower r.setState(Follower) r.setCurrentTerm(a.Term) @@ -1411,7 +1428,6 @@ func (r *Raft) appendEntries(rpc RPC, a *AppendEntriesRequest) { var prevLogTerm uint64 if a.PrevLogEntry == lastIdx { prevLogTerm = lastTerm - } else { var prevLog Log if err := r.logs.GetLog(a.PrevLogEntry, &prevLog); err != nil { @@ -1841,7 +1857,7 @@ func (r *Raft) electSelf() <-chan *voteResult { Candidate: r.trans.EncodePeer(r.localID, r.localAddr), LastLogIndex: lastIdx, LastLogTerm: lastTerm, - LeadershipTransfer: r.candidateFromLeadershipTransfer, + LeadershipTransfer: r.candidateFromLeadershipTransfer.Load(), } // Construct a function to ask for a vote @@ -1974,7 +1990,7 @@ func (r *Raft) initiateLeadershipTransfer(id *ServerID, address *ServerAddress) func (r *Raft) timeoutNow(rpc RPC, req *TimeoutNowRequest) { r.setLeader("", "") r.setState(Candidate) - r.candidateFromLeadershipTransfer = true + r.candidateFromLeadershipTransfer.Store(true) rpc.Respond(&TimeoutNowResponse{}, nil) } diff --git a/vendor/github.com/hashicorp/raft/tcp_transport.go b/vendor/github.com/hashicorp/raft/tcp_transport.go index 1a9610fc..573696e4 100644 --- a/vendor/github.com/hashicorp/raft/tcp_transport.go +++ b/vendor/github.com/hashicorp/raft/tcp_transport.go @@ -5,10 +5,11 @@ package raft import ( "errors" - "github.com/hashicorp/go-hclog" "io" "net" "time" + + "github.com/hashicorp/go-hclog" ) var ( diff --git a/vendor/github.com/hashicorp/raft/testing.go b/vendor/github.com/hashicorp/raft/testing.go index fd770d42..e0885714 100644 --- a/vendor/github.com/hashicorp/raft/testing.go +++ b/vendor/github.com/hashicorp/raft/testing.go @@ -15,21 +15,19 @@ import ( "time" "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-msgpack/codec" + "github.com/hashicorp/go-msgpack/v2/codec" ) -var ( - userSnapshotErrorsOnNoData = true -) +var userSnapshotErrorsOnNoData = true // Return configurations optimized for in-memory -func inmemConfig(t *testing.T) *Config { +func inmemConfig(tb testing.TB) *Config { conf := DefaultConfig() conf.HeartbeatTimeout = 50 * time.Millisecond conf.ElectionTimeout = 50 * time.Millisecond conf.LeaderLeaseTimeout = 50 * time.Millisecond conf.CommitTimeout = 5 * time.Millisecond - conf.Logger = newTestLogger(t) + conf.Logger = newTestLogger(tb) return conf } @@ -177,7 +175,7 @@ func (m *MockMonotonicLogStore) DeleteRange(min uint64, max uint64) error { // map them into calls to testing.T.Log, so that you only see // the logging for failed tests. type testLoggerAdapter struct { - t *testing.T + tb testing.TB prefix string } @@ -187,16 +185,16 @@ func (a *testLoggerAdapter) Write(d []byte) (int, error) { } if a.prefix != "" { l := a.prefix + ": " + string(d) - a.t.Log(l) + a.tb.Log(l) return len(l), nil } - a.t.Log(string(d)) + a.tb.Log(string(d)) return len(d), nil } -func newTestLogger(t *testing.T) hclog.Logger { - return newTestLoggerWithPrefix(t, "") +func newTestLogger(tb testing.TB) hclog.Logger { + return newTestLoggerWithPrefix(tb, "") } // newTestLoggerWithPrefix returns a Logger that can be used in tests. prefix @@ -211,14 +209,14 @@ func newTestLogger(t *testing.T) hclog.Logger { // causes a panic. This is common if you use it for a NetworkTransport for // example and then close the transport at the end of the test because an error // is logged after the test is complete. -func newTestLoggerWithPrefix(t *testing.T, prefix string) hclog.Logger { +func newTestLoggerWithPrefix(tb testing.TB, prefix string) hclog.Logger { if testing.Verbose() { return hclog.New(&hclog.LoggerOptions{Name: prefix}) } return hclog.New(&hclog.LoggerOptions{ Name: prefix, - Output: &testLoggerAdapter{t: t, prefix: prefix}, + Output: &testLoggerAdapter{tb: tb, prefix: prefix}, }) } @@ -433,9 +431,9 @@ func (c *cluster) GetInState(s RaftState) []*Raft { // Wait until we have a stable instate slice. Each time we see an // observation a state has changed, recheck it and if it has changed, // restart the timer. - var pollStartTime = time.Now() + pollStartTime := time.Now() for { - inState, highestTerm := c.pollState(s) + _, highestTerm := c.pollState(s) inStateTime := time.Now() // Sometimes this routine is called very early on before the @@ -481,8 +479,9 @@ func (c *cluster) GetInState(s RaftState) []*Raft { c.t.Fatalf("timer channel errored") } - c.logger.Info(fmt.Sprintf("stable state for %s reached at %s (%d nodes), %s from start of poll, %s from cluster start. Timeout at %s, %s after stability", - s, inStateTime, len(inState), inStateTime.Sub(pollStartTime), inStateTime.Sub(c.startTime), t, t.Sub(inStateTime))) + inState, highestTerm := c.pollState(s) + c.logger.Info(fmt.Sprintf("stable state for %s reached at %s (%d nodes), highestTerm is %d, %s from start of poll, %s from cluster start. Timeout at %s, %s after stability", + s, inStateTime, len(inState), highestTerm, inStateTime.Sub(pollStartTime), inStateTime.Sub(c.startTime), t, t.Sub(inStateTime))) return inState } } diff --git a/vendor/github.com/hashicorp/raft/util.go b/vendor/github.com/hashicorp/raft/util.go index d427cd61..09c7742b 100644 --- a/vendor/github.com/hashicorp/raft/util.go +++ b/vendor/github.com/hashicorp/raft/util.go @@ -12,7 +12,7 @@ import ( "math/rand" "time" - "github.com/hashicorp/go-msgpack/codec" + "github.com/hashicorp/go-msgpack/v2/codec" ) func init() { @@ -129,7 +129,11 @@ func decodeMsgPack(buf []byte, out interface{}) error { // Encode writes an encoded object to a new bytes buffer. func encodeMsgPack(in interface{}) (*bytes.Buffer, error) { buf := bytes.NewBuffer(nil) - hd := codec.MsgpackHandle{} + hd := codec.MsgpackHandle{ + BasicHandle: codec.BasicHandle{ + TimeNotBuiltin: true, + }, + } enc := codec.NewEncoder(buf, &hd) err := enc.Encode(in) return buf, err diff --git a/vendor/github.com/json-iterator/go/.codecov.yml b/vendor/github.com/json-iterator/go/.codecov.yml deleted file mode 100644 index 955dc0be..00000000 --- a/vendor/github.com/json-iterator/go/.codecov.yml +++ /dev/null @@ -1,3 +0,0 @@ -ignore: - - "output_tests/.*" - diff --git a/vendor/github.com/json-iterator/go/.gitignore b/vendor/github.com/json-iterator/go/.gitignore deleted file mode 100644 index 15556530..00000000 --- a/vendor/github.com/json-iterator/go/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/vendor -/bug_test.go -/coverage.txt -/.idea diff --git a/vendor/github.com/json-iterator/go/.travis.yml b/vendor/github.com/json-iterator/go/.travis.yml deleted file mode 100644 index 449e67cd..00000000 --- a/vendor/github.com/json-iterator/go/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go - -go: - - 1.8.x - - 1.x - -before_install: - - go get -t -v ./... - -script: - - ./test.sh - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/json-iterator/go/Gopkg.lock b/vendor/github.com/json-iterator/go/Gopkg.lock deleted file mode 100644 index c8a9fbb3..00000000 --- a/vendor/github.com/json-iterator/go/Gopkg.lock +++ /dev/null @@ -1,21 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/modern-go/concurrent" - packages = ["."] - revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a" - version = "1.0.0" - -[[projects]] - name = "github.com/modern-go/reflect2" - packages = ["."] - revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" - version = "1.0.1" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "ea54a775e5a354cb015502d2e7aa4b74230fc77e894f34a838b268c25ec8eeb8" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/vendor/github.com/json-iterator/go/Gopkg.toml b/vendor/github.com/json-iterator/go/Gopkg.toml deleted file mode 100644 index 313a0f88..00000000 --- a/vendor/github.com/json-iterator/go/Gopkg.toml +++ /dev/null @@ -1,26 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" - -ignored = ["github.com/davecgh/go-spew*","github.com/google/gofuzz*","github.com/stretchr/testify*"] - -[[constraint]] - name = "github.com/modern-go/reflect2" - version = "1.0.1" diff --git a/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md deleted file mode 100644 index c589addf..00000000 --- a/vendor/github.com/json-iterator/go/README.md +++ /dev/null @@ -1,85 +0,0 @@ -[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge) -[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://pkg.go.dev/github.com/json-iterator/go) -[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go) -[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go) -[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) -[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE) -[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) - -A high-performance 100% compatible drop-in replacement of "encoding/json" - -# Benchmark - -![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) - -Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/github.com/json-iterator/go-benchmark/benchmark_medium_payload_test.go - -Raw Result (easyjson requires static code generation) - -| | ns/op | allocation bytes | allocation times | -| --------------- | ----------- | ---------------- | ---------------- | -| std decode | 35510 ns/op | 1960 B/op | 99 allocs/op | -| easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op | -| jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op | -| std encode | 2213 ns/op | 712 B/op | 5 allocs/op | -| easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op | -| jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op | - -Always benchmark with your own workload. -The result depends heavily on the data input. - -# Usage - -100% compatibility with standard lib - -Replace - -```go -import "encoding/json" -json.Marshal(&data) -``` - -with - -```go -import jsoniter "github.com/json-iterator/go" - -var json = jsoniter.ConfigCompatibleWithStandardLibrary -json.Marshal(&data) -``` - -Replace - -```go -import "encoding/json" -json.Unmarshal(input, &data) -``` - -with - -```go -import jsoniter "github.com/json-iterator/go" - -var json = jsoniter.ConfigCompatibleWithStandardLibrary -json.Unmarshal(input, &data) -``` - -[More documentation](http://jsoniter.com/migrate-from-go-std.html) - -# How to get - -``` -go get github.com/json-iterator/go -``` - -# Contribution Welcomed ! - -Contributors - -- [thockin](https://github.com/thockin) -- [mattn](https://github.com/mattn) -- [cch123](https://github.com/cch123) -- [Oleg Shaldybin](https://github.com/olegshaldybin) -- [Jason Toffaletti](https://github.com/toffaletti) - -Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) diff --git a/vendor/github.com/json-iterator/go/adapter.go b/vendor/github.com/json-iterator/go/adapter.go deleted file mode 100644 index 92d2cc4a..00000000 --- a/vendor/github.com/json-iterator/go/adapter.go +++ /dev/null @@ -1,150 +0,0 @@ -package jsoniter - -import ( - "bytes" - "io" -) - -// RawMessage to make replace json with jsoniter -type RawMessage []byte - -// Unmarshal adapts to json/encoding Unmarshal API -// -// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. -// Refer to https://godoc.org/encoding/json#Unmarshal for more information -func Unmarshal(data []byte, v interface{}) error { - return ConfigDefault.Unmarshal(data, v) -} - -// UnmarshalFromString is a convenient method to read from string instead of []byte -func UnmarshalFromString(str string, v interface{}) error { - return ConfigDefault.UnmarshalFromString(str, v) -} - -// Get quick method to get value from deeply nested JSON structure -func Get(data []byte, path ...interface{}) Any { - return ConfigDefault.Get(data, path...) -} - -// Marshal adapts to json/encoding Marshal API -// -// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API -// Refer to https://godoc.org/encoding/json#Marshal for more information -func Marshal(v interface{}) ([]byte, error) { - return ConfigDefault.Marshal(v) -} - -// MarshalIndent same as json.MarshalIndent. Prefix is not supported. -func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { - return ConfigDefault.MarshalIndent(v, prefix, indent) -} - -// MarshalToString convenient method to write as string instead of []byte -func MarshalToString(v interface{}) (string, error) { - return ConfigDefault.MarshalToString(v) -} - -// NewDecoder adapts to json/stream NewDecoder API. -// -// NewDecoder returns a new decoder that reads from r. -// -// Instead of a json/encoding Decoder, an Decoder is returned -// Refer to https://godoc.org/encoding/json#NewDecoder for more information -func NewDecoder(reader io.Reader) *Decoder { - return ConfigDefault.NewDecoder(reader) -} - -// Decoder reads and decodes JSON values from an input stream. -// Decoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress) -type Decoder struct { - iter *Iterator -} - -// Decode decode JSON into interface{} -func (adapter *Decoder) Decode(obj interface{}) error { - if adapter.iter.head == adapter.iter.tail && adapter.iter.reader != nil { - if !adapter.iter.loadMore() { - return io.EOF - } - } - adapter.iter.ReadVal(obj) - err := adapter.iter.Error - if err == io.EOF { - return nil - } - return adapter.iter.Error -} - -// More is there more? -func (adapter *Decoder) More() bool { - iter := adapter.iter - if iter.Error != nil { - return false - } - c := iter.nextToken() - if c == 0 { - return false - } - iter.unreadByte() - return c != ']' && c != '}' -} - -// Buffered remaining buffer -func (adapter *Decoder) Buffered() io.Reader { - remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail] - return bytes.NewReader(remaining) -} - -// UseNumber causes the Decoder to unmarshal a number into an interface{} as a -// Number instead of as a float64. -func (adapter *Decoder) UseNumber() { - cfg := adapter.iter.cfg.configBeforeFrozen - cfg.UseNumber = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) -} - -// DisallowUnknownFields causes the Decoder to return an error when the destination -// is a struct and the input contains object keys which do not match any -// non-ignored, exported fields in the destination. -func (adapter *Decoder) DisallowUnknownFields() { - cfg := adapter.iter.cfg.configBeforeFrozen - cfg.DisallowUnknownFields = true - adapter.iter.cfg = cfg.frozeWithCacheReuse(adapter.iter.cfg.extraExtensions) -} - -// NewEncoder same as json.NewEncoder -func NewEncoder(writer io.Writer) *Encoder { - return ConfigDefault.NewEncoder(writer) -} - -// Encoder same as json.Encoder -type Encoder struct { - stream *Stream -} - -// Encode encode interface{} as JSON to io.Writer -func (adapter *Encoder) Encode(val interface{}) error { - adapter.stream.WriteVal(val) - adapter.stream.WriteRaw("\n") - adapter.stream.Flush() - return adapter.stream.Error -} - -// SetIndent set the indention. Prefix is not supported -func (adapter *Encoder) SetIndent(prefix, indent string) { - config := adapter.stream.cfg.configBeforeFrozen - config.IndentionStep = len(indent) - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) -} - -// SetEscapeHTML escape html by default, set to false to disable -func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) { - config := adapter.stream.cfg.configBeforeFrozen - config.EscapeHTML = escapeHTML - adapter.stream.cfg = config.frozeWithCacheReuse(adapter.stream.cfg.extraExtensions) -} - -// Valid reports whether data is a valid JSON encoding. -func Valid(data []byte) bool { - return ConfigDefault.Valid(data) -} diff --git a/vendor/github.com/json-iterator/go/any.go b/vendor/github.com/json-iterator/go/any.go deleted file mode 100644 index f6b8aeab..00000000 --- a/vendor/github.com/json-iterator/go/any.go +++ /dev/null @@ -1,325 +0,0 @@ -package jsoniter - -import ( - "errors" - "fmt" - "github.com/modern-go/reflect2" - "io" - "reflect" - "strconv" - "unsafe" -) - -// Any generic object representation. -// The lazy json implementation holds []byte and parse lazily. -type Any interface { - LastError() error - ValueType() ValueType - MustBeValid() Any - ToBool() bool - ToInt() int - ToInt32() int32 - ToInt64() int64 - ToUint() uint - ToUint32() uint32 - ToUint64() uint64 - ToFloat32() float32 - ToFloat64() float64 - ToString() string - ToVal(val interface{}) - Get(path ...interface{}) Any - Size() int - Keys() []string - GetInterface() interface{} - WriteTo(stream *Stream) -} - -type baseAny struct{} - -func (any *baseAny) Get(path ...interface{}) Any { - return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} -} - -func (any *baseAny) Size() int { - return 0 -} - -func (any *baseAny) Keys() []string { - return []string{} -} - -func (any *baseAny) ToVal(obj interface{}) { - panic("not implemented") -} - -// WrapInt32 turn int32 into Any interface -func WrapInt32(val int32) Any { - return &int32Any{baseAny{}, val} -} - -// WrapInt64 turn int64 into Any interface -func WrapInt64(val int64) Any { - return &int64Any{baseAny{}, val} -} - -// WrapUint32 turn uint32 into Any interface -func WrapUint32(val uint32) Any { - return &uint32Any{baseAny{}, val} -} - -// WrapUint64 turn uint64 into Any interface -func WrapUint64(val uint64) Any { - return &uint64Any{baseAny{}, val} -} - -// WrapFloat64 turn float64 into Any interface -func WrapFloat64(val float64) Any { - return &floatAny{baseAny{}, val} -} - -// WrapString turn string into Any interface -func WrapString(val string) Any { - return &stringAny{baseAny{}, val} -} - -// Wrap turn a go object into Any interface -func Wrap(val interface{}) Any { - if val == nil { - return &nilAny{} - } - asAny, isAny := val.(Any) - if isAny { - return asAny - } - typ := reflect2.TypeOf(val) - switch typ.Kind() { - case reflect.Slice: - return wrapArray(val) - case reflect.Struct: - return wrapStruct(val) - case reflect.Map: - return wrapMap(val) - case reflect.String: - return WrapString(val.(string)) - case reflect.Int: - if strconv.IntSize == 32 { - return WrapInt32(int32(val.(int))) - } - return WrapInt64(int64(val.(int))) - case reflect.Int8: - return WrapInt32(int32(val.(int8))) - case reflect.Int16: - return WrapInt32(int32(val.(int16))) - case reflect.Int32: - return WrapInt32(val.(int32)) - case reflect.Int64: - return WrapInt64(val.(int64)) - case reflect.Uint: - if strconv.IntSize == 32 { - return WrapUint32(uint32(val.(uint))) - } - return WrapUint64(uint64(val.(uint))) - case reflect.Uintptr: - if ptrSize == 32 { - return WrapUint32(uint32(val.(uintptr))) - } - return WrapUint64(uint64(val.(uintptr))) - case reflect.Uint8: - return WrapUint32(uint32(val.(uint8))) - case reflect.Uint16: - return WrapUint32(uint32(val.(uint16))) - case reflect.Uint32: - return WrapUint32(uint32(val.(uint32))) - case reflect.Uint64: - return WrapUint64(val.(uint64)) - case reflect.Float32: - return WrapFloat64(float64(val.(float32))) - case reflect.Float64: - return WrapFloat64(val.(float64)) - case reflect.Bool: - if val.(bool) == true { - return &trueAny{} - } - return &falseAny{} - } - return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)} -} - -// ReadAny read next JSON element as an Any object. It is a better json.RawMessage. -func (iter *Iterator) ReadAny() Any { - return iter.readAny() -} - -func (iter *Iterator) readAny() Any { - c := iter.nextToken() - switch c { - case '"': - iter.unreadByte() - return &stringAny{baseAny{}, iter.ReadString()} - case 'n': - iter.skipThreeBytes('u', 'l', 'l') // null - return &nilAny{} - case 't': - iter.skipThreeBytes('r', 'u', 'e') // true - return &trueAny{} - case 'f': - iter.skipFourBytes('a', 'l', 's', 'e') // false - return &falseAny{} - case '{': - return iter.readObjectAny() - case '[': - return iter.readArrayAny() - case '-': - return iter.readNumberAny(false) - case 0: - return &invalidAny{baseAny{}, errors.New("input is empty")} - default: - return iter.readNumberAny(true) - } -} - -func (iter *Iterator) readNumberAny(positive bool) Any { - iter.startCapture(iter.head - 1) - iter.skipNumber() - lazyBuf := iter.stopCapture() - return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} -} - -func (iter *Iterator) readObjectAny() Any { - iter.startCapture(iter.head - 1) - iter.skipObject() - lazyBuf := iter.stopCapture() - return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} -} - -func (iter *Iterator) readArrayAny() Any { - iter.startCapture(iter.head - 1) - iter.skipArray() - lazyBuf := iter.stopCapture() - return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} -} - -func locateObjectField(iter *Iterator, target string) []byte { - var found []byte - iter.ReadObjectCB(func(iter *Iterator, field string) bool { - if field == target { - found = iter.SkipAndReturnBytes() - return false - } - iter.Skip() - return true - }) - return found -} - -func locateArrayElement(iter *Iterator, target int) []byte { - var found []byte - n := 0 - iter.ReadArrayCB(func(iter *Iterator) bool { - if n == target { - found = iter.SkipAndReturnBytes() - return false - } - iter.Skip() - n++ - return true - }) - return found -} - -func locatePath(iter *Iterator, path []interface{}) Any { - for i, pathKeyObj := range path { - switch pathKey := pathKeyObj.(type) { - case string: - valueBytes := locateObjectField(iter, pathKey) - if valueBytes == nil { - return newInvalidAny(path[i:]) - } - iter.ResetBytes(valueBytes) - case int: - valueBytes := locateArrayElement(iter, pathKey) - if valueBytes == nil { - return newInvalidAny(path[i:]) - } - iter.ResetBytes(valueBytes) - case int32: - if '*' == pathKey { - return iter.readAny().Get(path[i:]...) - } - return newInvalidAny(path[i:]) - default: - return newInvalidAny(path[i:]) - } - } - if iter.Error != nil && iter.Error != io.EOF { - return &invalidAny{baseAny{}, iter.Error} - } - return iter.readAny() -} - -var anyType = reflect2.TypeOfPtr((*Any)(nil)).Elem() - -func createDecoderOfAny(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ == anyType { - return &directAnyCodec{} - } - if typ.Implements(anyType) { - return &anyCodec{ - valType: typ, - } - } - return nil -} - -func createEncoderOfAny(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ == anyType { - return &directAnyCodec{} - } - if typ.Implements(anyType) { - return &anyCodec{ - valType: typ, - } - } - return nil -} - -type anyCodec struct { - valType reflect2.Type -} - -func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - panic("not implemented") -} - -func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := codec.valType.UnsafeIndirect(ptr) - any := obj.(Any) - any.WriteTo(stream) -} - -func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool { - obj := codec.valType.UnsafeIndirect(ptr) - any := obj.(Any) - return any.Size() == 0 -} - -type directAnyCodec struct { -} - -func (codec *directAnyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - *(*Any)(ptr) = iter.readAny() -} - -func (codec *directAnyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - any := *(*Any)(ptr) - if any == nil { - stream.WriteNil() - return - } - any.WriteTo(stream) -} - -func (codec *directAnyCodec) IsEmpty(ptr unsafe.Pointer) bool { - any := *(*Any)(ptr) - return any.Size() == 0 -} diff --git a/vendor/github.com/json-iterator/go/any_array.go b/vendor/github.com/json-iterator/go/any_array.go deleted file mode 100644 index 0449e9aa..00000000 --- a/vendor/github.com/json-iterator/go/any_array.go +++ /dev/null @@ -1,278 +0,0 @@ -package jsoniter - -import ( - "reflect" - "unsafe" -) - -type arrayLazyAny struct { - baseAny - cfg *frozenConfig - buf []byte - err error -} - -func (any *arrayLazyAny) ValueType() ValueType { - return ArrayValue -} - -func (any *arrayLazyAny) MustBeValid() Any { - return any -} - -func (any *arrayLazyAny) LastError() error { - return any.err -} - -func (any *arrayLazyAny) ToBool() bool { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.ReadArray() -} - -func (any *arrayLazyAny) ToInt() int { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToInt32() int32 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToInt64() int64 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToUint() uint { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToUint32() uint32 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToUint64() uint64 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToFloat32() float32 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToFloat64() float64 { - if any.ToBool() { - return 1 - } - return 0 -} - -func (any *arrayLazyAny) ToString() string { - return *(*string)(unsafe.Pointer(&any.buf)) -} - -func (any *arrayLazyAny) ToVal(val interface{}) { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadVal(val) -} - -func (any *arrayLazyAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case int: - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - valueBytes := locateArrayElement(iter, firstPath) - if valueBytes == nil { - return newInvalidAny(path) - } - iter.ResetBytes(valueBytes) - return locatePath(iter, path[1:]) - case int32: - if '*' == firstPath { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - arr := make([]Any, 0) - iter.ReadArrayCB(func(iter *Iterator) bool { - found := iter.readAny().Get(path[1:]...) - if found.ValueType() != InvalidValue { - arr = append(arr, found) - } - return true - }) - return wrapArray(arr) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *arrayLazyAny) Size() int { - size := 0 - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadArrayCB(func(iter *Iterator) bool { - size++ - iter.Skip() - return true - }) - return size -} - -func (any *arrayLazyAny) WriteTo(stream *Stream) { - stream.Write(any.buf) -} - -func (any *arrayLazyAny) GetInterface() interface{} { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.Read() -} - -type arrayAny struct { - baseAny - val reflect.Value -} - -func wrapArray(val interface{}) *arrayAny { - return &arrayAny{baseAny{}, reflect.ValueOf(val)} -} - -func (any *arrayAny) ValueType() ValueType { - return ArrayValue -} - -func (any *arrayAny) MustBeValid() Any { - return any -} - -func (any *arrayAny) LastError() error { - return nil -} - -func (any *arrayAny) ToBool() bool { - return any.val.Len() != 0 -} - -func (any *arrayAny) ToInt() int { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToInt32() int32 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToInt64() int64 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToUint() uint { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToUint32() uint32 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToUint64() uint64 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToFloat32() float32 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToFloat64() float64 { - if any.val.Len() == 0 { - return 0 - } - return 1 -} - -func (any *arrayAny) ToString() string { - str, _ := MarshalToString(any.val.Interface()) - return str -} - -func (any *arrayAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case int: - if firstPath < 0 || firstPath >= any.val.Len() { - return newInvalidAny(path) - } - return Wrap(any.val.Index(firstPath).Interface()) - case int32: - if '*' == firstPath { - mappedAll := make([]Any, 0) - for i := 0; i < any.val.Len(); i++ { - mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...) - if mapped.ValueType() != InvalidValue { - mappedAll = append(mappedAll, mapped) - } - } - return wrapArray(mappedAll) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *arrayAny) Size() int { - return any.val.Len() -} - -func (any *arrayAny) WriteTo(stream *Stream) { - stream.WriteVal(any.val) -} - -func (any *arrayAny) GetInterface() interface{} { - return any.val.Interface() -} diff --git a/vendor/github.com/json-iterator/go/any_bool.go b/vendor/github.com/json-iterator/go/any_bool.go deleted file mode 100644 index 9452324a..00000000 --- a/vendor/github.com/json-iterator/go/any_bool.go +++ /dev/null @@ -1,137 +0,0 @@ -package jsoniter - -type trueAny struct { - baseAny -} - -func (any *trueAny) LastError() error { - return nil -} - -func (any *trueAny) ToBool() bool { - return true -} - -func (any *trueAny) ToInt() int { - return 1 -} - -func (any *trueAny) ToInt32() int32 { - return 1 -} - -func (any *trueAny) ToInt64() int64 { - return 1 -} - -func (any *trueAny) ToUint() uint { - return 1 -} - -func (any *trueAny) ToUint32() uint32 { - return 1 -} - -func (any *trueAny) ToUint64() uint64 { - return 1 -} - -func (any *trueAny) ToFloat32() float32 { - return 1 -} - -func (any *trueAny) ToFloat64() float64 { - return 1 -} - -func (any *trueAny) ToString() string { - return "true" -} - -func (any *trueAny) WriteTo(stream *Stream) { - stream.WriteTrue() -} - -func (any *trueAny) Parse() *Iterator { - return nil -} - -func (any *trueAny) GetInterface() interface{} { - return true -} - -func (any *trueAny) ValueType() ValueType { - return BoolValue -} - -func (any *trueAny) MustBeValid() Any { - return any -} - -type falseAny struct { - baseAny -} - -func (any *falseAny) LastError() error { - return nil -} - -func (any *falseAny) ToBool() bool { - return false -} - -func (any *falseAny) ToInt() int { - return 0 -} - -func (any *falseAny) ToInt32() int32 { - return 0 -} - -func (any *falseAny) ToInt64() int64 { - return 0 -} - -func (any *falseAny) ToUint() uint { - return 0 -} - -func (any *falseAny) ToUint32() uint32 { - return 0 -} - -func (any *falseAny) ToUint64() uint64 { - return 0 -} - -func (any *falseAny) ToFloat32() float32 { - return 0 -} - -func (any *falseAny) ToFloat64() float64 { - return 0 -} - -func (any *falseAny) ToString() string { - return "false" -} - -func (any *falseAny) WriteTo(stream *Stream) { - stream.WriteFalse() -} - -func (any *falseAny) Parse() *Iterator { - return nil -} - -func (any *falseAny) GetInterface() interface{} { - return false -} - -func (any *falseAny) ValueType() ValueType { - return BoolValue -} - -func (any *falseAny) MustBeValid() Any { - return any -} diff --git a/vendor/github.com/json-iterator/go/any_float.go b/vendor/github.com/json-iterator/go/any_float.go deleted file mode 100644 index 35fdb094..00000000 --- a/vendor/github.com/json-iterator/go/any_float.go +++ /dev/null @@ -1,83 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type floatAny struct { - baseAny - val float64 -} - -func (any *floatAny) Parse() *Iterator { - return nil -} - -func (any *floatAny) ValueType() ValueType { - return NumberValue -} - -func (any *floatAny) MustBeValid() Any { - return any -} - -func (any *floatAny) LastError() error { - return nil -} - -func (any *floatAny) ToBool() bool { - return any.ToFloat64() != 0 -} - -func (any *floatAny) ToInt() int { - return int(any.val) -} - -func (any *floatAny) ToInt32() int32 { - return int32(any.val) -} - -func (any *floatAny) ToInt64() int64 { - return int64(any.val) -} - -func (any *floatAny) ToUint() uint { - if any.val > 0 { - return uint(any.val) - } - return 0 -} - -func (any *floatAny) ToUint32() uint32 { - if any.val > 0 { - return uint32(any.val) - } - return 0 -} - -func (any *floatAny) ToUint64() uint64 { - if any.val > 0 { - return uint64(any.val) - } - return 0 -} - -func (any *floatAny) ToFloat32() float32 { - return float32(any.val) -} - -func (any *floatAny) ToFloat64() float64 { - return any.val -} - -func (any *floatAny) ToString() string { - return strconv.FormatFloat(any.val, 'E', -1, 64) -} - -func (any *floatAny) WriteTo(stream *Stream) { - stream.WriteFloat64(any.val) -} - -func (any *floatAny) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_int32.go b/vendor/github.com/json-iterator/go/any_int32.go deleted file mode 100644 index 1b56f399..00000000 --- a/vendor/github.com/json-iterator/go/any_int32.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type int32Any struct { - baseAny - val int32 -} - -func (any *int32Any) LastError() error { - return nil -} - -func (any *int32Any) ValueType() ValueType { - return NumberValue -} - -func (any *int32Any) MustBeValid() Any { - return any -} - -func (any *int32Any) ToBool() bool { - return any.val != 0 -} - -func (any *int32Any) ToInt() int { - return int(any.val) -} - -func (any *int32Any) ToInt32() int32 { - return any.val -} - -func (any *int32Any) ToInt64() int64 { - return int64(any.val) -} - -func (any *int32Any) ToUint() uint { - return uint(any.val) -} - -func (any *int32Any) ToUint32() uint32 { - return uint32(any.val) -} - -func (any *int32Any) ToUint64() uint64 { - return uint64(any.val) -} - -func (any *int32Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *int32Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *int32Any) ToString() string { - return strconv.FormatInt(int64(any.val), 10) -} - -func (any *int32Any) WriteTo(stream *Stream) { - stream.WriteInt32(any.val) -} - -func (any *int32Any) Parse() *Iterator { - return nil -} - -func (any *int32Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_int64.go b/vendor/github.com/json-iterator/go/any_int64.go deleted file mode 100644 index c440d72b..00000000 --- a/vendor/github.com/json-iterator/go/any_int64.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type int64Any struct { - baseAny - val int64 -} - -func (any *int64Any) LastError() error { - return nil -} - -func (any *int64Any) ValueType() ValueType { - return NumberValue -} - -func (any *int64Any) MustBeValid() Any { - return any -} - -func (any *int64Any) ToBool() bool { - return any.val != 0 -} - -func (any *int64Any) ToInt() int { - return int(any.val) -} - -func (any *int64Any) ToInt32() int32 { - return int32(any.val) -} - -func (any *int64Any) ToInt64() int64 { - return any.val -} - -func (any *int64Any) ToUint() uint { - return uint(any.val) -} - -func (any *int64Any) ToUint32() uint32 { - return uint32(any.val) -} - -func (any *int64Any) ToUint64() uint64 { - return uint64(any.val) -} - -func (any *int64Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *int64Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *int64Any) ToString() string { - return strconv.FormatInt(any.val, 10) -} - -func (any *int64Any) WriteTo(stream *Stream) { - stream.WriteInt64(any.val) -} - -func (any *int64Any) Parse() *Iterator { - return nil -} - -func (any *int64Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_invalid.go b/vendor/github.com/json-iterator/go/any_invalid.go deleted file mode 100644 index 1d859eac..00000000 --- a/vendor/github.com/json-iterator/go/any_invalid.go +++ /dev/null @@ -1,82 +0,0 @@ -package jsoniter - -import "fmt" - -type invalidAny struct { - baseAny - err error -} - -func newInvalidAny(path []interface{}) *invalidAny { - return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)} -} - -func (any *invalidAny) LastError() error { - return any.err -} - -func (any *invalidAny) ValueType() ValueType { - return InvalidValue -} - -func (any *invalidAny) MustBeValid() Any { - panic(any.err) -} - -func (any *invalidAny) ToBool() bool { - return false -} - -func (any *invalidAny) ToInt() int { - return 0 -} - -func (any *invalidAny) ToInt32() int32 { - return 0 -} - -func (any *invalidAny) ToInt64() int64 { - return 0 -} - -func (any *invalidAny) ToUint() uint { - return 0 -} - -func (any *invalidAny) ToUint32() uint32 { - return 0 -} - -func (any *invalidAny) ToUint64() uint64 { - return 0 -} - -func (any *invalidAny) ToFloat32() float32 { - return 0 -} - -func (any *invalidAny) ToFloat64() float64 { - return 0 -} - -func (any *invalidAny) ToString() string { - return "" -} - -func (any *invalidAny) WriteTo(stream *Stream) { -} - -func (any *invalidAny) Get(path ...interface{}) Any { - if any.err == nil { - return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)} - } - return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)} -} - -func (any *invalidAny) Parse() *Iterator { - return nil -} - -func (any *invalidAny) GetInterface() interface{} { - return nil -} diff --git a/vendor/github.com/json-iterator/go/any_nil.go b/vendor/github.com/json-iterator/go/any_nil.go deleted file mode 100644 index d04cb54c..00000000 --- a/vendor/github.com/json-iterator/go/any_nil.go +++ /dev/null @@ -1,69 +0,0 @@ -package jsoniter - -type nilAny struct { - baseAny -} - -func (any *nilAny) LastError() error { - return nil -} - -func (any *nilAny) ValueType() ValueType { - return NilValue -} - -func (any *nilAny) MustBeValid() Any { - return any -} - -func (any *nilAny) ToBool() bool { - return false -} - -func (any *nilAny) ToInt() int { - return 0 -} - -func (any *nilAny) ToInt32() int32 { - return 0 -} - -func (any *nilAny) ToInt64() int64 { - return 0 -} - -func (any *nilAny) ToUint() uint { - return 0 -} - -func (any *nilAny) ToUint32() uint32 { - return 0 -} - -func (any *nilAny) ToUint64() uint64 { - return 0 -} - -func (any *nilAny) ToFloat32() float32 { - return 0 -} - -func (any *nilAny) ToFloat64() float64 { - return 0 -} - -func (any *nilAny) ToString() string { - return "" -} - -func (any *nilAny) WriteTo(stream *Stream) { - stream.WriteNil() -} - -func (any *nilAny) Parse() *Iterator { - return nil -} - -func (any *nilAny) GetInterface() interface{} { - return nil -} diff --git a/vendor/github.com/json-iterator/go/any_number.go b/vendor/github.com/json-iterator/go/any_number.go deleted file mode 100644 index 9d1e901a..00000000 --- a/vendor/github.com/json-iterator/go/any_number.go +++ /dev/null @@ -1,123 +0,0 @@ -package jsoniter - -import ( - "io" - "unsafe" -) - -type numberLazyAny struct { - baseAny - cfg *frozenConfig - buf []byte - err error -} - -func (any *numberLazyAny) ValueType() ValueType { - return NumberValue -} - -func (any *numberLazyAny) MustBeValid() Any { - return any -} - -func (any *numberLazyAny) LastError() error { - return any.err -} - -func (any *numberLazyAny) ToBool() bool { - return any.ToFloat64() != 0 -} - -func (any *numberLazyAny) ToInt() int { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadInt() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToInt32() int32 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadInt32() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToInt64() int64 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadInt64() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToUint() uint { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadUint() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToUint32() uint32 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadUint32() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToUint64() uint64 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadUint64() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToFloat32() float32 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadFloat32() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToFloat64() float64 { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - val := iter.ReadFloat64() - if iter.Error != nil && iter.Error != io.EOF { - any.err = iter.Error - } - return val -} - -func (any *numberLazyAny) ToString() string { - return *(*string)(unsafe.Pointer(&any.buf)) -} - -func (any *numberLazyAny) WriteTo(stream *Stream) { - stream.Write(any.buf) -} - -func (any *numberLazyAny) GetInterface() interface{} { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.Read() -} diff --git a/vendor/github.com/json-iterator/go/any_object.go b/vendor/github.com/json-iterator/go/any_object.go deleted file mode 100644 index c44ef5c9..00000000 --- a/vendor/github.com/json-iterator/go/any_object.go +++ /dev/null @@ -1,374 +0,0 @@ -package jsoniter - -import ( - "reflect" - "unsafe" -) - -type objectLazyAny struct { - baseAny - cfg *frozenConfig - buf []byte - err error -} - -func (any *objectLazyAny) ValueType() ValueType { - return ObjectValue -} - -func (any *objectLazyAny) MustBeValid() Any { - return any -} - -func (any *objectLazyAny) LastError() error { - return any.err -} - -func (any *objectLazyAny) ToBool() bool { - return true -} - -func (any *objectLazyAny) ToInt() int { - return 0 -} - -func (any *objectLazyAny) ToInt32() int32 { - return 0 -} - -func (any *objectLazyAny) ToInt64() int64 { - return 0 -} - -func (any *objectLazyAny) ToUint() uint { - return 0 -} - -func (any *objectLazyAny) ToUint32() uint32 { - return 0 -} - -func (any *objectLazyAny) ToUint64() uint64 { - return 0 -} - -func (any *objectLazyAny) ToFloat32() float32 { - return 0 -} - -func (any *objectLazyAny) ToFloat64() float64 { - return 0 -} - -func (any *objectLazyAny) ToString() string { - return *(*string)(unsafe.Pointer(&any.buf)) -} - -func (any *objectLazyAny) ToVal(obj interface{}) { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadVal(obj) -} - -func (any *objectLazyAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case string: - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - valueBytes := locateObjectField(iter, firstPath) - if valueBytes == nil { - return newInvalidAny(path) - } - iter.ResetBytes(valueBytes) - return locatePath(iter, path[1:]) - case int32: - if '*' == firstPath { - mappedAll := map[string]Any{} - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadMapCB(func(iter *Iterator, field string) bool { - mapped := locatePath(iter, path[1:]) - if mapped.ValueType() != InvalidValue { - mappedAll[field] = mapped - } - return true - }) - return wrapMap(mappedAll) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *objectLazyAny) Keys() []string { - keys := []string{} - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadMapCB(func(iter *Iterator, field string) bool { - iter.Skip() - keys = append(keys, field) - return true - }) - return keys -} - -func (any *objectLazyAny) Size() int { - size := 0 - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - iter.ReadObjectCB(func(iter *Iterator, field string) bool { - iter.Skip() - size++ - return true - }) - return size -} - -func (any *objectLazyAny) WriteTo(stream *Stream) { - stream.Write(any.buf) -} - -func (any *objectLazyAny) GetInterface() interface{} { - iter := any.cfg.BorrowIterator(any.buf) - defer any.cfg.ReturnIterator(iter) - return iter.Read() -} - -type objectAny struct { - baseAny - err error - val reflect.Value -} - -func wrapStruct(val interface{}) *objectAny { - return &objectAny{baseAny{}, nil, reflect.ValueOf(val)} -} - -func (any *objectAny) ValueType() ValueType { - return ObjectValue -} - -func (any *objectAny) MustBeValid() Any { - return any -} - -func (any *objectAny) Parse() *Iterator { - return nil -} - -func (any *objectAny) LastError() error { - return any.err -} - -func (any *objectAny) ToBool() bool { - return any.val.NumField() != 0 -} - -func (any *objectAny) ToInt() int { - return 0 -} - -func (any *objectAny) ToInt32() int32 { - return 0 -} - -func (any *objectAny) ToInt64() int64 { - return 0 -} - -func (any *objectAny) ToUint() uint { - return 0 -} - -func (any *objectAny) ToUint32() uint32 { - return 0 -} - -func (any *objectAny) ToUint64() uint64 { - return 0 -} - -func (any *objectAny) ToFloat32() float32 { - return 0 -} - -func (any *objectAny) ToFloat64() float64 { - return 0 -} - -func (any *objectAny) ToString() string { - str, err := MarshalToString(any.val.Interface()) - any.err = err - return str -} - -func (any *objectAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case string: - field := any.val.FieldByName(firstPath) - if !field.IsValid() { - return newInvalidAny(path) - } - return Wrap(field.Interface()) - case int32: - if '*' == firstPath { - mappedAll := map[string]Any{} - for i := 0; i < any.val.NumField(); i++ { - field := any.val.Field(i) - if field.CanInterface() { - mapped := Wrap(field.Interface()).Get(path[1:]...) - if mapped.ValueType() != InvalidValue { - mappedAll[any.val.Type().Field(i).Name] = mapped - } - } - } - return wrapMap(mappedAll) - } - return newInvalidAny(path) - default: - return newInvalidAny(path) - } -} - -func (any *objectAny) Keys() []string { - keys := make([]string, 0, any.val.NumField()) - for i := 0; i < any.val.NumField(); i++ { - keys = append(keys, any.val.Type().Field(i).Name) - } - return keys -} - -func (any *objectAny) Size() int { - return any.val.NumField() -} - -func (any *objectAny) WriteTo(stream *Stream) { - stream.WriteVal(any.val) -} - -func (any *objectAny) GetInterface() interface{} { - return any.val.Interface() -} - -type mapAny struct { - baseAny - err error - val reflect.Value -} - -func wrapMap(val interface{}) *mapAny { - return &mapAny{baseAny{}, nil, reflect.ValueOf(val)} -} - -func (any *mapAny) ValueType() ValueType { - return ObjectValue -} - -func (any *mapAny) MustBeValid() Any { - return any -} - -func (any *mapAny) Parse() *Iterator { - return nil -} - -func (any *mapAny) LastError() error { - return any.err -} - -func (any *mapAny) ToBool() bool { - return true -} - -func (any *mapAny) ToInt() int { - return 0 -} - -func (any *mapAny) ToInt32() int32 { - return 0 -} - -func (any *mapAny) ToInt64() int64 { - return 0 -} - -func (any *mapAny) ToUint() uint { - return 0 -} - -func (any *mapAny) ToUint32() uint32 { - return 0 -} - -func (any *mapAny) ToUint64() uint64 { - return 0 -} - -func (any *mapAny) ToFloat32() float32 { - return 0 -} - -func (any *mapAny) ToFloat64() float64 { - return 0 -} - -func (any *mapAny) ToString() string { - str, err := MarshalToString(any.val.Interface()) - any.err = err - return str -} - -func (any *mapAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - switch firstPath := path[0].(type) { - case int32: - if '*' == firstPath { - mappedAll := map[string]Any{} - for _, key := range any.val.MapKeys() { - keyAsStr := key.String() - element := Wrap(any.val.MapIndex(key).Interface()) - mapped := element.Get(path[1:]...) - if mapped.ValueType() != InvalidValue { - mappedAll[keyAsStr] = mapped - } - } - return wrapMap(mappedAll) - } - return newInvalidAny(path) - default: - value := any.val.MapIndex(reflect.ValueOf(firstPath)) - if !value.IsValid() { - return newInvalidAny(path) - } - return Wrap(value.Interface()) - } -} - -func (any *mapAny) Keys() []string { - keys := make([]string, 0, any.val.Len()) - for _, key := range any.val.MapKeys() { - keys = append(keys, key.String()) - } - return keys -} - -func (any *mapAny) Size() int { - return any.val.Len() -} - -func (any *mapAny) WriteTo(stream *Stream) { - stream.WriteVal(any.val) -} - -func (any *mapAny) GetInterface() interface{} { - return any.val.Interface() -} diff --git a/vendor/github.com/json-iterator/go/any_str.go b/vendor/github.com/json-iterator/go/any_str.go deleted file mode 100644 index 1f12f661..00000000 --- a/vendor/github.com/json-iterator/go/any_str.go +++ /dev/null @@ -1,166 +0,0 @@ -package jsoniter - -import ( - "fmt" - "strconv" -) - -type stringAny struct { - baseAny - val string -} - -func (any *stringAny) Get(path ...interface{}) Any { - if len(path) == 0 { - return any - } - return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)} -} - -func (any *stringAny) Parse() *Iterator { - return nil -} - -func (any *stringAny) ValueType() ValueType { - return StringValue -} - -func (any *stringAny) MustBeValid() Any { - return any -} - -func (any *stringAny) LastError() error { - return nil -} - -func (any *stringAny) ToBool() bool { - str := any.ToString() - if str == "0" { - return false - } - for _, c := range str { - switch c { - case ' ', '\n', '\r', '\t': - default: - return true - } - } - return false -} - -func (any *stringAny) ToInt() int { - return int(any.ToInt64()) - -} - -func (any *stringAny) ToInt32() int32 { - return int32(any.ToInt64()) -} - -func (any *stringAny) ToInt64() int64 { - if any.val == "" { - return 0 - } - - flag := 1 - startPos := 0 - if any.val[0] == '+' || any.val[0] == '-' { - startPos = 1 - } - - if any.val[0] == '-' { - flag = -1 - } - - endPos := startPos - for i := startPos; i < len(any.val); i++ { - if any.val[i] >= '0' && any.val[i] <= '9' { - endPos = i + 1 - } else { - break - } - } - parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64) - return int64(flag) * parsed -} - -func (any *stringAny) ToUint() uint { - return uint(any.ToUint64()) -} - -func (any *stringAny) ToUint32() uint32 { - return uint32(any.ToUint64()) -} - -func (any *stringAny) ToUint64() uint64 { - if any.val == "" { - return 0 - } - - startPos := 0 - - if any.val[0] == '-' { - return 0 - } - if any.val[0] == '+' { - startPos = 1 - } - - endPos := startPos - for i := startPos; i < len(any.val); i++ { - if any.val[i] >= '0' && any.val[i] <= '9' { - endPos = i + 1 - } else { - break - } - } - parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64) - return parsed -} - -func (any *stringAny) ToFloat32() float32 { - return float32(any.ToFloat64()) -} - -func (any *stringAny) ToFloat64() float64 { - if len(any.val) == 0 { - return 0 - } - - // first char invalid - if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') { - return 0 - } - - // extract valid num expression from string - // eg 123true => 123, -12.12xxa => -12.12 - endPos := 1 - for i := 1; i < len(any.val); i++ { - if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' { - endPos = i + 1 - continue - } - - // end position is the first char which is not digit - if any.val[i] >= '0' && any.val[i] <= '9' { - endPos = i + 1 - } else { - endPos = i - break - } - } - parsed, _ := strconv.ParseFloat(any.val[:endPos], 64) - return parsed -} - -func (any *stringAny) ToString() string { - return any.val -} - -func (any *stringAny) WriteTo(stream *Stream) { - stream.WriteString(any.val) -} - -func (any *stringAny) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_uint32.go b/vendor/github.com/json-iterator/go/any_uint32.go deleted file mode 100644 index 656bbd33..00000000 --- a/vendor/github.com/json-iterator/go/any_uint32.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type uint32Any struct { - baseAny - val uint32 -} - -func (any *uint32Any) LastError() error { - return nil -} - -func (any *uint32Any) ValueType() ValueType { - return NumberValue -} - -func (any *uint32Any) MustBeValid() Any { - return any -} - -func (any *uint32Any) ToBool() bool { - return any.val != 0 -} - -func (any *uint32Any) ToInt() int { - return int(any.val) -} - -func (any *uint32Any) ToInt32() int32 { - return int32(any.val) -} - -func (any *uint32Any) ToInt64() int64 { - return int64(any.val) -} - -func (any *uint32Any) ToUint() uint { - return uint(any.val) -} - -func (any *uint32Any) ToUint32() uint32 { - return any.val -} - -func (any *uint32Any) ToUint64() uint64 { - return uint64(any.val) -} - -func (any *uint32Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *uint32Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *uint32Any) ToString() string { - return strconv.FormatInt(int64(any.val), 10) -} - -func (any *uint32Any) WriteTo(stream *Stream) { - stream.WriteUint32(any.val) -} - -func (any *uint32Any) Parse() *Iterator { - return nil -} - -func (any *uint32Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/any_uint64.go b/vendor/github.com/json-iterator/go/any_uint64.go deleted file mode 100644 index 7df2fce3..00000000 --- a/vendor/github.com/json-iterator/go/any_uint64.go +++ /dev/null @@ -1,74 +0,0 @@ -package jsoniter - -import ( - "strconv" -) - -type uint64Any struct { - baseAny - val uint64 -} - -func (any *uint64Any) LastError() error { - return nil -} - -func (any *uint64Any) ValueType() ValueType { - return NumberValue -} - -func (any *uint64Any) MustBeValid() Any { - return any -} - -func (any *uint64Any) ToBool() bool { - return any.val != 0 -} - -func (any *uint64Any) ToInt() int { - return int(any.val) -} - -func (any *uint64Any) ToInt32() int32 { - return int32(any.val) -} - -func (any *uint64Any) ToInt64() int64 { - return int64(any.val) -} - -func (any *uint64Any) ToUint() uint { - return uint(any.val) -} - -func (any *uint64Any) ToUint32() uint32 { - return uint32(any.val) -} - -func (any *uint64Any) ToUint64() uint64 { - return any.val -} - -func (any *uint64Any) ToFloat32() float32 { - return float32(any.val) -} - -func (any *uint64Any) ToFloat64() float64 { - return float64(any.val) -} - -func (any *uint64Any) ToString() string { - return strconv.FormatUint(any.val, 10) -} - -func (any *uint64Any) WriteTo(stream *Stream) { - stream.WriteUint64(any.val) -} - -func (any *uint64Any) Parse() *Iterator { - return nil -} - -func (any *uint64Any) GetInterface() interface{} { - return any.val -} diff --git a/vendor/github.com/json-iterator/go/build.sh b/vendor/github.com/json-iterator/go/build.sh deleted file mode 100644 index b45ef688..00000000 --- a/vendor/github.com/json-iterator/go/build.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -set -e -set -x - -if [ ! -d /tmp/build-golang/src/github.com/json-iterator ]; then - mkdir -p /tmp/build-golang/src/github.com/json-iterator - ln -s $PWD /tmp/build-golang/src/github.com/json-iterator/go -fi -export GOPATH=/tmp/build-golang -go get -u github.com/golang/dep/cmd/dep -cd /tmp/build-golang/src/github.com/json-iterator/go -exec $GOPATH/bin/dep ensure -update diff --git a/vendor/github.com/json-iterator/go/config.go b/vendor/github.com/json-iterator/go/config.go deleted file mode 100644 index 2adcdc3b..00000000 --- a/vendor/github.com/json-iterator/go/config.go +++ /dev/null @@ -1,375 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "io" - "reflect" - "sync" - "unsafe" - - "github.com/modern-go/concurrent" - "github.com/modern-go/reflect2" -) - -// Config customize how the API should behave. -// The API is created from Config by Froze. -type Config struct { - IndentionStep int - MarshalFloatWith6Digits bool - EscapeHTML bool - SortMapKeys bool - UseNumber bool - DisallowUnknownFields bool - TagKey string - OnlyTaggedField bool - ValidateJsonRawMessage bool - ObjectFieldMustBeSimpleString bool - CaseSensitive bool -} - -// API the public interface of this package. -// Primary Marshal and Unmarshal. -type API interface { - IteratorPool - StreamPool - MarshalToString(v interface{}) (string, error) - Marshal(v interface{}) ([]byte, error) - MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) - UnmarshalFromString(str string, v interface{}) error - Unmarshal(data []byte, v interface{}) error - Get(data []byte, path ...interface{}) Any - NewEncoder(writer io.Writer) *Encoder - NewDecoder(reader io.Reader) *Decoder - Valid(data []byte) bool - RegisterExtension(extension Extension) - DecoderOf(typ reflect2.Type) ValDecoder - EncoderOf(typ reflect2.Type) ValEncoder -} - -// ConfigDefault the default API -var ConfigDefault = Config{ - EscapeHTML: true, -}.Froze() - -// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior -var ConfigCompatibleWithStandardLibrary = Config{ - EscapeHTML: true, - SortMapKeys: true, - ValidateJsonRawMessage: true, -}.Froze() - -// ConfigFastest marshals float with only 6 digits precision -var ConfigFastest = Config{ - EscapeHTML: false, - MarshalFloatWith6Digits: true, // will lose precession - ObjectFieldMustBeSimpleString: true, // do not unescape object field -}.Froze() - -type frozenConfig struct { - configBeforeFrozen Config - sortMapKeys bool - indentionStep int - objectFieldMustBeSimpleString bool - onlyTaggedField bool - disallowUnknownFields bool - decoderCache *concurrent.Map - encoderCache *concurrent.Map - encoderExtension Extension - decoderExtension Extension - extraExtensions []Extension - streamPool *sync.Pool - iteratorPool *sync.Pool - caseSensitive bool -} - -func (cfg *frozenConfig) initCache() { - cfg.decoderCache = concurrent.NewMap() - cfg.encoderCache = concurrent.NewMap() -} - -func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) { - cfg.decoderCache.Store(cacheKey, decoder) -} - -func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) { - cfg.encoderCache.Store(cacheKey, encoder) -} - -func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder { - decoder, found := cfg.decoderCache.Load(cacheKey) - if found { - return decoder.(ValDecoder) - } - return nil -} - -func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { - encoder, found := cfg.encoderCache.Load(cacheKey) - if found { - return encoder.(ValEncoder) - } - return nil -} - -var cfgCache = concurrent.NewMap() - -func getFrozenConfigFromCache(cfg Config) *frozenConfig { - obj, found := cfgCache.Load(cfg) - if found { - return obj.(*frozenConfig) - } - return nil -} - -func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { - cfgCache.Store(cfg, frozenConfig) -} - -// Froze forge API from config -func (cfg Config) Froze() API { - api := &frozenConfig{ - sortMapKeys: cfg.SortMapKeys, - indentionStep: cfg.IndentionStep, - objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString, - onlyTaggedField: cfg.OnlyTaggedField, - disallowUnknownFields: cfg.DisallowUnknownFields, - caseSensitive: cfg.CaseSensitive, - } - api.streamPool = &sync.Pool{ - New: func() interface{} { - return NewStream(api, nil, 512) - }, - } - api.iteratorPool = &sync.Pool{ - New: func() interface{} { - return NewIterator(api) - }, - } - api.initCache() - encoderExtension := EncoderExtension{} - decoderExtension := DecoderExtension{} - if cfg.MarshalFloatWith6Digits { - api.marshalFloatWith6Digits(encoderExtension) - } - if cfg.EscapeHTML { - api.escapeHTML(encoderExtension) - } - if cfg.UseNumber { - api.useNumber(decoderExtension) - } - if cfg.ValidateJsonRawMessage { - api.validateJsonRawMessage(encoderExtension) - } - api.encoderExtension = encoderExtension - api.decoderExtension = decoderExtension - api.configBeforeFrozen = cfg - return api -} - -func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig { - api := getFrozenConfigFromCache(cfg) - if api != nil { - return api - } - api = cfg.Froze().(*frozenConfig) - for _, extension := range extraExtensions { - api.RegisterExtension(extension) - } - addFrozenConfigToCache(cfg, api) - return api -} - -func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) { - encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) { - rawMessage := *(*json.RawMessage)(ptr) - iter := cfg.BorrowIterator([]byte(rawMessage)) - defer cfg.ReturnIterator(iter) - iter.Read() - if iter.Error != nil && iter.Error != io.EOF { - stream.WriteRaw("null") - } else { - stream.WriteRaw(string(rawMessage)) - } - }, func(ptr unsafe.Pointer) bool { - return len(*((*json.RawMessage)(ptr))) == 0 - }} - extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder - extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder -} - -func (cfg *frozenConfig) useNumber(extension DecoderExtension) { - extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { - exitingValue := *((*interface{})(ptr)) - if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr { - iter.ReadVal(exitingValue) - return - } - if iter.WhatIsNext() == NumberValue { - *((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) - } else { - *((*interface{})(ptr)) = iter.Read() - } - }} -} -func (cfg *frozenConfig) getTagKey() string { - tagKey := cfg.configBeforeFrozen.TagKey - if tagKey == "" { - return "json" - } - return tagKey -} - -func (cfg *frozenConfig) RegisterExtension(extension Extension) { - cfg.extraExtensions = append(cfg.extraExtensions, extension) - copied := cfg.configBeforeFrozen - cfg.configBeforeFrozen = copied -} - -type lossyFloat32Encoder struct { -} - -func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat32Lossy(*((*float32)(ptr))) -} - -func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float32)(ptr)) == 0 -} - -type lossyFloat64Encoder struct { -} - -func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat64Lossy(*((*float64)(ptr))) -} - -func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float64)(ptr)) == 0 -} - -// EnableLossyFloatMarshalling keeps 10**(-6) precision -// for float variables for better performance. -func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) { - // for better performance - extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{} - extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{} -} - -type htmlEscapedStringEncoder struct { -} - -func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - str := *((*string)(ptr)) - stream.WriteStringWithHTMLEscaped(str) -} - -func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*string)(ptr)) == "" -} - -func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) { - encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{} -} - -func (cfg *frozenConfig) cleanDecoders() { - typeDecoders = map[string]ValDecoder{} - fieldDecoders = map[string]ValDecoder{} - *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) -} - -func (cfg *frozenConfig) cleanEncoders() { - typeEncoders = map[string]ValEncoder{} - fieldEncoders = map[string]ValEncoder{} - *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) -} - -func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { - stream := cfg.BorrowStream(nil) - defer cfg.ReturnStream(stream) - stream.WriteVal(v) - if stream.Error != nil { - return "", stream.Error - } - return string(stream.Buffer()), nil -} - -func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { - stream := cfg.BorrowStream(nil) - defer cfg.ReturnStream(stream) - stream.WriteVal(v) - if stream.Error != nil { - return nil, stream.Error - } - result := stream.Buffer() - copied := make([]byte, len(result)) - copy(copied, result) - return copied, nil -} - -func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { - if prefix != "" { - panic("prefix is not supported") - } - for _, r := range indent { - if r != ' ' { - panic("indent can only be space") - } - } - newCfg := cfg.configBeforeFrozen - newCfg.IndentionStep = len(indent) - return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v) -} - -func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { - data := []byte(str) - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - iter.ReadVal(v) - c := iter.nextToken() - if c == 0 { - if iter.Error == io.EOF { - return nil - } - return iter.Error - } - iter.ReportError("Unmarshal", "there are bytes left after unmarshal") - return iter.Error -} - -func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any { - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - return locatePath(iter, path) -} - -func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error { - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - iter.ReadVal(v) - c := iter.nextToken() - if c == 0 { - if iter.Error == io.EOF { - return nil - } - return iter.Error - } - iter.ReportError("Unmarshal", "there are bytes left after unmarshal") - return iter.Error -} - -func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder { - stream := NewStream(cfg, writer, 512) - return &Encoder{stream} -} - -func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { - iter := Parse(cfg, reader, 512) - return &Decoder{iter} -} - -func (cfg *frozenConfig) Valid(data []byte) bool { - iter := cfg.BorrowIterator(data) - defer cfg.ReturnIterator(iter) - iter.Skip() - return iter.Error == nil -} diff --git a/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md b/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md deleted file mode 100644 index 3095662b..00000000 --- a/vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md +++ /dev/null @@ -1,7 +0,0 @@ -| json type \ dest type | bool | int | uint | float |string| -| --- | --- | --- | --- |--|--| -| number | positive => true
negative => true
zero => false| 23.2 => 23
-32.1 => -32| 12.1 => 12
-12.1 => 0|as normal|same as origin| -| string | empty string => false
string "0" => false
other strings => true | "123.32" => 123
"-123.4" => -123
"123.23xxxw" => 123
"abcde12" => 0
"-32.1" => -32| 13.2 => 13
-1.1 => 0 |12.1 => 12.1
-12.3 => -12.3
12.4xxa => 12.4
+1.1e2 =>110 |same as origin| -| bool | true => true
false => false| true => 1
false => 0 | true => 1
false => 0 |true => 1
false => 0|true => "true"
false => "false"| -| object | true | 0 | 0 |0|originnal json| -| array | empty array => false
nonempty array => true| [] => 0
[1,2] => 1 | [] => 0
[1,2] => 1 |[] => 0
[1,2] => 1|original json| \ No newline at end of file diff --git a/vendor/github.com/json-iterator/go/iter.go b/vendor/github.com/json-iterator/go/iter.go deleted file mode 100644 index 29b31cf7..00000000 --- a/vendor/github.com/json-iterator/go/iter.go +++ /dev/null @@ -1,349 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "fmt" - "io" -) - -// ValueType the type for JSON element -type ValueType int - -const ( - // InvalidValue invalid JSON element - InvalidValue ValueType = iota - // StringValue JSON element "string" - StringValue - // NumberValue JSON element 100 or 0.10 - NumberValue - // NilValue JSON element null - NilValue - // BoolValue JSON element true or false - BoolValue - // ArrayValue JSON element [] - ArrayValue - // ObjectValue JSON element {} - ObjectValue -) - -var hexDigits []byte -var valueTypes []ValueType - -func init() { - hexDigits = make([]byte, 256) - for i := 0; i < len(hexDigits); i++ { - hexDigits[i] = 255 - } - for i := '0'; i <= '9'; i++ { - hexDigits[i] = byte(i - '0') - } - for i := 'a'; i <= 'f'; i++ { - hexDigits[i] = byte((i - 'a') + 10) - } - for i := 'A'; i <= 'F'; i++ { - hexDigits[i] = byte((i - 'A') + 10) - } - valueTypes = make([]ValueType, 256) - for i := 0; i < len(valueTypes); i++ { - valueTypes[i] = InvalidValue - } - valueTypes['"'] = StringValue - valueTypes['-'] = NumberValue - valueTypes['0'] = NumberValue - valueTypes['1'] = NumberValue - valueTypes['2'] = NumberValue - valueTypes['3'] = NumberValue - valueTypes['4'] = NumberValue - valueTypes['5'] = NumberValue - valueTypes['6'] = NumberValue - valueTypes['7'] = NumberValue - valueTypes['8'] = NumberValue - valueTypes['9'] = NumberValue - valueTypes['t'] = BoolValue - valueTypes['f'] = BoolValue - valueTypes['n'] = NilValue - valueTypes['['] = ArrayValue - valueTypes['{'] = ObjectValue -} - -// Iterator is a io.Reader like object, with JSON specific read functions. -// Error is not returned as return value, but stored as Error member on this iterator instance. -type Iterator struct { - cfg *frozenConfig - reader io.Reader - buf []byte - head int - tail int - depth int - captureStartedAt int - captured []byte - Error error - Attachment interface{} // open for customized decoder -} - -// NewIterator creates an empty Iterator instance -func NewIterator(cfg API) *Iterator { - return &Iterator{ - cfg: cfg.(*frozenConfig), - reader: nil, - buf: nil, - head: 0, - tail: 0, - depth: 0, - } -} - -// Parse creates an Iterator instance from io.Reader -func Parse(cfg API, reader io.Reader, bufSize int) *Iterator { - return &Iterator{ - cfg: cfg.(*frozenConfig), - reader: reader, - buf: make([]byte, bufSize), - head: 0, - tail: 0, - depth: 0, - } -} - -// ParseBytes creates an Iterator instance from byte array -func ParseBytes(cfg API, input []byte) *Iterator { - return &Iterator{ - cfg: cfg.(*frozenConfig), - reader: nil, - buf: input, - head: 0, - tail: len(input), - depth: 0, - } -} - -// ParseString creates an Iterator instance from string -func ParseString(cfg API, input string) *Iterator { - return ParseBytes(cfg, []byte(input)) -} - -// Pool returns a pool can provide more iterator with same configuration -func (iter *Iterator) Pool() IteratorPool { - return iter.cfg -} - -// Reset reuse iterator instance by specifying another reader -func (iter *Iterator) Reset(reader io.Reader) *Iterator { - iter.reader = reader - iter.head = 0 - iter.tail = 0 - iter.depth = 0 - return iter -} - -// ResetBytes reuse iterator instance by specifying another byte array as input -func (iter *Iterator) ResetBytes(input []byte) *Iterator { - iter.reader = nil - iter.buf = input - iter.head = 0 - iter.tail = len(input) - iter.depth = 0 - return iter -} - -// WhatIsNext gets ValueType of relatively next json element -func (iter *Iterator) WhatIsNext() ValueType { - valueType := valueTypes[iter.nextToken()] - iter.unreadByte() - return valueType -} - -func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case ' ', '\n', '\t', '\r': - continue - } - iter.head = i - return false - } - return true -} - -func (iter *Iterator) isObjectEnd() bool { - c := iter.nextToken() - if c == ',' { - return false - } - if c == '}' { - return true - } - iter.ReportError("isObjectEnd", "object ended prematurely, unexpected char "+string([]byte{c})) - return true -} - -func (iter *Iterator) nextToken() byte { - // a variation of skip whitespaces, returning the next non-whitespace token - for { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case ' ', '\n', '\t', '\r': - continue - } - iter.head = i + 1 - return c - } - if !iter.loadMore() { - return 0 - } - } -} - -// ReportError record a error in iterator instance with current position. -func (iter *Iterator) ReportError(operation string, msg string) { - if iter.Error != nil { - if iter.Error != io.EOF { - return - } - } - peekStart := iter.head - 10 - if peekStart < 0 { - peekStart = 0 - } - peekEnd := iter.head + 10 - if peekEnd > iter.tail { - peekEnd = iter.tail - } - parsing := string(iter.buf[peekStart:peekEnd]) - contextStart := iter.head - 50 - if contextStart < 0 { - contextStart = 0 - } - contextEnd := iter.head + 50 - if contextEnd > iter.tail { - contextEnd = iter.tail - } - context := string(iter.buf[contextStart:contextEnd]) - iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...", - operation, msg, iter.head-peekStart, parsing, context) -} - -// CurrentBuffer gets current buffer as string for debugging purpose -func (iter *Iterator) CurrentBuffer() string { - peekStart := iter.head - 10 - if peekStart < 0 { - peekStart = 0 - } - return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head, - string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) -} - -func (iter *Iterator) readByte() (ret byte) { - if iter.head == iter.tail { - if iter.loadMore() { - ret = iter.buf[iter.head] - iter.head++ - return ret - } - return 0 - } - ret = iter.buf[iter.head] - iter.head++ - return ret -} - -func (iter *Iterator) loadMore() bool { - if iter.reader == nil { - if iter.Error == nil { - iter.head = iter.tail - iter.Error = io.EOF - } - return false - } - if iter.captured != nil { - iter.captured = append(iter.captured, - iter.buf[iter.captureStartedAt:iter.tail]...) - iter.captureStartedAt = 0 - } - for { - n, err := iter.reader.Read(iter.buf) - if n == 0 { - if err != nil { - if iter.Error == nil { - iter.Error = err - } - return false - } - } else { - iter.head = 0 - iter.tail = n - return true - } - } -} - -func (iter *Iterator) unreadByte() { - if iter.Error != nil { - return - } - iter.head-- - return -} - -// Read read the next JSON element as generic interface{}. -func (iter *Iterator) Read() interface{} { - valueType := iter.WhatIsNext() - switch valueType { - case StringValue: - return iter.ReadString() - case NumberValue: - if iter.cfg.configBeforeFrozen.UseNumber { - return json.Number(iter.readNumberAsString()) - } - return iter.ReadFloat64() - case NilValue: - iter.skipFourBytes('n', 'u', 'l', 'l') - return nil - case BoolValue: - return iter.ReadBool() - case ArrayValue: - arr := []interface{}{} - iter.ReadArrayCB(func(iter *Iterator) bool { - var elem interface{} - iter.ReadVal(&elem) - arr = append(arr, elem) - return true - }) - return arr - case ObjectValue: - obj := map[string]interface{}{} - iter.ReadMapCB(func(Iter *Iterator, field string) bool { - var elem interface{} - iter.ReadVal(&elem) - obj[field] = elem - return true - }) - return obj - default: - iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) - return nil - } -} - -// limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9 -const maxDepth = 10000 - -func (iter *Iterator) incrementDepth() (success bool) { - iter.depth++ - if iter.depth <= maxDepth { - return true - } - iter.ReportError("incrementDepth", "exceeded max depth") - return false -} - -func (iter *Iterator) decrementDepth() (success bool) { - iter.depth-- - if iter.depth >= 0 { - return true - } - iter.ReportError("decrementDepth", "unexpected negative nesting") - return false -} diff --git a/vendor/github.com/json-iterator/go/iter_array.go b/vendor/github.com/json-iterator/go/iter_array.go deleted file mode 100644 index 204fe0e0..00000000 --- a/vendor/github.com/json-iterator/go/iter_array.go +++ /dev/null @@ -1,64 +0,0 @@ -package jsoniter - -// ReadArray read array element, tells if the array has more element to read. -func (iter *Iterator) ReadArray() (ret bool) { - c := iter.nextToken() - switch c { - case 'n': - iter.skipThreeBytes('u', 'l', 'l') - return false // null - case '[': - c = iter.nextToken() - if c != ']' { - iter.unreadByte() - return true - } - return false - case ']': - return false - case ',': - return true - default: - iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c})) - return - } -} - -// ReadArrayCB read array with callback -func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { - c := iter.nextToken() - if c == '[' { - if !iter.incrementDepth() { - return false - } - c = iter.nextToken() - if c != ']' { - iter.unreadByte() - if !callback(iter) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - for c == ',' { - if !callback(iter) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - } - if c != ']' { - iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c})) - iter.decrementDepth() - return false - } - return iter.decrementDepth() - } - return iter.decrementDepth() - } - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return true // null - } - iter.ReportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c})) - return false -} diff --git a/vendor/github.com/json-iterator/go/iter_float.go b/vendor/github.com/json-iterator/go/iter_float.go deleted file mode 100644 index 8a3d8b6f..00000000 --- a/vendor/github.com/json-iterator/go/iter_float.go +++ /dev/null @@ -1,342 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "io" - "math/big" - "strconv" - "strings" - "unsafe" -) - -var floatDigits []int8 - -const invalidCharForNumber = int8(-1) -const endOfNumber = int8(-2) -const dotInNumber = int8(-3) - -func init() { - floatDigits = make([]int8, 256) - for i := 0; i < len(floatDigits); i++ { - floatDigits[i] = invalidCharForNumber - } - for i := int8('0'); i <= int8('9'); i++ { - floatDigits[i] = i - int8('0') - } - floatDigits[','] = endOfNumber - floatDigits[']'] = endOfNumber - floatDigits['}'] = endOfNumber - floatDigits[' '] = endOfNumber - floatDigits['\t'] = endOfNumber - floatDigits['\n'] = endOfNumber - floatDigits['.'] = dotInNumber -} - -// ReadBigFloat read big.Float -func (iter *Iterator) ReadBigFloat() (ret *big.Float) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return nil - } - prec := 64 - if len(str) > prec { - prec = len(str) - } - val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero) - if err != nil { - iter.Error = err - return nil - } - return val -} - -// ReadBigInt read big.Int -func (iter *Iterator) ReadBigInt() (ret *big.Int) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return nil - } - ret = big.NewInt(0) - var success bool - ret, success = ret.SetString(str, 10) - if !success { - iter.ReportError("ReadBigInt", "invalid big int") - return nil - } - return ret -} - -//ReadFloat32 read float32 -func (iter *Iterator) ReadFloat32() (ret float32) { - c := iter.nextToken() - if c == '-' { - return -iter.readPositiveFloat32() - } - iter.unreadByte() - return iter.readPositiveFloat32() -} - -func (iter *Iterator) readPositiveFloat32() (ret float32) { - i := iter.head - // first char - if i == iter.tail { - return iter.readFloat32SlowPath() - } - c := iter.buf[i] - i++ - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat32SlowPath() - case endOfNumber: - iter.ReportError("readFloat32", "empty number") - return - case dotInNumber: - iter.ReportError("readFloat32", "leading dot is invalid") - return - case 0: - if i == iter.tail { - return iter.readFloat32SlowPath() - } - c = iter.buf[i] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - iter.ReportError("readFloat32", "leading zero is invalid") - return - } - } - value := uint64(ind) - // chars before dot -non_decimal_loop: - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat32SlowPath() - case endOfNumber: - iter.head = i - return float32(value) - case dotInNumber: - break non_decimal_loop - } - if value > uint64SafeToMultiple10 { - return iter.readFloat32SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; - } - // chars after dot - if c == '.' { - i++ - decimalPlaces := 0 - if i == iter.tail { - return iter.readFloat32SlowPath() - } - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case endOfNumber: - if decimalPlaces > 0 && decimalPlaces < len(pow10) { - iter.head = i - return float32(float64(value) / float64(pow10[decimalPlaces])) - } - // too many decimal places - return iter.readFloat32SlowPath() - case invalidCharForNumber, dotInNumber: - return iter.readFloat32SlowPath() - } - decimalPlaces++ - if value > uint64SafeToMultiple10 { - return iter.readFloat32SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) - } - } - return iter.readFloat32SlowPath() -} - -func (iter *Iterator) readNumberAsString() (ret string) { - strBuf := [16]byte{} - str := strBuf[0:0] -load_loop: - for { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - str = append(str, c) - continue - default: - iter.head = i - break load_loop - } - } - if !iter.loadMore() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF { - return - } - if len(str) == 0 { - iter.ReportError("readNumberAsString", "invalid number") - } - return *(*string)(unsafe.Pointer(&str)) -} - -func (iter *Iterator) readFloat32SlowPath() (ret float32) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return - } - errMsg := validateFloat(str) - if errMsg != "" { - iter.ReportError("readFloat32SlowPath", errMsg) - return - } - val, err := strconv.ParseFloat(str, 32) - if err != nil { - iter.Error = err - return - } - return float32(val) -} - -// ReadFloat64 read float64 -func (iter *Iterator) ReadFloat64() (ret float64) { - c := iter.nextToken() - if c == '-' { - return -iter.readPositiveFloat64() - } - iter.unreadByte() - return iter.readPositiveFloat64() -} - -func (iter *Iterator) readPositiveFloat64() (ret float64) { - i := iter.head - // first char - if i == iter.tail { - return iter.readFloat64SlowPath() - } - c := iter.buf[i] - i++ - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat64SlowPath() - case endOfNumber: - iter.ReportError("readFloat64", "empty number") - return - case dotInNumber: - iter.ReportError("readFloat64", "leading dot is invalid") - return - case 0: - if i == iter.tail { - return iter.readFloat64SlowPath() - } - c = iter.buf[i] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - iter.ReportError("readFloat64", "leading zero is invalid") - return - } - } - value := uint64(ind) - // chars before dot -non_decimal_loop: - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case invalidCharForNumber: - return iter.readFloat64SlowPath() - case endOfNumber: - iter.head = i - return float64(value) - case dotInNumber: - break non_decimal_loop - } - if value > uint64SafeToMultiple10 { - return iter.readFloat64SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; - } - // chars after dot - if c == '.' { - i++ - decimalPlaces := 0 - if i == iter.tail { - return iter.readFloat64SlowPath() - } - for ; i < iter.tail; i++ { - c = iter.buf[i] - ind := floatDigits[c] - switch ind { - case endOfNumber: - if decimalPlaces > 0 && decimalPlaces < len(pow10) { - iter.head = i - return float64(value) / float64(pow10[decimalPlaces]) - } - // too many decimal places - return iter.readFloat64SlowPath() - case invalidCharForNumber, dotInNumber: - return iter.readFloat64SlowPath() - } - decimalPlaces++ - if value > uint64SafeToMultiple10 { - return iter.readFloat64SlowPath() - } - value = (value << 3) + (value << 1) + uint64(ind) - if value > maxFloat64 { - return iter.readFloat64SlowPath() - } - } - } - return iter.readFloat64SlowPath() -} - -func (iter *Iterator) readFloat64SlowPath() (ret float64) { - str := iter.readNumberAsString() - if iter.Error != nil && iter.Error != io.EOF { - return - } - errMsg := validateFloat(str) - if errMsg != "" { - iter.ReportError("readFloat64SlowPath", errMsg) - return - } - val, err := strconv.ParseFloat(str, 64) - if err != nil { - iter.Error = err - return - } - return val -} - -func validateFloat(str string) string { - // strconv.ParseFloat is not validating `1.` or `1.e1` - if len(str) == 0 { - return "empty number" - } - if str[0] == '-' { - return "-- is not valid" - } - dotPos := strings.IndexByte(str, '.') - if dotPos != -1 { - if dotPos == len(str)-1 { - return "dot can not be last character" - } - switch str[dotPos+1] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - return "missing digit after dot" - } - } - return "" -} - -// ReadNumber read json.Number -func (iter *Iterator) ReadNumber() (ret json.Number) { - return json.Number(iter.readNumberAsString()) -} diff --git a/vendor/github.com/json-iterator/go/iter_int.go b/vendor/github.com/json-iterator/go/iter_int.go deleted file mode 100644 index d786a89f..00000000 --- a/vendor/github.com/json-iterator/go/iter_int.go +++ /dev/null @@ -1,346 +0,0 @@ -package jsoniter - -import ( - "math" - "strconv" -) - -var intDigits []int8 - -const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 -const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 -const maxFloat64 = 1<<53 - 1 - -func init() { - intDigits = make([]int8, 256) - for i := 0; i < len(intDigits); i++ { - intDigits[i] = invalidCharForNumber - } - for i := int8('0'); i <= int8('9'); i++ { - intDigits[i] = i - int8('0') - } -} - -// ReadUint read uint -func (iter *Iterator) ReadUint() uint { - if strconv.IntSize == 32 { - return uint(iter.ReadUint32()) - } - return uint(iter.ReadUint64()) -} - -// ReadInt read int -func (iter *Iterator) ReadInt() int { - if strconv.IntSize == 32 { - return int(iter.ReadInt32()) - } - return int(iter.ReadInt64()) -} - -// ReadInt8 read int8 -func (iter *Iterator) ReadInt8() (ret int8) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint32(iter.readByte()) - if val > math.MaxInt8+1 { - iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return -int8(val) - } - val := iter.readUint32(c) - if val > math.MaxInt8 { - iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int8(val) -} - -// ReadUint8 read uint8 -func (iter *Iterator) ReadUint8() (ret uint8) { - val := iter.readUint32(iter.nextToken()) - if val > math.MaxUint8 { - iter.ReportError("ReadUint8", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return uint8(val) -} - -// ReadInt16 read int16 -func (iter *Iterator) ReadInt16() (ret int16) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint32(iter.readByte()) - if val > math.MaxInt16+1 { - iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return -int16(val) - } - val := iter.readUint32(c) - if val > math.MaxInt16 { - iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int16(val) -} - -// ReadUint16 read uint16 -func (iter *Iterator) ReadUint16() (ret uint16) { - val := iter.readUint32(iter.nextToken()) - if val > math.MaxUint16 { - iter.ReportError("ReadUint16", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return uint16(val) -} - -// ReadInt32 read int32 -func (iter *Iterator) ReadInt32() (ret int32) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint32(iter.readByte()) - if val > math.MaxInt32+1 { - iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return -int32(val) - } - val := iter.readUint32(c) - if val > math.MaxInt32 { - iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) - return - } - return int32(val) -} - -// ReadUint32 read uint32 -func (iter *Iterator) ReadUint32() (ret uint32) { - return iter.readUint32(iter.nextToken()) -} - -func (iter *Iterator) readUint32(c byte) (ret uint32) { - ind := intDigits[c] - if ind == 0 { - iter.assertInteger() - return 0 // single zero - } - if ind == invalidCharForNumber { - iter.ReportError("readUint32", "unexpected character: "+string([]byte{byte(ind)})) - return - } - value := uint32(ind) - if iter.tail-iter.head > 10 { - i := iter.head - ind2 := intDigits[iter.buf[i]] - if ind2 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - i++ - ind3 := intDigits[iter.buf[i]] - if ind3 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10 + uint32(ind2) - } - //iter.head = i + 1 - //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) - i++ - ind4 := intDigits[iter.buf[i]] - if ind4 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100 + uint32(ind2)*10 + uint32(ind3) - } - i++ - ind5 := intDigits[iter.buf[i]] - if ind5 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) - } - i++ - ind6 := intDigits[iter.buf[i]] - if ind6 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) - } - i++ - ind7 := intDigits[iter.buf[i]] - if ind7 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) - } - i++ - ind8 := intDigits[iter.buf[i]] - if ind8 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) - } - i++ - ind9 := intDigits[iter.buf[i]] - value = value*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) - iter.head = i - if ind9 == invalidCharForNumber { - iter.assertInteger() - return value - } - } - for { - for i := iter.head; i < iter.tail; i++ { - ind = intDigits[iter.buf[i]] - if ind == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - if value > uint32SafeToMultiply10 { - value2 := (value << 3) + (value << 1) + uint32(ind) - if value2 < value { - iter.ReportError("readUint32", "overflow") - return - } - value = value2 - continue - } - value = (value << 3) + (value << 1) + uint32(ind) - } - if !iter.loadMore() { - iter.assertInteger() - return value - } - } -} - -// ReadInt64 read int64 -func (iter *Iterator) ReadInt64() (ret int64) { - c := iter.nextToken() - if c == '-' { - val := iter.readUint64(iter.readByte()) - if val > math.MaxInt64+1 { - iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) - return - } - return -int64(val) - } - val := iter.readUint64(c) - if val > math.MaxInt64 { - iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) - return - } - return int64(val) -} - -// ReadUint64 read uint64 -func (iter *Iterator) ReadUint64() uint64 { - return iter.readUint64(iter.nextToken()) -} - -func (iter *Iterator) readUint64(c byte) (ret uint64) { - ind := intDigits[c] - if ind == 0 { - iter.assertInteger() - return 0 // single zero - } - if ind == invalidCharForNumber { - iter.ReportError("readUint64", "unexpected character: "+string([]byte{byte(ind)})) - return - } - value := uint64(ind) - if iter.tail-iter.head > 10 { - i := iter.head - ind2 := intDigits[iter.buf[i]] - if ind2 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - i++ - ind3 := intDigits[iter.buf[i]] - if ind3 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10 + uint64(ind2) - } - //iter.head = i + 1 - //value = value * 100 + uint32(ind2) * 10 + uint32(ind3) - i++ - ind4 := intDigits[iter.buf[i]] - if ind4 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100 + uint64(ind2)*10 + uint64(ind3) - } - i++ - ind5 := intDigits[iter.buf[i]] - if ind5 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000 + uint64(ind2)*100 + uint64(ind3)*10 + uint64(ind4) - } - i++ - ind6 := intDigits[iter.buf[i]] - if ind6 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*10000 + uint64(ind2)*1000 + uint64(ind3)*100 + uint64(ind4)*10 + uint64(ind5) - } - i++ - ind7 := intDigits[iter.buf[i]] - if ind7 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*100000 + uint64(ind2)*10000 + uint64(ind3)*1000 + uint64(ind4)*100 + uint64(ind5)*10 + uint64(ind6) - } - i++ - ind8 := intDigits[iter.buf[i]] - if ind8 == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value*1000000 + uint64(ind2)*100000 + uint64(ind3)*10000 + uint64(ind4)*1000 + uint64(ind5)*100 + uint64(ind6)*10 + uint64(ind7) - } - i++ - ind9 := intDigits[iter.buf[i]] - value = value*10000000 + uint64(ind2)*1000000 + uint64(ind3)*100000 + uint64(ind4)*10000 + uint64(ind5)*1000 + uint64(ind6)*100 + uint64(ind7)*10 + uint64(ind8) - iter.head = i - if ind9 == invalidCharForNumber { - iter.assertInteger() - return value - } - } - for { - for i := iter.head; i < iter.tail; i++ { - ind = intDigits[iter.buf[i]] - if ind == invalidCharForNumber { - iter.head = i - iter.assertInteger() - return value - } - if value > uint64SafeToMultiple10 { - value2 := (value << 3) + (value << 1) + uint64(ind) - if value2 < value { - iter.ReportError("readUint64", "overflow") - return - } - value = value2 - continue - } - value = (value << 3) + (value << 1) + uint64(ind) - } - if !iter.loadMore() { - iter.assertInteger() - return value - } - } -} - -func (iter *Iterator) assertInteger() { - if iter.head < iter.tail && iter.buf[iter.head] == '.' { - iter.ReportError("assertInteger", "can not decode float as int") - } -} diff --git a/vendor/github.com/json-iterator/go/iter_object.go b/vendor/github.com/json-iterator/go/iter_object.go deleted file mode 100644 index 58ee89c8..00000000 --- a/vendor/github.com/json-iterator/go/iter_object.go +++ /dev/null @@ -1,267 +0,0 @@ -package jsoniter - -import ( - "fmt" - "strings" -) - -// ReadObject read one field from object. -// If object ended, returns empty string. -// Otherwise, returns the field name. -func (iter *Iterator) ReadObject() (ret string) { - c := iter.nextToken() - switch c { - case 'n': - iter.skipThreeBytes('u', 'l', 'l') - return "" // null - case '{': - c = iter.nextToken() - if c == '"' { - iter.unreadByte() - field := iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - return field - } - if c == '}' { - return "" // end of object - } - iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c})) - return - case ',': - field := iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - return field - case '}': - return "" // end of object - default: - iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c}))) - return - } -} - -// CaseInsensitive -func (iter *Iterator) readFieldHash() int64 { - hash := int64(0x811c9dc5) - c := iter.nextToken() - if c != '"' { - iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c})) - return 0 - } - for { - for i := iter.head; i < iter.tail; i++ { - // require ascii string and no escape - b := iter.buf[i] - if b == '\\' { - iter.head = i - for _, b := range iter.readStringSlowPath() { - if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { - b += 'a' - 'A' - } - hash ^= int64(b) - hash *= 0x1000193 - } - c = iter.nextToken() - if c != ':' { - iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) - return 0 - } - return hash - } - if b == '"' { - iter.head = i + 1 - c = iter.nextToken() - if c != ':' { - iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) - return 0 - } - return hash - } - if 'A' <= b && b <= 'Z' && !iter.cfg.caseSensitive { - b += 'a' - 'A' - } - hash ^= int64(b) - hash *= 0x1000193 - } - if !iter.loadMore() { - iter.ReportError("readFieldHash", `incomplete field name`) - return 0 - } - } -} - -func calcHash(str string, caseSensitive bool) int64 { - if !caseSensitive { - str = strings.ToLower(str) - } - hash := int64(0x811c9dc5) - for _, b := range []byte(str) { - hash ^= int64(b) - hash *= 0x1000193 - } - return int64(hash) -} - -// ReadObjectCB read object with callback, the key is ascii only and field name not copied -func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { - c := iter.nextToken() - var field string - if c == '{' { - if !iter.incrementDepth() { - return false - } - c = iter.nextToken() - if c == '"' { - iter.unreadByte() - field = iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - for c == ',' { - field = iter.ReadString() - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - } - if c != '}' { - iter.ReportError("ReadObjectCB", `object not ended with }`) - iter.decrementDepth() - return false - } - return iter.decrementDepth() - } - if c == '}' { - return iter.decrementDepth() - } - iter.ReportError("ReadObjectCB", `expect " after {, but found `+string([]byte{c})) - iter.decrementDepth() - return false - } - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return true // null - } - iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c})) - return false -} - -// ReadMapCB read map with callback, the key can be any string -func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { - c := iter.nextToken() - if c == '{' { - if !iter.incrementDepth() { - return false - } - c = iter.nextToken() - if c == '"' { - iter.unreadByte() - field := iter.ReadString() - if iter.nextToken() != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - iter.decrementDepth() - return false - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - for c == ',' { - field = iter.ReadString() - if iter.nextToken() != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - iter.decrementDepth() - return false - } - if !callback(iter, field) { - iter.decrementDepth() - return false - } - c = iter.nextToken() - } - if c != '}' { - iter.ReportError("ReadMapCB", `object not ended with }`) - iter.decrementDepth() - return false - } - return iter.decrementDepth() - } - if c == '}' { - return iter.decrementDepth() - } - iter.ReportError("ReadMapCB", `expect " after {, but found `+string([]byte{c})) - iter.decrementDepth() - return false - } - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return true // null - } - iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) - return false -} - -func (iter *Iterator) readObjectStart() bool { - c := iter.nextToken() - if c == '{' { - c = iter.nextToken() - if c == '}' { - return false - } - iter.unreadByte() - return true - } else if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return false - } - iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c})) - return false -} - -func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) { - str := iter.ReadStringAsSlice() - if iter.skipWhitespacesWithoutLoadMore() { - if ret == nil { - ret = make([]byte, len(str)) - copy(ret, str) - } - if !iter.loadMore() { - return - } - } - if iter.buf[iter.head] != ':' { - iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]})) - return - } - iter.head++ - if iter.skipWhitespacesWithoutLoadMore() { - if ret == nil { - ret = make([]byte, len(str)) - copy(ret, str) - } - if !iter.loadMore() { - return - } - } - if ret == nil { - return str - } - return ret -} diff --git a/vendor/github.com/json-iterator/go/iter_skip.go b/vendor/github.com/json-iterator/go/iter_skip.go deleted file mode 100644 index e91eefb1..00000000 --- a/vendor/github.com/json-iterator/go/iter_skip.go +++ /dev/null @@ -1,130 +0,0 @@ -package jsoniter - -import "fmt" - -// ReadNil reads a json object as nil and -// returns whether it's a nil or not -func (iter *Iterator) ReadNil() (ret bool) { - c := iter.nextToken() - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') // null - return true - } - iter.unreadByte() - return false -} - -// ReadBool reads a json object as BoolValue -func (iter *Iterator) ReadBool() (ret bool) { - c := iter.nextToken() - if c == 't' { - iter.skipThreeBytes('r', 'u', 'e') - return true - } - if c == 'f' { - iter.skipFourBytes('a', 'l', 's', 'e') - return false - } - iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c})) - return -} - -// SkipAndReturnBytes skip next JSON element, and return its content as []byte. -// The []byte can be kept, it is a copy of data. -func (iter *Iterator) SkipAndReturnBytes() []byte { - iter.startCapture(iter.head) - iter.Skip() - return iter.stopCapture() -} - -// SkipAndAppendBytes skips next JSON element and appends its content to -// buffer, returning the result. -func (iter *Iterator) SkipAndAppendBytes(buf []byte) []byte { - iter.startCaptureTo(buf, iter.head) - iter.Skip() - return iter.stopCapture() -} - -func (iter *Iterator) startCaptureTo(buf []byte, captureStartedAt int) { - if iter.captured != nil { - panic("already in capture mode") - } - iter.captureStartedAt = captureStartedAt - iter.captured = buf -} - -func (iter *Iterator) startCapture(captureStartedAt int) { - iter.startCaptureTo(make([]byte, 0, 32), captureStartedAt) -} - -func (iter *Iterator) stopCapture() []byte { - if iter.captured == nil { - panic("not in capture mode") - } - captured := iter.captured - remaining := iter.buf[iter.captureStartedAt:iter.head] - iter.captureStartedAt = -1 - iter.captured = nil - return append(captured, remaining...) -} - -// Skip skips a json object and positions to relatively the next json object -func (iter *Iterator) Skip() { - c := iter.nextToken() - switch c { - case '"': - iter.skipString() - case 'n': - iter.skipThreeBytes('u', 'l', 'l') // null - case 't': - iter.skipThreeBytes('r', 'u', 'e') // true - case 'f': - iter.skipFourBytes('a', 'l', 's', 'e') // false - case '0': - iter.unreadByte() - iter.ReadFloat32() - case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': - iter.skipNumber() - case '[': - iter.skipArray() - case '{': - iter.skipObject() - default: - iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) - return - } -} - -func (iter *Iterator) skipFourBytes(b1, b2, b3, b4 byte) { - if iter.readByte() != b1 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } - if iter.readByte() != b2 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } - if iter.readByte() != b3 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } - if iter.readByte() != b4 { - iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) - return - } -} - -func (iter *Iterator) skipThreeBytes(b1, b2, b3 byte) { - if iter.readByte() != b1 { - iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) - return - } - if iter.readByte() != b2 { - iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) - return - } - if iter.readByte() != b3 { - iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) - return - } -} diff --git a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go deleted file mode 100644 index 9303de41..00000000 --- a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go +++ /dev/null @@ -1,163 +0,0 @@ -//+build jsoniter_sloppy - -package jsoniter - -// sloppy but faster implementation, do not validate the input json - -func (iter *Iterator) skipNumber() { - for { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case ' ', '\n', '\r', '\t', ',', '}', ']': - iter.head = i - return - } - } - if !iter.loadMore() { - return - } - } -} - -func (iter *Iterator) skipArray() { - level := 1 - if !iter.incrementDepth() { - return - } - for { - for i := iter.head; i < iter.tail; i++ { - switch iter.buf[i] { - case '"': // If inside string, skip it - iter.head = i + 1 - iter.skipString() - i = iter.head - 1 // it will be i++ soon - case '[': // If open symbol, increase level - level++ - if !iter.incrementDepth() { - return - } - case ']': // If close symbol, increase level - level-- - if !iter.decrementDepth() { - return - } - - // If we have returned to the original level, we're done - if level == 0 { - iter.head = i + 1 - return - } - } - } - if !iter.loadMore() { - iter.ReportError("skipObject", "incomplete array") - return - } - } -} - -func (iter *Iterator) skipObject() { - level := 1 - if !iter.incrementDepth() { - return - } - - for { - for i := iter.head; i < iter.tail; i++ { - switch iter.buf[i] { - case '"': // If inside string, skip it - iter.head = i + 1 - iter.skipString() - i = iter.head - 1 // it will be i++ soon - case '{': // If open symbol, increase level - level++ - if !iter.incrementDepth() { - return - } - case '}': // If close symbol, increase level - level-- - if !iter.decrementDepth() { - return - } - - // If we have returned to the original level, we're done - if level == 0 { - iter.head = i + 1 - return - } - } - } - if !iter.loadMore() { - iter.ReportError("skipObject", "incomplete object") - return - } - } -} - -func (iter *Iterator) skipString() { - for { - end, escaped := iter.findStringEnd() - if end == -1 { - if !iter.loadMore() { - iter.ReportError("skipString", "incomplete string") - return - } - if escaped { - iter.head = 1 // skip the first char as last char read is \ - } - } else { - iter.head = end - return - } - } -} - -// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go -// Tries to find the end of string -// Support if string contains escaped quote symbols. -func (iter *Iterator) findStringEnd() (int, bool) { - escaped := false - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - if c == '"' { - if !escaped { - return i + 1, false - } - j := i - 1 - for { - if j < iter.head || iter.buf[j] != '\\' { - // even number of backslashes - // either end of buffer, or " found - return i + 1, true - } - j-- - if j < iter.head || iter.buf[j] != '\\' { - // odd number of backslashes - // it is \" or \\\" - break - } - j-- - } - } else if c == '\\' { - escaped = true - } - } - j := iter.tail - 1 - for { - if j < iter.head || iter.buf[j] != '\\' { - // even number of backslashes - // either end of buffer, or " found - return -1, false // do not end with \ - } - j-- - if j < iter.head || iter.buf[j] != '\\' { - // odd number of backslashes - // it is \" or \\\" - break - } - j-- - - } - return -1, true // end with \ -} diff --git a/vendor/github.com/json-iterator/go/iter_skip_strict.go b/vendor/github.com/json-iterator/go/iter_skip_strict.go deleted file mode 100644 index 6cf66d04..00000000 --- a/vendor/github.com/json-iterator/go/iter_skip_strict.go +++ /dev/null @@ -1,99 +0,0 @@ -//+build !jsoniter_sloppy - -package jsoniter - -import ( - "fmt" - "io" -) - -func (iter *Iterator) skipNumber() { - if !iter.trySkipNumber() { - iter.unreadByte() - if iter.Error != nil && iter.Error != io.EOF { - return - } - iter.ReadFloat64() - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = nil - iter.ReadBigFloat() - } - } -} - -func (iter *Iterator) trySkipNumber() bool { - dotFound := false - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - case '.': - if dotFound { - iter.ReportError("validateNumber", `more than one dot found in number`) - return true // already failed - } - if i+1 == iter.tail { - return false - } - c = iter.buf[i+1] - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - default: - iter.ReportError("validateNumber", `missing digit after dot`) - return true // already failed - } - dotFound = true - default: - switch c { - case ',', ']', '}', ' ', '\t', '\n', '\r': - if iter.head == i { - return false // if - without following digits - } - iter.head = i - return true // must be valid - } - return false // may be invalid - } - } - return false -} - -func (iter *Iterator) skipString() { - if !iter.trySkipString() { - iter.unreadByte() - iter.ReadString() - } -} - -func (iter *Iterator) trySkipString() bool { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - if c == '"' { - iter.head = i + 1 - return true // valid - } else if c == '\\' { - return false - } else if c < ' ' { - iter.ReportError("trySkipString", - fmt.Sprintf(`invalid control character found: %d`, c)) - return true // already failed - } - } - return false -} - -func (iter *Iterator) skipObject() { - iter.unreadByte() - iter.ReadObjectCB(func(iter *Iterator, field string) bool { - iter.Skip() - return true - }) -} - -func (iter *Iterator) skipArray() { - iter.unreadByte() - iter.ReadArrayCB(func(iter *Iterator) bool { - iter.Skip() - return true - }) -} diff --git a/vendor/github.com/json-iterator/go/iter_str.go b/vendor/github.com/json-iterator/go/iter_str.go deleted file mode 100644 index adc487ea..00000000 --- a/vendor/github.com/json-iterator/go/iter_str.go +++ /dev/null @@ -1,215 +0,0 @@ -package jsoniter - -import ( - "fmt" - "unicode/utf16" -) - -// ReadString read string from iterator -func (iter *Iterator) ReadString() (ret string) { - c := iter.nextToken() - if c == '"' { - for i := iter.head; i < iter.tail; i++ { - c := iter.buf[i] - if c == '"' { - ret = string(iter.buf[iter.head:i]) - iter.head = i + 1 - return ret - } else if c == '\\' { - break - } else if c < ' ' { - iter.ReportError("ReadString", - fmt.Sprintf(`invalid control character found: %d`, c)) - return - } - } - return iter.readStringSlowPath() - } else if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return "" - } - iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c})) - return -} - -func (iter *Iterator) readStringSlowPath() (ret string) { - var str []byte - var c byte - for iter.Error == nil { - c = iter.readByte() - if c == '"' { - return string(str) - } - if c == '\\' { - c = iter.readByte() - str = iter.readEscapedChar(c, str) - } else { - str = append(str, c) - } - } - iter.ReportError("readStringSlowPath", "unexpected end of input") - return -} - -func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte { - switch c { - case 'u': - r := iter.readU4() - if utf16.IsSurrogate(r) { - c = iter.readByte() - if iter.Error != nil { - return nil - } - if c != '\\' { - iter.unreadByte() - str = appendRune(str, r) - return str - } - c = iter.readByte() - if iter.Error != nil { - return nil - } - if c != 'u' { - str = appendRune(str, r) - return iter.readEscapedChar(c, str) - } - r2 := iter.readU4() - if iter.Error != nil { - return nil - } - combined := utf16.DecodeRune(r, r2) - if combined == '\uFFFD' { - str = appendRune(str, r) - str = appendRune(str, r2) - } else { - str = appendRune(str, combined) - } - } else { - str = appendRune(str, r) - } - case '"': - str = append(str, '"') - case '\\': - str = append(str, '\\') - case '/': - str = append(str, '/') - case 'b': - str = append(str, '\b') - case 'f': - str = append(str, '\f') - case 'n': - str = append(str, '\n') - case 'r': - str = append(str, '\r') - case 't': - str = append(str, '\t') - default: - iter.ReportError("readEscapedChar", - `invalid escape char after \`) - return nil - } - return str -} - -// ReadStringAsSlice read string from iterator without copying into string form. -// The []byte can not be kept, as it will change after next iterator call. -func (iter *Iterator) ReadStringAsSlice() (ret []byte) { - c := iter.nextToken() - if c == '"' { - for i := iter.head; i < iter.tail; i++ { - // require ascii string and no escape - // for: field name, base64, number - if iter.buf[i] == '"' { - // fast path: reuse the underlying buffer - ret = iter.buf[iter.head:i] - iter.head = i + 1 - return ret - } - } - readLen := iter.tail - iter.head - copied := make([]byte, readLen, readLen*2) - copy(copied, iter.buf[iter.head:iter.tail]) - iter.head = iter.tail - for iter.Error == nil { - c := iter.readByte() - if c == '"' { - return copied - } - copied = append(copied, c) - } - return copied - } - iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c})) - return -} - -func (iter *Iterator) readU4() (ret rune) { - for i := 0; i < 4; i++ { - c := iter.readByte() - if iter.Error != nil { - return - } - if c >= '0' && c <= '9' { - ret = ret*16 + rune(c-'0') - } else if c >= 'a' && c <= 'f' { - ret = ret*16 + rune(c-'a'+10) - } else if c >= 'A' && c <= 'F' { - ret = ret*16 + rune(c-'A'+10) - } else { - iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c})) - return - } - } - return ret -} - -const ( - t1 = 0x00 // 0000 0000 - tx = 0x80 // 1000 0000 - t2 = 0xC0 // 1100 0000 - t3 = 0xE0 // 1110 0000 - t4 = 0xF0 // 1111 0000 - t5 = 0xF8 // 1111 1000 - - maskx = 0x3F // 0011 1111 - mask2 = 0x1F // 0001 1111 - mask3 = 0x0F // 0000 1111 - mask4 = 0x07 // 0000 0111 - - rune1Max = 1<<7 - 1 - rune2Max = 1<<11 - 1 - rune3Max = 1<<16 - 1 - - surrogateMin = 0xD800 - surrogateMax = 0xDFFF - - maxRune = '\U0010FFFF' // Maximum valid Unicode code point. - runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character" -) - -func appendRune(p []byte, r rune) []byte { - // Negative values are erroneous. Making it unsigned addresses the problem. - switch i := uint32(r); { - case i <= rune1Max: - p = append(p, byte(r)) - return p - case i <= rune2Max: - p = append(p, t2|byte(r>>6)) - p = append(p, tx|byte(r)&maskx) - return p - case i > maxRune, surrogateMin <= i && i <= surrogateMax: - r = runeError - fallthrough - case i <= rune3Max: - p = append(p, t3|byte(r>>12)) - p = append(p, tx|byte(r>>6)&maskx) - p = append(p, tx|byte(r)&maskx) - return p - default: - p = append(p, t4|byte(r>>18)) - p = append(p, tx|byte(r>>12)&maskx) - p = append(p, tx|byte(r>>6)&maskx) - p = append(p, tx|byte(r)&maskx) - return p - } -} diff --git a/vendor/github.com/json-iterator/go/jsoniter.go b/vendor/github.com/json-iterator/go/jsoniter.go deleted file mode 100644 index c2934f91..00000000 --- a/vendor/github.com/json-iterator/go/jsoniter.go +++ /dev/null @@ -1,18 +0,0 @@ -// Package jsoniter implements encoding and decoding of JSON as defined in -// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json. -// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter -// and variable type declarations (if any). -// jsoniter interfaces gives 100% compatibility with code using standard lib. -// -// "JSON and Go" -// (https://golang.org/doc/articles/json_and_go.html) -// gives a description of how Marshal/Unmarshal operate -// between arbitrary or predefined json objects and bytes, -// and it applies to jsoniter.Marshal/Unmarshal as well. -// -// Besides, jsoniter.Iterator provides a different set of interfaces -// iterating given bytes/string/reader -// and yielding parsed elements one by one. -// This set of interfaces reads input as required and gives -// better performance. -package jsoniter diff --git a/vendor/github.com/json-iterator/go/pool.go b/vendor/github.com/json-iterator/go/pool.go deleted file mode 100644 index e2389b56..00000000 --- a/vendor/github.com/json-iterator/go/pool.go +++ /dev/null @@ -1,42 +0,0 @@ -package jsoniter - -import ( - "io" -) - -// IteratorPool a thread safe pool of iterators with same configuration -type IteratorPool interface { - BorrowIterator(data []byte) *Iterator - ReturnIterator(iter *Iterator) -} - -// StreamPool a thread safe pool of streams with same configuration -type StreamPool interface { - BorrowStream(writer io.Writer) *Stream - ReturnStream(stream *Stream) -} - -func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream { - stream := cfg.streamPool.Get().(*Stream) - stream.Reset(writer) - return stream -} - -func (cfg *frozenConfig) ReturnStream(stream *Stream) { - stream.out = nil - stream.Error = nil - stream.Attachment = nil - cfg.streamPool.Put(stream) -} - -func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator { - iter := cfg.iteratorPool.Get().(*Iterator) - iter.ResetBytes(data) - return iter -} - -func (cfg *frozenConfig) ReturnIterator(iter *Iterator) { - iter.Error = nil - iter.Attachment = nil - cfg.iteratorPool.Put(iter) -} diff --git a/vendor/github.com/json-iterator/go/reflect.go b/vendor/github.com/json-iterator/go/reflect.go deleted file mode 100644 index 39acb320..00000000 --- a/vendor/github.com/json-iterator/go/reflect.go +++ /dev/null @@ -1,337 +0,0 @@ -package jsoniter - -import ( - "fmt" - "reflect" - "unsafe" - - "github.com/modern-go/reflect2" -) - -// ValDecoder is an internal type registered to cache as needed. -// Don't confuse jsoniter.ValDecoder with json.Decoder. -// For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link). -// -// Reflection on type to create decoders, which is then cached -// Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions -// 1. create instance of new value, for example *int will need a int to be allocated -// 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New -// 3. assignment to map, both key and value will be reflect.Value -// For a simple struct binding, it will be reflect.Value free and allocation free -type ValDecoder interface { - Decode(ptr unsafe.Pointer, iter *Iterator) -} - -// ValEncoder is an internal type registered to cache as needed. -// Don't confuse jsoniter.ValEncoder with json.Encoder. -// For json.Encoder's adapter, refer to jsoniter.AdapterEncoder(todo godoc link). -type ValEncoder interface { - IsEmpty(ptr unsafe.Pointer) bool - Encode(ptr unsafe.Pointer, stream *Stream) -} - -type checkIsEmpty interface { - IsEmpty(ptr unsafe.Pointer) bool -} - -type ctx struct { - *frozenConfig - prefix string - encoders map[reflect2.Type]ValEncoder - decoders map[reflect2.Type]ValDecoder -} - -func (b *ctx) caseSensitive() bool { - if b.frozenConfig == nil { - // default is case-insensitive - return false - } - return b.frozenConfig.caseSensitive -} - -func (b *ctx) append(prefix string) *ctx { - return &ctx{ - frozenConfig: b.frozenConfig, - prefix: b.prefix + " " + prefix, - encoders: b.encoders, - decoders: b.decoders, - } -} - -// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal -func (iter *Iterator) ReadVal(obj interface{}) { - depth := iter.depth - cacheKey := reflect2.RTypeOf(obj) - decoder := iter.cfg.getDecoderFromCache(cacheKey) - if decoder == nil { - typ := reflect2.TypeOf(obj) - if typ == nil || typ.Kind() != reflect.Ptr { - iter.ReportError("ReadVal", "can only unmarshal into pointer") - return - } - decoder = iter.cfg.DecoderOf(typ) - } - ptr := reflect2.PtrOf(obj) - if ptr == nil { - iter.ReportError("ReadVal", "can not read into nil pointer") - return - } - decoder.Decode(ptr, iter) - if iter.depth != depth { - iter.ReportError("ReadVal", "unexpected mismatched nesting") - return - } -} - -// WriteVal copy the go interface into underlying JSON, same as json.Marshal -func (stream *Stream) WriteVal(val interface{}) { - if nil == val { - stream.WriteNil() - return - } - cacheKey := reflect2.RTypeOf(val) - encoder := stream.cfg.getEncoderFromCache(cacheKey) - if encoder == nil { - typ := reflect2.TypeOf(val) - encoder = stream.cfg.EncoderOf(typ) - } - encoder.Encode(reflect2.PtrOf(val), stream) -} - -func (cfg *frozenConfig) DecoderOf(typ reflect2.Type) ValDecoder { - cacheKey := typ.RType() - decoder := cfg.getDecoderFromCache(cacheKey) - if decoder != nil { - return decoder - } - ctx := &ctx{ - frozenConfig: cfg, - prefix: "", - decoders: map[reflect2.Type]ValDecoder{}, - encoders: map[reflect2.Type]ValEncoder{}, - } - ptrType := typ.(*reflect2.UnsafePtrType) - decoder = decoderOfType(ctx, ptrType.Elem()) - cfg.addDecoderToCache(cacheKey, decoder) - return decoder -} - -func decoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := getTypeDecoderFromExtension(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfType(ctx, typ) - for _, extension := range extensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - decoder = ctx.decoderExtension.DecorateDecoder(typ, decoder) - for _, extension := range ctx.extraExtensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - return decoder -} - -func createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := ctx.decoders[typ] - if decoder != nil { - return decoder - } - placeholder := &placeholderDecoder{} - ctx.decoders[typ] = placeholder - decoder = _createDecoderOfType(ctx, typ) - placeholder.decoder = decoder - return decoder -} - -func _createDecoderOfType(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := createDecoderOfJsonRawMessage(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfJsonNumber(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfMarshaler(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfAny(ctx, typ) - if decoder != nil { - return decoder - } - decoder = createDecoderOfNative(ctx, typ) - if decoder != nil { - return decoder - } - switch typ.Kind() { - case reflect.Interface: - ifaceType, isIFace := typ.(*reflect2.UnsafeIFaceType) - if isIFace { - return &ifaceDecoder{valType: ifaceType} - } - return &efaceDecoder{} - case reflect.Struct: - return decoderOfStruct(ctx, typ) - case reflect.Array: - return decoderOfArray(ctx, typ) - case reflect.Slice: - return decoderOfSlice(ctx, typ) - case reflect.Map: - return decoderOfMap(ctx, typ) - case reflect.Ptr: - return decoderOfOptional(ctx, typ) - default: - return &lazyErrorDecoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} - } -} - -func (cfg *frozenConfig) EncoderOf(typ reflect2.Type) ValEncoder { - cacheKey := typ.RType() - encoder := cfg.getEncoderFromCache(cacheKey) - if encoder != nil { - return encoder - } - ctx := &ctx{ - frozenConfig: cfg, - prefix: "", - decoders: map[reflect2.Type]ValDecoder{}, - encoders: map[reflect2.Type]ValEncoder{}, - } - encoder = encoderOfType(ctx, typ) - if typ.LikePtr() { - encoder = &onePtrEncoder{encoder} - } - cfg.addEncoderToCache(cacheKey, encoder) - return encoder -} - -type onePtrEncoder struct { - encoder ValEncoder -} - -func (encoder *onePtrEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) -} - -func (encoder *onePtrEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) -} - -func encoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := getTypeEncoderFromExtension(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfType(ctx, typ) - for _, extension := range extensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - encoder = ctx.encoderExtension.DecorateEncoder(typ, encoder) - for _, extension := range ctx.extraExtensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - return encoder -} - -func createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := ctx.encoders[typ] - if encoder != nil { - return encoder - } - placeholder := &placeholderEncoder{} - ctx.encoders[typ] = placeholder - encoder = _createEncoderOfType(ctx, typ) - placeholder.encoder = encoder - return encoder -} -func _createEncoderOfType(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := createEncoderOfJsonRawMessage(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfJsonNumber(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfMarshaler(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfAny(ctx, typ) - if encoder != nil { - return encoder - } - encoder = createEncoderOfNative(ctx, typ) - if encoder != nil { - return encoder - } - kind := typ.Kind() - switch kind { - case reflect.Interface: - return &dynamicEncoder{typ} - case reflect.Struct: - return encoderOfStruct(ctx, typ) - case reflect.Array: - return encoderOfArray(ctx, typ) - case reflect.Slice: - return encoderOfSlice(ctx, typ) - case reflect.Map: - return encoderOfMap(ctx, typ) - case reflect.Ptr: - return encoderOfOptional(ctx, typ) - default: - return &lazyErrorEncoder{err: fmt.Errorf("%s%s is unsupported type", ctx.prefix, typ.String())} - } -} - -type lazyErrorDecoder struct { - err error -} - -func (decoder *lazyErrorDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.WhatIsNext() != NilValue { - if iter.Error == nil { - iter.Error = decoder.err - } - } else { - iter.Skip() - } -} - -type lazyErrorEncoder struct { - err error -} - -func (encoder *lazyErrorEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if ptr == nil { - stream.WriteNil() - } else if stream.Error == nil { - stream.Error = encoder.err - } -} - -func (encoder *lazyErrorEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type placeholderDecoder struct { - decoder ValDecoder -} - -func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.decoder.Decode(ptr, iter) -} - -type placeholderEncoder struct { - encoder ValEncoder -} - -func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.encoder.Encode(ptr, stream) -} - -func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.encoder.IsEmpty(ptr) -} diff --git a/vendor/github.com/json-iterator/go/reflect_array.go b/vendor/github.com/json-iterator/go/reflect_array.go deleted file mode 100644 index 13a0b7b0..00000000 --- a/vendor/github.com/json-iterator/go/reflect_array.go +++ /dev/null @@ -1,104 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "unsafe" -) - -func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder { - arrayType := typ.(*reflect2.UnsafeArrayType) - decoder := decoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) - return &arrayDecoder{arrayType, decoder} -} - -func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder { - arrayType := typ.(*reflect2.UnsafeArrayType) - if arrayType.Len() == 0 { - return emptyArrayEncoder{} - } - encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem()) - return &arrayEncoder{arrayType, encoder} -} - -type emptyArrayEncoder struct{} - -func (encoder emptyArrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteEmptyArray() -} - -func (encoder emptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return true -} - -type arrayEncoder struct { - arrayType *reflect2.UnsafeArrayType - elemEncoder ValEncoder -} - -func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteArrayStart() - elemPtr := unsafe.Pointer(ptr) - encoder.elemEncoder.Encode(elemPtr, stream) - for i := 1; i < encoder.arrayType.Len(); i++ { - stream.WriteMore() - elemPtr = encoder.arrayType.UnsafeGetIndex(ptr, i) - encoder.elemEncoder.Encode(elemPtr, stream) - } - stream.WriteArrayEnd() - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error()) - } -} - -func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type arrayDecoder struct { - arrayType *reflect2.UnsafeArrayType - elemDecoder ValDecoder -} - -func (decoder *arrayDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.doDecode(ptr, iter) - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error()) - } -} - -func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { - c := iter.nextToken() - arrayType := decoder.arrayType - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - return - } - if c != '[' { - iter.ReportError("decode array", "expect [ or n, but found "+string([]byte{c})) - return - } - c = iter.nextToken() - if c == ']' { - return - } - iter.unreadByte() - elemPtr := arrayType.UnsafeGetIndex(ptr, 0) - decoder.elemDecoder.Decode(elemPtr, iter) - length := 1 - for c = iter.nextToken(); c == ','; c = iter.nextToken() { - if length >= arrayType.Len() { - iter.Skip() - continue - } - idx := length - length += 1 - elemPtr = arrayType.UnsafeGetIndex(ptr, idx) - decoder.elemDecoder.Decode(elemPtr, iter) - } - if c != ']' { - iter.ReportError("decode array", "expect ], but found "+string([]byte{c})) - return - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_dynamic.go b/vendor/github.com/json-iterator/go/reflect_dynamic.go deleted file mode 100644 index 8b6bc8b4..00000000 --- a/vendor/github.com/json-iterator/go/reflect_dynamic.go +++ /dev/null @@ -1,70 +0,0 @@ -package jsoniter - -import ( - "github.com/modern-go/reflect2" - "reflect" - "unsafe" -) - -type dynamicEncoder struct { - valType reflect2.Type -} - -func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - stream.WriteVal(obj) -} - -func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.valType.UnsafeIndirect(ptr) == nil -} - -type efaceDecoder struct { -} - -func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - pObj := (*interface{})(ptr) - obj := *pObj - if obj == nil { - *pObj = iter.Read() - return - } - typ := reflect2.TypeOf(obj) - if typ.Kind() != reflect.Ptr { - *pObj = iter.Read() - return - } - ptrType := typ.(*reflect2.UnsafePtrType) - ptrElemType := ptrType.Elem() - if iter.WhatIsNext() == NilValue { - if ptrElemType.Kind() != reflect.Ptr { - iter.skipFourBytes('n', 'u', 'l', 'l') - *pObj = nil - return - } - } - if reflect2.IsNil(obj) { - obj := ptrElemType.New() - iter.ReadVal(obj) - *pObj = obj - return - } - iter.ReadVal(obj) -} - -type ifaceDecoder struct { - valType *reflect2.UnsafeIFaceType -} - -func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew()) - return - } - obj := decoder.valType.UnsafeIndirect(ptr) - if reflect2.IsNil(obj) { - iter.ReportError("decode non empty interface", "can not unmarshal into nil") - return - } - iter.ReadVal(obj) -} diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go deleted file mode 100644 index 74a97bfe..00000000 --- a/vendor/github.com/json-iterator/go/reflect_extension.go +++ /dev/null @@ -1,483 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "reflect" - "sort" - "strings" - "unicode" - "unsafe" -) - -var typeDecoders = map[string]ValDecoder{} -var fieldDecoders = map[string]ValDecoder{} -var typeEncoders = map[string]ValEncoder{} -var fieldEncoders = map[string]ValEncoder{} -var extensions = []Extension{} - -// StructDescriptor describe how should we encode/decode the struct -type StructDescriptor struct { - Type reflect2.Type - Fields []*Binding -} - -// GetField get one field from the descriptor by its name. -// Can not use map here to keep field orders. -func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding { - for _, binding := range structDescriptor.Fields { - if binding.Field.Name() == fieldName { - return binding - } - } - return nil -} - -// Binding describe how should we encode/decode the struct field -type Binding struct { - levels []int - Field reflect2.StructField - FromNames []string - ToNames []string - Encoder ValEncoder - Decoder ValDecoder -} - -// Extension the one for all SPI. Customize encoding/decoding by specifying alternate encoder/decoder. -// Can also rename fields by UpdateStructDescriptor. -type Extension interface { - UpdateStructDescriptor(structDescriptor *StructDescriptor) - CreateMapKeyDecoder(typ reflect2.Type) ValDecoder - CreateMapKeyEncoder(typ reflect2.Type) ValEncoder - CreateDecoder(typ reflect2.Type) ValDecoder - CreateEncoder(typ reflect2.Type) ValEncoder - DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder - DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder -} - -// DummyExtension embed this type get dummy implementation for all methods of Extension -type DummyExtension struct { -} - -// UpdateStructDescriptor No-op -func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { -} - -// CreateMapKeyDecoder No-op -func (extension *DummyExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateMapKeyEncoder No-op -func (extension *DummyExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// CreateDecoder No-op -func (extension *DummyExtension) CreateDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateEncoder No-op -func (extension *DummyExtension) CreateEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// DecorateDecoder No-op -func (extension *DummyExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { - return decoder -} - -// DecorateEncoder No-op -func (extension *DummyExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { - return encoder -} - -type EncoderExtension map[reflect2.Type]ValEncoder - -// UpdateStructDescriptor No-op -func (extension EncoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { -} - -// CreateDecoder No-op -func (extension EncoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateEncoder get encoder from map -func (extension EncoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { - return extension[typ] -} - -// CreateMapKeyDecoder No-op -func (extension EncoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateMapKeyEncoder No-op -func (extension EncoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// DecorateDecoder No-op -func (extension EncoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { - return decoder -} - -// DecorateEncoder No-op -func (extension EncoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { - return encoder -} - -type DecoderExtension map[reflect2.Type]ValDecoder - -// UpdateStructDescriptor No-op -func (extension DecoderExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { -} - -// CreateMapKeyDecoder No-op -func (extension DecoderExtension) CreateMapKeyDecoder(typ reflect2.Type) ValDecoder { - return nil -} - -// CreateMapKeyEncoder No-op -func (extension DecoderExtension) CreateMapKeyEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// CreateDecoder get decoder from map -func (extension DecoderExtension) CreateDecoder(typ reflect2.Type) ValDecoder { - return extension[typ] -} - -// CreateEncoder No-op -func (extension DecoderExtension) CreateEncoder(typ reflect2.Type) ValEncoder { - return nil -} - -// DecorateDecoder No-op -func (extension DecoderExtension) DecorateDecoder(typ reflect2.Type, decoder ValDecoder) ValDecoder { - return decoder -} - -// DecorateEncoder No-op -func (extension DecoderExtension) DecorateEncoder(typ reflect2.Type, encoder ValEncoder) ValEncoder { - return encoder -} - -type funcDecoder struct { - fun DecoderFunc -} - -func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.fun(ptr, iter) -} - -type funcEncoder struct { - fun EncoderFunc - isEmptyFunc func(ptr unsafe.Pointer) bool -} - -func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.fun(ptr, stream) -} - -func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool { - if encoder.isEmptyFunc == nil { - return false - } - return encoder.isEmptyFunc(ptr) -} - -// DecoderFunc the function form of TypeDecoder -type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator) - -// EncoderFunc the function form of TypeEncoder -type EncoderFunc func(ptr unsafe.Pointer, stream *Stream) - -// RegisterTypeDecoderFunc register TypeDecoder for a type with function -func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { - typeDecoders[typ] = &funcDecoder{fun} -} - -// RegisterTypeDecoder register TypeDecoder for a typ -func RegisterTypeDecoder(typ string, decoder ValDecoder) { - typeDecoders[typ] = decoder -} - -// RegisterFieldDecoderFunc register TypeDecoder for a struct field with function -func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) { - RegisterFieldDecoder(typ, field, &funcDecoder{fun}) -} - -// RegisterFieldDecoder register TypeDecoder for a struct field -func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) { - fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder -} - -// RegisterTypeEncoderFunc register TypeEncoder for a type with encode/isEmpty function -func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { - typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc} -} - -// RegisterTypeEncoder register TypeEncoder for a type -func RegisterTypeEncoder(typ string, encoder ValEncoder) { - typeEncoders[typ] = encoder -} - -// RegisterFieldEncoderFunc register TypeEncoder for a struct field with encode/isEmpty function -func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) { - RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc}) -} - -// RegisterFieldEncoder register TypeEncoder for a struct field -func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) { - fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder -} - -// RegisterExtension register extension -func RegisterExtension(extension Extension) { - extensions = append(extensions, extension) -} - -func getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := _getTypeDecoderFromExtension(ctx, typ) - if decoder != nil { - for _, extension := range extensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - decoder = ctx.decoderExtension.DecorateDecoder(typ, decoder) - for _, extension := range ctx.extraExtensions { - decoder = extension.DecorateDecoder(typ, decoder) - } - } - return decoder -} -func _getTypeDecoderFromExtension(ctx *ctx, typ reflect2.Type) ValDecoder { - for _, extension := range extensions { - decoder := extension.CreateDecoder(typ) - if decoder != nil { - return decoder - } - } - decoder := ctx.decoderExtension.CreateDecoder(typ) - if decoder != nil { - return decoder - } - for _, extension := range ctx.extraExtensions { - decoder := extension.CreateDecoder(typ) - if decoder != nil { - return decoder - } - } - typeName := typ.String() - decoder = typeDecoders[typeName] - if decoder != nil { - return decoder - } - if typ.Kind() == reflect.Ptr { - ptrType := typ.(*reflect2.UnsafePtrType) - decoder := typeDecoders[ptrType.Elem().String()] - if decoder != nil { - return &OptionalDecoder{ptrType.Elem(), decoder} - } - } - return nil -} - -func getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := _getTypeEncoderFromExtension(ctx, typ) - if encoder != nil { - for _, extension := range extensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - encoder = ctx.encoderExtension.DecorateEncoder(typ, encoder) - for _, extension := range ctx.extraExtensions { - encoder = extension.DecorateEncoder(typ, encoder) - } - } - return encoder -} - -func _getTypeEncoderFromExtension(ctx *ctx, typ reflect2.Type) ValEncoder { - for _, extension := range extensions { - encoder := extension.CreateEncoder(typ) - if encoder != nil { - return encoder - } - } - encoder := ctx.encoderExtension.CreateEncoder(typ) - if encoder != nil { - return encoder - } - for _, extension := range ctx.extraExtensions { - encoder := extension.CreateEncoder(typ) - if encoder != nil { - return encoder - } - } - typeName := typ.String() - encoder = typeEncoders[typeName] - if encoder != nil { - return encoder - } - if typ.Kind() == reflect.Ptr { - typePtr := typ.(*reflect2.UnsafePtrType) - encoder := typeEncoders[typePtr.Elem().String()] - if encoder != nil { - return &OptionalEncoder{encoder} - } - } - return nil -} - -func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor { - structType := typ.(*reflect2.UnsafeStructType) - embeddedBindings := []*Binding{} - bindings := []*Binding{} - for i := 0; i < structType.NumField(); i++ { - field := structType.Field(i) - tag, hastag := field.Tag().Lookup(ctx.getTagKey()) - if ctx.onlyTaggedField && !hastag && !field.Anonymous() { - continue - } - if tag == "-" || field.Name() == "_" { - continue - } - tagParts := strings.Split(tag, ",") - if field.Anonymous() && (tag == "" || tagParts[0] == "") { - if field.Type().Kind() == reflect.Struct { - structDescriptor := describeStruct(ctx, field.Type()) - for _, binding := range structDescriptor.Fields { - binding.levels = append([]int{i}, binding.levels...) - omitempty := binding.Encoder.(*structFieldEncoder).omitempty - binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} - binding.Decoder = &structFieldDecoder{field, binding.Decoder} - embeddedBindings = append(embeddedBindings, binding) - } - continue - } else if field.Type().Kind() == reflect.Ptr { - ptrType := field.Type().(*reflect2.UnsafePtrType) - if ptrType.Elem().Kind() == reflect.Struct { - structDescriptor := describeStruct(ctx, ptrType.Elem()) - for _, binding := range structDescriptor.Fields { - binding.levels = append([]int{i}, binding.levels...) - omitempty := binding.Encoder.(*structFieldEncoder).omitempty - binding.Encoder = &dereferenceEncoder{binding.Encoder} - binding.Encoder = &structFieldEncoder{field, binding.Encoder, omitempty} - binding.Decoder = &dereferenceDecoder{ptrType.Elem(), binding.Decoder} - binding.Decoder = &structFieldDecoder{field, binding.Decoder} - embeddedBindings = append(embeddedBindings, binding) - } - continue - } - } - } - fieldNames := calcFieldNames(field.Name(), tagParts[0], tag) - fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name()) - decoder := fieldDecoders[fieldCacheKey] - if decoder == nil { - decoder = decoderOfType(ctx.append(field.Name()), field.Type()) - } - encoder := fieldEncoders[fieldCacheKey] - if encoder == nil { - encoder = encoderOfType(ctx.append(field.Name()), field.Type()) - } - binding := &Binding{ - Field: field, - FromNames: fieldNames, - ToNames: fieldNames, - Decoder: decoder, - Encoder: encoder, - } - binding.levels = []int{i} - bindings = append(bindings, binding) - } - return createStructDescriptor(ctx, typ, bindings, embeddedBindings) -} -func createStructDescriptor(ctx *ctx, typ reflect2.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor { - structDescriptor := &StructDescriptor{ - Type: typ, - Fields: bindings, - } - for _, extension := range extensions { - extension.UpdateStructDescriptor(structDescriptor) - } - ctx.encoderExtension.UpdateStructDescriptor(structDescriptor) - ctx.decoderExtension.UpdateStructDescriptor(structDescriptor) - for _, extension := range ctx.extraExtensions { - extension.UpdateStructDescriptor(structDescriptor) - } - processTags(structDescriptor, ctx.frozenConfig) - // merge normal & embedded bindings & sort with original order - allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) - sort.Sort(allBindings) - structDescriptor.Fields = allBindings - return structDescriptor -} - -type sortableBindings []*Binding - -func (bindings sortableBindings) Len() int { - return len(bindings) -} - -func (bindings sortableBindings) Less(i, j int) bool { - left := bindings[i].levels - right := bindings[j].levels - k := 0 - for { - if left[k] < right[k] { - return true - } else if left[k] > right[k] { - return false - } - k++ - } -} - -func (bindings sortableBindings) Swap(i, j int) { - bindings[i], bindings[j] = bindings[j], bindings[i] -} - -func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) { - for _, binding := range structDescriptor.Fields { - shouldOmitEmpty := false - tagParts := strings.Split(binding.Field.Tag().Get(cfg.getTagKey()), ",") - for _, tagPart := range tagParts[1:] { - if tagPart == "omitempty" { - shouldOmitEmpty = true - } else if tagPart == "string" { - if binding.Field.Type().Kind() == reflect.String { - binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg} - binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg} - } else { - binding.Decoder = &stringModeNumberDecoder{binding.Decoder} - binding.Encoder = &stringModeNumberEncoder{binding.Encoder} - } - } - } - binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder} - binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty} - } -} - -func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string { - // ignore? - if wholeTag == "-" { - return []string{} - } - // rename? - var fieldNames []string - if tagProvidedFieldName == "" { - fieldNames = []string{originalFieldName} - } else { - fieldNames = []string{tagProvidedFieldName} - } - // private? - isNotExported := unicode.IsLower(rune(originalFieldName[0])) || originalFieldName[0] == '_' - if isNotExported { - fieldNames = []string{} - } - return fieldNames -} diff --git a/vendor/github.com/json-iterator/go/reflect_json_number.go b/vendor/github.com/json-iterator/go/reflect_json_number.go deleted file mode 100644 index 98d45c1e..00000000 --- a/vendor/github.com/json-iterator/go/reflect_json_number.go +++ /dev/null @@ -1,112 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "github.com/modern-go/reflect2" - "strconv" - "unsafe" -) - -type Number string - -// String returns the literal text of the number. -func (n Number) String() string { return string(n) } - -// Float64 returns the number as a float64. -func (n Number) Float64() (float64, error) { - return strconv.ParseFloat(string(n), 64) -} - -// Int64 returns the number as an int64. -func (n Number) Int64() (int64, error) { - return strconv.ParseInt(string(n), 10, 64) -} - -func CastJsonNumber(val interface{}) (string, bool) { - switch typedVal := val.(type) { - case json.Number: - return string(typedVal), true - case Number: - return string(typedVal), true - } - return "", false -} - -var jsonNumberType = reflect2.TypeOfPtr((*json.Number)(nil)).Elem() -var jsoniterNumberType = reflect2.TypeOfPtr((*Number)(nil)).Elem() - -func createDecoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ.AssignableTo(jsonNumberType) { - return &jsonNumberCodec{} - } - if typ.AssignableTo(jsoniterNumberType) { - return &jsoniterNumberCodec{} - } - return nil -} - -func createEncoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ.AssignableTo(jsonNumberType) { - return &jsonNumberCodec{} - } - if typ.AssignableTo(jsoniterNumberType) { - return &jsoniterNumberCodec{} - } - return nil -} - -type jsonNumberCodec struct { -} - -func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - switch iter.WhatIsNext() { - case StringValue: - *((*json.Number)(ptr)) = json.Number(iter.ReadString()) - case NilValue: - iter.skipFourBytes('n', 'u', 'l', 'l') - *((*json.Number)(ptr)) = "" - default: - *((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString())) - } -} - -func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - number := *((*json.Number)(ptr)) - if len(number) == 0 { - stream.writeByte('0') - } else { - stream.WriteRaw(string(number)) - } -} - -func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*json.Number)(ptr))) == 0 -} - -type jsoniterNumberCodec struct { -} - -func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - switch iter.WhatIsNext() { - case StringValue: - *((*Number)(ptr)) = Number(iter.ReadString()) - case NilValue: - iter.skipFourBytes('n', 'u', 'l', 'l') - *((*Number)(ptr)) = "" - default: - *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString())) - } -} - -func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - number := *((*Number)(ptr)) - if len(number) == 0 { - stream.writeByte('0') - } else { - stream.WriteRaw(string(number)) - } -} - -func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*Number)(ptr))) == 0 -} diff --git a/vendor/github.com/json-iterator/go/reflect_json_raw_message.go b/vendor/github.com/json-iterator/go/reflect_json_raw_message.go deleted file mode 100644 index eba434f2..00000000 --- a/vendor/github.com/json-iterator/go/reflect_json_raw_message.go +++ /dev/null @@ -1,76 +0,0 @@ -package jsoniter - -import ( - "encoding/json" - "github.com/modern-go/reflect2" - "unsafe" -) - -var jsonRawMessageType = reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem() -var jsoniterRawMessageType = reflect2.TypeOfPtr((*RawMessage)(nil)).Elem() - -func createEncoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ == jsonRawMessageType { - return &jsonRawMessageCodec{} - } - if typ == jsoniterRawMessageType { - return &jsoniterRawMessageCodec{} - } - return nil -} - -func createDecoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ == jsonRawMessageType { - return &jsonRawMessageCodec{} - } - if typ == jsoniterRawMessageType { - return &jsoniterRawMessageCodec{} - } - return nil -} - -type jsonRawMessageCodec struct { -} - -func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - *((*json.RawMessage)(ptr)) = nil - } else { - *((*json.RawMessage)(ptr)) = iter.SkipAndReturnBytes() - } -} - -func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - if *((*json.RawMessage)(ptr)) == nil { - stream.WriteNil() - } else { - stream.WriteRaw(string(*((*json.RawMessage)(ptr)))) - } -} - -func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*json.RawMessage)(ptr))) == 0 -} - -type jsoniterRawMessageCodec struct { -} - -func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - *((*RawMessage)(ptr)) = nil - } else { - *((*RawMessage)(ptr)) = iter.SkipAndReturnBytes() - } -} - -func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - if *((*RawMessage)(ptr)) == nil { - stream.WriteNil() - } else { - stream.WriteRaw(string(*((*RawMessage)(ptr)))) - } -} - -func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*RawMessage)(ptr))) == 0 -} diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go deleted file mode 100644 index 58296713..00000000 --- a/vendor/github.com/json-iterator/go/reflect_map.go +++ /dev/null @@ -1,346 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "reflect" - "sort" - "unsafe" -) - -func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder { - mapType := typ.(*reflect2.UnsafeMapType) - keyDecoder := decoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()) - elemDecoder := decoderOfType(ctx.append("[mapElem]"), mapType.Elem()) - return &mapDecoder{ - mapType: mapType, - keyType: mapType.Key(), - elemType: mapType.Elem(), - keyDecoder: keyDecoder, - elemDecoder: elemDecoder, - } -} - -func encoderOfMap(ctx *ctx, typ reflect2.Type) ValEncoder { - mapType := typ.(*reflect2.UnsafeMapType) - if ctx.sortMapKeys { - return &sortKeysMapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), - } - } - return &mapEncoder{ - mapType: mapType, - keyEncoder: encoderOfMapKey(ctx.append("[mapKey]"), mapType.Key()), - elemEncoder: encoderOfType(ctx.append("[mapElem]"), mapType.Elem()), - } -} - -func decoderOfMapKey(ctx *ctx, typ reflect2.Type) ValDecoder { - decoder := ctx.decoderExtension.CreateMapKeyDecoder(typ) - if decoder != nil { - return decoder - } - for _, extension := range ctx.extraExtensions { - decoder := extension.CreateMapKeyDecoder(typ) - if decoder != nil { - return decoder - } - } - - ptrType := reflect2.PtrTo(typ) - if ptrType.Implements(unmarshalerType) { - return &referenceDecoder{ - &unmarshalerDecoder{ - valType: ptrType, - }, - } - } - if typ.Implements(unmarshalerType) { - return &unmarshalerDecoder{ - valType: typ, - } - } - if ptrType.Implements(textUnmarshalerType) { - return &referenceDecoder{ - &textUnmarshalerDecoder{ - valType: ptrType, - }, - } - } - if typ.Implements(textUnmarshalerType) { - return &textUnmarshalerDecoder{ - valType: typ, - } - } - - switch typ.Kind() { - case reflect.String: - return decoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) - case reflect.Bool, - reflect.Uint8, reflect.Int8, - reflect.Uint16, reflect.Int16, - reflect.Uint32, reflect.Int32, - reflect.Uint64, reflect.Int64, - reflect.Uint, reflect.Int, - reflect.Float32, reflect.Float64, - reflect.Uintptr: - typ = reflect2.DefaultTypeOfKind(typ.Kind()) - return &numericMapKeyDecoder{decoderOfType(ctx, typ)} - default: - return &lazyErrorDecoder{err: fmt.Errorf("unsupported map key type: %v", typ)} - } -} - -func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder { - encoder := ctx.encoderExtension.CreateMapKeyEncoder(typ) - if encoder != nil { - return encoder - } - for _, extension := range ctx.extraExtensions { - encoder := extension.CreateMapKeyEncoder(typ) - if encoder != nil { - return encoder - } - } - - if typ == textMarshalerType { - return &directTextMarshalerEncoder{ - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - } - if typ.Implements(textMarshalerType) { - return &textMarshalerEncoder{ - valType: typ, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - } - - switch typ.Kind() { - case reflect.String: - return encoderOfType(ctx, reflect2.DefaultTypeOfKind(reflect.String)) - case reflect.Bool, - reflect.Uint8, reflect.Int8, - reflect.Uint16, reflect.Int16, - reflect.Uint32, reflect.Int32, - reflect.Uint64, reflect.Int64, - reflect.Uint, reflect.Int, - reflect.Float32, reflect.Float64, - reflect.Uintptr: - typ = reflect2.DefaultTypeOfKind(typ.Kind()) - return &numericMapKeyEncoder{encoderOfType(ctx, typ)} - default: - if typ.Kind() == reflect.Interface { - return &dynamicMapKeyEncoder{ctx, typ} - } - return &lazyErrorEncoder{err: fmt.Errorf("unsupported map key type: %v", typ)} - } -} - -type mapDecoder struct { - mapType *reflect2.UnsafeMapType - keyType reflect2.Type - elemType reflect2.Type - keyDecoder ValDecoder - elemDecoder ValDecoder -} - -func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - mapType := decoder.mapType - c := iter.nextToken() - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - *(*unsafe.Pointer)(ptr) = nil - mapType.UnsafeSet(ptr, mapType.UnsafeNew()) - return - } - if mapType.UnsafeIsNil(ptr) { - mapType.UnsafeSet(ptr, mapType.UnsafeMakeMap(0)) - } - if c != '{' { - iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c})) - return - } - c = iter.nextToken() - if c == '}' { - return - } - iter.unreadByte() - key := decoder.keyType.UnsafeNew() - decoder.keyDecoder.Decode(key, iter) - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - return - } - elem := decoder.elemType.UnsafeNew() - decoder.elemDecoder.Decode(elem, iter) - decoder.mapType.UnsafeSetIndex(ptr, key, elem) - for c = iter.nextToken(); c == ','; c = iter.nextToken() { - key := decoder.keyType.UnsafeNew() - decoder.keyDecoder.Decode(key, iter) - c = iter.nextToken() - if c != ':' { - iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c})) - return - } - elem := decoder.elemType.UnsafeNew() - decoder.elemDecoder.Decode(elem, iter) - decoder.mapType.UnsafeSetIndex(ptr, key, elem) - } - if c != '}' { - iter.ReportError("ReadMapCB", `expect }, but found `+string([]byte{c})) - } -} - -type numericMapKeyDecoder struct { - decoder ValDecoder -} - -func (decoder *numericMapKeyDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - c := iter.nextToken() - if c != '"' { - iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) - return - } - decoder.decoder.Decode(ptr, iter) - c = iter.nextToken() - if c != '"' { - iter.ReportError("ReadMapCB", `expect ", but found `+string([]byte{c})) - return - } -} - -type numericMapKeyEncoder struct { - encoder ValEncoder -} - -func (encoder *numericMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.writeByte('"') - encoder.encoder.Encode(ptr, stream) - stream.writeByte('"') -} - -func (encoder *numericMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type dynamicMapKeyEncoder struct { - ctx *ctx - valType reflect2.Type -} - -func (encoder *dynamicMapKeyEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).Encode(reflect2.PtrOf(obj), stream) -} - -func (encoder *dynamicMapKeyEncoder) IsEmpty(ptr unsafe.Pointer) bool { - obj := encoder.valType.UnsafeIndirect(ptr) - return encoderOfMapKey(encoder.ctx, reflect2.TypeOf(obj)).IsEmpty(reflect2.PtrOf(obj)) -} - -type mapEncoder struct { - mapType *reflect2.UnsafeMapType - keyEncoder ValEncoder - elemEncoder ValEncoder -} - -func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *(*unsafe.Pointer)(ptr) == nil { - stream.WriteNil() - return - } - stream.WriteObjectStart() - iter := encoder.mapType.UnsafeIterate(ptr) - for i := 0; iter.HasNext(); i++ { - if i != 0 { - stream.WriteMore() - } - key, elem := iter.UnsafeNext() - encoder.keyEncoder.Encode(key, stream) - if stream.indention > 0 { - stream.writeTwoBytes(byte(':'), byte(' ')) - } else { - stream.writeByte(':') - } - encoder.elemEncoder.Encode(elem, stream) - } - stream.WriteObjectEnd() -} - -func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { - iter := encoder.mapType.UnsafeIterate(ptr) - return !iter.HasNext() -} - -type sortKeysMapEncoder struct { - mapType *reflect2.UnsafeMapType - keyEncoder ValEncoder - elemEncoder ValEncoder -} - -func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *(*unsafe.Pointer)(ptr) == nil { - stream.WriteNil() - return - } - stream.WriteObjectStart() - mapIter := encoder.mapType.UnsafeIterate(ptr) - subStream := stream.cfg.BorrowStream(nil) - subStream.Attachment = stream.Attachment - subIter := stream.cfg.BorrowIterator(nil) - keyValues := encodedKeyValues{} - for mapIter.HasNext() { - key, elem := mapIter.UnsafeNext() - subStreamIndex := subStream.Buffered() - encoder.keyEncoder.Encode(key, subStream) - if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil { - stream.Error = subStream.Error - } - encodedKey := subStream.Buffer()[subStreamIndex:] - subIter.ResetBytes(encodedKey) - decodedKey := subIter.ReadString() - if stream.indention > 0 { - subStream.writeTwoBytes(byte(':'), byte(' ')) - } else { - subStream.writeByte(':') - } - encoder.elemEncoder.Encode(elem, subStream) - keyValues = append(keyValues, encodedKV{ - key: decodedKey, - keyValue: subStream.Buffer()[subStreamIndex:], - }) - } - sort.Sort(keyValues) - for i, keyValue := range keyValues { - if i != 0 { - stream.WriteMore() - } - stream.Write(keyValue.keyValue) - } - if subStream.Error != nil && stream.Error == nil { - stream.Error = subStream.Error - } - stream.WriteObjectEnd() - stream.cfg.ReturnStream(subStream) - stream.cfg.ReturnIterator(subIter) -} - -func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool { - iter := encoder.mapType.UnsafeIterate(ptr) - return !iter.HasNext() -} - -type encodedKeyValues []encodedKV - -type encodedKV struct { - key string - keyValue []byte -} - -func (sv encodedKeyValues) Len() int { return len(sv) } -func (sv encodedKeyValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } -func (sv encodedKeyValues) Less(i, j int) bool { return sv[i].key < sv[j].key } diff --git a/vendor/github.com/json-iterator/go/reflect_marshaler.go b/vendor/github.com/json-iterator/go/reflect_marshaler.go deleted file mode 100644 index 3e21f375..00000000 --- a/vendor/github.com/json-iterator/go/reflect_marshaler.go +++ /dev/null @@ -1,225 +0,0 @@ -package jsoniter - -import ( - "encoding" - "encoding/json" - "unsafe" - - "github.com/modern-go/reflect2" -) - -var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem() -var unmarshalerType = reflect2.TypeOfPtr((*json.Unmarshaler)(nil)).Elem() -var textMarshalerType = reflect2.TypeOfPtr((*encoding.TextMarshaler)(nil)).Elem() -var textUnmarshalerType = reflect2.TypeOfPtr((*encoding.TextUnmarshaler)(nil)).Elem() - -func createDecoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValDecoder { - ptrType := reflect2.PtrTo(typ) - if ptrType.Implements(unmarshalerType) { - return &referenceDecoder{ - &unmarshalerDecoder{ptrType}, - } - } - if ptrType.Implements(textUnmarshalerType) { - return &referenceDecoder{ - &textUnmarshalerDecoder{ptrType}, - } - } - return nil -} - -func createEncoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ == marshalerType { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &directMarshalerEncoder{ - checkIsEmpty: checkIsEmpty, - } - return encoder - } - if typ.Implements(marshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &marshalerEncoder{ - valType: typ, - checkIsEmpty: checkIsEmpty, - } - return encoder - } - ptrType := reflect2.PtrTo(typ) - if ctx.prefix != "" && ptrType.Implements(marshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, ptrType) - var encoder ValEncoder = &marshalerEncoder{ - valType: ptrType, - checkIsEmpty: checkIsEmpty, - } - return &referenceEncoder{encoder} - } - if typ == textMarshalerType { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &directTextMarshalerEncoder{ - checkIsEmpty: checkIsEmpty, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - } - return encoder - } - if typ.Implements(textMarshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, typ) - var encoder ValEncoder = &textMarshalerEncoder{ - valType: typ, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - checkIsEmpty: checkIsEmpty, - } - return encoder - } - // if prefix is empty, the type is the root type - if ctx.prefix != "" && ptrType.Implements(textMarshalerType) { - checkIsEmpty := createCheckIsEmpty(ctx, ptrType) - var encoder ValEncoder = &textMarshalerEncoder{ - valType: ptrType, - stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")), - checkIsEmpty: checkIsEmpty, - } - return &referenceEncoder{encoder} - } - return nil -} - -type marshalerEncoder struct { - checkIsEmpty checkIsEmpty - valType reflect2.Type -} - -func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - if encoder.valType.IsNullable() && reflect2.IsNil(obj) { - stream.WriteNil() - return - } - marshaler := obj.(json.Marshaler) - bytes, err := marshaler.MarshalJSON() - if err != nil { - stream.Error = err - } else { - // html escape was already done by jsoniter - // but the extra '\n' should be trimed - l := len(bytes) - if l > 0 && bytes[l-1] == '\n' { - bytes = bytes[:l-1] - } - stream.Write(bytes) - } -} - -func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type directMarshalerEncoder struct { - checkIsEmpty checkIsEmpty -} - -func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - marshaler := *(*json.Marshaler)(ptr) - if marshaler == nil { - stream.WriteNil() - return - } - bytes, err := marshaler.MarshalJSON() - if err != nil { - stream.Error = err - } else { - stream.Write(bytes) - } -} - -func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type textMarshalerEncoder struct { - valType reflect2.Type - stringEncoder ValEncoder - checkIsEmpty checkIsEmpty -} - -func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - obj := encoder.valType.UnsafeIndirect(ptr) - if encoder.valType.IsNullable() && reflect2.IsNil(obj) { - stream.WriteNil() - return - } - marshaler := (obj).(encoding.TextMarshaler) - bytes, err := marshaler.MarshalText() - if err != nil { - stream.Error = err - } else { - str := string(bytes) - encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) - } -} - -func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type directTextMarshalerEncoder struct { - stringEncoder ValEncoder - checkIsEmpty checkIsEmpty -} - -func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - marshaler := *(*encoding.TextMarshaler)(ptr) - if marshaler == nil { - stream.WriteNil() - return - } - bytes, err := marshaler.MarshalText() - if err != nil { - stream.Error = err - } else { - str := string(bytes) - encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream) - } -} - -func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.checkIsEmpty.IsEmpty(ptr) -} - -type unmarshalerDecoder struct { - valType reflect2.Type -} - -func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - valType := decoder.valType - obj := valType.UnsafeIndirect(ptr) - unmarshaler := obj.(json.Unmarshaler) - iter.nextToken() - iter.unreadByte() // skip spaces - bytes := iter.SkipAndReturnBytes() - err := unmarshaler.UnmarshalJSON(bytes) - if err != nil { - iter.ReportError("unmarshalerDecoder", err.Error()) - } -} - -type textUnmarshalerDecoder struct { - valType reflect2.Type -} - -func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - valType := decoder.valType - obj := valType.UnsafeIndirect(ptr) - if reflect2.IsNil(obj) { - ptrType := valType.(*reflect2.UnsafePtrType) - elemType := ptrType.Elem() - elem := elemType.UnsafeNew() - ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem)) - obj = valType.UnsafeIndirect(ptr) - } - unmarshaler := (obj).(encoding.TextUnmarshaler) - str := iter.ReadString() - err := unmarshaler.UnmarshalText([]byte(str)) - if err != nil { - iter.ReportError("textUnmarshalerDecoder", err.Error()) - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_native.go b/vendor/github.com/json-iterator/go/reflect_native.go deleted file mode 100644 index f88722d1..00000000 --- a/vendor/github.com/json-iterator/go/reflect_native.go +++ /dev/null @@ -1,453 +0,0 @@ -package jsoniter - -import ( - "encoding/base64" - "reflect" - "strconv" - "unsafe" - - "github.com/modern-go/reflect2" -) - -const ptrSize = 32 << uintptr(^uintptr(0)>>63) - -func createEncoderOfNative(ctx *ctx, typ reflect2.Type) ValEncoder { - if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { - sliceDecoder := decoderOfSlice(ctx, typ) - return &base64Codec{sliceDecoder: sliceDecoder} - } - typeName := typ.String() - kind := typ.Kind() - switch kind { - case reflect.String: - if typeName != "string" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) - } - return &stringCodec{} - case reflect.Int: - if typeName != "int" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &int32Codec{} - } - return &int64Codec{} - case reflect.Int8: - if typeName != "int8" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) - } - return &int8Codec{} - case reflect.Int16: - if typeName != "int16" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) - } - return &int16Codec{} - case reflect.Int32: - if typeName != "int32" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) - } - return &int32Codec{} - case reflect.Int64: - if typeName != "int64" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) - } - return &int64Codec{} - case reflect.Uint: - if typeName != "uint" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint8: - if typeName != "uint8" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) - } - return &uint8Codec{} - case reflect.Uint16: - if typeName != "uint16" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) - } - return &uint16Codec{} - case reflect.Uint32: - if typeName != "uint32" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) - } - return &uint32Codec{} - case reflect.Uintptr: - if typeName != "uintptr" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) - } - if ptrSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint64: - if typeName != "uint64" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) - } - return &uint64Codec{} - case reflect.Float32: - if typeName != "float32" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) - } - return &float32Codec{} - case reflect.Float64: - if typeName != "float64" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) - } - return &float64Codec{} - case reflect.Bool: - if typeName != "bool" { - return encoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) - } - return &boolCodec{} - } - return nil -} - -func createDecoderOfNative(ctx *ctx, typ reflect2.Type) ValDecoder { - if typ.Kind() == reflect.Slice && typ.(reflect2.SliceType).Elem().Kind() == reflect.Uint8 { - sliceDecoder := decoderOfSlice(ctx, typ) - return &base64Codec{sliceDecoder: sliceDecoder} - } - typeName := typ.String() - switch typ.Kind() { - case reflect.String: - if typeName != "string" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*string)(nil)).Elem()) - } - return &stringCodec{} - case reflect.Int: - if typeName != "int" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &int32Codec{} - } - return &int64Codec{} - case reflect.Int8: - if typeName != "int8" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int8)(nil)).Elem()) - } - return &int8Codec{} - case reflect.Int16: - if typeName != "int16" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int16)(nil)).Elem()) - } - return &int16Codec{} - case reflect.Int32: - if typeName != "int32" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int32)(nil)).Elem()) - } - return &int32Codec{} - case reflect.Int64: - if typeName != "int64" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*int64)(nil)).Elem()) - } - return &int64Codec{} - case reflect.Uint: - if typeName != "uint" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint)(nil)).Elem()) - } - if strconv.IntSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint8: - if typeName != "uint8" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint8)(nil)).Elem()) - } - return &uint8Codec{} - case reflect.Uint16: - if typeName != "uint16" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint16)(nil)).Elem()) - } - return &uint16Codec{} - case reflect.Uint32: - if typeName != "uint32" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint32)(nil)).Elem()) - } - return &uint32Codec{} - case reflect.Uintptr: - if typeName != "uintptr" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uintptr)(nil)).Elem()) - } - if ptrSize == 32 { - return &uint32Codec{} - } - return &uint64Codec{} - case reflect.Uint64: - if typeName != "uint64" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*uint64)(nil)).Elem()) - } - return &uint64Codec{} - case reflect.Float32: - if typeName != "float32" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*float32)(nil)).Elem()) - } - return &float32Codec{} - case reflect.Float64: - if typeName != "float64" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*float64)(nil)).Elem()) - } - return &float64Codec{} - case reflect.Bool: - if typeName != "bool" { - return decoderOfType(ctx, reflect2.TypeOfPtr((*bool)(nil)).Elem()) - } - return &boolCodec{} - } - return nil -} - -type stringCodec struct { -} - -func (codec *stringCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - *((*string)(ptr)) = iter.ReadString() -} - -func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - str := *((*string)(ptr)) - stream.WriteString(str) -} - -func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*string)(ptr)) == "" -} - -type int8Codec struct { -} - -func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int8)(ptr)) = iter.ReadInt8() - } -} - -func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt8(*((*int8)(ptr))) -} - -func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int8)(ptr)) == 0 -} - -type int16Codec struct { -} - -func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int16)(ptr)) = iter.ReadInt16() - } -} - -func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt16(*((*int16)(ptr))) -} - -func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int16)(ptr)) == 0 -} - -type int32Codec struct { -} - -func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int32)(ptr)) = iter.ReadInt32() - } -} - -func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt32(*((*int32)(ptr))) -} - -func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int32)(ptr)) == 0 -} - -type int64Codec struct { -} - -func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*int64)(ptr)) = iter.ReadInt64() - } -} - -func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteInt64(*((*int64)(ptr))) -} - -func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*int64)(ptr)) == 0 -} - -type uint8Codec struct { -} - -func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint8)(ptr)) = iter.ReadUint8() - } -} - -func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint8(*((*uint8)(ptr))) -} - -func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint8)(ptr)) == 0 -} - -type uint16Codec struct { -} - -func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint16)(ptr)) = iter.ReadUint16() - } -} - -func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint16(*((*uint16)(ptr))) -} - -func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint16)(ptr)) == 0 -} - -type uint32Codec struct { -} - -func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint32)(ptr)) = iter.ReadUint32() - } -} - -func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint32(*((*uint32)(ptr))) -} - -func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint32)(ptr)) == 0 -} - -type uint64Codec struct { -} - -func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*uint64)(ptr)) = iter.ReadUint64() - } -} - -func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteUint64(*((*uint64)(ptr))) -} - -func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*uint64)(ptr)) == 0 -} - -type float32Codec struct { -} - -func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*float32)(ptr)) = iter.ReadFloat32() - } -} - -func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat32(*((*float32)(ptr))) -} - -func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float32)(ptr)) == 0 -} - -type float64Codec struct { -} - -func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*float64)(ptr)) = iter.ReadFloat64() - } -} - -func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteFloat64(*((*float64)(ptr))) -} - -func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return *((*float64)(ptr)) == 0 -} - -type boolCodec struct { -} - -func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.ReadNil() { - *((*bool)(ptr)) = iter.ReadBool() - } -} - -func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteBool(*((*bool)(ptr))) -} - -func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { - return !(*((*bool)(ptr))) -} - -type base64Codec struct { - sliceType *reflect2.UnsafeSliceType - sliceDecoder ValDecoder -} - -func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - codec.sliceType.UnsafeSetNil(ptr) - return - } - switch iter.WhatIsNext() { - case StringValue: - src := iter.ReadString() - dst, err := base64.StdEncoding.DecodeString(src) - if err != nil { - iter.ReportError("decode base64", err.Error()) - } else { - codec.sliceType.UnsafeSet(ptr, unsafe.Pointer(&dst)) - } - case ArrayValue: - codec.sliceDecoder.Decode(ptr, iter) - default: - iter.ReportError("base64Codec", "invalid input") - } -} - -func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { - if codec.sliceType.UnsafeIsNil(ptr) { - stream.WriteNil() - return - } - src := *((*[]byte)(ptr)) - encoding := base64.StdEncoding - stream.writeByte('"') - if len(src) != 0 { - size := encoding.EncodedLen(len(src)) - buf := make([]byte, size) - encoding.Encode(buf, src) - stream.buf = append(stream.buf, buf...) - } - stream.writeByte('"') -} - -func (codec *base64Codec) IsEmpty(ptr unsafe.Pointer) bool { - return len(*((*[]byte)(ptr))) == 0 -} diff --git a/vendor/github.com/json-iterator/go/reflect_optional.go b/vendor/github.com/json-iterator/go/reflect_optional.go deleted file mode 100644 index fa71f474..00000000 --- a/vendor/github.com/json-iterator/go/reflect_optional.go +++ /dev/null @@ -1,129 +0,0 @@ -package jsoniter - -import ( - "github.com/modern-go/reflect2" - "unsafe" -) - -func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder { - ptrType := typ.(*reflect2.UnsafePtrType) - elemType := ptrType.Elem() - decoder := decoderOfType(ctx, elemType) - return &OptionalDecoder{elemType, decoder} -} - -func encoderOfOptional(ctx *ctx, typ reflect2.Type) ValEncoder { - ptrType := typ.(*reflect2.UnsafePtrType) - elemType := ptrType.Elem() - elemEncoder := encoderOfType(ctx, elemType) - encoder := &OptionalEncoder{elemEncoder} - return encoder -} - -type OptionalDecoder struct { - ValueType reflect2.Type - ValueDecoder ValDecoder -} - -func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.ReadNil() { - *((*unsafe.Pointer)(ptr)) = nil - } else { - if *((*unsafe.Pointer)(ptr)) == nil { - //pointer to null, we have to allocate memory to hold the value - newPtr := decoder.ValueType.UnsafeNew() - decoder.ValueDecoder.Decode(newPtr, iter) - *((*unsafe.Pointer)(ptr)) = newPtr - } else { - //reuse existing instance - decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) - } - } -} - -type dereferenceDecoder struct { - // only to deference a pointer - valueType reflect2.Type - valueDecoder ValDecoder -} - -func (decoder *dereferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if *((*unsafe.Pointer)(ptr)) == nil { - //pointer to null, we have to allocate memory to hold the value - newPtr := decoder.valueType.UnsafeNew() - decoder.valueDecoder.Decode(newPtr, iter) - *((*unsafe.Pointer)(ptr)) = newPtr - } else { - //reuse existing instance - decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) - } -} - -type OptionalEncoder struct { - ValueEncoder ValEncoder -} - -func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *((*unsafe.Pointer)(ptr)) == nil { - stream.WriteNil() - } else { - encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) - } -} - -func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return *((*unsafe.Pointer)(ptr)) == nil -} - -type dereferenceEncoder struct { - ValueEncoder ValEncoder -} - -func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if *((*unsafe.Pointer)(ptr)) == nil { - stream.WriteNil() - } else { - encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) - } -} - -func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { - dePtr := *((*unsafe.Pointer)(ptr)) - if dePtr == nil { - return true - } - return encoder.ValueEncoder.IsEmpty(dePtr) -} - -func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { - deReferenced := *((*unsafe.Pointer)(ptr)) - if deReferenced == nil { - return true - } - isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil) - if !converted { - return false - } - fieldPtr := unsafe.Pointer(deReferenced) - return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) -} - -type referenceEncoder struct { - encoder ValEncoder -} - -func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - encoder.encoder.Encode(unsafe.Pointer(&ptr), stream) -} - -func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr)) -} - -type referenceDecoder struct { - decoder ValDecoder -} - -func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.decoder.Decode(unsafe.Pointer(&ptr), iter) -} diff --git a/vendor/github.com/json-iterator/go/reflect_slice.go b/vendor/github.com/json-iterator/go/reflect_slice.go deleted file mode 100644 index 9441d79d..00000000 --- a/vendor/github.com/json-iterator/go/reflect_slice.go +++ /dev/null @@ -1,99 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "unsafe" -) - -func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder { - sliceType := typ.(*reflect2.UnsafeSliceType) - decoder := decoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) - return &sliceDecoder{sliceType, decoder} -} - -func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder { - sliceType := typ.(*reflect2.UnsafeSliceType) - encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem()) - return &sliceEncoder{sliceType, encoder} -} - -type sliceEncoder struct { - sliceType *reflect2.UnsafeSliceType - elemEncoder ValEncoder -} - -func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - if encoder.sliceType.UnsafeIsNil(ptr) { - stream.WriteNil() - return - } - length := encoder.sliceType.UnsafeLengthOf(ptr) - if length == 0 { - stream.WriteEmptyArray() - return - } - stream.WriteArrayStart() - encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream) - for i := 1; i < length; i++ { - stream.WriteMore() - elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i) - encoder.elemEncoder.Encode(elemPtr, stream) - } - stream.WriteArrayEnd() - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error()) - } -} - -func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.sliceType.UnsafeLengthOf(ptr) == 0 -} - -type sliceDecoder struct { - sliceType *reflect2.UnsafeSliceType - elemDecoder ValDecoder -} - -func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.doDecode(ptr, iter) - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error()) - } -} - -func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { - c := iter.nextToken() - sliceType := decoder.sliceType - if c == 'n' { - iter.skipThreeBytes('u', 'l', 'l') - sliceType.UnsafeSetNil(ptr) - return - } - if c != '[' { - iter.ReportError("decode slice", "expect [ or n, but found "+string([]byte{c})) - return - } - c = iter.nextToken() - if c == ']' { - sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0)) - return - } - iter.unreadByte() - sliceType.UnsafeGrow(ptr, 1) - elemPtr := sliceType.UnsafeGetIndex(ptr, 0) - decoder.elemDecoder.Decode(elemPtr, iter) - length := 1 - for c = iter.nextToken(); c == ','; c = iter.nextToken() { - idx := length - length += 1 - sliceType.UnsafeGrow(ptr, length) - elemPtr = sliceType.UnsafeGetIndex(ptr, idx) - decoder.elemDecoder.Decode(elemPtr, iter) - } - if c != ']' { - iter.ReportError("decode slice", "expect ], but found "+string([]byte{c})) - return - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go deleted file mode 100644 index 92ae912d..00000000 --- a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go +++ /dev/null @@ -1,1097 +0,0 @@ -package jsoniter - -import ( - "fmt" - "io" - "strings" - "unsafe" - - "github.com/modern-go/reflect2" -) - -func decoderOfStruct(ctx *ctx, typ reflect2.Type) ValDecoder { - bindings := map[string]*Binding{} - structDescriptor := describeStruct(ctx, typ) - for _, binding := range structDescriptor.Fields { - for _, fromName := range binding.FromNames { - old := bindings[fromName] - if old == nil { - bindings[fromName] = binding - continue - } - ignoreOld, ignoreNew := resolveConflictBinding(ctx.frozenConfig, old, binding) - if ignoreOld { - delete(bindings, fromName) - } - if !ignoreNew { - bindings[fromName] = binding - } - } - } - fields := map[string]*structFieldDecoder{} - for k, binding := range bindings { - fields[k] = binding.Decoder.(*structFieldDecoder) - } - - if !ctx.caseSensitive() { - for k, binding := range bindings { - if _, found := fields[strings.ToLower(k)]; !found { - fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder) - } - } - } - - return createStructDecoder(ctx, typ, fields) -} - -func createStructDecoder(ctx *ctx, typ reflect2.Type, fields map[string]*structFieldDecoder) ValDecoder { - if ctx.disallowUnknownFields { - return &generalStructDecoder{typ: typ, fields: fields, disallowUnknownFields: true} - } - knownHash := map[int64]struct{}{ - 0: {}, - } - - switch len(fields) { - case 0: - return &skipObjectDecoder{typ} - case 1: - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder} - } - case 2: - var fieldHash1 int64 - var fieldHash2 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldHash1 == 0 { - fieldHash1 = fieldHash - fieldDecoder1 = fieldDecoder - } else { - fieldHash2 = fieldHash - fieldDecoder2 = fieldDecoder - } - } - return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2} - case 3: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } - } - return &threeFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3} - case 4: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } - } - return &fourFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4} - case 5: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } - } - return &fiveFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5} - case 6: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } - } - return &sixFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6} - case 7: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } - } - return &sevenFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7} - case 8: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldName8 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else if fieldName7 == 0 { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } else { - fieldName8 = fieldHash - fieldDecoder8 = fieldDecoder - } - } - return &eightFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, - fieldName8, fieldDecoder8} - case 9: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldName8 int64 - var fieldName9 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - var fieldDecoder9 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else if fieldName7 == 0 { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } else if fieldName8 == 0 { - fieldName8 = fieldHash - fieldDecoder8 = fieldDecoder - } else { - fieldName9 = fieldHash - fieldDecoder9 = fieldDecoder - } - } - return &nineFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, - fieldName8, fieldDecoder8, - fieldName9, fieldDecoder9} - case 10: - var fieldName1 int64 - var fieldName2 int64 - var fieldName3 int64 - var fieldName4 int64 - var fieldName5 int64 - var fieldName6 int64 - var fieldName7 int64 - var fieldName8 int64 - var fieldName9 int64 - var fieldName10 int64 - var fieldDecoder1 *structFieldDecoder - var fieldDecoder2 *structFieldDecoder - var fieldDecoder3 *structFieldDecoder - var fieldDecoder4 *structFieldDecoder - var fieldDecoder5 *structFieldDecoder - var fieldDecoder6 *structFieldDecoder - var fieldDecoder7 *structFieldDecoder - var fieldDecoder8 *structFieldDecoder - var fieldDecoder9 *structFieldDecoder - var fieldDecoder10 *structFieldDecoder - for fieldName, fieldDecoder := range fields { - fieldHash := calcHash(fieldName, ctx.caseSensitive()) - _, known := knownHash[fieldHash] - if known { - return &generalStructDecoder{typ, fields, false} - } - knownHash[fieldHash] = struct{}{} - if fieldName1 == 0 { - fieldName1 = fieldHash - fieldDecoder1 = fieldDecoder - } else if fieldName2 == 0 { - fieldName2 = fieldHash - fieldDecoder2 = fieldDecoder - } else if fieldName3 == 0 { - fieldName3 = fieldHash - fieldDecoder3 = fieldDecoder - } else if fieldName4 == 0 { - fieldName4 = fieldHash - fieldDecoder4 = fieldDecoder - } else if fieldName5 == 0 { - fieldName5 = fieldHash - fieldDecoder5 = fieldDecoder - } else if fieldName6 == 0 { - fieldName6 = fieldHash - fieldDecoder6 = fieldDecoder - } else if fieldName7 == 0 { - fieldName7 = fieldHash - fieldDecoder7 = fieldDecoder - } else if fieldName8 == 0 { - fieldName8 = fieldHash - fieldDecoder8 = fieldDecoder - } else if fieldName9 == 0 { - fieldName9 = fieldHash - fieldDecoder9 = fieldDecoder - } else { - fieldName10 = fieldHash - fieldDecoder10 = fieldDecoder - } - } - return &tenFieldsStructDecoder{typ, - fieldName1, fieldDecoder1, - fieldName2, fieldDecoder2, - fieldName3, fieldDecoder3, - fieldName4, fieldDecoder4, - fieldName5, fieldDecoder5, - fieldName6, fieldDecoder6, - fieldName7, fieldDecoder7, - fieldName8, fieldDecoder8, - fieldName9, fieldDecoder9, - fieldName10, fieldDecoder10} - } - return &generalStructDecoder{typ, fields, false} -} - -type generalStructDecoder struct { - typ reflect2.Type - fields map[string]*structFieldDecoder - disallowUnknownFields bool -} - -func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - var c byte - for c = ','; c == ','; c = iter.nextToken() { - decoder.decodeOneField(ptr, iter) - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - if c != '}' { - iter.ReportError("struct Decode", `expect }, but found `+string([]byte{c})) - } - iter.decrementDepth() -} - -func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) { - var field string - var fieldDecoder *structFieldDecoder - if iter.cfg.objectFieldMustBeSimpleString { - fieldBytes := iter.ReadStringAsSlice() - field = *(*string)(unsafe.Pointer(&fieldBytes)) - fieldDecoder = decoder.fields[field] - if fieldDecoder == nil && !iter.cfg.caseSensitive { - fieldDecoder = decoder.fields[strings.ToLower(field)] - } - } else { - field = iter.ReadString() - fieldDecoder = decoder.fields[field] - if fieldDecoder == nil && !iter.cfg.caseSensitive { - fieldDecoder = decoder.fields[strings.ToLower(field)] - } - } - if fieldDecoder == nil { - if decoder.disallowUnknownFields { - msg := "found unknown field: " + field - iter.ReportError("ReadObject", msg) - } - c := iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - iter.Skip() - return - } - c := iter.nextToken() - if c != ':' { - iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c})) - } - fieldDecoder.Decode(ptr, iter) -} - -type skipObjectDecoder struct { - typ reflect2.Type -} - -func (decoder *skipObjectDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - valueType := iter.WhatIsNext() - if valueType != ObjectValue && valueType != NilValue { - iter.ReportError("skipObjectDecoder", "expect object or null") - return - } - iter.Skip() -} - -type oneFieldStructDecoder struct { - typ reflect2.Type - fieldHash int64 - fieldDecoder *structFieldDecoder -} - -func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - if iter.readFieldHash() == decoder.fieldHash { - decoder.fieldDecoder.Decode(ptr, iter) - } else { - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type twoFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder -} - -func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type threeFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder -} - -func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type fourFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder -} - -func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type fiveFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder -} - -func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type sixFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder -} - -func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type sevenFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder -} - -func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type eightFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder - fieldHash8 int64 - fieldDecoder8 *structFieldDecoder -} - -func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - case decoder.fieldHash8: - decoder.fieldDecoder8.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type nineFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder - fieldHash8 int64 - fieldDecoder8 *structFieldDecoder - fieldHash9 int64 - fieldDecoder9 *structFieldDecoder -} - -func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - case decoder.fieldHash8: - decoder.fieldDecoder8.Decode(ptr, iter) - case decoder.fieldHash9: - decoder.fieldDecoder9.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type tenFieldsStructDecoder struct { - typ reflect2.Type - fieldHash1 int64 - fieldDecoder1 *structFieldDecoder - fieldHash2 int64 - fieldDecoder2 *structFieldDecoder - fieldHash3 int64 - fieldDecoder3 *structFieldDecoder - fieldHash4 int64 - fieldDecoder4 *structFieldDecoder - fieldHash5 int64 - fieldDecoder5 *structFieldDecoder - fieldHash6 int64 - fieldDecoder6 *structFieldDecoder - fieldHash7 int64 - fieldDecoder7 *structFieldDecoder - fieldHash8 int64 - fieldDecoder8 *structFieldDecoder - fieldHash9 int64 - fieldDecoder9 *structFieldDecoder - fieldHash10 int64 - fieldDecoder10 *structFieldDecoder -} - -func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if !iter.readObjectStart() { - return - } - if !iter.incrementDepth() { - return - } - for { - switch iter.readFieldHash() { - case decoder.fieldHash1: - decoder.fieldDecoder1.Decode(ptr, iter) - case decoder.fieldHash2: - decoder.fieldDecoder2.Decode(ptr, iter) - case decoder.fieldHash3: - decoder.fieldDecoder3.Decode(ptr, iter) - case decoder.fieldHash4: - decoder.fieldDecoder4.Decode(ptr, iter) - case decoder.fieldHash5: - decoder.fieldDecoder5.Decode(ptr, iter) - case decoder.fieldHash6: - decoder.fieldDecoder6.Decode(ptr, iter) - case decoder.fieldHash7: - decoder.fieldDecoder7.Decode(ptr, iter) - case decoder.fieldHash8: - decoder.fieldDecoder8.Decode(ptr, iter) - case decoder.fieldHash9: - decoder.fieldDecoder9.Decode(ptr, iter) - case decoder.fieldHash10: - decoder.fieldDecoder10.Decode(ptr, iter) - default: - iter.Skip() - } - if iter.isObjectEnd() { - break - } - } - if iter.Error != nil && iter.Error != io.EOF && len(decoder.typ.Type1().Name()) != 0 { - iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error()) - } - iter.decrementDepth() -} - -type structFieldDecoder struct { - field reflect2.StructField - fieldDecoder ValDecoder -} - -func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - fieldPtr := decoder.field.UnsafeGet(ptr) - decoder.fieldDecoder.Decode(fieldPtr, iter) - if iter.Error != nil && iter.Error != io.EOF { - iter.Error = fmt.Errorf("%s: %s", decoder.field.Name(), iter.Error.Error()) - } -} - -type stringModeStringDecoder struct { - elemDecoder ValDecoder - cfg *frozenConfig -} - -func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - decoder.elemDecoder.Decode(ptr, iter) - str := *((*string)(ptr)) - tempIter := decoder.cfg.BorrowIterator([]byte(str)) - defer decoder.cfg.ReturnIterator(tempIter) - *((*string)(ptr)) = tempIter.ReadString() -} - -type stringModeNumberDecoder struct { - elemDecoder ValDecoder -} - -func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { - if iter.WhatIsNext() == NilValue { - decoder.elemDecoder.Decode(ptr, iter) - return - } - - c := iter.nextToken() - if c != '"' { - iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) - return - } - decoder.elemDecoder.Decode(ptr, iter) - if iter.Error != nil { - return - } - c = iter.readByte() - if c != '"' { - iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c})) - return - } -} diff --git a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go deleted file mode 100644 index 152e3ef5..00000000 --- a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go +++ /dev/null @@ -1,211 +0,0 @@ -package jsoniter - -import ( - "fmt" - "github.com/modern-go/reflect2" - "io" - "reflect" - "unsafe" -) - -func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder { - type bindingTo struct { - binding *Binding - toName string - ignored bool - } - orderedBindings := []*bindingTo{} - structDescriptor := describeStruct(ctx, typ) - for _, binding := range structDescriptor.Fields { - for _, toName := range binding.ToNames { - new := &bindingTo{ - binding: binding, - toName: toName, - } - for _, old := range orderedBindings { - if old.toName != toName { - continue - } - old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding) - } - orderedBindings = append(orderedBindings, new) - } - } - if len(orderedBindings) == 0 { - return &emptyStructEncoder{} - } - finalOrderedFields := []structFieldTo{} - for _, bindingTo := range orderedBindings { - if !bindingTo.ignored { - finalOrderedFields = append(finalOrderedFields, structFieldTo{ - encoder: bindingTo.binding.Encoder.(*structFieldEncoder), - toName: bindingTo.toName, - }) - } - } - return &structEncoder{typ, finalOrderedFields} -} - -func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty { - encoder := createEncoderOfNative(ctx, typ) - if encoder != nil { - return encoder - } - kind := typ.Kind() - switch kind { - case reflect.Interface: - return &dynamicEncoder{typ} - case reflect.Struct: - return &structEncoder{typ: typ} - case reflect.Array: - return &arrayEncoder{} - case reflect.Slice: - return &sliceEncoder{} - case reflect.Map: - return encoderOfMap(ctx, typ) - case reflect.Ptr: - return &OptionalEncoder{} - default: - return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)} - } -} - -func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) { - newTagged := new.Field.Tag().Get(cfg.getTagKey()) != "" - oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != "" - if newTagged { - if oldTagged { - if len(old.levels) > len(new.levels) { - return true, false - } else if len(new.levels) > len(old.levels) { - return false, true - } else { - return true, true - } - } else { - return true, false - } - } else { - if oldTagged { - return true, false - } - if len(old.levels) > len(new.levels) { - return true, false - } else if len(new.levels) > len(old.levels) { - return false, true - } else { - return true, true - } - } -} - -type structFieldEncoder struct { - field reflect2.StructField - fieldEncoder ValEncoder - omitempty bool -} - -func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - fieldPtr := encoder.field.UnsafeGet(ptr) - encoder.fieldEncoder.Encode(fieldPtr, stream) - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error()) - } -} - -func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool { - fieldPtr := encoder.field.UnsafeGet(ptr) - return encoder.fieldEncoder.IsEmpty(fieldPtr) -} - -func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool { - isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil) - if !converted { - return false - } - fieldPtr := encoder.field.UnsafeGet(ptr) - return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr) -} - -type IsEmbeddedPtrNil interface { - IsEmbeddedPtrNil(ptr unsafe.Pointer) bool -} - -type structEncoder struct { - typ reflect2.Type - fields []structFieldTo -} - -type structFieldTo struct { - encoder *structFieldEncoder - toName string -} - -func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteObjectStart() - isNotFirst := false - for _, field := range encoder.fields { - if field.encoder.omitempty && field.encoder.IsEmpty(ptr) { - continue - } - if field.encoder.IsEmbeddedPtrNil(ptr) { - continue - } - if isNotFirst { - stream.WriteMore() - } - stream.WriteObjectField(field.toName) - field.encoder.Encode(ptr, stream) - isNotFirst = true - } - stream.WriteObjectEnd() - if stream.Error != nil && stream.Error != io.EOF { - stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error()) - } -} - -func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type emptyStructEncoder struct { -} - -func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.WriteEmptyObject() -} - -func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return false -} - -type stringModeNumberEncoder struct { - elemEncoder ValEncoder -} - -func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - stream.writeByte('"') - encoder.elemEncoder.Encode(ptr, stream) - stream.writeByte('"') -} - -func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.elemEncoder.IsEmpty(ptr) -} - -type stringModeStringEncoder struct { - elemEncoder ValEncoder - cfg *frozenConfig -} - -func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { - tempStream := encoder.cfg.BorrowStream(nil) - tempStream.Attachment = stream.Attachment - defer encoder.cfg.ReturnStream(tempStream) - encoder.elemEncoder.Encode(ptr, tempStream) - stream.WriteString(string(tempStream.Buffer())) -} - -func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { - return encoder.elemEncoder.IsEmpty(ptr) -} diff --git a/vendor/github.com/json-iterator/go/stream.go b/vendor/github.com/json-iterator/go/stream.go deleted file mode 100644 index 23d8a3ad..00000000 --- a/vendor/github.com/json-iterator/go/stream.go +++ /dev/null @@ -1,210 +0,0 @@ -package jsoniter - -import ( - "io" -) - -// stream is a io.Writer like object, with JSON specific write functions. -// Error is not returned as return value, but stored as Error member on this stream instance. -type Stream struct { - cfg *frozenConfig - out io.Writer - buf []byte - Error error - indention int - Attachment interface{} // open for customized encoder -} - -// NewStream create new stream instance. -// cfg can be jsoniter.ConfigDefault. -// out can be nil if write to internal buffer. -// bufSize is the initial size for the internal buffer in bytes. -func NewStream(cfg API, out io.Writer, bufSize int) *Stream { - return &Stream{ - cfg: cfg.(*frozenConfig), - out: out, - buf: make([]byte, 0, bufSize), - Error: nil, - indention: 0, - } -} - -// Pool returns a pool can provide more stream with same configuration -func (stream *Stream) Pool() StreamPool { - return stream.cfg -} - -// Reset reuse this stream instance by assign a new writer -func (stream *Stream) Reset(out io.Writer) { - stream.out = out - stream.buf = stream.buf[:0] -} - -// Available returns how many bytes are unused in the buffer. -func (stream *Stream) Available() int { - return cap(stream.buf) - len(stream.buf) -} - -// Buffered returns the number of bytes that have been written into the current buffer. -func (stream *Stream) Buffered() int { - return len(stream.buf) -} - -// Buffer if writer is nil, use this method to take the result -func (stream *Stream) Buffer() []byte { - return stream.buf -} - -// SetBuffer allows to append to the internal buffer directly -func (stream *Stream) SetBuffer(buf []byte) { - stream.buf = buf -} - -// Write writes the contents of p into the buffer. -// It returns the number of bytes written. -// If nn < len(p), it also returns an error explaining -// why the write is short. -func (stream *Stream) Write(p []byte) (nn int, err error) { - stream.buf = append(stream.buf, p...) - if stream.out != nil { - nn, err = stream.out.Write(stream.buf) - stream.buf = stream.buf[nn:] - return - } - return len(p), nil -} - -// WriteByte writes a single byte. -func (stream *Stream) writeByte(c byte) { - stream.buf = append(stream.buf, c) -} - -func (stream *Stream) writeTwoBytes(c1 byte, c2 byte) { - stream.buf = append(stream.buf, c1, c2) -} - -func (stream *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { - stream.buf = append(stream.buf, c1, c2, c3) -} - -func (stream *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { - stream.buf = append(stream.buf, c1, c2, c3, c4) -} - -func (stream *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { - stream.buf = append(stream.buf, c1, c2, c3, c4, c5) -} - -// Flush writes any buffered data to the underlying io.Writer. -func (stream *Stream) Flush() error { - if stream.out == nil { - return nil - } - if stream.Error != nil { - return stream.Error - } - _, err := stream.out.Write(stream.buf) - if err != nil { - if stream.Error == nil { - stream.Error = err - } - return err - } - stream.buf = stream.buf[:0] - return nil -} - -// WriteRaw write string out without quotes, just like []byte -func (stream *Stream) WriteRaw(s string) { - stream.buf = append(stream.buf, s...) -} - -// WriteNil write null to stream -func (stream *Stream) WriteNil() { - stream.writeFourBytes('n', 'u', 'l', 'l') -} - -// WriteTrue write true to stream -func (stream *Stream) WriteTrue() { - stream.writeFourBytes('t', 'r', 'u', 'e') -} - -// WriteFalse write false to stream -func (stream *Stream) WriteFalse() { - stream.writeFiveBytes('f', 'a', 'l', 's', 'e') -} - -// WriteBool write true or false into stream -func (stream *Stream) WriteBool(val bool) { - if val { - stream.WriteTrue() - } else { - stream.WriteFalse() - } -} - -// WriteObjectStart write { with possible indention -func (stream *Stream) WriteObjectStart() { - stream.indention += stream.cfg.indentionStep - stream.writeByte('{') - stream.writeIndention(0) -} - -// WriteObjectField write "field": with possible indention -func (stream *Stream) WriteObjectField(field string) { - stream.WriteString(field) - if stream.indention > 0 { - stream.writeTwoBytes(':', ' ') - } else { - stream.writeByte(':') - } -} - -// WriteObjectEnd write } with possible indention -func (stream *Stream) WriteObjectEnd() { - stream.writeIndention(stream.cfg.indentionStep) - stream.indention -= stream.cfg.indentionStep - stream.writeByte('}') -} - -// WriteEmptyObject write {} -func (stream *Stream) WriteEmptyObject() { - stream.writeByte('{') - stream.writeByte('}') -} - -// WriteMore write , with possible indention -func (stream *Stream) WriteMore() { - stream.writeByte(',') - stream.writeIndention(0) -} - -// WriteArrayStart write [ with possible indention -func (stream *Stream) WriteArrayStart() { - stream.indention += stream.cfg.indentionStep - stream.writeByte('[') - stream.writeIndention(0) -} - -// WriteEmptyArray write [] -func (stream *Stream) WriteEmptyArray() { - stream.writeTwoBytes('[', ']') -} - -// WriteArrayEnd write ] with possible indention -func (stream *Stream) WriteArrayEnd() { - stream.writeIndention(stream.cfg.indentionStep) - stream.indention -= stream.cfg.indentionStep - stream.writeByte(']') -} - -func (stream *Stream) writeIndention(delta int) { - if stream.indention == 0 { - return - } - stream.writeByte('\n') - toWrite := stream.indention - delta - for i := 0; i < toWrite; i++ { - stream.buf = append(stream.buf, ' ') - } -} diff --git a/vendor/github.com/json-iterator/go/stream_float.go b/vendor/github.com/json-iterator/go/stream_float.go deleted file mode 100644 index 826aa594..00000000 --- a/vendor/github.com/json-iterator/go/stream_float.go +++ /dev/null @@ -1,111 +0,0 @@ -package jsoniter - -import ( - "fmt" - "math" - "strconv" -) - -var pow10 []uint64 - -func init() { - pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} -} - -// WriteFloat32 write float32 to stream -func (stream *Stream) WriteFloat32(val float32) { - if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - abs := math.Abs(float64(val)) - fmt := byte('f') - // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs != 0 { - if float32(abs) < 1e-6 || float32(abs) >= 1e21 { - fmt = 'e' - } - } - stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32) -} - -// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster -func (stream *Stream) WriteFloat32Lossy(val float32) { - if math.IsInf(float64(val), 0) || math.IsNaN(float64(val)) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - if val < 0 { - stream.writeByte('-') - val = -val - } - if val > 0x4ffffff { - stream.WriteFloat32(val) - return - } - precision := 6 - exp := uint64(1000000) // 6 - lval := uint64(float64(val)*float64(exp) + 0.5) - stream.WriteUint64(lval / exp) - fval := lval % exp - if fval == 0 { - return - } - stream.writeByte('.') - for p := precision - 1; p > 0 && fval < pow10[p]; p-- { - stream.writeByte('0') - } - stream.WriteUint64(fval) - for stream.buf[len(stream.buf)-1] == '0' { - stream.buf = stream.buf[:len(stream.buf)-1] - } -} - -// WriteFloat64 write float64 to stream -func (stream *Stream) WriteFloat64(val float64) { - if math.IsInf(val, 0) || math.IsNaN(val) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - abs := math.Abs(val) - fmt := byte('f') - // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. - if abs != 0 { - if abs < 1e-6 || abs >= 1e21 { - fmt = 'e' - } - } - stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64) -} - -// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster -func (stream *Stream) WriteFloat64Lossy(val float64) { - if math.IsInf(val, 0) || math.IsNaN(val) { - stream.Error = fmt.Errorf("unsupported value: %f", val) - return - } - if val < 0 { - stream.writeByte('-') - val = -val - } - if val > 0x4ffffff { - stream.WriteFloat64(val) - return - } - precision := 6 - exp := uint64(1000000) // 6 - lval := uint64(val*float64(exp) + 0.5) - stream.WriteUint64(lval / exp) - fval := lval % exp - if fval == 0 { - return - } - stream.writeByte('.') - for p := precision - 1; p > 0 && fval < pow10[p]; p-- { - stream.writeByte('0') - } - stream.WriteUint64(fval) - for stream.buf[len(stream.buf)-1] == '0' { - stream.buf = stream.buf[:len(stream.buf)-1] - } -} diff --git a/vendor/github.com/json-iterator/go/stream_int.go b/vendor/github.com/json-iterator/go/stream_int.go deleted file mode 100644 index d1059ee4..00000000 --- a/vendor/github.com/json-iterator/go/stream_int.go +++ /dev/null @@ -1,190 +0,0 @@ -package jsoniter - -var digits []uint32 - -func init() { - digits = make([]uint32, 1000) - for i := uint32(0); i < 1000; i++ { - digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' - if i < 10 { - digits[i] += 2 << 24 - } else if i < 100 { - digits[i] += 1 << 24 - } - } -} - -func writeFirstBuf(space []byte, v uint32) []byte { - start := v >> 24 - if start == 0 { - space = append(space, byte(v>>16), byte(v>>8)) - } else if start == 1 { - space = append(space, byte(v>>8)) - } - space = append(space, byte(v)) - return space -} - -func writeBuf(buf []byte, v uint32) []byte { - return append(buf, byte(v>>16), byte(v>>8), byte(v)) -} - -// WriteUint8 write uint8 to stream -func (stream *Stream) WriteUint8(val uint8) { - stream.buf = writeFirstBuf(stream.buf, digits[val]) -} - -// WriteInt8 write int8 to stream -func (stream *Stream) WriteInt8(nval int8) { - var val uint8 - if nval < 0 { - val = uint8(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint8(nval) - } - stream.buf = writeFirstBuf(stream.buf, digits[val]) -} - -// WriteUint16 write uint16 to stream -func (stream *Stream) WriteUint16(val uint16) { - q1 := val / 1000 - if q1 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[val]) - return - } - r1 := val - q1*1000 - stream.buf = writeFirstBuf(stream.buf, digits[q1]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return -} - -// WriteInt16 write int16 to stream -func (stream *Stream) WriteInt16(nval int16) { - var val uint16 - if nval < 0 { - val = uint16(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint16(nval) - } - stream.WriteUint16(val) -} - -// WriteUint32 write uint32 to stream -func (stream *Stream) WriteUint32(val uint32) { - q1 := val / 1000 - if q1 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[val]) - return - } - r1 := val - q1*1000 - q2 := q1 / 1000 - if q2 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q1]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r2 := q1 - q2*1000 - q3 := q2 / 1000 - if q3 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q2]) - } else { - r3 := q2 - q3*1000 - stream.buf = append(stream.buf, byte(q3+'0')) - stream.buf = writeBuf(stream.buf, digits[r3]) - } - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) -} - -// WriteInt32 write int32 to stream -func (stream *Stream) WriteInt32(nval int32) { - var val uint32 - if nval < 0 { - val = uint32(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint32(nval) - } - stream.WriteUint32(val) -} - -// WriteUint64 write uint64 to stream -func (stream *Stream) WriteUint64(val uint64) { - q1 := val / 1000 - if q1 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[val]) - return - } - r1 := val - q1*1000 - q2 := q1 / 1000 - if q2 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q1]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r2 := q1 - q2*1000 - q3 := q2 / 1000 - if q3 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q2]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r3 := q2 - q3*1000 - q4 := q3 / 1000 - if q4 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q3]) - stream.buf = writeBuf(stream.buf, digits[r3]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r4 := q3 - q4*1000 - q5 := q4 / 1000 - if q5 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q4]) - stream.buf = writeBuf(stream.buf, digits[r4]) - stream.buf = writeBuf(stream.buf, digits[r3]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) - return - } - r5 := q4 - q5*1000 - q6 := q5 / 1000 - if q6 == 0 { - stream.buf = writeFirstBuf(stream.buf, digits[q5]) - } else { - stream.buf = writeFirstBuf(stream.buf, digits[q6]) - r6 := q5 - q6*1000 - stream.buf = writeBuf(stream.buf, digits[r6]) - } - stream.buf = writeBuf(stream.buf, digits[r5]) - stream.buf = writeBuf(stream.buf, digits[r4]) - stream.buf = writeBuf(stream.buf, digits[r3]) - stream.buf = writeBuf(stream.buf, digits[r2]) - stream.buf = writeBuf(stream.buf, digits[r1]) -} - -// WriteInt64 write int64 to stream -func (stream *Stream) WriteInt64(nval int64) { - var val uint64 - if nval < 0 { - val = uint64(-nval) - stream.buf = append(stream.buf, '-') - } else { - val = uint64(nval) - } - stream.WriteUint64(val) -} - -// WriteInt write int to stream -func (stream *Stream) WriteInt(val int) { - stream.WriteInt64(int64(val)) -} - -// WriteUint write uint to stream -func (stream *Stream) WriteUint(val uint) { - stream.WriteUint64(uint64(val)) -} diff --git a/vendor/github.com/json-iterator/go/stream_str.go b/vendor/github.com/json-iterator/go/stream_str.go deleted file mode 100644 index 54c2ba0b..00000000 --- a/vendor/github.com/json-iterator/go/stream_str.go +++ /dev/null @@ -1,372 +0,0 @@ -package jsoniter - -import ( - "unicode/utf8" -) - -// htmlSafeSet holds the value true if the ASCII character with the given -// array position can be safely represented inside a JSON string, embedded -// inside of HTML