From 9b638b866662778f254dba167f414dbddab325ba Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 11:46:01 -0700 Subject: fixup! Fix compilation with Go 1.20 This invovles upgrading golangci-lint, as v1.51.0 is needed to support Go 1.20. --- .golangci.yml | 1 + Makefile | 2 +- tools/src/golangci-lint/go.mod | 81 +++++++++--------- tools/src/golangci-lint/go.sum | 189 ++++++++++++++++++++++------------------- 4 files changed, 146 insertions(+), 127 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 866c5a4..3675d1d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -82,6 +82,7 @@ issues: - godot - gofumpt - gosec + - musttag - noctx - stylecheck - path: "borrowed_.*_test\\.go" diff --git a/Makefile b/Makefile index 867bae9..0bb62fe 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ go-mod-tidy: go-mod-tidy: go-mod-tidy/main go-mod-tidy/main: rm -f go.sum - go mod tidy -go $(goversion) -compat $(goversion) + go mod tidy -go 1.20 -compat $(goversion) .PHONY: go-mod-tidy/main go-mod-tidy: $(patsubst tools/src/%/go.mod,go-mod-tidy/tools/%,$(wildcard tools/src/*/go.mod)) diff --git a/tools/src/golangci-lint/go.mod b/tools/src/golangci-lint/go.mod index 6461446..4d016f0 100644 --- a/tools/src/golangci-lint/go.mod +++ b/tools/src/golangci-lint/go.mod @@ -2,11 +2,12 @@ module local go 1.18 -require github.com/golangci/golangci-lint v1.50.1 +require github.com/golangci/golangci-lint v1.51.1 require ( - 4d63.com/gochecknoglobals v0.1.0 // indirect - github.com/Abirdcfly/dupword v0.0.7 // indirect + 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect + 4d63.com/gochecknoglobals v0.2.1 // indirect + github.com/Abirdcfly/dupword v0.0.9 // indirect github.com/Antonboom/errname v0.1.7 // indirect github.com/Antonboom/nilnil v0.1.1 // indirect github.com/BurntSushi/toml v1.2.1 // indirect @@ -27,27 +28,27 @@ require ( github.com/butuzov/ireturn v0.1.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/charithe/durationcheck v0.0.9 // indirect - github.com/chavacava/garif v0.0.0-20220630083739-93517212f375 // indirect + github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect - github.com/daixiang0/gci v0.8.1 // indirect + github.com/daixiang0/gci v0.9.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/denis-tingaikin/go-header v0.4.3 // indirect github.com/esimonov/ifshort v1.0.4 // indirect github.com/ettle/strcase v0.1.1 // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/fatih/color v1.14.1 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/firefart/nonamedreturns v1.0.4 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect github.com/go-critic/go-critic v0.6.5 // indirect github.com/go-toolsmith/astcast v1.0.0 // indirect - github.com/go-toolsmith/astcopy v1.0.2 // indirect + github.com/go-toolsmith/astcopy v1.0.3 // indirect github.com/go-toolsmith/astequal v1.0.3 // indirect github.com/go-toolsmith/astfmt v1.0.0 // indirect github.com/go-toolsmith/astp v1.0.0 // indirect github.com/go-toolsmith/strparse v1.0.0 // indirect github.com/go-toolsmith/typep v1.0.2 // indirect - github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect + github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/golang/protobuf v1.5.2 // indirect @@ -57,11 +58,11 @@ require ( github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // indirect github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect - github.com/golangci/misspell v0.3.5 // indirect + github.com/golangci/misspell v0.4.0 // indirect github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect + github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.4.2 // indirect github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect @@ -76,40 +77,41 @@ require ( github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect github.com/julz/importas v0.1.0 // indirect - github.com/kisielk/errcheck v1.6.2 // indirect + github.com/junk1tm/musttag v0.4.4 // indirect + github.com/kisielk/errcheck v1.6.3 // indirect github.com/kisielk/gotool v1.0.0 // indirect github.com/kkHAIKE/contextcheck v1.1.3 // indirect github.com/kulti/thelper v0.6.3 // indirect github.com/kunwardeep/paralleltest v1.0.6 // indirect - github.com/kyoh86/exportloopref v0.1.8 // indirect + github.com/kyoh86/exportloopref v0.1.11 // indirect github.com/ldez/gomoddirectives v0.2.3 // indirect - github.com/ldez/tagliatelle v0.3.1 // indirect - github.com/leonklingele/grouper v1.1.0 // indirect + github.com/ldez/tagliatelle v0.4.0 // indirect + github.com/leonklingele/grouper v1.1.1 // indirect github.com/lufeee/execinquery v1.2.1 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/maratori/testableexamples v1.0.0 // indirect github.com/maratori/testpackage v1.1.0 // indirect github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mbilski/exhaustivestruct v1.2.0 // indirect - github.com/mgechev/revive v1.2.4 // indirect + github.com/mgechev/revive v1.2.5 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moricho/tparallel v0.2.1 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect - github.com/nishanths/exhaustive v0.8.3 // indirect + github.com/nishanths/exhaustive v0.9.5 // indirect github.com/nishanths/predeclared v0.2.2 // indirect + github.com/nunnatsa/ginkgolinter v0.8.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect - github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/polyfloyd/go-errorlint v1.0.5 // indirect + github.com/polyfloyd/go-errorlint v1.0.6 // indirect github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect @@ -118,35 +120,36 @@ require ( github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f // indirect github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/ryancurrah/gomodguard v1.2.4 // indirect - github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect - github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect + github.com/ryancurrah/gomodguard v1.3.0 // indirect + github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect + github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect - github.com/sashamelentyev/usestdlibvars v1.20.0 // indirect - github.com/securego/gosec/v2 v2.13.1 // indirect + github.com/sashamelentyev/usestdlibvars v1.21.1 // indirect + github.com/securego/gosec/v2 v2.14.0 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/sivchari/containedctx v1.0.2 // indirect github.com/sivchari/nosnakecase v1.7.0 // indirect - github.com/sivchari/tenv v1.7.0 // indirect + github.com/sivchari/tenv v1.7.1 // indirect github.com/sonatard/noctx v0.0.1 // indirect - github.com/sourcegraph/go-diff v0.6.1 // indirect + github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/cobra v1.6.0 // indirect + github.com/spf13/cobra v1.6.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.12.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect - github.com/stretchr/objx v0.4.0 // indirect - github.com/stretchr/testify v1.8.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/testify v1.8.1 // indirect github.com/subosito/gotenv v1.4.1 // indirect + github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect github.com/tdakkota/asciicheck v0.1.1 // indirect github.com/tetafro/godot v1.4.11 // indirect - github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect + github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e // indirect github.com/timonwong/loggercheck v0.9.3 // indirect - github.com/tomarrell/wrapcheck/v2 v2.7.0 // indirect + github.com/tomarrell/wrapcheck/v2 v2.8.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.0.3 // indirect github.com/ultraware/whitespace v0.0.5 // indirect @@ -158,19 +161,19 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.17.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 // indirect - golang.org/x/mod v0.6.0 // indirect - golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect - golang.org/x/sys v0.1.0 // indirect - golang.org/x/text v0.3.8 // indirect - golang.org/x/tools v0.2.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect + golang.org/x/mod v0.7.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect + golang.org/x/tools v0.5.0 // indirect google.golang.org/protobuf v1.28.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 - honnef.co/go/tools v0.3.3 // indirect + honnef.co/go/tools v0.4.0 // indirect mvdan.cc/gofumpt v0.4.0 // indirect mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect - mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 // indirect + mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect ) diff --git a/tools/src/golangci-lint/go.sum b/tools/src/golangci-lint/go.sum index db26e7e..6ab4dcd 100644 --- a/tools/src/golangci-lint/go.sum +++ b/tools/src/golangci-lint/go.sum @@ -1,5 +1,7 @@ -4d63.com/gochecknoglobals v0.1.0 h1:zeZSRqj5yCg28tCkIV/z/lWbwvNm5qnKVS15PI8nhD0= -4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= +4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= +4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= +4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -38,8 +40,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Abirdcfly/dupword v0.0.7 h1:z14n0yytA3wNO2gpCD/jVtp/acEXPGmYu0esewpBt6Q= -github.com/Abirdcfly/dupword v0.0.7/go.mod h1:K/4M1kj+Zh39d2aotRwypvasonOyAMH1c/IZJzE0dmk= +github.com/Abirdcfly/dupword v0.0.9 h1:MxprGjKq3yDBICXDgEEsyGirIXfMYXkLNT/agPsE1tk= +github.com/Abirdcfly/dupword v0.0.9/go.mod h1:PzmHVLLZ27MvHSzV7eFmMXSFArWXZPZmfuuziuUrf2g= github.com/Antonboom/errname v0.1.7 h1:mBBDKvEYwPl4WFFNwec1CZO096G6vzK9vvDQzAwkako= github.com/Antonboom/errname v0.1.7/go.mod h1:g0ONh16msHIPgJSGsecu1G/dcF2hlYR/0SddnIAGavU= github.com/Antonboom/nilnil v0.1.1 h1:PHhrh5ANKFWRBh7TdYmyyq2gyT2lotnvFvvFbylF81Q= @@ -91,8 +93,8 @@ github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cb github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.9 h1:mPP4ucLrf/rKZiIG/a9IPXHGlh8p4CzgpyTy6EEutYk= github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= -github.com/chavacava/garif v0.0.0-20220630083739-93517212f375 h1:E7LT642ysztPWE0dfz43cWOvMiF42DyTRC+eZIaO4yI= -github.com/chavacava/garif v0.0.0-20220630083739-93517212f375/go.mod h1:4m1Rv7xfuwWPNKXlThldNuJvutYM6J95wNuuVmn55To= +github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348 h1:cy5GCEZLUCshCGCRRUjxHrDUqkB4l5cuUt3ShEckQEo= +github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348/go.mod h1:f/miWtG3SSuTxKsNK3o58H1xl+XV6ZIfbC6p7lPPB8U= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -105,8 +107,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/cristalhq/acmd v0.8.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= -github.com/daixiang0/gci v0.8.1 h1:T4xpSC+hmsi4CSyuYfIJdMZAr9o7xZmHpQVygMghGZ4= -github.com/daixiang0/gci v0.8.1/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= +github.com/daixiang0/gci v0.9.0 h1:t8XZ0vK6l0pwPoOmoGyqW2NwQlvbpAQNVvu/GRBgykM= +github.com/daixiang0/gci v0.9.0/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= 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= @@ -122,8 +124,8 @@ github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStB github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= @@ -144,12 +146,12 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= -github.com/go-toolsmith/astcopy v1.0.2 h1:YnWf5Rnh1hUudj11kei53kI57quN/VH6Hp1n+erozn0= github.com/go-toolsmith/astcopy v1.0.2/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y= +github.com/go-toolsmith/astcopy v1.0.3 h1:r0bgSRlMOAgO+BdQnVAcpMSMkrQCnV6ZJmIkrJgcJj0= +github.com/go-toolsmith/astcopy v1.0.3/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y= github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= github.com/go-toolsmith/astequal v1.0.2/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/astequal v1.0.3 h1:+LVdyRatFS+XO78SGV4I3TCEA0AC7fKEGma+fH+674o= @@ -164,8 +166,8 @@ github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUD github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk= github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= @@ -207,14 +209,14 @@ github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6 github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzrdA+Nx5WA3tV1N0goTspwmKCQvBY= github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs= -github.com/golangci/golangci-lint v1.50.1 h1:C829clMcZXEORakZlwpk7M4iDw2XiwxxKaG504SZ9zY= -github.com/golangci/golangci-lint v1.50.1/go.mod h1:AQjHBopYS//oB8xs0y0M/dtxdKHkdhl0RvmjUct0/4w= +github.com/golangci/golangci-lint v1.51.1 h1:N5HD/x0ZrhJYsgKWyz7yJxxQ8JKR0Acc+FOP7QtGSAA= +github.com/golangci/golangci-lint v1.51.1/go.mod h1:hnyNNO3fJ2Rjwo6HM+VXvcmLkKDOuBAnR9gVlS1mW1E= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo= -github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0= +github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc= github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ= github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= @@ -253,9 +255,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U= -github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= -github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 h1:9alfqbrhuD+9fLZ4iaAVwhlp5PEhmnBt7yvK2Oy5C1U= +github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= @@ -293,7 +294,6 @@ github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjz github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -305,8 +305,10 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= -github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7c= -github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= +github.com/junk1tm/musttag v0.4.4 h1:VK4L7v7lvWAhKDDx0cUJgbb0UBNipYinv8pPeHJzH9Q= +github.com/junk1tm/musttag v0.4.4/go.mod h1:XkcL/9O6RmD88JBXb+I15nYRl9W4ExhgQeCBEhfMC8U= +github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8= +github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.3 h1:l4pNvrb8JSwRd51ojtcOxOeHJzHek+MtOyXbaR0uvmw= @@ -325,15 +327,14 @@ github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoaGS+Ugg8g= github.com/kunwardeep/paralleltest v1.0.6/go.mod h1:Y0Y0XISdZM5IKm3TREQMZ6iteqn1YuwCsJO/0kL9Zes= -github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= -github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= +github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= -github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKiM= -github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= -github.com/leonklingele/grouper v1.1.0 h1:tC2y/ygPbMFSBOs3DcyaEMKnnwH7eYKzohOtRrf0SAg= -github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/ldez/tagliatelle v0.4.0 h1:sylp7d9kh6AdXN2DpVGHBRb5guTVAgOxqNGhbqc4b1c= +github.com/ldez/tagliatelle v0.4.0/go.mod h1:mNtTfrHy2haaBAw+VT7IBV6VXBThS7TCreYWbBcJ87I= +github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU= +github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= @@ -346,22 +347,19 @@ github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7 github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 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 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mgechev/revive v1.2.4 h1:+2Hd/S8oO2H0Ikq2+egtNwQsVhAeELHjxjIUFX5ajLI= -github.com/mgechev/revive v1.2.4/go.mod h1:iAWlQishqCuj4yhV24FTnKSXGpbAA+0SckXB8GQMX/Q= +github.com/mgechev/revive v1.2.5 h1:UF9AR8pOAuwNmhXj2odp4mxv9Nx2qUIwVz8ZsU+Mbec= +github.com/mgechev/revive v1.2.5/go.mod h1:nFOXent79jMTISAfOAasKfy0Z2Ejq0WX7Qn/KAdYopI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -381,14 +379,16 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6Fx github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/exhaustive v0.8.3 h1:pw5O09vwg8ZaditDp/nQRqVnrMczSJDxRDJMowvhsrM= -github.com/nishanths/exhaustive v0.8.3/go.mod h1:qj+zJJUgJ76tR92+25+03oYUhzF4R7/2Wk7fGTfCHmg= +github.com/nishanths/exhaustive v0.9.5 h1:TzssWan6orBiLYVqewCG8faud9qlFntJE30ACpzmGME= +github.com/nishanths/exhaustive v0.9.5/go.mod h1:IbwrGdVMizvDcIxPYGVdQn5BqWJaOwpCvg4RGb8r/TA= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nunnatsa/ginkgolinter v0.8.1 h1:/y4o/0hV+ruUHj4xXh89xlFjoaitnI4LnkpuYs02q1c= +github.com/nunnatsa/ginkgolinter v0.8.1/go.mod h1:FYYLtszIdmzCH8XMaMPyxPVXZ7VCaIm55bA+gugx+14= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= -github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= +github.com/onsi/ginkgo/v2 v2.3.1 h1:8SbseP7qM32WcvE6VaN6vfXxv698izmsJ1UQX9ve7T8= +github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI= github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -399,8 +399,6 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -408,8 +406,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v1.0.5 h1:AHB5JRCjlmelh9RrLxT9sgzpalIwwq4hqE8EkwIwKdY= -github.com/polyfloyd/go-errorlint v1.0.5/go.mod h1:APVvOesVSAnne5SClsPxPdfvZTVDojXh1/G3qb5wjGI= +github.com/polyfloyd/go-errorlint v1.0.6 h1:ZevdyEGxDoHAMQUVvdTT06hnYuKULe8TQkOmIYx6s1c= +github.com/polyfloyd/go-errorlint v1.0.6/go.mod h1:NcnNncnm8fVV7vfQWiI4HZrzWFzGp24C262IQutNcMs= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -448,18 +446,18 @@ github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.2.4 h1:CpMSDKan0LtNGGhPrvupAoLeObRFjND8/tU1rEOtBp4= -github.com/ryancurrah/gomodguard v1.2.4/go.mod h1:+Kem4VjWwvFpUJRJSwa16s1tBJe+vbv02+naTow2f6M= -github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw= -github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= -github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA= -github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= +github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= +github.com/ryanrolds/sqlclosecheck v0.4.0 h1:i8SX60Rppc1wRuyQjMciLqIzV3xnoHB7/tXbr6RGYNI= +github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ= +github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= +github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.20.0 h1:K6CXjqqtSYSsuyRDDC7Sjn6vTMLiSJa4ZmDkiokoqtw= -github.com/sashamelentyev/usestdlibvars v1.20.0/go.mod h1:0GaP+ecfZMXShS0A94CJn6aEuPRILv8h/VuWI9n1ygg= -github.com/securego/gosec/v2 v2.13.1 h1:7mU32qn2dyC81MH9L2kefnQyRMUarfDER3iQyMHcjYM= -github.com/securego/gosec/v2 v2.13.1/go.mod h1:EO1sImBMBWFjOTFzMWfTRrZW6M15gm60ljzrmy/wtHo= +github.com/sashamelentyev/usestdlibvars v1.21.1 h1:GQGlReyL9Ek8DdJmwtwhHbhwHnuPfsKaprpjnrPcjxc= +github.com/sashamelentyev/usestdlibvars v1.21.1/go.mod h1:MPI52Qq99iO9sFZZcKJ2y/bx6BNjs+/2bw3PCggIbew= +github.com/securego/gosec/v2 v2.14.0 h1:U1hfs0oBackChXA72plCYVA4cOlQ4gO+209dHiSNZbI= +github.com/securego/gosec/v2 v2.14.0/go.mod h1:Ff03zEi5NwSOfXj9nFpBfhbWTtROCkg9N+9goggrYn4= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -473,18 +471,18 @@ github.com/sivchari/containedctx v1.0.2 h1:0hLQKpgC53OVF1VT7CeoFHk9YKstur1XOgfYI github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8= github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= -github.com/sivchari/tenv v1.7.0 h1:d4laZMBK6jpe5PWepxlV9S+LC0yXqvYHiq8E6ceoVVE= -github.com/sivchari/tenv v1.7.0/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= +github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY= github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= -github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0HZqLQ= -github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= -github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -497,8 +495,9 @@ github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= 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 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -506,10 +505,13 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A= github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= @@ -518,12 +520,12 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= -github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro= -github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e h1:MV6KaVu/hzByHP0UvJ4HcMGE/8a6A4Rggc/0wx2AvJo= +github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= github.com/timonwong/loggercheck v0.9.3 h1:ecACo9fNiHxX4/Bc02rW2+kaJIAMAes7qJ7JKxt0EZI= github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= -github.com/tomarrell/wrapcheck/v2 v2.7.0 h1:J/F8DbSKJC83bAvC6FoZaRjZiZ/iKoueSdrEkmGeacA= -github.com/tomarrell/wrapcheck/v2 v2.7.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= +github.com/tomarrell/wrapcheck/v2 v2.8.0 h1:qDzbir0xmoE+aNxGCPrn+rUSxAX+nG6vREgbbXAR81I= +github.com/tomarrell/wrapcheck/v2 v2.8.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA= @@ -566,6 +568,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -579,8 +582,9 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 h1:Ic/qN6TEifvObMGQy72k0n1LlJr7DjWWEi+MOsDOiSk= golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE= +golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -608,8 +612,9 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -647,7 +652,11 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -670,8 +679,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -689,7 +698,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/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-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -718,7 +726,6 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -728,10 +735,17 @@ golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -740,8 +754,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -755,7 +771,6 @@ golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -794,9 +809,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -806,7 +819,6 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -824,8 +836,11 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -950,16 +965,16 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA= -honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= +honnef.co/go/tools v0.4.0 h1:lyXVV1c8wUBJRKqI8JgIpT8TW1VDagfYYaxbKa/HoL8= +honnef.co/go/tools v0.4.0/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM= mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 h1:seuXWbRB1qPrS3NQnHmFKLJLtskWyueeIzmLXghMGgk= -mvdan.cc/unparam v0.0.0-20220706161116-678bad134442/go.mod h1:F/Cxw/6mVrNKqrR2YjFf5CaW0Bw4RL8RfbEf4GRggJk= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w= +mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -- cgit v1.2.3-2-g168b From 043e2a3030489da944263d858a7567d7508ffa77 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 12:19:23 -0700 Subject: fixup! Move the base64 decode to the internal package --- .../06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 | 2 ++ .../24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a | 2 ++ .../2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 | 2 ++ .../356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd | 2 ++ .../582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 | 2 ++ .../60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 | 2 ++ .../66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d | 2 ++ .../731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b | 2 ++ .../7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c | 2 ++ .../8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c | 2 ++ .../9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c | 2 ++ .../92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f | 2 ++ .../93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 | 2 ++ .../a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a | 2 ++ .../a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c | 2 ++ .../beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 | 2 ++ .../c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 | 2 ++ .../caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 | 2 ++ .../cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 | 2 ++ .../ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a | 2 ++ .../f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 | 2 ++ .../fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 | 2 ++ .../06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 | 2 -- .../24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a | 2 -- .../2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 | 2 -- .../356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd | 2 -- .../582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 | 2 -- .../60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 | 2 -- .../66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d | 2 -- .../731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b | 2 -- .../7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c | 2 -- .../8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c | 2 -- .../9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c | 2 -- .../92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f | 2 -- .../93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 | 2 -- .../a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a | 2 -- .../a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c | 2 -- .../beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 | 2 -- .../c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 | 2 -- .../caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 | 2 -- .../cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 | 2 -- .../ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a | 2 -- .../f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 | 2 -- .../fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 | 2 -- 44 files changed, 44 insertions(+), 44 deletions(-) create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 create mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a delete mode 100644 testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd delete mode 100644 testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d delete mode 100644 testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b delete mode 100644 testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c delete mode 100644 testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c delete mode 100644 testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c delete mode 100644 testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f delete mode 100644 testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a delete mode 100644 testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c delete mode 100644 testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a delete mode 100644 testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 delete mode 100644 testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 b/internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 new file mode 100644 index 0000000..c3774e7 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a b/internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a new file mode 100644 index 0000000..4c861db --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 b/internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 new file mode 100644 index 0000000..3d32e14 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd b/internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd new file mode 100644 index 0000000..d08ef92 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 b/internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 new file mode 100644 index 0000000..87c024d --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d b/internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d new file mode 100644 index 0000000..959401e --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b b/internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b new file mode 100644 index 0000000..bd1ae59 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c b/internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c new file mode 100644 index 0000000..09e0ad2 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c b/internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c new file mode 100644 index 0000000..e8000f3 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c b/internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c new file mode 100644 index 0000000..aac6b7d --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f b/internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f new file mode 100644 index 0000000..f3bf6d9 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 b/internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 new file mode 100644 index 0000000..2e7f462 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a b/internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a new file mode 100644 index 0000000..c541f52 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c b/internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c new file mode 100644 index 0000000..5d56f29 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 b/internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 new file mode 100644 index 0000000..4b4d59f --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 b/internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 new file mode 100644 index 0000000..ef9f9d4 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 b/internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 new file mode 100644 index 0000000..67322c7 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 b/internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 new file mode 100644 index 0000000..f195330 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\x04000000000000\r00000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a b/internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a new file mode 100644 index 0000000..5b0d392 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 b/internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 new file mode 100644 index 0000000..a389d3c --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 b/internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 new file mode 100644 index 0000000..17d10b2 --- /dev/null +++ b/internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 b/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 deleted file mode 100644 index c3774e7..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a b/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a deleted file mode 100644 index 4c861db..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 b/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 deleted file mode 100644 index 3d32e14..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd b/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd deleted file mode 100644 index d08ef92..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 deleted file mode 100644 index a96f559..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0") diff --git a/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 b/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 deleted file mode 100644 index 87c024d..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d b/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d deleted file mode 100644 index 959401e..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b b/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b deleted file mode 100644 index bd1ae59..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c b/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c deleted file mode 100644 index 09e0ad2..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c b/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c deleted file mode 100644 index e8000f3..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00") diff --git a/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c b/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c deleted file mode 100644 index aac6b7d..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f b/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f deleted file mode 100644 index f3bf6d9..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 b/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 deleted file mode 100644 index 2e7f462..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a b/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a deleted file mode 100644 index c541f52..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c b/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c deleted file mode 100644 index 5d56f29..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 b/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 deleted file mode 100644 index 4b4d59f..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 b/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 deleted file mode 100644 index ef9f9d4..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000") diff --git a/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 b/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 deleted file mode 100644 index 67322c7..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("") diff --git a/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 b/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 deleted file mode 100644 index f195330..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\x04000000000000\r00000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a b/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a deleted file mode 100644 index 5b0d392..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000000000000000000000000000000000000") diff --git a/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 b/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 deleted file mode 100644 index a389d3c..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000") diff --git a/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 b/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 deleted file mode 100644 index 17d10b2..0000000 --- a/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000") -- cgit v1.2.3-2-g168b From ad615abffa4c215858624e9d2cf06a7207e427ac Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 12:42:53 -0700 Subject: struct.go: Fix a typo in a comment --- struct.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/struct.go b/struct.go index 8a664c6..81bc22d 100644 --- a/struct.go +++ b/struct.go @@ -123,7 +123,7 @@ func indexStructReal(typ reflect.Type) structIndex { } // indexStructInner crawls the struct `typ`, storing information on -// all struct fields foun in to `byPos` and `byName`. If `typ` +// all struct fields found in to `byPos` and `byName`. If `typ` // contains other structs as fields, indexStructInner will recurse and // call itself; keeping track of stack information with `stackPath` // (which identifies where we are in the parent struct) and -- cgit v1.2.3-2-g168b From c25137b6d7d5945ae5cde2349a002d84c50d0e59 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 13:24:02 -0700 Subject: decode: Fix decoding an actively growing file --- ReleaseNotes.md | 11 +++++++++++ decode.go | 8 +------- decode_scan.go | 2 ++ decode_test.go | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 5d85254..f71967c 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,14 @@ +# v0.3.5 (TBD) + + Theme: TBD + + User-facing changes: + + - Decoder: Fixes a bug where if an EOF is encountered, the reader + is appended to, then another Decode is attempted, that EOF + poisons future Decodes. This is something that `encoding/json` + supports. + # v0.3.4 (2023-02-05) Theme: Fix compilation with Go 1.20 diff --git a/decode.go b/decode.go index 60b530f..8638148 100644 --- a/decode.go +++ b/decode.go @@ -90,7 +90,6 @@ type Decoder struct { useNumber bool // state - err error posStack []int64 structStack []decodeStackItem } @@ -240,18 +239,13 @@ func (dec *Decoder) Decode(ptr any) (err error) { } } - if dec.err != nil { - return dec.err - } - dec.io.Reset() dec.io.PushReadBarrier() defer func() { if r := recover(); r != nil { if de, ok := r.(decodeError); ok { pub := DecodeError(de) - dec.err = &pub - err = dec.err + err = &pub } else { panic(r) } diff --git a/decode_scan.go b/decode_scan.go index e233caf..521c5c4 100644 --- a/decode_scan.go +++ b/decode_scan.go @@ -45,6 +45,8 @@ func (sc *runeTypeScanner) Reset() { } // tell it to use that rType and rErr _ = sc.UnreadRune() // we set it up to always succeed + } else { + sc.initialized = false } } diff --git a/decode_test.go b/decode_test.go index 73ce903..456f363 100644 --- a/decode_test.go +++ b/decode_test.go @@ -5,6 +5,7 @@ package lowmemjson import ( + "bytes" "io" "strings" "testing" @@ -34,3 +35,16 @@ func TestDecodeObject(t *testing.T) { }) assert.ErrorContains(t, err, "did not consume entire") } + +func TestDecodeGrowing(t *testing.T) { + t.Parallel() + var buf bytes.Buffer + dec := NewDecoder(&buf) + var x any + assert.ErrorIs(t, dec.Decode(&x), io.EOF) + buf.WriteString("1\n") + assert.NoError(t, dec.Decode(&x)) + buf.WriteString("1\n") + assert.NoError(t, dec.Decode(&x)) + assert.ErrorIs(t, dec.Decode(&x), io.EOF) +} -- cgit v1.2.3-2-g168b From eab38672b2467810592b61fe5b0067086d3cbd2c Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 13:24:02 -0700 Subject: Fix being able to run the benchmarks --- compat/json/testdata/code.json.gz | Bin 0 -> 120432 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 compat/json/testdata/code.json.gz diff --git a/compat/json/testdata/code.json.gz b/compat/json/testdata/code.json.gz new file mode 100644 index 0000000..1572a92 Binary files /dev/null and b/compat/json/testdata/code.json.gz differ -- cgit v1.2.3-2-g168b From 2b9473f5e8816eeea76b2fdada184532be00d3a2 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 12:18:29 -0700 Subject: internal: Split in to sub-packages --- compat/json/compat_test.go | 14 +- decode.go | 164 ++-- decode_scan.go | 18 +- decode_scan_test.go | 240 +++--- encode_string.go | 26 +- errors.go | 4 +- internal/allwriter.go | 174 ----- internal/base64.go | 128 ---- internal/base64_test.go | 44 -- internal/base64dec/base64.go | 130 ++++ internal/base64dec/base64_test.go | 44 ++ ...ad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 | 2 + ...5cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a | 2 + ...a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 | 2 + ...3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd | 2 + ...775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 | 2 + ...1b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 | 2 + ...be1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d | 2 + ...f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b | 2 + ...920b5202cd1269174416ce32769c7f59376e76b7dd3129c | 2 + ...7433233f3a90099024e580a6ba319ea2bf539880c50bd7c | 2 + ...326638b8915f80863feab0ba0108183b3093934bdc0420c | 2 + ...aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f | 2 + ...7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 | 2 + ...5bd136874415dddfff5c586e662f21420caa7a94131a56a | 2 + ...d54218d2ad8112204672cc1fb30be297853616788208a5c | 2 + ...eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 | 2 + ...77408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 | 2 + ...1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 | 2 + ...c70baf6d7821a5a6f3a90cabb033575790be91723593680 | 2 + ...9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a | 2 + ...27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 | 2 + ...1a201281dbf6568628b4135c35c811dd9bce97620a75d43 | 2 + internal/borrowed_tags.go | 40 - internal/encode.go | 14 - internal/fastio/allwriter.go | 174 +++++ internal/hex.go | 20 - internal/jsonparse/hex.go | 20 + internal/jsonparse/parse.go | 845 +++++++++++++++++++++ internal/jsonparse/parse_test.go | 78 ++ internal/jsontags/borrowed_tags.go | 40 + internal/jsontags/tags.go | 7 + internal/jsontest/jsontest.go | 14 + internal/parse.go | 845 --------------------- internal/parse_test.go | 78 -- internal/tags.go | 7 - ...ad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 | 2 - ...5cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a | 2 - ...a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 | 2 - ...3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd | 2 - ...775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 | 2 - ...1b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 | 2 - ...be1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d | 2 - ...f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b | 2 - ...920b5202cd1269174416ce32769c7f59376e76b7dd3129c | 2 - ...7433233f3a90099024e580a6ba319ea2bf539880c50bd7c | 2 - ...326638b8915f80863feab0ba0108183b3093934bdc0420c | 2 - ...aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f | 2 - ...7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 | 2 - ...5bd136874415dddfff5c586e662f21420caa7a94131a56a | 2 - ...d54218d2ad8112204672cc1fb30be297853616788208a5c | 2 - ...eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 | 2 - ...77408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 | 2 - ...1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 | 2 - ...c70baf6d7821a5a6f3a90cabb033575790be91723593680 | 2 - ...9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a | 2 - ...27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 | 2 - ...1a201281dbf6568628b4135c35c811dd9bce97620a75d43 | 2 - reencode.go | 95 +-- struct.go | 4 +- 70 files changed, 1682 insertions(+), 1673 deletions(-) delete mode 100644 internal/allwriter.go delete mode 100644 internal/base64.go delete mode 100644 internal/base64_test.go create mode 100644 internal/base64dec/base64.go create mode 100644 internal/base64dec/base64_test.go create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 create mode 100644 internal/base64dec/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 delete mode 100644 internal/borrowed_tags.go delete mode 100644 internal/encode.go create mode 100644 internal/fastio/allwriter.go delete mode 100644 internal/hex.go create mode 100644 internal/jsonparse/hex.go create mode 100644 internal/jsonparse/parse.go create mode 100644 internal/jsonparse/parse_test.go create mode 100644 internal/jsontags/borrowed_tags.go create mode 100644 internal/jsontags/tags.go create mode 100644 internal/jsontest/jsontest.go delete mode 100644 internal/parse.go delete mode 100644 internal/parse_test.go delete mode 100644 internal/tags.go delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 delete mode 100644 internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 diff --git a/compat/json/compat_test.go b/compat/json/compat_test.go index feb850b..4b167d1 100644 --- a/compat/json/compat_test.go +++ b/compat/json/compat_test.go @@ -9,10 +9,12 @@ import ( "io" "git.lukeshu.com/go/lowmemjson" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/jsonparse" + "git.lukeshu.com/go/lowmemjson/internal/jsontags" + "git.lukeshu.com/go/lowmemjson/internal/jsontest" ) -var parseTag = internal.ParseTag +var parseTag = jsontags.ParseTag type scanner = lowmemjson.ReEncoderConfig @@ -21,13 +23,13 @@ func checkValid(in []byte, scan *lowmemjson.ReEncoderConfig) error { } func isValidNumber(s string) bool { - var parser internal.Parser + var parser jsonparse.Parser for _, r := range s { if t, _ := parser.HandleRune(r); !t.IsNumber() { return false } } - if t, _ := parser.HandleEOF(); t == internal.RuneTypeError { + if t, _ := parser.HandleEOF(); t == jsonparse.RuneTypeError { return false } return true @@ -51,9 +53,9 @@ type encodeState struct { } func (es *encodeState) string(str string, _ bool) { - internal.EncodeStringFromString(&es.Buffer, str) + jsontest.EncodeStringFromString(&es.Buffer, str) } func (es *encodeState) stringBytes(str []byte, _ bool) { - internal.EncodeStringFromBytes(&es.Buffer, str) + jsontest.EncodeStringFromBytes(&es.Buffer, str) } diff --git a/decode.go b/decode.go index 8638148..3a9a4b1 100644 --- a/decode.go +++ b/decode.go @@ -23,7 +23,9 @@ import ( "unicode/utf16" "unicode/utf8" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/base64dec" + "git.lukeshu.com/go/lowmemjson/internal/fastio" + "git.lukeshu.com/go/lowmemjson/internal/jsonparse" ) // Decodable is the interface implemented by types that can decode a @@ -105,7 +107,7 @@ func NewDecoder(r io.RuneScanner) *Decoder { return &Decoder{ io: runeTypeScanner{ inner: r, - parser: internal.Parser{ + parser: jsonparse.Parser{ MaxDepth: maxNestingDepth, }, }, @@ -145,7 +147,7 @@ func (dec *Decoder) More() bool { dec.io.Reset() _, _, t, e := dec.io.ReadRuneType() _ = dec.io.UnreadRune() // best effort - return e == nil && t != internal.RuneTypeEOF + return e == nil && t != jsonparse.RuneTypeEOF } func (dec *Decoder) posStackPush() { @@ -206,7 +208,7 @@ func (dec *Decoder) DecodeThenEOF(ptr any) (err error) { return err } c, s, t, _ := dec.io.ReadRuneType() - if t != internal.RuneTypeEOF { + if t != jsonparse.RuneTypeEOF { panic("should not happen") } if s > 0 { @@ -274,7 +276,7 @@ func (dec *Decoder) panicType(jTyp string, gTyp reflect.Type, err error) { }) } -func (dec *Decoder) readRune() (rune, internal.RuneType) { +func (dec *Decoder) readRune() (rune, jsonparse.RuneType) { c, _, t, e := dec.io.ReadRuneType() if e != nil { panic(decodeError{ @@ -295,20 +297,20 @@ func (dec *Decoder) unreadRune() { } } -func (dec *Decoder) peekRuneType() internal.RuneType { +func (dec *Decoder) peekRuneType() jsonparse.RuneType { _, t := dec.readRune() dec.unreadRune() return t } -func (dec *Decoder) expectRune(ec rune, et internal.RuneType) { +func (dec *Decoder) expectRune(ec rune, et jsonparse.RuneType) { ac, at := dec.readRune() if ac != ec || at != et { panic("should not happen") } } -func (dec *Decoder) expectRuneType(ec rune, et internal.RuneType, gt reflect.Type) { +func (dec *Decoder) expectRuneType(ec rune, et jsonparse.RuneType, gt reflect.Type) { ac, at := dec.readRune() if ac != ec || at != et { dec.panicType(at.JSONType(), gt, nil) @@ -325,7 +327,7 @@ func (sc *decRuneScanner) ReadRune() (rune, int, error) { return 0, 0, io.EOF } c, s, t, e := sc.dec.io.ReadRuneType() - if t == internal.RuneTypeEOF { + if t == jsonparse.RuneTypeEOF { sc.eof = true sc.dec.io.PopReadBarrier() return 0, 0, io.EOF @@ -412,7 +414,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { dec.panicType(t.JSONType(), reflect.PointerTo(typ), err) } case val.CanAddr() && reflect.PointerTo(typ).Implements(textUnmarshalerType): - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } @@ -425,13 +427,13 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { default: switch kind := typ.Kind(); kind { case reflect.Bool: - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } val.SetBool(dec.decodeBool(typ)) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } @@ -443,7 +445,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } val.SetInt(n) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } @@ -455,7 +457,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } val.SetUint(n) case reflect.Float32, reflect.Float64: - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } @@ -467,7 +469,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } val.SetFloat(n) case reflect.String: - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } @@ -508,25 +510,25 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { // in the loop) because the only way it's possible is if there's // an interface in there, which'd break from the loop on its own. // - // ptr.CanSet() || dec.peekRuneType() != internal.RuneTypeNullN + // ptr.CanSet() || dec.peekRuneType() != jsonparse.RuneTypeNullN // // We only need the pointer itself to be settable if we're // decoding null. - if ptr.Elem() != val && (ptr.CanSet() || dec.peekRuneType() != internal.RuneTypeNullN) { + if ptr.Elem() != val && (ptr.CanSet() || dec.peekRuneType() != jsonparse.RuneTypeNullN) { dec.decode(ptr, false) break } } // Couldn't get type information from a pointer; fall back to untyped mode. switch dec.peekRuneType() { - case internal.RuneTypeNullN: + case jsonparse.RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) default: val.Set(reflect.ValueOf(dec.decodeAny())) } case reflect.Struct: - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } @@ -557,7 +559,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { if dec.disallowUnknownFields { dec.panicType("", typ, fmt.Errorf("json: unknown field %q", name)) } - dec.scan(internal.Discard) + dec.scan(fastio.Discard) return } field := index.byPos[idx] @@ -569,7 +571,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", fVal.Type().Elem())) } - if dec.peekRuneType() != internal.RuneTypeNullN { + if dec.peekRuneType() != jsonparse.RuneTypeNullN { if fVal.IsNil() { fVal.Set(reflect.New(fVal.Type().Elem())) } @@ -580,7 +582,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } if field.Quote { switch t := dec.peekRuneType(); t { - case internal.RuneTypeNullN: + case jsonparse.RuneTypeNullN: dec.decodeNull() switch fVal.Kind() { // XXX: I can't justify this list, other than "it's what encoding/json @@ -590,7 +592,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { default: // do nothing??? } - case internal.RuneTypeStringBeg: + case jsonparse.RuneTypeStringBeg: // TODO: Figure out how to do this without buffering, have correct offsets. var buf bytes.Buffer dec.decodeString(nil, &buf) @@ -612,10 +614,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { }) case reflect.Map: switch t := dec.peekRuneType(); t { - case internal.RuneTypeNullN: + case jsonparse.RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) - case internal.RuneTypeObjectBeg: + case jsonparse.RuneTypeObjectBeg: if val.IsNil() { val.Set(reflect.MakeMap(typ)) } @@ -670,24 +672,24 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } case reflect.Slice: switch { - case typ.Elem().Kind() == reflect.Uint8 && !(dec.peekRuneType() == internal.RuneTypeArrayBeg && (false || + case typ.Elem().Kind() == reflect.Uint8 && !(dec.peekRuneType() == jsonparse.RuneTypeArrayBeg && (false || reflect.PointerTo(typ.Elem()).Implements(decodableType) || reflect.PointerTo(typ.Elem()).Implements(jsonUnmarshalerType) || reflect.PointerTo(typ.Elem()).Implements(textUnmarshalerType))): switch t := dec.peekRuneType(); t { - case internal.RuneTypeNullN: + case jsonparse.RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) - case internal.RuneTypeStringBeg: + case jsonparse.RuneTypeStringBeg: if typ.Elem() == byteType { var buf bytes.Buffer - dec.decodeString(typ, internal.NewBase64Decoder(&buf)) + dec.decodeString(typ, base64dec.NewBase64Decoder(&buf)) val.Set(reflect.ValueOf(buf.Bytes())) } else { // TODO: Surely there's a better way. At the very least, we should // avoid buffering. var buf bytes.Buffer - dec.decodeString(typ, internal.NewBase64Decoder(&buf)) + dec.decodeString(typ, base64dec.NewBase64Decoder(&buf)) bs := buf.Bytes() val.Set(reflect.MakeSlice(typ, len(bs), len(bs))) for i := 0; i < len(bs); i++ { @@ -699,10 +701,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } default: switch t := dec.peekRuneType(); t { - case internal.RuneTypeNullN: + case jsonparse.RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) - case internal.RuneTypeArrayBeg: + case jsonparse.RuneTypeArrayBeg: if val.IsNil() { val.Set(reflect.MakeSlice(typ, 0, 0)) } @@ -725,7 +727,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } } case reflect.Array: - if nullOK && dec.peekRuneType() == internal.RuneTypeNullN { + if nullOK && dec.peekRuneType() == jsonparse.RuneTypeNullN { dec.decodeNull() return } @@ -741,7 +743,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { dec.decode(mValPtr.Elem(), false) val.Index(i).Set(mValPtr.Elem()) } else { - dec.scan(internal.Discard) + dec.scan(fastio.Discard) } i++ }) @@ -750,7 +752,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } case reflect.Pointer: switch dec.peekRuneType() { - case internal.RuneTypeNullN: + case jsonparse.RuneTypeNullN: dec.decodeNull() val.Set(reflect.Zero(typ)) default: @@ -765,7 +767,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { } } -func (dec *Decoder) scan(out internal.RuneWriter) { +func (dec *Decoder) scan(out fastio.RuneWriter) { limiter := dec.limitingScanner() for { c, _, err := limiter.ReadRune() @@ -776,7 +778,7 @@ func (dec *Decoder) scan(out internal.RuneWriter) { } } -func (dec *Decoder) scanNumber(gTyp reflect.Type, out internal.RuneWriter) { +func (dec *Decoder) scanNumber(gTyp reflect.Type, out fastio.RuneWriter) { if t := dec.peekRuneType(); !t.IsNumber() { dec.panicType(t.JSONType(), gTyp, nil) } @@ -901,23 +903,23 @@ func DecodeObject(r io.RuneScanner, decodeKey, decodeVal func(io.RuneScanner) er } func (dec *Decoder) decodeObject(gTyp reflect.Type, decodeKey, decodeVal func()) { - dec.expectRuneType('{', internal.RuneTypeObjectBeg, gTyp) + dec.expectRuneType('{', jsonparse.RuneTypeObjectBeg, gTyp) _, t := dec.readRune() switch t { - case internal.RuneTypeObjectEnd: + case jsonparse.RuneTypeObjectEnd: return - case internal.RuneTypeStringBeg: + case jsonparse.RuneTypeStringBeg: decodeMember: dec.unreadRune() decodeKey() - dec.expectRune(':', internal.RuneTypeObjectColon) + dec.expectRune(':', jsonparse.RuneTypeObjectColon) decodeVal() _, t := dec.readRune() switch t { - case internal.RuneTypeObjectComma: - dec.expectRune('"', internal.RuneTypeStringBeg) + case jsonparse.RuneTypeObjectComma: + dec.expectRune('"', jsonparse.RuneTypeStringBeg) goto decodeMember - case internal.RuneTypeObjectEnd: + case jsonparse.RuneTypeObjectEnd: return default: panic("should not happen") @@ -972,10 +974,10 @@ func DecodeArray(r io.RuneScanner, decodeMember func(r io.RuneScanner) error) (e } func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) { - dec.expectRuneType('[', internal.RuneTypeArrayBeg, gTyp) + dec.expectRuneType('[', jsonparse.RuneTypeArrayBeg, gTyp) _, t := dec.readRune() switch t { - case internal.RuneTypeArrayEnd: + case jsonparse.RuneTypeArrayEnd: return default: dec.unreadRune() @@ -983,9 +985,9 @@ func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) { decodeMember() _, t := dec.readRune() switch t { - case internal.RuneTypeArrayComma: + case jsonparse.RuneTypeArrayComma: goto decodeNextMember - case internal.RuneTypeArrayEnd: + case jsonparse.RuneTypeArrayEnd: return default: panic("should not happen") @@ -993,17 +995,17 @@ func (dec *Decoder) decodeArray(gTyp reflect.Type, decodeMember func()) { } } -func (dec *Decoder) decodeString(gTyp reflect.Type, out internal.RuneWriter) { - dec.expectRuneType('"', internal.RuneTypeStringBeg, gTyp) +func (dec *Decoder) decodeString(gTyp reflect.Type, out fastio.RuneWriter) { + dec.expectRuneType('"', jsonparse.RuneTypeStringBeg, gTyp) var uhex [4]byte for { c, t := dec.readRune() switch t { - case internal.RuneTypeStringChar: + case jsonparse.RuneTypeStringChar: _, _ = out.WriteRune(c) - case internal.RuneTypeStringEsc, internal.RuneTypeStringEscU: + case jsonparse.RuneTypeStringEsc, jsonparse.RuneTypeStringEscU: // do nothing - case internal.RuneTypeStringEsc1: + case jsonparse.RuneTypeStringEsc1: switch c { case '"': _, _ = out.WriteRune('"') @@ -1024,14 +1026,14 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out internal.RuneWriter) { default: panic("should not happen") } - case internal.RuneTypeStringEscUA: - uhex[0], _ = internal.HexToInt(c) - case internal.RuneTypeStringEscUB: - uhex[1], _ = internal.HexToInt(c) - case internal.RuneTypeStringEscUC: - uhex[2], _ = internal.HexToInt(c) - case internal.RuneTypeStringEscUD: - uhex[3], _ = internal.HexToInt(c) + case jsonparse.RuneTypeStringEscUA: + uhex[0], _ = jsonparse.HexToInt(c) + case jsonparse.RuneTypeStringEscUB: + uhex[1], _ = jsonparse.HexToInt(c) + case jsonparse.RuneTypeStringEscUC: + uhex[2], _ = jsonparse.HexToInt(c) + case jsonparse.RuneTypeStringEscUD: + uhex[3], _ = jsonparse.HexToInt(c) c = 0 | rune(uhex[0])<<12 | rune(uhex[1])<<8 | @@ -1039,25 +1041,25 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out internal.RuneWriter) { rune(uhex[3])<<0 handleUnicode: if utf16.IsSurrogate(c) { - if dec.peekRuneType() != internal.RuneTypeStringEsc { + if dec.peekRuneType() != jsonparse.RuneTypeStringEsc { _, _ = out.WriteRune(utf8.RuneError) break } - dec.expectRune('\\', internal.RuneTypeStringEsc) - if dec.peekRuneType() != internal.RuneTypeStringEscU { + dec.expectRune('\\', jsonparse.RuneTypeStringEsc) + if dec.peekRuneType() != jsonparse.RuneTypeStringEscU { _, _ = out.WriteRune(utf8.RuneError) break } - dec.expectRune('u', internal.RuneTypeStringEscU) + dec.expectRune('u', jsonparse.RuneTypeStringEscU) b, _ := dec.readRune() - uhex[0], _ = internal.HexToInt(b) + uhex[0], _ = jsonparse.HexToInt(b) b, _ = dec.readRune() - uhex[1], _ = internal.HexToInt(b) + uhex[1], _ = jsonparse.HexToInt(b) b, _ = dec.readRune() - uhex[2], _ = internal.HexToInt(b) + uhex[2], _ = jsonparse.HexToInt(b) b, _ = dec.readRune() - uhex[3], _ = internal.HexToInt(b) + uhex[3], _ = jsonparse.HexToInt(b) c2 := 0 | rune(uhex[0])<<12 | rune(uhex[1])<<8 | @@ -1073,7 +1075,7 @@ func (dec *Decoder) decodeString(gTyp reflect.Type, out internal.RuneWriter) { } else { _, _ = out.WriteRune(c) } - case internal.RuneTypeStringEnd: + case jsonparse.RuneTypeStringEnd: return default: panic("should not happen") @@ -1085,15 +1087,15 @@ func (dec *Decoder) decodeBool(gTyp reflect.Type) bool { c, t := dec.readRune() switch c { case 't': - dec.expectRune('r', internal.RuneTypeTrueR) - dec.expectRune('u', internal.RuneTypeTrueU) - dec.expectRune('e', internal.RuneTypeTrueE) + dec.expectRune('r', jsonparse.RuneTypeTrueR) + dec.expectRune('u', jsonparse.RuneTypeTrueU) + dec.expectRune('e', jsonparse.RuneTypeTrueE) return true case 'f': - dec.expectRune('a', internal.RuneTypeFalseA) - dec.expectRune('l', internal.RuneTypeFalseL) - dec.expectRune('s', internal.RuneTypeFalseS) - dec.expectRune('e', internal.RuneTypeFalseE) + dec.expectRune('a', jsonparse.RuneTypeFalseA) + dec.expectRune('l', jsonparse.RuneTypeFalseL) + dec.expectRune('s', jsonparse.RuneTypeFalseS) + dec.expectRune('e', jsonparse.RuneTypeFalseE) return false default: dec.panicType(t.JSONType(), gTyp, nil) @@ -1102,8 +1104,8 @@ func (dec *Decoder) decodeBool(gTyp reflect.Type) bool { } func (dec *Decoder) decodeNull() { - dec.expectRune('n', internal.RuneTypeNullN) - dec.expectRune('u', internal.RuneTypeNullU) - dec.expectRune('l', internal.RuneTypeNullL1) - dec.expectRune('l', internal.RuneTypeNullL2) + dec.expectRune('n', jsonparse.RuneTypeNullN) + dec.expectRune('u', jsonparse.RuneTypeNullU) + dec.expectRune('l', jsonparse.RuneTypeNullL1) + dec.expectRune('l', jsonparse.RuneTypeNullL2) } diff --git a/decode_scan.go b/decode_scan.go index 521c5c4..7a52975 100644 --- a/decode_scan.go +++ b/decode_scan.go @@ -7,7 +7,7 @@ package lowmemjson import ( "io" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/jsonparse" ) type runeTypeScanner struct { @@ -16,7 +16,7 @@ type runeTypeScanner struct { inner io.RuneScanner // initialized by constructor - parser internal.Parser // initialized by constructor + parser jsonparse.Parser // initialized by constructor offset int64 initialized bool @@ -24,13 +24,13 @@ type runeTypeScanner struct { rRune rune rSize int - rType internal.RuneType + rType jsonparse.RuneType rErr error } func (sc *runeTypeScanner) Reset() { sc.parser.Reset() - if sc.repeat || (sc.rType == internal.RuneTypeEOF && sc.rSize > 0) { + if sc.repeat || (sc.rType == jsonparse.RuneTypeEOF && sc.rSize > 0) { sc.repeat = false // re-figure the rType and rErr var err error @@ -57,9 +57,9 @@ func (sc *runeTypeScanner) Reset() { // end of both value and file: (_, 0, RuneTypeEOF, nil) // end of file in middle of value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.ErrUnexepctedEOF}) // end of file at start of value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.EOF}) -func (sc *runeTypeScanner) ReadRuneType() (rune, int, internal.RuneType, error) { +func (sc *runeTypeScanner) ReadRuneType() (rune, int, jsonparse.RuneType, error) { switch { - case sc.initialized && (sc.rType == internal.RuneTypeError || sc.rType == internal.RuneTypeEOF): + case sc.initialized && (sc.rType == jsonparse.RuneTypeError || sc.rType == jsonparse.RuneTypeEOF): // do nothing case sc.repeat: _, _, _ = sc.inner.ReadRune() @@ -80,7 +80,7 @@ func (sc *runeTypeScanner) ReadRuneType() (rune, int, internal.RuneType, error) } else { sc.rErr = nil } - if sc.rType == internal.RuneTypeSpace { + if sc.rType == jsonparse.RuneTypeSpace { goto again } case io.EOF: @@ -133,7 +133,7 @@ func (sc *runeTypeScanner) PushReadBarrier() { func (sc *runeTypeScanner) PopReadBarrier() { sc.parser.PopBarrier() - if sc.repeat || (sc.rType == internal.RuneTypeEOF && sc.rSize > 0) { + if sc.repeat || (sc.rType == jsonparse.RuneTypeEOF && sc.rSize > 0) { // re-figure the rType and rErr var err error sc.rType, err = sc.parser.HandleRune(sc.rRune) @@ -147,7 +147,7 @@ func (sc *runeTypeScanner) PopReadBarrier() { } // tell it to use that rType and rErr _ = sc.UnreadRune() // we set it up to always succeed - } else if sc.rType == internal.RuneTypeEOF { + } else if sc.rType == jsonparse.RuneTypeEOF { // re-figure the rType and rErr var err error sc.rType, err = sc.parser.HandleEOF() diff --git a/decode_scan_test.go b/decode_scan_test.go index d0725e5..1d61157 100644 --- a/decode_scan_test.go +++ b/decode_scan_test.go @@ -12,13 +12,13 @@ import ( "github.com/stretchr/testify/assert" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/jsonparse" ) type ReadRuneTypeResult struct { r rune s int - t internal.RuneType + t jsonparse.RuneType e error } @@ -54,149 +54,149 @@ func TestRuneTypeScanner(t *testing.T) { t.Parallel() testcases := map[string]runeTypeScannerTestcase{ "basic": {`{"foo": 12.0}`, ``, []ReadRuneTypeResult{ - {'{', 1, internal.RuneTypeObjectBeg, nil}, - {'"', 1, internal.RuneTypeStringBeg, nil}, - {'f', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'"', 1, internal.RuneTypeStringEnd, nil}, - {':', 1, internal.RuneTypeObjectColon, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {'2', 1, internal.RuneTypeNumberIntDig, nil}, - {'.', 1, internal.RuneTypeNumberFracDot, nil}, - {'0', 1, internal.RuneTypeNumberFracDig, nil}, - {'}', 1, internal.RuneTypeObjectEnd, nil}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {'{', 1, jsonparse.RuneTypeObjectBeg, nil}, + {'"', 1, jsonparse.RuneTypeStringBeg, nil}, + {'f', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'"', 1, jsonparse.RuneTypeStringEnd, nil}, + {':', 1, jsonparse.RuneTypeObjectColon, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'2', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'.', 1, jsonparse.RuneTypeNumberFracDot, nil}, + {'0', 1, jsonparse.RuneTypeNumberFracDig, nil}, + {'}', 1, jsonparse.RuneTypeObjectEnd, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, }}, "unread": {`{"foo": 12.0}`, ``, []ReadRuneTypeResult{ - {'{', 1, internal.RuneTypeObjectBeg, nil}, - {'"', 1, internal.RuneTypeStringBeg, nil}, - {'f', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'"', 1, internal.RuneTypeStringEnd, nil}, - {':', 1, internal.RuneTypeObjectColon, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, + {'{', 1, jsonparse.RuneTypeObjectBeg, nil}, + {'"', 1, jsonparse.RuneTypeStringBeg, nil}, + {'f', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'"', 1, jsonparse.RuneTypeStringEnd, nil}, + {':', 1, jsonparse.RuneTypeObjectColon, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, {0, unreadRune, 0, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {'2', 1, internal.RuneTypeNumberIntDig, nil}, - {'.', 1, internal.RuneTypeNumberFracDot, nil}, - {'0', 1, internal.RuneTypeNumberFracDig, nil}, - {'}', 1, internal.RuneTypeObjectEnd, nil}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'2', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'.', 1, jsonparse.RuneTypeNumberFracDot, nil}, + {'0', 1, jsonparse.RuneTypeNumberFracDig, nil}, + {'}', 1, jsonparse.RuneTypeObjectEnd, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, }}, "unread2": {`{"foo": 12.0}`, ``, []ReadRuneTypeResult{ - {'{', 1, internal.RuneTypeObjectBeg, nil}, - {'"', 1, internal.RuneTypeStringBeg, nil}, - {'f', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'"', 1, internal.RuneTypeStringEnd, nil}, - {':', 1, internal.RuneTypeObjectColon, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, + {'{', 1, jsonparse.RuneTypeObjectBeg, nil}, + {'"', 1, jsonparse.RuneTypeStringBeg, nil}, + {'f', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'"', 1, jsonparse.RuneTypeStringEnd, nil}, + {':', 1, jsonparse.RuneTypeObjectColon, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, {0, unreadRune, 0, nil}, {0, unreadRune, 0, ErrInvalidUnreadRune}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {'2', 1, internal.RuneTypeNumberIntDig, nil}, - {'.', 1, internal.RuneTypeNumberFracDot, nil}, - {'0', 1, internal.RuneTypeNumberFracDig, nil}, - {'}', 1, internal.RuneTypeObjectEnd, nil}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'2', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'.', 1, jsonparse.RuneTypeNumberFracDot, nil}, + {'0', 1, jsonparse.RuneTypeNumberFracDig, nil}, + {'}', 1, jsonparse.RuneTypeObjectEnd, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, }}, "unread-eof": {`{"foo": 12.0}`, ``, []ReadRuneTypeResult{ - {'{', 1, internal.RuneTypeObjectBeg, nil}, - {'"', 1, internal.RuneTypeStringBeg, nil}, - {'f', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'"', 1, internal.RuneTypeStringEnd, nil}, - {':', 1, internal.RuneTypeObjectColon, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {'2', 1, internal.RuneTypeNumberIntDig, nil}, - {'.', 1, internal.RuneTypeNumberFracDot, nil}, - {'0', 1, internal.RuneTypeNumberFracDig, nil}, - {'}', 1, internal.RuneTypeObjectEnd, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {'{', 1, jsonparse.RuneTypeObjectBeg, nil}, + {'"', 1, jsonparse.RuneTypeStringBeg, nil}, + {'f', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'"', 1, jsonparse.RuneTypeStringEnd, nil}, + {':', 1, jsonparse.RuneTypeObjectColon, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'2', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'.', 1, jsonparse.RuneTypeNumberFracDot, nil}, + {'0', 1, jsonparse.RuneTypeNumberFracDig, nil}, + {'}', 1, jsonparse.RuneTypeObjectEnd, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, {0, unreadRune, 0, ErrInvalidUnreadRune}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, }}, "tail-ws": {`{"foo": 12.0} `, ``, []ReadRuneTypeResult{ - {'{', 1, internal.RuneTypeObjectBeg, nil}, - {'"', 1, internal.RuneTypeStringBeg, nil}, - {'f', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'"', 1, internal.RuneTypeStringEnd, nil}, - {':', 1, internal.RuneTypeObjectColon, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {'2', 1, internal.RuneTypeNumberIntDig, nil}, - {'.', 1, internal.RuneTypeNumberFracDot, nil}, - {'0', 1, internal.RuneTypeNumberFracDig, nil}, - {'}', 1, internal.RuneTypeObjectEnd, nil}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {'{', 1, jsonparse.RuneTypeObjectBeg, nil}, + {'"', 1, jsonparse.RuneTypeStringBeg, nil}, + {'f', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'"', 1, jsonparse.RuneTypeStringEnd, nil}, + {':', 1, jsonparse.RuneTypeObjectColon, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'2', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'.', 1, jsonparse.RuneTypeNumberFracDot, nil}, + {'0', 1, jsonparse.RuneTypeNumberFracDig, nil}, + {'}', 1, jsonparse.RuneTypeObjectEnd, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, }}, "syntax-error": {`[[0,]`, ``, []ReadRuneTypeResult{ - {'[', 1, internal.RuneTypeArrayBeg, nil}, - {'[', 1, internal.RuneTypeArrayBeg, nil}, - {'0', 1, internal.RuneTypeNumberIntZero, nil}, - {',', 1, internal.RuneTypeArrayComma, nil}, - {']', 1, internal.RuneTypeError, &DecodeSyntaxError{Offset: 4, Err: fmt.Errorf("invalid character %q looking for beginning of value", ']')}}, - {']', 1, internal.RuneTypeError, &DecodeSyntaxError{Offset: 4, Err: fmt.Errorf("invalid character %q looking for beginning of value", ']')}}, - {']', 1, internal.RuneTypeError, &DecodeSyntaxError{Offset: 4, Err: fmt.Errorf("invalid character %q looking for beginning of value", ']')}}, + {'[', 1, jsonparse.RuneTypeArrayBeg, nil}, + {'[', 1, jsonparse.RuneTypeArrayBeg, nil}, + {'0', 1, jsonparse.RuneTypeNumberIntZero, nil}, + {',', 1, jsonparse.RuneTypeArrayComma, nil}, + {']', 1, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 4, Err: fmt.Errorf("invalid character %q looking for beginning of value", ']')}}, + {']', 1, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 4, Err: fmt.Errorf("invalid character %q looking for beginning of value", ']')}}, + {']', 1, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 4, Err: fmt.Errorf("invalid character %q looking for beginning of value", ']')}}, }}, "multi-value": {`1{}`, `}`, []ReadRuneTypeResult{ - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {'{', 1, internal.RuneTypeEOF, nil}, - {'{', 1, internal.RuneTypeEOF, nil}, - {'{', 1, internal.RuneTypeEOF, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'{', 1, jsonparse.RuneTypeEOF, nil}, + {'{', 1, jsonparse.RuneTypeEOF, nil}, + {'{', 1, jsonparse.RuneTypeEOF, nil}, }}, "early-eof": {` {`, ``, []ReadRuneTypeResult{ - {'{', 1, internal.RuneTypeObjectBeg, nil}, - {0, 0, internal.RuneTypeError, &DecodeSyntaxError{Offset: 2, Err: io.ErrUnexpectedEOF}}, - {0, 0, internal.RuneTypeError, &DecodeSyntaxError{Offset: 2, Err: io.ErrUnexpectedEOF}}, - {0, 0, internal.RuneTypeError, &DecodeSyntaxError{Offset: 2, Err: io.ErrUnexpectedEOF}}, + {'{', 1, jsonparse.RuneTypeObjectBeg, nil}, + {0, 0, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 2, Err: io.ErrUnexpectedEOF}}, + {0, 0, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 2, Err: io.ErrUnexpectedEOF}}, + {0, 0, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 2, Err: io.ErrUnexpectedEOF}}, }}, "empty": {``, ``, []ReadRuneTypeResult{ - {0, 0, internal.RuneTypeError, &DecodeSyntaxError{Offset: 0, Err: io.EOF}}, - {0, 0, internal.RuneTypeError, &DecodeSyntaxError{Offset: 0, Err: io.EOF}}, - {0, 0, internal.RuneTypeError, &DecodeSyntaxError{Offset: 0, Err: io.EOF}}, + {0, 0, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 0, Err: io.EOF}}, + {0, 0, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 0, Err: io.EOF}}, + {0, 0, jsonparse.RuneTypeError, &DecodeSyntaxError{Offset: 0, Err: io.EOF}}, }}, "basic2": {`1`, ``, []ReadRuneTypeResult{ - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, }}, "fragment": {`1,`, ``, []ReadRuneTypeResult{ - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {',', 1, internal.RuneTypeEOF, nil}, - {',', 1, internal.RuneTypeEOF, nil}, - {',', 1, internal.RuneTypeEOF, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {',', 1, jsonparse.RuneTypeEOF, nil}, + {',', 1, jsonparse.RuneTypeEOF, nil}, + {',', 1, jsonparse.RuneTypeEOF, nil}, }}, "elem": {` { "foo" : 12.0 } `, ``, []ReadRuneTypeResult{ - {'{', 1, internal.RuneTypeObjectBeg, nil}, - {'"', 1, internal.RuneTypeStringBeg, nil}, - {'f', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'o', 1, internal.RuneTypeStringChar, nil}, - {'"', 1, internal.RuneTypeStringEnd, nil}, - {':', 1, internal.RuneTypeObjectColon, nil}, + {'{', 1, jsonparse.RuneTypeObjectBeg, nil}, + {'"', 1, jsonparse.RuneTypeStringBeg, nil}, + {'f', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'o', 1, jsonparse.RuneTypeStringChar, nil}, + {'"', 1, jsonparse.RuneTypeStringEnd, nil}, + {':', 1, jsonparse.RuneTypeObjectColon, nil}, {0, pushReadBarrier, 0, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {'2', 1, internal.RuneTypeNumberIntDig, nil}, - {'.', 1, internal.RuneTypeNumberFracDot, nil}, - {'0', 1, internal.RuneTypeNumberFracDig, nil}, - {'}', 1, internal.RuneTypeEOF, nil}, - {'}', 1, internal.RuneTypeEOF, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'2', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {'.', 1, jsonparse.RuneTypeNumberFracDot, nil}, + {'0', 1, jsonparse.RuneTypeNumberFracDig, nil}, + {'}', 1, jsonparse.RuneTypeEOF, nil}, + {'}', 1, jsonparse.RuneTypeEOF, nil}, {0, popReadBarrier, 0, nil}, - {'}', 1, internal.RuneTypeObjectEnd, nil}, - {0, 0, internal.RuneTypeEOF, nil}, - {0, 0, internal.RuneTypeEOF, nil}, + {'}', 1, jsonparse.RuneTypeObjectEnd, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, + {0, 0, jsonparse.RuneTypeEOF, nil}, }}, } func() { @@ -214,9 +214,9 @@ func TestRuneTypeScanner(t *testing.T) { } tc.Input = `[1,` + tc.Input tc.Exp = append([]ReadRuneTypeResult{ - {'[', 1, internal.RuneTypeArrayBeg, nil}, - {'1', 1, internal.RuneTypeNumberIntDig, nil}, - {',', 1, internal.RuneTypeArrayComma, nil}, + {'[', 1, jsonparse.RuneTypeArrayBeg, nil}, + {'1', 1, jsonparse.RuneTypeNumberIntDig, nil}, + {',', 1, jsonparse.RuneTypeArrayComma, nil}, {0, pushReadBarrier, 0, nil}, }, tc.Exp...) for i := 2; i < len(tc.Exp); i++ { diff --git a/encode_string.go b/encode_string.go index 12f934e..a5d6633 100644 --- a/encode_string.go +++ b/encode_string.go @@ -8,17 +8,19 @@ import ( "io" "unicode/utf8" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/fastio" + "git.lukeshu.com/go/lowmemjson/internal/jsonparse" + "git.lukeshu.com/go/lowmemjson/internal/jsontest" ) func writeStringUnicodeEscape(w io.Writer, c rune) (int, error) { buf := [6]byte{ '\\', 'u', - internal.Hex[(c>>12)&0xf], - internal.Hex[(c>>8)&0xf], - internal.Hex[(c>>4)&0xf], - internal.Hex[(c>>0)&0xf], + jsonparse.Hex[(c>>12)&0xf], + jsonparse.Hex[(c>>8)&0xf], + jsonparse.Hex[(c>>4)&0xf], + jsonparse.Hex[(c>>0)&0xf], } return w.Write(buf[:]) } @@ -45,7 +47,7 @@ func writeStringShortEscape(w io.Writer, c rune) (int, error) { return w.Write(buf[:]) } -func writeStringChar(w internal.AllWriter, c rune, wasEscaped BackslashEscapeMode, escaper BackslashEscaper) (int, error) { +func writeStringChar(w fastio.AllWriter, c rune, wasEscaped BackslashEscapeMode, escaper BackslashEscaper) (int, error) { if escaper == nil { escaper = EscapeDefault } @@ -83,7 +85,7 @@ func writeStringChar(w internal.AllWriter, c rune, wasEscaped BackslashEscapeMod } } -func encodeStringFromString(w internal.AllWriter, escaper BackslashEscaper, str string) error { +func encodeStringFromString(w fastio.AllWriter, escaper BackslashEscaper, str string) error { if err := w.WriteByte('"'); err != nil { return err } @@ -98,7 +100,7 @@ func encodeStringFromString(w internal.AllWriter, escaper BackslashEscaper, str return nil } -func encodeStringFromBytes(w internal.AllWriter, escaper BackslashEscaper, str []byte) error { +func encodeStringFromBytes(w fastio.AllWriter, escaper BackslashEscaper, str []byte) error { if err := w.WriteByte('"'); err != nil { return err } @@ -116,13 +118,13 @@ func encodeStringFromBytes(w internal.AllWriter, escaper BackslashEscaper, str [ } func init() { - internal.EncodeStringFromString = func(w io.Writer, s string) { - if err := encodeStringFromString(internal.NewAllWriter(w), nil, s); err != nil { + jsontest.EncodeStringFromString = func(w io.Writer, s string) { + if err := encodeStringFromString(fastio.NewAllWriter(w), nil, s); err != nil { panic(err) } } - internal.EncodeStringFromBytes = func(w io.Writer, s []byte) { - if err := encodeStringFromBytes(internal.NewAllWriter(w), nil, s); err != nil { + jsontest.EncodeStringFromBytes = func(w io.Writer, s []byte) { + if err := encodeStringFromBytes(fastio.NewAllWriter(w), nil, s); err != nil { panic(err) } } diff --git a/errors.go b/errors.go index fe48723..0a47db4 100644 --- a/errors.go +++ b/errors.go @@ -11,7 +11,7 @@ import ( "reflect" "strings" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/jsonparse" ) // ErrInvalidUnreadRune is returned to Decodable.DecodeJSON(scanner) @@ -24,7 +24,7 @@ var ErrInvalidUnreadRune = errors.New("lowmemjson: invalid use of UnreadRune") // ErrParserExceededMaxDepth is the base error that a // *DecodeSyntaxError wraps when the depth of the JSON document // exceeds 10000. -var ErrParserExceededMaxDepth = internal.ErrParserExceededMaxDepth +var ErrParserExceededMaxDepth = jsonparse.ErrParserExceededMaxDepth // low-level decode errors ///////////////////////////////////////////////////////////////////////// // These will be wrapped in a *DecodeError. diff --git a/internal/allwriter.go b/internal/allwriter.go deleted file mode 100644 index 187aa8e..0000000 --- a/internal/allwriter.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (C) 2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -import ( - "io" - "unicode/utf8" -) - -// interfaces ///////////////////////////////////////////////////////////////// - -type RuneWriter interface { - WriteRune(rune) (int, error) -} - -// An AllWriter is the union of several common writer interfaces. -type AllWriter interface { - io.Writer - io.ByteWriter - RuneWriter - io.StringWriter -} - -// implementations //////////////////////////////////////////////////////////// - -func WriteByte(w io.Writer, b byte) error { - var buf [1]byte - buf[0] = b - _, err := w.Write(buf[:]) - return err -} - -func WriteRune(w io.Writer, r rune) (int, error) { - var buf [utf8.UTFMax]byte - n := utf8.EncodeRune(buf[:], r) - return w.Write(buf[:n]) -} - -func WriteString(w io.Writer, s string) (int, error) { - return w.Write([]byte(s)) -} - -// wrappers /////////////////////////////////////////////////////////////////// - -// NNN - -type ( - writerNNN interface{ io.Writer } - writerNNNWrapper struct{ writerNNN } -) - -func (w writerNNNWrapper) WriteByte(b byte) error { return WriteByte(w, b) } -func (w writerNNNWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } -func (w writerNNNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } - -// NNY - -type ( - writerNNY interface { - io.Writer - io.StringWriter - } - writerNNYWrapper struct{ writerNNY } -) - -func (w writerNNYWrapper) WriteByte(b byte) error { return WriteByte(w, b) } -func (w writerNNYWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } - -// NYN - -type ( - writerNYN interface { - io.Writer - RuneWriter - } - writerNYNWrapper struct{ writerNYN } -) - -func (w writerNYNWrapper) WriteByte(b byte) error { return WriteByte(w, b) } -func (w writerNYNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } - -// NYY - -type ( - writerNYY interface { - io.Writer - RuneWriter - io.StringWriter - } - writerNYYWrapper struct{ writerNYY } -) - -func (w writerNYYWrapper) WriteByte(b byte) error { return WriteByte(w, b) } - -// YNN - -type ( - writerYNN interface { - io.Writer - io.ByteWriter - } - writerYNNWrapper struct{ writerYNN } -) - -func (w writerYNNWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } -func (w writerYNNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } - -// YNY - -type ( - writerYNY interface { - io.Writer - io.ByteWriter - io.StringWriter - } - writerYNYWrapper struct{ writerYNY } -) - -func (w writerYNYWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } - -// YYN - -type ( - writerYYN interface { - io.Writer - io.ByteWriter - RuneWriter - } - writerYYNWrapper struct{ writerYYN } -) - -func (w writerYYNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } - -// NewAllWriter wraps an io.Writer turning it in to an AllWriter. If -// the io.Writer already has any of the other write methods, then its -// native version of those methods are used. -func NewAllWriter(inner io.Writer) AllWriter { - switch inner := inner.(type) { - // 3 Y bits - case AllWriter: // YYY: - return inner - // 2 Y bits - case writerNYY: - return writerNYYWrapper{writerNYY: inner} - case writerYNY: - return writerYNYWrapper{writerYNY: inner} - case writerYYN: - return writerYYNWrapper{writerYYN: inner} - // 1 Y bit - case writerNNY: - return writerNNYWrapper{writerNNY: inner} - case writerNYN: - return writerNYNWrapper{writerNYN: inner} - case writerYNN: - return writerYNNWrapper{writerYNN: inner} - // 0 Y bits - default: // NNN: - return writerNNNWrapper{writerNNN: inner} - } -} - -// discard ///////////////////////////////////////////////////////////////////// - -// Discard is like io.Discard, but implements AllWriter. -var Discard = discard{} - -type discard struct{} - -func (discard) Write(p []byte) (int, error) { return len(p), nil } -func (discard) WriteByte(b byte) error { return nil } -func (discard) WriteRune(r rune) (int, error) { return 0, nil } -func (discard) WriteString(s string) (int, error) { return len(s), nil } diff --git a/internal/base64.go b/internal/base64.go deleted file mode 100644 index 291a229..0000000 --- a/internal/base64.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -import ( - "encoding/base64" - "io" - "strings" -) - -type base64Decoder struct { - dst io.Writer - - err error - pos int64 - buf [4]byte - bufLen int -} - -func NewBase64Decoder(w io.Writer) interface { - io.WriteCloser - RuneWriter -} { - return &base64Decoder{ - dst: w, - } -} - -func (dec *base64Decoder) decodeByte(b byte) (byte, bool) { - const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - n := strings.IndexByte(alphabet, b) - if n < 0 { - return 0, false - } - dec.pos++ - return byte(n), true -} - -func (dec *base64Decoder) decodeTuple(a, b, c, d byte) error { - var decodedLen int - var encoded [4]byte - var ok bool - - if a != '=' { - encoded[0], ok = dec.decodeByte(a) - if !ok { - return base64.CorruptInputError(dec.pos) - } - decodedLen++ - } - if b != '=' { - encoded[1], ok = dec.decodeByte(b) - if !ok { - return base64.CorruptInputError(dec.pos) - } - // do NOT increment decodedLen here - } - if c != '=' { - encoded[2], ok = dec.decodeByte(c) - if !ok { - return base64.CorruptInputError(dec.pos) - } - decodedLen++ - } - if d != '=' { - encoded[3], ok = dec.decodeByte(d) - if !ok { - return base64.CorruptInputError(dec.pos) - } - decodedLen++ - } - - val := 0 | - uint32(encoded[0])<<18 | - uint32(encoded[1])<<12 | - uint32(encoded[2])<<6 | - uint32(encoded[3])<<0 - var decoded [3]byte - decoded[0] = byte(val >> 16) - decoded[1] = byte(val >> 8) - decoded[2] = byte(val >> 0) - - _, err := dec.dst.Write(decoded[:decodedLen]) - return err -} - -func (dec *base64Decoder) Write(dat []byte) (int, error) { - if len(dat) == 0 { - return 0, nil - } - if dec.err != nil { - return 0, dec.err - } - var n int - if dec.bufLen > 0 { - n = copy(dec.buf[dec.bufLen:], dat) - dec.bufLen += n - if dec.bufLen < 4 { - return len(dat), nil - } - if err := dec.decodeTuple(dec.buf[0], dec.buf[1], dec.buf[2], dec.buf[3]); err != nil { - dec.err = err - return 0, dec.err - } - } - for ; n+3 < len(dat); n += 4 { - if err := dec.decodeTuple(dat[n], dat[n+1], dat[n+2], dat[n+3]); err != nil { - dec.err = err - return n, dec.err - } - } - dec.bufLen = copy(dec.buf[:], dat[n:]) - return len(dat), nil -} - -func (dec *base64Decoder) WriteRune(r rune) (int, error) { - return WriteRune(dec, r) -} - -func (dec *base64Decoder) Close() error { - if dec.bufLen == 0 { - return nil - } - copy(dec.buf[:], "====") - return dec.decodeTuple(dec.buf[0], dec.buf[1], dec.buf[2], dec.buf[3]) -} diff --git a/internal/base64_test.go b/internal/base64_test.go deleted file mode 100644 index f18bcd7..0000000 --- a/internal/base64_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -import ( - "bytes" - "encoding/base64" - "testing" - - "github.com/stretchr/testify/require" -) - -func b64encode(t *testing.T, input []byte) []byte { - var encoded bytes.Buffer - enc := base64.NewEncoder(base64.StdEncoding, &encoded) - _, err := enc.Write(input) - require.NoError(t, err) - require.NoError(t, enc.Close()) - return encoded.Bytes() -} - -func b64decode(t *testing.T, input []byte) []byte { - var decoded bytes.Buffer - dec := NewBase64Decoder(&decoded) - _, err := dec.Write(input) - require.NoError(t, err) - require.NoError(t, dec.Close()) - return decoded.Bytes() -} - -func FuzzBase64Decoder(f *testing.F) { - f.Fuzz(func(t *testing.T, input []byte) { - encoded := b64encode(t, input) - decoded := b64decode(t, encoded) - t.Logf("input b64 = %q", encoded) - t.Logf("expected decoded = %#v", input) - t.Logf("actual decoded = %#v", decoded) - if !bytes.Equal(input, decoded) { - t.Fail() - } - }) -} diff --git a/internal/base64dec/base64.go b/internal/base64dec/base64.go new file mode 100644 index 0000000..dcb4b1c --- /dev/null +++ b/internal/base64dec/base64.go @@ -0,0 +1,130 @@ +// Copyright (C) 2022-2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package base64dec + +import ( + "encoding/base64" + "io" + "strings" + + "git.lukeshu.com/go/lowmemjson/internal/fastio" +) + +type base64Decoder struct { + dst io.Writer + + err error + pos int64 + buf [4]byte + bufLen int +} + +func NewBase64Decoder(w io.Writer) interface { + io.WriteCloser + fastio.RuneWriter +} { + return &base64Decoder{ + dst: w, + } +} + +func (dec *base64Decoder) decodeByte(b byte) (byte, bool) { + const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + n := strings.IndexByte(alphabet, b) + if n < 0 { + return 0, false + } + dec.pos++ + return byte(n), true +} + +func (dec *base64Decoder) decodeTuple(a, b, c, d byte) error { + var decodedLen int + var encoded [4]byte + var ok bool + + if a != '=' { + encoded[0], ok = dec.decodeByte(a) + if !ok { + return base64.CorruptInputError(dec.pos) + } + decodedLen++ + } + if b != '=' { + encoded[1], ok = dec.decodeByte(b) + if !ok { + return base64.CorruptInputError(dec.pos) + } + // do NOT increment decodedLen here + } + if c != '=' { + encoded[2], ok = dec.decodeByte(c) + if !ok { + return base64.CorruptInputError(dec.pos) + } + decodedLen++ + } + if d != '=' { + encoded[3], ok = dec.decodeByte(d) + if !ok { + return base64.CorruptInputError(dec.pos) + } + decodedLen++ + } + + val := 0 | + uint32(encoded[0])<<18 | + uint32(encoded[1])<<12 | + uint32(encoded[2])<<6 | + uint32(encoded[3])<<0 + var decoded [3]byte + decoded[0] = byte(val >> 16) + decoded[1] = byte(val >> 8) + decoded[2] = byte(val >> 0) + + _, err := dec.dst.Write(decoded[:decodedLen]) + return err +} + +func (dec *base64Decoder) Write(dat []byte) (int, error) { + if len(dat) == 0 { + return 0, nil + } + if dec.err != nil { + return 0, dec.err + } + var n int + if dec.bufLen > 0 { + n = copy(dec.buf[dec.bufLen:], dat) + dec.bufLen += n + if dec.bufLen < 4 { + return len(dat), nil + } + if err := dec.decodeTuple(dec.buf[0], dec.buf[1], dec.buf[2], dec.buf[3]); err != nil { + dec.err = err + return 0, dec.err + } + } + for ; n+3 < len(dat); n += 4 { + if err := dec.decodeTuple(dat[n], dat[n+1], dat[n+2], dat[n+3]); err != nil { + dec.err = err + return n, dec.err + } + } + dec.bufLen = copy(dec.buf[:], dat[n:]) + return len(dat), nil +} + +func (dec *base64Decoder) WriteRune(r rune) (int, error) { + return fastio.WriteRune(dec, r) +} + +func (dec *base64Decoder) Close() error { + if dec.bufLen == 0 { + return nil + } + copy(dec.buf[:], "====") + return dec.decodeTuple(dec.buf[0], dec.buf[1], dec.buf[2], dec.buf[3]) +} diff --git a/internal/base64dec/base64_test.go b/internal/base64dec/base64_test.go new file mode 100644 index 0000000..cb3063d --- /dev/null +++ b/internal/base64dec/base64_test.go @@ -0,0 +1,44 @@ +// Copyright (C) 2022-2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package base64dec + +import ( + "bytes" + "encoding/base64" + "testing" + + "github.com/stretchr/testify/require" +) + +func b64encode(t *testing.T, input []byte) []byte { + var encoded bytes.Buffer + enc := base64.NewEncoder(base64.StdEncoding, &encoded) + _, err := enc.Write(input) + require.NoError(t, err) + require.NoError(t, enc.Close()) + return encoded.Bytes() +} + +func b64decode(t *testing.T, input []byte) []byte { + var decoded bytes.Buffer + dec := NewBase64Decoder(&decoded) + _, err := dec.Write(input) + require.NoError(t, err) + require.NoError(t, dec.Close()) + return decoded.Bytes() +} + +func FuzzBase64Decoder(f *testing.F) { + f.Fuzz(func(t *testing.T, input []byte) { + encoded := b64encode(t, input) + decoded := b64decode(t, encoded) + t.Logf("input b64 = %q", encoded) + t.Logf("expected decoded = %#v", input) + t.Logf("actual decoded = %#v", decoded) + if !bytes.Equal(input, decoded) { + t.Fail() + } + }) +} diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 new file mode 100644 index 0000000..c3774e7 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a new file mode 100644 index 0000000..4c861db --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 new file mode 100644 index 0000000..3d32e14 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd new file mode 100644 index 0000000..d08ef92 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 0000000..a96f559 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 new file mode 100644 index 0000000..87c024d --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d new file mode 100644 index 0000000..959401e --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b new file mode 100644 index 0000000..bd1ae59 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c new file mode 100644 index 0000000..09e0ad2 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c new file mode 100644 index 0000000..e8000f3 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c new file mode 100644 index 0000000..aac6b7d --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f new file mode 100644 index 0000000..f3bf6d9 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 new file mode 100644 index 0000000..2e7f462 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a new file mode 100644 index 0000000..c541f52 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c new file mode 100644 index 0000000..5d56f29 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 new file mode 100644 index 0000000..4b4d59f --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 new file mode 100644 index 0000000..ef9f9d4 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 new file mode 100644 index 0000000..67322c7 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 new file mode 100644 index 0000000..f195330 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\x04000000000000\r00000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a new file mode 100644 index 0000000..5b0d392 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000000000000000000000000000000000000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 new file mode 100644 index 0000000..a389d3c --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("00000") diff --git a/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 new file mode 100644 index 0000000..17d10b2 --- /dev/null +++ b/internal/base64dec/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000") diff --git a/internal/borrowed_tags.go b/internal/borrowed_tags.go deleted file mode 100644 index 6eaf5da..0000000 --- a/internal/borrowed_tags.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2011 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. -// -// SPDX-License-Identifier: BSD-3-Clause - -package internal // MODIFIED: changed package name - -import ( - "strings" -) - -// tagOptions is the string following a comma in a struct field's "json" -// tag, or the empty string. It does not include the leading comma. -type tagOptions string - -// parseTag splits a struct field's json tag into its name and -// comma-separated options. -func parseTag(tag string) (string, tagOptions) { - tag, opt, _ := strings.Cut(tag, ",") - return tag, tagOptions(opt) -} - -// Contains reports whether a comma-separated list of options -// contains a particular substr flag. substr must be surrounded by a -// string boundary or commas. -func (o tagOptions) Contains(optionName string) bool { - if len(o) == 0 { - return false - } - s := string(o) - for s != "" { - var name string - name, s, _ = strings.Cut(s, ",") - if name == optionName { - return true - } - } - return false -} diff --git a/internal/encode.go b/internal/encode.go deleted file mode 100644 index 8aae673..0000000 --- a/internal/encode.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -import ( - "io" -) - -var ( - EncodeStringFromBytes func(io.Writer, []byte) - EncodeStringFromString func(io.Writer, string) -) diff --git a/internal/fastio/allwriter.go b/internal/fastio/allwriter.go new file mode 100644 index 0000000..9de8fdc --- /dev/null +++ b/internal/fastio/allwriter.go @@ -0,0 +1,174 @@ +// Copyright (C) 2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package fastio + +import ( + "io" + "unicode/utf8" +) + +// interfaces ///////////////////////////////////////////////////////////////// + +type RuneWriter interface { + WriteRune(rune) (int, error) +} + +// An AllWriter is the union of several common writer interfaces. +type AllWriter interface { + io.Writer + io.ByteWriter + RuneWriter + io.StringWriter +} + +// implementations //////////////////////////////////////////////////////////// + +func WriteByte(w io.Writer, b byte) error { + var buf [1]byte + buf[0] = b + _, err := w.Write(buf[:]) + return err +} + +func WriteRune(w io.Writer, r rune) (int, error) { + var buf [utf8.UTFMax]byte + n := utf8.EncodeRune(buf[:], r) + return w.Write(buf[:n]) +} + +func WriteString(w io.Writer, s string) (int, error) { + return w.Write([]byte(s)) +} + +// wrappers /////////////////////////////////////////////////////////////////// + +// NNN + +type ( + writerNNN interface{ io.Writer } + writerNNNWrapper struct{ writerNNN } +) + +func (w writerNNNWrapper) WriteByte(b byte) error { return WriteByte(w, b) } +func (w writerNNNWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } +func (w writerNNNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } + +// NNY + +type ( + writerNNY interface { + io.Writer + io.StringWriter + } + writerNNYWrapper struct{ writerNNY } +) + +func (w writerNNYWrapper) WriteByte(b byte) error { return WriteByte(w, b) } +func (w writerNNYWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } + +// NYN + +type ( + writerNYN interface { + io.Writer + RuneWriter + } + writerNYNWrapper struct{ writerNYN } +) + +func (w writerNYNWrapper) WriteByte(b byte) error { return WriteByte(w, b) } +func (w writerNYNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } + +// NYY + +type ( + writerNYY interface { + io.Writer + RuneWriter + io.StringWriter + } + writerNYYWrapper struct{ writerNYY } +) + +func (w writerNYYWrapper) WriteByte(b byte) error { return WriteByte(w, b) } + +// YNN + +type ( + writerYNN interface { + io.Writer + io.ByteWriter + } + writerYNNWrapper struct{ writerYNN } +) + +func (w writerYNNWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } +func (w writerYNNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } + +// YNY + +type ( + writerYNY interface { + io.Writer + io.ByteWriter + io.StringWriter + } + writerYNYWrapper struct{ writerYNY } +) + +func (w writerYNYWrapper) WriteRune(r rune) (int, error) { return WriteRune(w, r) } + +// YYN + +type ( + writerYYN interface { + io.Writer + io.ByteWriter + RuneWriter + } + writerYYNWrapper struct{ writerYYN } +) + +func (w writerYYNWrapper) WriteString(s string) (int, error) { return WriteString(w, s) } + +// NewAllWriter wraps an io.Writer turning it in to an AllWriter. If +// the io.Writer already has any of the other write methods, then its +// native version of those methods are used. +func NewAllWriter(inner io.Writer) AllWriter { + switch inner := inner.(type) { + // 3 Y bits + case AllWriter: // YYY: + return inner + // 2 Y bits + case writerNYY: + return writerNYYWrapper{writerNYY: inner} + case writerYNY: + return writerYNYWrapper{writerYNY: inner} + case writerYYN: + return writerYYNWrapper{writerYYN: inner} + // 1 Y bit + case writerNNY: + return writerNNYWrapper{writerNNY: inner} + case writerNYN: + return writerNYNWrapper{writerNYN: inner} + case writerYNN: + return writerYNNWrapper{writerYNN: inner} + // 0 Y bits + default: // NNN: + return writerNNNWrapper{writerNNN: inner} + } +} + +// discard ///////////////////////////////////////////////////////////////////// + +// Discard is like io.Discard, but implements AllWriter. +var Discard = discard{} + +type discard struct{} + +func (discard) Write(p []byte) (int, error) { return len(p), nil } +func (discard) WriteByte(b byte) error { return nil } +func (discard) WriteRune(r rune) (int, error) { return 0, nil } +func (discard) WriteString(s string) (int, error) { return len(s), nil } diff --git a/internal/hex.go b/internal/hex.go deleted file mode 100644 index 62a818f..0000000 --- a/internal/hex.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -const Hex = "0123456789abcdef" - -func HexToInt(c rune) (byte, bool) { - switch { - case '0' <= c && c <= '9': - return byte(c) - '0', true - case 'a' <= c && c <= 'f': - return byte(c) - 'a' + 10, true - case 'A' <= c && c <= 'F': - return byte(c) - 'A' + 10, true - default: - return 0, false - } -} diff --git a/internal/jsonparse/hex.go b/internal/jsonparse/hex.go new file mode 100644 index 0000000..3ed5f01 --- /dev/null +++ b/internal/jsonparse/hex.go @@ -0,0 +1,20 @@ +// Copyright (C) 2022-2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package jsonparse + +const Hex = "0123456789abcdef" + +func HexToInt(c rune) (byte, bool) { + switch { + case '0' <= c && c <= '9': + return byte(c) - '0', true + case 'a' <= c && c <= 'f': + return byte(c) - 'a' + 10, true + case 'A' <= c && c <= 'F': + return byte(c) - 'A' + 10, true + default: + return 0, false + } +} diff --git a/internal/jsonparse/parse.go b/internal/jsonparse/parse.go new file mode 100644 index 0000000..7d97be0 --- /dev/null +++ b/internal/jsonparse/parse.go @@ -0,0 +1,845 @@ +// Copyright (C) 2022-2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package jsonparse + +import ( + "errors" + "fmt" + "io" + iofs "io/fs" + "strings" +) + +var ErrParserExceededMaxDepth = errors.New("exceeded max depth") + +// RuneType is the classification of a rune when parsing JSON input. +// A Parser, rather than grouping runes into tokens and classifying +// tokens, classifies runes directly. +type RuneType uint8 + +const ( + RuneTypeError RuneType = iota + + RuneTypeSpace // whitespace + + RuneTypeObjectBeg // '{' + RuneTypeObjectColon // ':' + RuneTypeObjectComma // ',' + RuneTypeObjectEnd // '}' + + RuneTypeArrayBeg // '[' + RuneTypeArrayComma // ',' + RuneTypeArrayEnd // ']' + + RuneTypeStringBeg // opening '"' + RuneTypeStringChar // normal character + RuneTypeStringEsc // backslash + RuneTypeStringEsc1 // single-char after a backslash + RuneTypeStringEscU // \uABCD : u + RuneTypeStringEscUA // \uABCD : A + RuneTypeStringEscUB // \uABCD : B + RuneTypeStringEscUC // \uABCD : C + RuneTypeStringEscUD // \uABCD : D + RuneTypeStringEnd // closing '"' + + RuneTypeNumberIntNeg + RuneTypeNumberIntZero // leading zero only; non-leading zeros are IntDig, not IntZero + RuneTypeNumberIntDig + RuneTypeNumberFracDot + RuneTypeNumberFracDig + RuneTypeNumberExpE + RuneTypeNumberExpSign + RuneTypeNumberExpDig + + RuneTypeTrueT + RuneTypeTrueR + RuneTypeTrueU + RuneTypeTrueE + + RuneTypeFalseF + RuneTypeFalseA + RuneTypeFalseL + RuneTypeFalseS + RuneTypeFalseE + + RuneTypeNullN + RuneTypeNullU + RuneTypeNullL1 + RuneTypeNullL2 + + RuneTypeEOF + + // Not a real rune type, but used as a stack state. + runeTypeAny +) + +// GoString implements fmt.GoStringer. +// +//nolint:dupl // False positive due to similarly shaped AST. +func (t RuneType) GoString() string { + str, ok := map[RuneType]string{ + RuneTypeError: "RuneTypeError", + + RuneTypeSpace: "RuneTypeSpace", + + RuneTypeObjectBeg: "RuneTypeObjectBeg", + RuneTypeObjectColon: "RuneTypeObjectColon", + RuneTypeObjectComma: "RuneTypeObjectComma", + RuneTypeObjectEnd: "RuneTypeObjectEnd", + + RuneTypeArrayBeg: "RuneTypeArrayBeg", + RuneTypeArrayComma: "RuneTypeArrayComma", + RuneTypeArrayEnd: "RuneTypeArrayEnd", + + RuneTypeStringBeg: "RuneTypeStringBeg", + RuneTypeStringChar: "RuneTypeStringChar", + RuneTypeStringEsc: "RuneTypeStringEsc", + RuneTypeStringEsc1: "RuneTypeStringEsc1", + RuneTypeStringEscU: "RuneTypeStringEscU", + RuneTypeStringEscUA: "RuneTypeStringEscUA", + RuneTypeStringEscUB: "RuneTypeStringEscUB", + RuneTypeStringEscUC: "RuneTypeStringEscUC", + RuneTypeStringEscUD: "RuneTypeStringEscUD", + RuneTypeStringEnd: "RuneTypeStringEnd", + + RuneTypeNumberIntNeg: "RuneTypeNumberIntNeg", + RuneTypeNumberIntZero: "RuneTypeNumberIntZero", + RuneTypeNumberIntDig: "RuneTypeNumberIntDig", + RuneTypeNumberFracDot: "RuneTypeNumberFracDot", + RuneTypeNumberFracDig: "RuneTypeNumberFracDig", + RuneTypeNumberExpE: "RuneTypeNumberExpE", + RuneTypeNumberExpSign: "RuneTypeNumberExpSign", + RuneTypeNumberExpDig: "RuneTypeNumberExpDig", + + RuneTypeTrueT: "RuneTypeTrueT", + RuneTypeTrueR: "RuneTypeTrueR", + RuneTypeTrueU: "RuneTypeTrueU", + RuneTypeTrueE: "RuneTypeTrueE", + + RuneTypeFalseF: "RuneTypeFalseF", + RuneTypeFalseA: "RuneTypeFalseA", + RuneTypeFalseL: "RuneTypeFalseL", + RuneTypeFalseS: "RuneTypeFalseS", + RuneTypeFalseE: "RuneTypeFalseE", + + RuneTypeNullN: "RuneTypeNullN", + RuneTypeNullU: "RuneTypeNullU", + RuneTypeNullL1: "RuneTypeNullL1", + RuneTypeNullL2: "RuneTypeNullL2", + + RuneTypeEOF: "RuneTypeEOF", + + runeTypeAny: "runeTypeAny", + }[t] + if ok { + return str + } + return fmt.Sprintf("RuneType(%d)", t) +} + +// String implements fmt.Stringer. +// +//nolint:dupl // False positive due to similarly shaped AST. +func (t RuneType) String() string { + str, ok := map[RuneType]string{ + RuneTypeError: "x", + + RuneTypeSpace: " ", + + RuneTypeObjectBeg: "{", + RuneTypeObjectColon: ":", + RuneTypeObjectComma: "o", + RuneTypeObjectEnd: "}", + + RuneTypeArrayBeg: "[", + RuneTypeArrayComma: "a", + RuneTypeArrayEnd: "]", + + RuneTypeStringBeg: "\"", + RuneTypeStringChar: "c", + RuneTypeStringEsc: "\\", + RuneTypeStringEsc1: "b", + RuneTypeStringEscU: "u", + RuneTypeStringEscUA: "A", + RuneTypeStringEscUB: "B", + RuneTypeStringEscUC: "C", + RuneTypeStringEscUD: "D", + RuneTypeStringEnd: "»", + + RuneTypeNumberIntNeg: "-", + RuneTypeNumberIntZero: "0", + RuneTypeNumberIntDig: "1", + RuneTypeNumberFracDot: ".", + RuneTypeNumberFracDig: "2", + RuneTypeNumberExpE: "e", + RuneTypeNumberExpSign: "+", + RuneTypeNumberExpDig: "3", + + RuneTypeTrueT: "𝕥", // double-struck + RuneTypeTrueR: "𝕣", + RuneTypeTrueU: "𝕦", + RuneTypeTrueE: "𝕖", + + RuneTypeFalseF: "𝔣", // fraktur + RuneTypeFalseA: "𝔞", + RuneTypeFalseL: "𝔩", + RuneTypeFalseS: "𝔰", + RuneTypeFalseE: "𝔢", + + RuneTypeNullN: "ⓝ", // circled + RuneTypeNullU: "ⓤ", + RuneTypeNullL1: "ⓛ", + RuneTypeNullL2: "Ⓛ", // +uppercase + + RuneTypeEOF: "$", + + runeTypeAny: "?", + }[t] + if ok { + return str + } + return fmt.Sprintf("<%d>", t) +} + +func (t RuneType) JSONType() string { + return map[RuneType]string{ + RuneTypeObjectBeg: "object", + RuneTypeArrayBeg: "array", + RuneTypeStringBeg: "string", + RuneTypeNumberIntNeg: "number", + RuneTypeNumberIntZero: "number", + RuneTypeNumberIntDig: "number", + RuneTypeTrueT: "true", + RuneTypeFalseF: "false", + RuneTypeNullN: "null", + RuneTypeEOF: "eof", + }[t] +} + +// IsNumber returns whether the RuneType is one of the +// RuneTypeNumberXXX values. +func (t RuneType) IsNumber() bool { + return RuneTypeNumberIntNeg <= t && t <= RuneTypeNumberExpDig +} + +// Parser is the low-level JSON parser that powers both *Decoder and +// *ReEncoder. +type Parser struct { + // Setting MaxError to a value greater than 0 causes + // HandleRune to return ErrParserExceededMaxDepth if + // objects/arrays become nested more deeply than this. + MaxDepth int + + initialized bool + + err error + closed bool + + // We reuse RuneTypes to store the stack. The base idea is: + // stack items are "the most recently read stack-relevant + // RuneType". + // + // The stack starts out with the special pseudo-RuneType + // `runeTypeAny` that means we're willing to accept any + // element type; an empty stack means that we have reached the + // end of the top-level element and should accept no more + // input except for whitespace. + // + // The "normal" stack-relevant RuneTypes are: + // + // "\uABC for strings + // -01.2e+3 for numbers + // 𝕥𝕣𝕦 for "true" + // 𝔣𝔞𝔩𝔰 for "false" + // ⓝⓤⓛ for "null" + // + // Objects and arrays break the "most recently read RuneType" + // rule; they need some special assignments: + // + // { object: waiting for key to start or '}' + // » object: reading key / waiting for colon + // o object: reading value / waiting for ',' or '}' + // + // [ array: waiting for item to start or ']' + // a array: reading item / waiting for ',' or ']' + // + // Within each element type, the stack item is replaced, not pushed. + // + // (Keep each of these examples in-sync with parse_test.go.) + // + // For example, given the input string + // + // {"x":"y","a":"b"} + // + // The stack would be + // + // stack processed + // ? + // { { + // »" {" + // »" {"x + // » {"x" + // o? {"x": + // o" {"x":" + // o" {"x":"y + // o {"x":"y" + // { {"x":"y", + // »" {"x":"y"," + // »" {"x":"y","a + // » {"x":"y","a" + // o? {"x":"y","a": + // o" {"x":"y","a":" + // o" {"x":"y","a":"b + // o {"x":"y","a":"b" + // {"x":"y","a":"b"} + // + // Or, given the input string + // + // ["x","y"] + // + // The stack would be + // + // stack processed + // ? + // [ [ + // a" [" + // a" ["x + // a ["x" + // a? ["x", + // a" ["x"," + // a" ["x","y + // a ["x","y" + // ["x","y"] + stack []RuneType + + barriers []barrier +} + +type barrier struct { + closed bool + stack []RuneType +} + +func (par *Parser) init() { + if !par.initialized { + par.initialized = true + par.pushState(runeTypeAny) + } +} + +func (par *Parser) pushState(state RuneType) RuneType { + par.stack = append(par.stack, state) + return state +} + +func (par *Parser) replaceState(state RuneType) RuneType { + par.stack[len(par.stack)-1] = state + return state +} + +func (par *Parser) popState() { + par.stack = par.stack[:len(par.stack)-1] +} + +func (par *Parser) stackString() string { + par.init() + var buf strings.Builder + for _, s := range par.stack { + buf.WriteString(s.String()) + } + return buf.String() +} + +func (par *Parser) depth() int { + n := len(par.stack) + for _, barrier := range par.barriers { + n += len(barrier.stack) + } + return n +} + +func (par *Parser) StackIsEmpty() bool { + if len(par.barriers) > 0 { + return false + } + if len(par.stack) == 0 { + return true + } + return len(par.stack) == 1 && par.stack[0] == runeTypeAny +} + +func (par *Parser) StackSize() int { + return len(par.stack) +} + +// Reset all Parser state. +func (par *Parser) Reset() { + *par = Parser{ + MaxDepth: par.MaxDepth, + } +} + +// PushReadBarrier causes the parser to expect EOF once the end of the +// element that is started by the current top-of-stack is reached, +// until this is un-done with PopBarrier. It essentially turns the +// parser in to a sub-parser. +// +// PushReadBarrier may only be called at the beginning of an element, +// whether that be +// +// - runeTypeAny +// - RuneTypeObjectBeg +// - RuneTypeArrayBeg +// - RuneTypeStringBeg +// - RuneTypeNumberIntNeg, RuneTypeNumberIntZero, RuneTypeNumberIntDig +// - RuneTypeTrueT +// - RuneTypeFalseF +// - RuneTypeNullN +func (par *Parser) PushReadBarrier() { + // Sanity checking. + par.init() + if len(par.stack) == 0 { + panic(errors.New("illegal PushReadBarrier call: empty stack")) + } + curState := par.stack[len(par.stack)-1] + switch curState { + case runeTypeAny, + RuneTypeObjectBeg, + RuneTypeArrayBeg, + RuneTypeStringBeg, + RuneTypeNumberIntNeg, RuneTypeNumberIntZero, RuneTypeNumberIntDig, + RuneTypeTrueT, + RuneTypeFalseF, + RuneTypeNullN: + // OK + default: + panic(fmt.Errorf("illegal PushReadBarrier call: %q", curState)) + } + // Actually push. + par.barriers = append(par.barriers, barrier{ + closed: par.closed, + stack: par.stack[:len(par.stack)-1], + }) + par.stack = []RuneType{curState} +} + +// PushWriteBarrier causes the parser to expect EOF once the end of +// the about-to-start element is reached, until this is un-done with +// PopBarrier. It essentially turns the parser in to a sub-parser. +// +// PushWriteBarrier may only be called at the places where an element +// of any type may start: +// +// - runeTypeAny for top-level and object-value elements +// - RuneTypeArrayBeg for array-item elements +// +// PushWriteBarrier signals intent to write an element; if it is +// called in a place where an element is optional (at the beginning of +// an array), it becomes a syntax error to not write the element. +func (par *Parser) PushWriteBarrier() { + par.init() + if len(par.stack) == 0 { + panic(errors.New("illegal PushWriteBarrier call: empty stack")) + } + switch par.stack[len(par.stack)-1] { + case runeTypeAny: + par.popState() + par.barriers = append(par.barriers, barrier{ + closed: par.closed, + stack: par.stack, + }) + par.stack = []RuneType{runeTypeAny} + case RuneTypeArrayBeg: + par.replaceState(RuneTypeArrayComma) + par.barriers = append(par.barriers, barrier{ + closed: par.closed, + stack: par.stack, + }) + par.stack = []RuneType{runeTypeAny} + default: + panic(fmt.Errorf("illegal PushWriteBarrier call: %q", par.stack[len(par.stack)-1])) + } +} + +// PopBarrier reverses a call to PushReadBarrier or PushWriteBarrier. +func (par *Parser) PopBarrier() { + if len(par.barriers) == 0 { + panic(errors.New("illegal PopBarrier call: empty barrier stack")) + } + barrier := par.barriers[len(par.barriers)-1] + par.barriers = par.barriers[:len(par.barriers)-1] + par.closed = barrier.closed + par.stack = append(barrier.stack, par.stack...) +} + +// HandleEOF feeds EOF to the Parser. The returned RuneType is either +// RuneTypeEOF or RuneTypeError. +// +// An error is returned if and only if the RuneType is RuneTypeError. +// Returns io/fs.ErrClosed if .HandleEOF() has previously been called +// (and .Reset() has not been called since). +// +// Once RuneTypeError or RuneTypeEOF has been returned, it will keep +// being returned from both .HandleRune(c) and .HandleEOF() until +// .Reset() is called. +// +// RuneTypeEOF indicates that a complete JSON document has been read. +func (par *Parser) HandleEOF() (RuneType, error) { + if par.closed { + return RuneTypeError, iofs.ErrClosed + } + defer func() { + par.closed = true + }() + if par.err != nil { + return RuneTypeError, par.err + } + par.init() + switch len(par.stack) { + case 0: + return RuneTypeEOF, nil + case 1: + switch { + case par.stack[0].IsNumber(): + if _, err := par.HandleRune('\n'); err == nil { + return RuneTypeEOF, nil + } + case par.stack[0] == runeTypeAny: + par.err = io.EOF + return RuneTypeError, par.err + } + fallthrough + default: + par.err = io.ErrUnexpectedEOF + return RuneTypeError, par.err + } +} + +// HandleRune feeds a Unicode rune to the Parser. +// +// An error is returned if and only if the RuneType is RuneTypeError. +// Returns io/fs.ErrClosed if .HandleEOF() has previously been called +// (and .Reset() has not been called since). +// +// Once RuneTypeError or RuneTypeEOF has been returned, it will keep +// being returned from both .HandleRune(c) and .HandleEOF() until +// .Reset() is called. +// +// RuneTypeEOF indicates that the rune cannot be appended to the JSON +// document; a new JSON document must be started in order to process +// that rune. +func (par *Parser) HandleRune(c rune) (RuneType, error) { + if par.closed { + return RuneTypeError, iofs.ErrClosed + } + if par.err != nil { + return RuneTypeError, par.err + } + par.init() + if len(par.stack) == 0 { + switch c { + case 0x0020, 0x000A, 0x000D, 0x0009: + return RuneTypeSpace, nil + default: + return RuneTypeEOF, nil + } + } + switch par.stack[len(par.stack)-1] { + // any ///////////////////////////////////////////////////////////////////////////////////// + case runeTypeAny: + switch c { + case 0x0020, 0x000A, 0x000D, 0x0009: + return RuneTypeSpace, nil + case '{': + if par.MaxDepth > 0 && par.depth() > par.MaxDepth { + return RuneTypeError, ErrParserExceededMaxDepth + } + return par.replaceState(RuneTypeObjectBeg), nil + case '[': + if par.MaxDepth > 0 && par.depth() > par.MaxDepth { + return RuneTypeError, ErrParserExceededMaxDepth + } + return par.replaceState(RuneTypeArrayBeg), nil + case '"': + return par.replaceState(RuneTypeStringBeg), nil + case '-': + return par.replaceState(RuneTypeNumberIntNeg), nil + case '0': + return par.replaceState(RuneTypeNumberIntZero), nil + case '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberIntDig), nil + case 't': + return par.replaceState(RuneTypeTrueT), nil + case 'f': + return par.replaceState(RuneTypeFalseF), nil + case 'n': + return par.replaceState(RuneTypeNullN), nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q looking for beginning of value", c) + } + // object ////////////////////////////////////////////////////////////////////////////////// + case RuneTypeObjectBeg: // waiting for key to start or '}' + switch c { + case 0x0020, 0x000A, 0x000D, 0x0009: + return RuneTypeSpace, nil + case '"': + par.replaceState(RuneTypeStringEnd) + return par.pushState(RuneTypeStringBeg), nil + case '}': + par.popState() + return RuneTypeObjectEnd, nil + default: + return RuneTypeError, fmt.Errorf("object: unexpected character: %q", c) + } + case RuneTypeStringEnd: // waiting for ':' + switch c { + case 0x0020, 0x000A, 0x000D, 0x0009: + return RuneTypeSpace, nil + case ':': + par.replaceState(RuneTypeObjectComma) + par.pushState(runeTypeAny) + return RuneTypeObjectColon, nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q after object key", c) + } + case RuneTypeObjectComma: // waiting for ',' or '}' + switch c { + case 0x0020, 0x000A, 0x000D, 0x0009: + return RuneTypeSpace, nil + case ',': + par.replaceState(RuneTypeObjectBeg) + return RuneTypeObjectComma, nil + case '}': + par.popState() + return RuneTypeObjectEnd, nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q after object key:value pair", c) + } + // array /////////////////////////////////////////////////////////////////////////////////// + case RuneTypeArrayBeg: // waiting for item to start or ']' + switch c { + case 0x0020, 0x000A, 0x000D, 0x0009: + return RuneTypeSpace, nil + case ']': + par.popState() + return RuneTypeArrayEnd, nil + default: + par.replaceState(RuneTypeArrayComma) + par.pushState(runeTypeAny) + return par.HandleRune(c) + } + case RuneTypeArrayComma: // waiting for ',' or ']' + switch c { + case 0x0020, 0x000A, 0x000D, 0x0009: + return RuneTypeSpace, nil + case ',': + par.pushState(runeTypeAny) + return RuneTypeArrayComma, nil + case ']': + par.popState() + return RuneTypeArrayEnd, nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q after array element", c) + } + // string ////////////////////////////////////////////////////////////////////////////////// + case RuneTypeStringBeg: // waiting for char or '"' + switch { + case c == '\\': + return par.replaceState(RuneTypeStringEsc), nil + case c == '"': + par.popState() + return RuneTypeStringEnd, nil + case 0x0020 <= c && c <= 0x10FFFF: + return RuneTypeStringChar, nil + default: + return RuneTypeError, fmt.Errorf("string: unexpected character: %q", c) + } + case RuneTypeStringEsc: // waiting for escape char + switch c { + case '"', '\\', '/', 'b', 'f', 'n', 'r', 't': + par.replaceState(RuneTypeStringBeg) + return RuneTypeStringEsc1, nil + case 'u': + return par.replaceState(RuneTypeStringEscU), nil + default: + return RuneTypeError, fmt.Errorf("string backslash sequence: unexpected character: %q", c) + } + case RuneTypeStringEscU: + if _, ok := HexToInt(c); ok { + return par.replaceState(RuneTypeStringEscUA), nil + } else { + return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) + } + case RuneTypeStringEscUA: + if _, ok := HexToInt(c); ok { + return par.replaceState(RuneTypeStringEscUB), nil + } else { + return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) + } + case RuneTypeStringEscUB: + if _, ok := HexToInt(c); ok { + return par.replaceState(RuneTypeStringEscUC), nil + } else { + return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) + } + case RuneTypeStringEscUC: + if _, ok := HexToInt(c); ok { + par.replaceState(RuneTypeStringBeg) + return RuneTypeStringEscUD, nil + } else { + return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) + } + // number ////////////////////////////////////////////////////////////////////////////////// + // + // Here's a flattened drawing of the syntax diagram from www.json.org : + // + // [------------ integer ----------][-- fraction ---][-------- exponent -------] + // >─╮─────╭─╮─"0"───────╭─────────╭──╮─────────────╭──╮───────────────────────╭─> + // │ │ │ │ │ │ │ │ │ + // ╰─"-"─╯ ╰─digit 1-9─╯─╭digit╮─╯ ╰─"."─╭digit╮─╯ ╰─"e"─╭─╮─────╭─╭digit╮─╯ + // ╰──<──╯ ╰──<──╯ │ │ │ │ ╰──<──╯ + // ╰─"E"─╯ ╰─"-"─╯ + // │ │ + // ╰─"+"─╯ + // + // Now here it is slightly redrawn, and with each distinct state our + // parser can be in marked with a single-capital-letter: + // + // [-------------- integer ------------][--------- fraction --------][--------- exponent ---------] + // >─A─╮───────╭──╮─"0"─────────C─╭─────────╮──────────────────╭─────────╮──────────────────────────╭─> + // │ │ │ │ │ │ │ │ + // ╰─"-"─B─╯ ╰─digit 1-9─╭─D─╯─digit╮ ╰─"."─E─digit──╭─F─╯─digit╮ ╰─"e"─╭─G─╮─────╭─╭digit─I─╯ + // ╰────<─────╯ ╰────<─────╯ │ │ │ H ╰────<───╯ + // ╰─"E"─╯ ╰─"-"─╯ + // │ │ + // ╰─"+"─╯ + // + // You may notice that each of these states may be uniquely identified + // by the last-read RuneType: + // + // A = (nothing yet) + // B = IntNeg + // C = IntZero + // D = IntDig + // E = FracDot + // F = FracDig + // G = ExpE + // H = ExpSign + // I = ExpDig + // + // The 'A' state is part of the runeTypeAny case above, and + // the remainder follow: + case RuneTypeNumberIntNeg: // B + switch c { + case '0': + return par.replaceState(RuneTypeNumberIntZero), nil + case '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberIntDig), nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) + } + case RuneTypeNumberIntZero: // C + switch c { + case '.': + return par.replaceState(RuneTypeNumberFracDot), nil + case 'e', 'E': + return par.replaceState(RuneTypeNumberExpE), nil + default: + par.popState() + return par.HandleRune(c) + } + case RuneTypeNumberIntDig: // D + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberIntDig), nil + case '.': + return par.replaceState(RuneTypeNumberFracDot), nil + case 'e', 'E': + return par.replaceState(RuneTypeNumberExpE), nil + default: + par.popState() + return par.HandleRune(c) + } + case RuneTypeNumberFracDot: // E + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberFracDig), nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) + } + case RuneTypeNumberFracDig: // F + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberFracDig), nil + case 'e', 'E': + return par.replaceState(RuneTypeNumberExpE), nil + default: + par.popState() + return par.HandleRune(c) + } + case RuneTypeNumberExpE: // G + switch c { + case '-', '+': + return par.replaceState(RuneTypeNumberExpSign), nil + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberExpDig), nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) + } + case RuneTypeNumberExpSign: // H + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberExpDig), nil + default: + return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) + } + case RuneTypeNumberExpDig: // I + switch c { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return par.replaceState(RuneTypeNumberExpDig), nil + default: + par.popState() + return par.HandleRune(c) + } + // literals //////////////////////////////////////////////////////////////////////////////// + // true + case RuneTypeTrueT: + return par.expectRune(c, 'r', RuneTypeTrueR, "true", false) + case RuneTypeTrueR: + return par.expectRune(c, 'u', RuneTypeTrueU, "true", false) + case RuneTypeTrueU: + return par.expectRune(c, 'e', RuneTypeTrueE, "true", true) + // false + case RuneTypeFalseF: + return par.expectRune(c, 'a', RuneTypeFalseA, "false", false) + case RuneTypeFalseA: + return par.expectRune(c, 'l', RuneTypeFalseL, "false", false) + case RuneTypeFalseL: + return par.expectRune(c, 's', RuneTypeFalseS, "false", false) + case RuneTypeFalseS: + return par.expectRune(c, 'e', RuneTypeFalseE, "false", true) + // null + case RuneTypeNullN: + return par.expectRune(c, 'u', RuneTypeNullU, "null", false) + case RuneTypeNullU: + return par.expectRune(c, 'l', RuneTypeNullL1, "null", false) + case RuneTypeNullL1: + return par.expectRune(c, 'l', RuneTypeNullL2, "null", true) + default: + panic(fmt.Errorf(`invalid stack: "%s"`, par.stackString())) + } +} + +func (par *Parser) expectRune(c, exp rune, typ RuneType, context string, pop bool) (RuneType, error) { + if c != exp { + return RuneTypeError, fmt.Errorf("invalid character %q in literal %s (expecting %q)", c, context, exp) + } + if pop { + par.popState() + return typ, nil + } else { + return par.replaceState(typ), nil + } +} diff --git a/internal/jsonparse/parse_test.go b/internal/jsonparse/parse_test.go new file mode 100644 index 0000000..e531daf --- /dev/null +++ b/internal/jsonparse/parse_test.go @@ -0,0 +1,78 @@ +// Copyright (C) 2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package jsonparse + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParserHandleRune(t *testing.T) { + t.Parallel() + type testcase struct { + Input string + ExpStack []string + } + testcases := map[string]testcase{ + // Keep these test-cases in-sync with the examples in parse.go. + "object": { + Input: `{"x":"y","a":"b"}`, + ExpStack: []string{ + // st,// processed + `?`, + `{`, // { + `»"`, // {" + `»"`, // {"x + `»`, // {"x" + `o?`, // {"x": + `o"`, // {"x":" + `o"`, // {"x":"y + `o`, // {"x":"y" + `{`, // {"x":"y", + `»"`, // {"x":"y"," + `»"`, // {"x":"y","a + `»`, // {"x":"y","a" + `o?`, // {"x":"y","a": + `o"`, // {"x":"y","a":" + `o"`, // {"x":"y","a":"b + `o`, // {"x":"y","a":"b" + ``, // {"x":"y","a":"b"} + }, + }, + "array": { + Input: `["x","y"]`, + ExpStack: []string{ + // st,// processed + `?`, + `[`, // [ + `a"`, // [" + `a"`, // ["x + `a`, // ["x" + `a?`, // ["x", + `a"`, // ["x"," + `a"`, // ["x","y + `a`, // ["x","y" + ``, // ["x","y"] + }, + }, + } + for tcName, tc := range testcases { + tc := tc + t.Run(tcName, func(t *testing.T) { + t.Parallel() + var par Parser + if !assert.Equal(t, len(tc.Input)+1, len(tc.ExpStack)) { + return + } + for i, r := range tc.Input { + assert.Equal(t, tc.ExpStack[i], par.stackString()) + _, err := par.HandleRune(r) + assert.NoError(t, err) + assert.Equal(t, tc.ExpStack[i+1], par.stackString()) + } + }) + } +} diff --git a/internal/jsontags/borrowed_tags.go b/internal/jsontags/borrowed_tags.go new file mode 100644 index 0000000..aa94b9b --- /dev/null +++ b/internal/jsontags/borrowed_tags.go @@ -0,0 +1,40 @@ +// Copyright 2011 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. +// +// SPDX-License-Identifier: BSD-3-Clause + +package jsontags // MODIFIED: changed package name + +import ( + "strings" +) + +// tagOptions is the string following a comma in a struct field's "json" +// tag, or the empty string. It does not include the leading comma. +type tagOptions string + +// parseTag splits a struct field's json tag into its name and +// comma-separated options. +func parseTag(tag string) (string, tagOptions) { + tag, opt, _ := strings.Cut(tag, ",") + return tag, tagOptions(opt) +} + +// Contains reports whether a comma-separated list of options +// contains a particular substr flag. substr must be surrounded by a +// string boundary or commas. +func (o tagOptions) Contains(optionName string) bool { + if len(o) == 0 { + return false + } + s := string(o) + for s != "" { + var name string + name, s, _ = strings.Cut(s, ",") + if name == optionName { + return true + } + } + return false +} diff --git a/internal/jsontags/tags.go b/internal/jsontags/tags.go new file mode 100644 index 0000000..386824d --- /dev/null +++ b/internal/jsontags/tags.go @@ -0,0 +1,7 @@ +// Copyright (C) 2022-2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package jsontags + +var ParseTag = parseTag diff --git a/internal/jsontest/jsontest.go b/internal/jsontest/jsontest.go new file mode 100644 index 0000000..fbc775d --- /dev/null +++ b/internal/jsontest/jsontest.go @@ -0,0 +1,14 @@ +// Copyright (C) 2022-2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package jsontest + +import ( + "io" +) + +var ( + EncodeStringFromBytes func(io.Writer, []byte) + EncodeStringFromString func(io.Writer, string) +) diff --git a/internal/parse.go b/internal/parse.go deleted file mode 100644 index 36db4a9..0000000 --- a/internal/parse.go +++ /dev/null @@ -1,845 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -import ( - "errors" - "fmt" - "io" - iofs "io/fs" - "strings" -) - -var ErrParserExceededMaxDepth = errors.New("exceeded max depth") - -// RuneType is the classification of a rune when parsing JSON input. -// A Parser, rather than grouping runes into tokens and classifying -// tokens, classifies runes directly. -type RuneType uint8 - -const ( - RuneTypeError RuneType = iota - - RuneTypeSpace // whitespace - - RuneTypeObjectBeg // '{' - RuneTypeObjectColon // ':' - RuneTypeObjectComma // ',' - RuneTypeObjectEnd // '}' - - RuneTypeArrayBeg // '[' - RuneTypeArrayComma // ',' - RuneTypeArrayEnd // ']' - - RuneTypeStringBeg // opening '"' - RuneTypeStringChar // normal character - RuneTypeStringEsc // backslash - RuneTypeStringEsc1 // single-char after a backslash - RuneTypeStringEscU // \uABCD : u - RuneTypeStringEscUA // \uABCD : A - RuneTypeStringEscUB // \uABCD : B - RuneTypeStringEscUC // \uABCD : C - RuneTypeStringEscUD // \uABCD : D - RuneTypeStringEnd // closing '"' - - RuneTypeNumberIntNeg - RuneTypeNumberIntZero // leading zero only; non-leading zeros are IntDig, not IntZero - RuneTypeNumberIntDig - RuneTypeNumberFracDot - RuneTypeNumberFracDig - RuneTypeNumberExpE - RuneTypeNumberExpSign - RuneTypeNumberExpDig - - RuneTypeTrueT - RuneTypeTrueR - RuneTypeTrueU - RuneTypeTrueE - - RuneTypeFalseF - RuneTypeFalseA - RuneTypeFalseL - RuneTypeFalseS - RuneTypeFalseE - - RuneTypeNullN - RuneTypeNullU - RuneTypeNullL1 - RuneTypeNullL2 - - RuneTypeEOF - - // Not a real rune type, but used as a stack state. - runeTypeAny -) - -// GoString implements fmt.GoStringer. -// -//nolint:dupl // False positive due to similarly shaped AST. -func (t RuneType) GoString() string { - str, ok := map[RuneType]string{ - RuneTypeError: "RuneTypeError", - - RuneTypeSpace: "RuneTypeSpace", - - RuneTypeObjectBeg: "RuneTypeObjectBeg", - RuneTypeObjectColon: "RuneTypeObjectColon", - RuneTypeObjectComma: "RuneTypeObjectComma", - RuneTypeObjectEnd: "RuneTypeObjectEnd", - - RuneTypeArrayBeg: "RuneTypeArrayBeg", - RuneTypeArrayComma: "RuneTypeArrayComma", - RuneTypeArrayEnd: "RuneTypeArrayEnd", - - RuneTypeStringBeg: "RuneTypeStringBeg", - RuneTypeStringChar: "RuneTypeStringChar", - RuneTypeStringEsc: "RuneTypeStringEsc", - RuneTypeStringEsc1: "RuneTypeStringEsc1", - RuneTypeStringEscU: "RuneTypeStringEscU", - RuneTypeStringEscUA: "RuneTypeStringEscUA", - RuneTypeStringEscUB: "RuneTypeStringEscUB", - RuneTypeStringEscUC: "RuneTypeStringEscUC", - RuneTypeStringEscUD: "RuneTypeStringEscUD", - RuneTypeStringEnd: "RuneTypeStringEnd", - - RuneTypeNumberIntNeg: "RuneTypeNumberIntNeg", - RuneTypeNumberIntZero: "RuneTypeNumberIntZero", - RuneTypeNumberIntDig: "RuneTypeNumberIntDig", - RuneTypeNumberFracDot: "RuneTypeNumberFracDot", - RuneTypeNumberFracDig: "RuneTypeNumberFracDig", - RuneTypeNumberExpE: "RuneTypeNumberExpE", - RuneTypeNumberExpSign: "RuneTypeNumberExpSign", - RuneTypeNumberExpDig: "RuneTypeNumberExpDig", - - RuneTypeTrueT: "RuneTypeTrueT", - RuneTypeTrueR: "RuneTypeTrueR", - RuneTypeTrueU: "RuneTypeTrueU", - RuneTypeTrueE: "RuneTypeTrueE", - - RuneTypeFalseF: "RuneTypeFalseF", - RuneTypeFalseA: "RuneTypeFalseA", - RuneTypeFalseL: "RuneTypeFalseL", - RuneTypeFalseS: "RuneTypeFalseS", - RuneTypeFalseE: "RuneTypeFalseE", - - RuneTypeNullN: "RuneTypeNullN", - RuneTypeNullU: "RuneTypeNullU", - RuneTypeNullL1: "RuneTypeNullL1", - RuneTypeNullL2: "RuneTypeNullL2", - - RuneTypeEOF: "RuneTypeEOF", - - runeTypeAny: "runeTypeAny", - }[t] - if ok { - return str - } - return fmt.Sprintf("RuneType(%d)", t) -} - -// String implements fmt.Stringer. -// -//nolint:dupl // False positive due to similarly shaped AST. -func (t RuneType) String() string { - str, ok := map[RuneType]string{ - RuneTypeError: "x", - - RuneTypeSpace: " ", - - RuneTypeObjectBeg: "{", - RuneTypeObjectColon: ":", - RuneTypeObjectComma: "o", - RuneTypeObjectEnd: "}", - - RuneTypeArrayBeg: "[", - RuneTypeArrayComma: "a", - RuneTypeArrayEnd: "]", - - RuneTypeStringBeg: "\"", - RuneTypeStringChar: "c", - RuneTypeStringEsc: "\\", - RuneTypeStringEsc1: "b", - RuneTypeStringEscU: "u", - RuneTypeStringEscUA: "A", - RuneTypeStringEscUB: "B", - RuneTypeStringEscUC: "C", - RuneTypeStringEscUD: "D", - RuneTypeStringEnd: "»", - - RuneTypeNumberIntNeg: "-", - RuneTypeNumberIntZero: "0", - RuneTypeNumberIntDig: "1", - RuneTypeNumberFracDot: ".", - RuneTypeNumberFracDig: "2", - RuneTypeNumberExpE: "e", - RuneTypeNumberExpSign: "+", - RuneTypeNumberExpDig: "3", - - RuneTypeTrueT: "𝕥", // double-struck - RuneTypeTrueR: "𝕣", - RuneTypeTrueU: "𝕦", - RuneTypeTrueE: "𝕖", - - RuneTypeFalseF: "𝔣", // fraktur - RuneTypeFalseA: "𝔞", - RuneTypeFalseL: "𝔩", - RuneTypeFalseS: "𝔰", - RuneTypeFalseE: "𝔢", - - RuneTypeNullN: "ⓝ", // circled - RuneTypeNullU: "ⓤ", - RuneTypeNullL1: "ⓛ", - RuneTypeNullL2: "Ⓛ", // +uppercase - - RuneTypeEOF: "$", - - runeTypeAny: "?", - }[t] - if ok { - return str - } - return fmt.Sprintf("<%d>", t) -} - -func (t RuneType) JSONType() string { - return map[RuneType]string{ - RuneTypeObjectBeg: "object", - RuneTypeArrayBeg: "array", - RuneTypeStringBeg: "string", - RuneTypeNumberIntNeg: "number", - RuneTypeNumberIntZero: "number", - RuneTypeNumberIntDig: "number", - RuneTypeTrueT: "true", - RuneTypeFalseF: "false", - RuneTypeNullN: "null", - RuneTypeEOF: "eof", - }[t] -} - -// IsNumber returns whether the RuneType is one of the -// RuneTypeNumberXXX values. -func (t RuneType) IsNumber() bool { - return RuneTypeNumberIntNeg <= t && t <= RuneTypeNumberExpDig -} - -// Parser is the low-level JSON parser that powers both *Decoder and -// *ReEncoder. -type Parser struct { - // Setting MaxError to a value greater than 0 causes - // HandleRune to return ErrParserExceededMaxDepth if - // objects/arrays become nested more deeply than this. - MaxDepth int - - initialized bool - - err error - closed bool - - // We reuse RuneTypes to store the stack. The base idea is: - // stack items are "the most recently read stack-relevant - // RuneType". - // - // The stack starts out with the special pseudo-RuneType - // `runeTypeAny` that means we're willing to accept any - // element type; an empty stack means that we have reached the - // end of the top-level element and should accept no more - // input except for whitespace. - // - // The "normal" stack-relevant RuneTypes are: - // - // "\uABC for strings - // -01.2e+3 for numbers - // 𝕥𝕣𝕦 for "true" - // 𝔣𝔞𝔩𝔰 for "false" - // ⓝⓤⓛ for "null" - // - // Objects and arrays break the "most recently read RuneType" - // rule; they need some special assignments: - // - // { object: waiting for key to start or '}' - // » object: reading key / waiting for colon - // o object: reading value / waiting for ',' or '}' - // - // [ array: waiting for item to start or ']' - // a array: reading item / waiting for ',' or ']' - // - // Within each element type, the stack item is replaced, not pushed. - // - // (Keep each of these examples in-sync with parse_test.go.) - // - // For example, given the input string - // - // {"x":"y","a":"b"} - // - // The stack would be - // - // stack processed - // ? - // { { - // »" {" - // »" {"x - // » {"x" - // o? {"x": - // o" {"x":" - // o" {"x":"y - // o {"x":"y" - // { {"x":"y", - // »" {"x":"y"," - // »" {"x":"y","a - // » {"x":"y","a" - // o? {"x":"y","a": - // o" {"x":"y","a":" - // o" {"x":"y","a":"b - // o {"x":"y","a":"b" - // {"x":"y","a":"b"} - // - // Or, given the input string - // - // ["x","y"] - // - // The stack would be - // - // stack processed - // ? - // [ [ - // a" [" - // a" ["x - // a ["x" - // a? ["x", - // a" ["x"," - // a" ["x","y - // a ["x","y" - // ["x","y"] - stack []RuneType - - barriers []barrier -} - -type barrier struct { - closed bool - stack []RuneType -} - -func (par *Parser) init() { - if !par.initialized { - par.initialized = true - par.pushState(runeTypeAny) - } -} - -func (par *Parser) pushState(state RuneType) RuneType { - par.stack = append(par.stack, state) - return state -} - -func (par *Parser) replaceState(state RuneType) RuneType { - par.stack[len(par.stack)-1] = state - return state -} - -func (par *Parser) popState() { - par.stack = par.stack[:len(par.stack)-1] -} - -func (par *Parser) stackString() string { - par.init() - var buf strings.Builder - for _, s := range par.stack { - buf.WriteString(s.String()) - } - return buf.String() -} - -func (par *Parser) depth() int { - n := len(par.stack) - for _, barrier := range par.barriers { - n += len(barrier.stack) - } - return n -} - -func (par *Parser) StackIsEmpty() bool { - if len(par.barriers) > 0 { - return false - } - if len(par.stack) == 0 { - return true - } - return len(par.stack) == 1 && par.stack[0] == runeTypeAny -} - -func (par *Parser) StackSize() int { - return len(par.stack) -} - -// Reset all Parser state. -func (par *Parser) Reset() { - *par = Parser{ - MaxDepth: par.MaxDepth, - } -} - -// PushReadBarrier causes the parser to expect EOF once the end of the -// element that is started by the current top-of-stack is reached, -// until this is un-done with PopBarrier. It essentially turns the -// parser in to a sub-parser. -// -// PushReadBarrier may only be called at the beginning of an element, -// whether that be -// -// - runeTypeAny -// - RuneTypeObjectBeg -// - RuneTypeArrayBeg -// - RuneTypeStringBeg -// - RuneTypeNumberIntNeg, RuneTypeNumberIntZero, RuneTypeNumberIntDig -// - RuneTypeTrueT -// - RuneTypeFalseF -// - RuneTypeNullN -func (par *Parser) PushReadBarrier() { - // Sanity checking. - par.init() - if len(par.stack) == 0 { - panic(errors.New("illegal PushReadBarrier call: empty stack")) - } - curState := par.stack[len(par.stack)-1] - switch curState { - case runeTypeAny, - RuneTypeObjectBeg, - RuneTypeArrayBeg, - RuneTypeStringBeg, - RuneTypeNumberIntNeg, RuneTypeNumberIntZero, RuneTypeNumberIntDig, - RuneTypeTrueT, - RuneTypeFalseF, - RuneTypeNullN: - // OK - default: - panic(fmt.Errorf("illegal PushReadBarrier call: %q", curState)) - } - // Actually push. - par.barriers = append(par.barriers, barrier{ - closed: par.closed, - stack: par.stack[:len(par.stack)-1], - }) - par.stack = []RuneType{curState} -} - -// PushWriteBarrier causes the parser to expect EOF once the end of -// the about-to-start element is reached, until this is un-done with -// PopBarrier. It essentially turns the parser in to a sub-parser. -// -// PushWriteBarrier may only be called at the places where an element -// of any type may start: -// -// - runeTypeAny for top-level and object-value elements -// - RuneTypeArrayBeg for array-item elements -// -// PushWriteBarrier signals intent to write an element; if it is -// called in a place where an element is optional (at the beginning of -// an array), it becomes a syntax error to not write the element. -func (par *Parser) PushWriteBarrier() { - par.init() - if len(par.stack) == 0 { - panic(errors.New("illegal PushWriteBarrier call: empty stack")) - } - switch par.stack[len(par.stack)-1] { - case runeTypeAny: - par.popState() - par.barriers = append(par.barriers, barrier{ - closed: par.closed, - stack: par.stack, - }) - par.stack = []RuneType{runeTypeAny} - case RuneTypeArrayBeg: - par.replaceState(RuneTypeArrayComma) - par.barriers = append(par.barriers, barrier{ - closed: par.closed, - stack: par.stack, - }) - par.stack = []RuneType{runeTypeAny} - default: - panic(fmt.Errorf("illegal PushWriteBarrier call: %q", par.stack[len(par.stack)-1])) - } -} - -// PopBarrier reverses a call to PushReadBarrier or PushWriteBarrier. -func (par *Parser) PopBarrier() { - if len(par.barriers) == 0 { - panic(errors.New("illegal PopBarrier call: empty barrier stack")) - } - barrier := par.barriers[len(par.barriers)-1] - par.barriers = par.barriers[:len(par.barriers)-1] - par.closed = barrier.closed - par.stack = append(barrier.stack, par.stack...) -} - -// HandleEOF feeds EOF to the Parser. The returned RuneType is either -// RuneTypeEOF or RuneTypeError. -// -// An error is returned if and only if the RuneType is RuneTypeError. -// Returns io/fs.ErrClosed if .HandleEOF() has previously been called -// (and .Reset() has not been called since). -// -// Once RuneTypeError or RuneTypeEOF has been returned, it will keep -// being returned from both .HandleRune(c) and .HandleEOF() until -// .Reset() is called. -// -// RuneTypeEOF indicates that a complete JSON document has been read. -func (par *Parser) HandleEOF() (RuneType, error) { - if par.closed { - return RuneTypeError, iofs.ErrClosed - } - defer func() { - par.closed = true - }() - if par.err != nil { - return RuneTypeError, par.err - } - par.init() - switch len(par.stack) { - case 0: - return RuneTypeEOF, nil - case 1: - switch { - case par.stack[0].IsNumber(): - if _, err := par.HandleRune('\n'); err == nil { - return RuneTypeEOF, nil - } - case par.stack[0] == runeTypeAny: - par.err = io.EOF - return RuneTypeError, par.err - } - fallthrough - default: - par.err = io.ErrUnexpectedEOF - return RuneTypeError, par.err - } -} - -// HandleRune feeds a Unicode rune to the Parser. -// -// An error is returned if and only if the RuneType is RuneTypeError. -// Returns io/fs.ErrClosed if .HandleEOF() has previously been called -// (and .Reset() has not been called since). -// -// Once RuneTypeError or RuneTypeEOF has been returned, it will keep -// being returned from both .HandleRune(c) and .HandleEOF() until -// .Reset() is called. -// -// RuneTypeEOF indicates that the rune cannot be appended to the JSON -// document; a new JSON document must be started in order to process -// that rune. -func (par *Parser) HandleRune(c rune) (RuneType, error) { - if par.closed { - return RuneTypeError, iofs.ErrClosed - } - if par.err != nil { - return RuneTypeError, par.err - } - par.init() - if len(par.stack) == 0 { - switch c { - case 0x0020, 0x000A, 0x000D, 0x0009: - return RuneTypeSpace, nil - default: - return RuneTypeEOF, nil - } - } - switch par.stack[len(par.stack)-1] { - // any ///////////////////////////////////////////////////////////////////////////////////// - case runeTypeAny: - switch c { - case 0x0020, 0x000A, 0x000D, 0x0009: - return RuneTypeSpace, nil - case '{': - if par.MaxDepth > 0 && par.depth() > par.MaxDepth { - return RuneTypeError, ErrParserExceededMaxDepth - } - return par.replaceState(RuneTypeObjectBeg), nil - case '[': - if par.MaxDepth > 0 && par.depth() > par.MaxDepth { - return RuneTypeError, ErrParserExceededMaxDepth - } - return par.replaceState(RuneTypeArrayBeg), nil - case '"': - return par.replaceState(RuneTypeStringBeg), nil - case '-': - return par.replaceState(RuneTypeNumberIntNeg), nil - case '0': - return par.replaceState(RuneTypeNumberIntZero), nil - case '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberIntDig), nil - case 't': - return par.replaceState(RuneTypeTrueT), nil - case 'f': - return par.replaceState(RuneTypeFalseF), nil - case 'n': - return par.replaceState(RuneTypeNullN), nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q looking for beginning of value", c) - } - // object ////////////////////////////////////////////////////////////////////////////////// - case RuneTypeObjectBeg: // waiting for key to start or '}' - switch c { - case 0x0020, 0x000A, 0x000D, 0x0009: - return RuneTypeSpace, nil - case '"': - par.replaceState(RuneTypeStringEnd) - return par.pushState(RuneTypeStringBeg), nil - case '}': - par.popState() - return RuneTypeObjectEnd, nil - default: - return RuneTypeError, fmt.Errorf("object: unexpected character: %q", c) - } - case RuneTypeStringEnd: // waiting for ':' - switch c { - case 0x0020, 0x000A, 0x000D, 0x0009: - return RuneTypeSpace, nil - case ':': - par.replaceState(RuneTypeObjectComma) - par.pushState(runeTypeAny) - return RuneTypeObjectColon, nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q after object key", c) - } - case RuneTypeObjectComma: // waiting for ',' or '}' - switch c { - case 0x0020, 0x000A, 0x000D, 0x0009: - return RuneTypeSpace, nil - case ',': - par.replaceState(RuneTypeObjectBeg) - return RuneTypeObjectComma, nil - case '}': - par.popState() - return RuneTypeObjectEnd, nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q after object key:value pair", c) - } - // array /////////////////////////////////////////////////////////////////////////////////// - case RuneTypeArrayBeg: // waiting for item to start or ']' - switch c { - case 0x0020, 0x000A, 0x000D, 0x0009: - return RuneTypeSpace, nil - case ']': - par.popState() - return RuneTypeArrayEnd, nil - default: - par.replaceState(RuneTypeArrayComma) - par.pushState(runeTypeAny) - return par.HandleRune(c) - } - case RuneTypeArrayComma: // waiting for ',' or ']' - switch c { - case 0x0020, 0x000A, 0x000D, 0x0009: - return RuneTypeSpace, nil - case ',': - par.pushState(runeTypeAny) - return RuneTypeArrayComma, nil - case ']': - par.popState() - return RuneTypeArrayEnd, nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q after array element", c) - } - // string ////////////////////////////////////////////////////////////////////////////////// - case RuneTypeStringBeg: // waiting for char or '"' - switch { - case c == '\\': - return par.replaceState(RuneTypeStringEsc), nil - case c == '"': - par.popState() - return RuneTypeStringEnd, nil - case 0x0020 <= c && c <= 0x10FFFF: - return RuneTypeStringChar, nil - default: - return RuneTypeError, fmt.Errorf("string: unexpected character: %q", c) - } - case RuneTypeStringEsc: // waiting for escape char - switch c { - case '"', '\\', '/', 'b', 'f', 'n', 'r', 't': - par.replaceState(RuneTypeStringBeg) - return RuneTypeStringEsc1, nil - case 'u': - return par.replaceState(RuneTypeStringEscU), nil - default: - return RuneTypeError, fmt.Errorf("string backslash sequence: unexpected character: %q", c) - } - case RuneTypeStringEscU: - if _, ok := HexToInt(c); ok { - return par.replaceState(RuneTypeStringEscUA), nil - } else { - return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) - } - case RuneTypeStringEscUA: - if _, ok := HexToInt(c); ok { - return par.replaceState(RuneTypeStringEscUB), nil - } else { - return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) - } - case RuneTypeStringEscUB: - if _, ok := HexToInt(c); ok { - return par.replaceState(RuneTypeStringEscUC), nil - } else { - return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) - } - case RuneTypeStringEscUC: - if _, ok := HexToInt(c); ok { - par.replaceState(RuneTypeStringBeg) - return RuneTypeStringEscUD, nil - } else { - return RuneTypeError, fmt.Errorf("string unicode sequence: unexpected character: %q", c) - } - // number ////////////////////////////////////////////////////////////////////////////////// - // - // Here's a flattened drawing of the syntax diagram from www.json.org : - // - // [------------ integer ----------][-- fraction ---][-------- exponent -------] - // >─╮─────╭─╮─"0"───────╭─────────╭──╮─────────────╭──╮───────────────────────╭─> - // │ │ │ │ │ │ │ │ │ - // ╰─"-"─╯ ╰─digit 1-9─╯─╭digit╮─╯ ╰─"."─╭digit╮─╯ ╰─"e"─╭─╮─────╭─╭digit╮─╯ - // ╰──<──╯ ╰──<──╯ │ │ │ │ ╰──<──╯ - // ╰─"E"─╯ ╰─"-"─╯ - // │ │ - // ╰─"+"─╯ - // - // Now here it is slightly redrawn, and with each distinct state our - // parser can be in marked with a single-capital-letter: - // - // [-------------- integer ------------][--------- fraction --------][--------- exponent ---------] - // >─A─╮───────╭──╮─"0"─────────C─╭─────────╮──────────────────╭─────────╮──────────────────────────╭─> - // │ │ │ │ │ │ │ │ - // ╰─"-"─B─╯ ╰─digit 1-9─╭─D─╯─digit╮ ╰─"."─E─digit──╭─F─╯─digit╮ ╰─"e"─╭─G─╮─────╭─╭digit─I─╯ - // ╰────<─────╯ ╰────<─────╯ │ │ │ H ╰────<───╯ - // ╰─"E"─╯ ╰─"-"─╯ - // │ │ - // ╰─"+"─╯ - // - // You may notice that each of these states may be uniquely identified - // by the last-read RuneType: - // - // A = (nothing yet) - // B = IntNeg - // C = IntZero - // D = IntDig - // E = FracDot - // F = FracDig - // G = ExpE - // H = ExpSign - // I = ExpDig - // - // The 'A' state is part of the runeTypeAny case above, and - // the remainder follow: - case RuneTypeNumberIntNeg: // B - switch c { - case '0': - return par.replaceState(RuneTypeNumberIntZero), nil - case '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberIntDig), nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) - } - case RuneTypeNumberIntZero: // C - switch c { - case '.': - return par.replaceState(RuneTypeNumberFracDot), nil - case 'e', 'E': - return par.replaceState(RuneTypeNumberExpE), nil - default: - par.popState() - return par.HandleRune(c) - } - case RuneTypeNumberIntDig: // D - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberIntDig), nil - case '.': - return par.replaceState(RuneTypeNumberFracDot), nil - case 'e', 'E': - return par.replaceState(RuneTypeNumberExpE), nil - default: - par.popState() - return par.HandleRune(c) - } - case RuneTypeNumberFracDot: // E - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberFracDig), nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) - } - case RuneTypeNumberFracDig: // F - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberFracDig), nil - case 'e', 'E': - return par.replaceState(RuneTypeNumberExpE), nil - default: - par.popState() - return par.HandleRune(c) - } - case RuneTypeNumberExpE: // G - switch c { - case '-', '+': - return par.replaceState(RuneTypeNumberExpSign), nil - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberExpDig), nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) - } - case RuneTypeNumberExpSign: // H - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberExpDig), nil - default: - return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) - } - case RuneTypeNumberExpDig: // I - switch c { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return par.replaceState(RuneTypeNumberExpDig), nil - default: - par.popState() - return par.HandleRune(c) - } - // literals //////////////////////////////////////////////////////////////////////////////// - // true - case RuneTypeTrueT: - return par.expectRune(c, 'r', RuneTypeTrueR, "true", false) - case RuneTypeTrueR: - return par.expectRune(c, 'u', RuneTypeTrueU, "true", false) - case RuneTypeTrueU: - return par.expectRune(c, 'e', RuneTypeTrueE, "true", true) - // false - case RuneTypeFalseF: - return par.expectRune(c, 'a', RuneTypeFalseA, "false", false) - case RuneTypeFalseA: - return par.expectRune(c, 'l', RuneTypeFalseL, "false", false) - case RuneTypeFalseL: - return par.expectRune(c, 's', RuneTypeFalseS, "false", false) - case RuneTypeFalseS: - return par.expectRune(c, 'e', RuneTypeFalseE, "false", true) - // null - case RuneTypeNullN: - return par.expectRune(c, 'u', RuneTypeNullU, "null", false) - case RuneTypeNullU: - return par.expectRune(c, 'l', RuneTypeNullL1, "null", false) - case RuneTypeNullL1: - return par.expectRune(c, 'l', RuneTypeNullL2, "null", true) - default: - panic(fmt.Errorf(`invalid stack: "%s"`, par.stackString())) - } -} - -func (par *Parser) expectRune(c, exp rune, typ RuneType, context string, pop bool) (RuneType, error) { - if c != exp { - return RuneTypeError, fmt.Errorf("invalid character %q in literal %s (expecting %q)", c, context, exp) - } - if pop { - par.popState() - return typ, nil - } else { - return par.replaceState(typ), nil - } -} diff --git a/internal/parse_test.go b/internal/parse_test.go deleted file mode 100644 index 34977fb..0000000 --- a/internal/parse_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParserHandleRune(t *testing.T) { - t.Parallel() - type testcase struct { - Input string - ExpStack []string - } - testcases := map[string]testcase{ - // Keep these test-cases in-sync with the examples in parse.go. - "object": { - Input: `{"x":"y","a":"b"}`, - ExpStack: []string{ - // st,// processed - `?`, - `{`, // { - `»"`, // {" - `»"`, // {"x - `»`, // {"x" - `o?`, // {"x": - `o"`, // {"x":" - `o"`, // {"x":"y - `o`, // {"x":"y" - `{`, // {"x":"y", - `»"`, // {"x":"y"," - `»"`, // {"x":"y","a - `»`, // {"x":"y","a" - `o?`, // {"x":"y","a": - `o"`, // {"x":"y","a":" - `o"`, // {"x":"y","a":"b - `o`, // {"x":"y","a":"b" - ``, // {"x":"y","a":"b"} - }, - }, - "array": { - Input: `["x","y"]`, - ExpStack: []string{ - // st,// processed - `?`, - `[`, // [ - `a"`, // [" - `a"`, // ["x - `a`, // ["x" - `a?`, // ["x", - `a"`, // ["x"," - `a"`, // ["x","y - `a`, // ["x","y" - ``, // ["x","y"] - }, - }, - } - for tcName, tc := range testcases { - tc := tc - t.Run(tcName, func(t *testing.T) { - t.Parallel() - var par Parser - if !assert.Equal(t, len(tc.Input)+1, len(tc.ExpStack)) { - return - } - for i, r := range tc.Input { - assert.Equal(t, tc.ExpStack[i], par.stackString()) - _, err := par.HandleRune(r) - assert.NoError(t, err) - assert.Equal(t, tc.ExpStack[i+1], par.stackString()) - } - }) - } -} diff --git a/internal/tags.go b/internal/tags.go deleted file mode 100644 index bdf1f72..0000000 --- a/internal/tags.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package internal - -var ParseTag = parseTag diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 b/internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 deleted file mode 100644 index c3774e7..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/06e2c9db80a08b67fad7f1a4606dc7419750995a57828aa25ea57fe7099d5c03 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a b/internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a deleted file mode 100644 index 4c861db..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/24f53a36f8832fec65cac0aa0f3b43ec1c904414fa6d38f6fc288b0bbd69588a +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 b/internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 deleted file mode 100644 index 3d32e14..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/2d49311ef22319f70a3590a86b406b9f2565987a4a3b6d7660ddc308b5b2fae2 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd b/internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd deleted file mode 100644 index d08ef92..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/356e28f5914a0f16f3cef81330f1d92060be4d694a93dedd654bf48743a7d2bd +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 deleted file mode 100644 index a96f559..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 b/internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 deleted file mode 100644 index 87c024d..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/60c81ee499a7f1e151b66b08f0a4ff81edd7cb53d00dce8ee0eaf31683996026 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d b/internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d deleted file mode 100644 index 959401e..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/66498f377f38b53eebe1ceaa4a53e4de01a04efc02ac9cfda60f9815f80e9b9d +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b b/internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b deleted file mode 100644 index bd1ae59..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/731951fe84fa6f3a7f6ee8adaa585d4f6a01f359a04737e51ffc70f16f480b9b +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c b/internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c deleted file mode 100644 index 09e0ad2..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/7d6367ba84cd18550920b5202cd1269174416ce32769c7f59376e76b7dd3129c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c b/internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c deleted file mode 100644 index e8000f3..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/8727b16d337d7b8187433233f3a90099024e580a6ba319ea2bf539880c50bd7c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c b/internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c deleted file mode 100644 index aac6b7d..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/9201a772731543760326638b8915f80863feab0ba0108183b3093934bdc0420c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f b/internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f deleted file mode 100644 index f3bf6d9..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/92f75f690317ace34aeaae3fe39f5f2ff9830777253ff371c5ef6f403a0f8f0f +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 b/internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 deleted file mode 100644 index 2e7f462..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/93d6f7bc0d93f998c7b7fe654ff46010d6fa76f0a142c3523c42454f8ad10b07 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a b/internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a deleted file mode 100644 index c541f52..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/a7450fd77fc7c53cc5bd136874415dddfff5c586e662f21420caa7a94131a56a +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c b/internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c deleted file mode 100644 index 5d56f29..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/a95d2a0f87501a643d54218d2ad8112204672cc1fb30be297853616788208a5c +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 b/internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 deleted file mode 100644 index 4b4d59f..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/beed435aa2fee4819eab217543561dfd8001d4a44f53ceb664aaba86cebfaf21 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 b/internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 deleted file mode 100644 index ef9f9d4..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/c2501043394e49f2477408be5ef9389790e33ed1886073dec445d4cf05bcd4b4 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 b/internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 deleted file mode 100644 index 67322c7..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/caf81e9797b19c76c1fc4dbf537d4d81f389524539f402d13aa01f93a65ac7e9 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 b/internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 deleted file mode 100644 index f195330..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/cc90a4a40ae9b3beac70baf6d7821a5a6f3a90cabb033575790be91723593680 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\x04000000000000\r00000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a b/internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a deleted file mode 100644 index 5b0d392..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/ec72f669d648d8d9b9f75a3b303897c59b11e4bfb7622f25ff251a92f182bc2a +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("0000000000000000000000000000000000000000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 b/internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 deleted file mode 100644 index a389d3c..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/f34630c44c11bb13d27531927c5c1e65d159b70f39cd161da0dba348c1221ab3 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("00000") diff --git a/internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 b/internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 deleted file mode 100644 index 17d10b2..0000000 --- a/internal/testdata/fuzz/FuzzBase64Decoder/fd67efb09d433a1351a201281dbf6568628b4135c35c811dd9bce97620a75d43 +++ /dev/null @@ -1,2 +0,0 @@ -go test fuzz v1 -[]byte("000000000000") diff --git a/reencode.go b/reencode.go index 3e9cf37..232d91d 100644 --- a/reencode.go +++ b/reencode.go @@ -10,7 +10,8 @@ import ( "io" "unicode/utf8" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/fastio" + "git.lukeshu.com/go/lowmemjson/internal/jsonparse" ) // A ReEncoderConfig controls how a ReEncoder should behave. @@ -71,7 +72,7 @@ type ReEncoderConfig struct { func NewReEncoder(out io.Writer, cfg ReEncoderConfig) *ReEncoder { return &ReEncoder{ ReEncoderConfig: cfg, - out: internal.NewAllWriter(out), + out: fastio.NewAllWriter(out), specu: new(speculation), } } @@ -86,7 +87,7 @@ func NewReEncoder(out io.Writer, cfg ReEncoderConfig) *ReEncoder { // The memory use of a ReEncoder is O(CompactIfUnder+depth). type ReEncoder struct { ReEncoderConfig - out internal.AllWriter + out fastio.AllWriter // state: .Write's and .WriteString's utf8-decoding buffer buf [utf8.UTFMax]byte @@ -94,13 +95,13 @@ type ReEncoder struct { // state: .WriteRune err error - par internal.Parser + par jsonparse.Parser written int inputPos int64 // state: .handleRune - lastNonSpace internal.RuneType - lastNonSpaceNonEOF internal.RuneType + lastNonSpace jsonparse.RuneType + lastNonSpaceNonEOF jsonparse.RuneType wasNumber bool curIndent int uhex [4]byte // "\uABCD"-encoded characters in strings @@ -135,15 +136,15 @@ func (specu *speculation) Reset() { type inputTuple struct { c rune - t internal.RuneType + t jsonparse.RuneType stackSize int } // public API ////////////////////////////////////////////////////////////////// var ( - _ internal.AllWriter = (*ReEncoder)(nil) - _ io.Closer = (*ReEncoder)(nil) + _ fastio.AllWriter = (*ReEncoder)(nil) + _ io.Closer = (*ReEncoder)(nil) ) // Write implements io.Writer; it does what you'd expect. @@ -208,7 +209,7 @@ func (enc *ReEncoder) WriteString(p string) (int, error) { // WriteByte implements io.ByteWriter; it does what you'd expect. func (enc *ReEncoder) WriteByte(b byte) error { - return internal.WriteByte(enc, b) + return fastio.WriteByte(enc, b) } // Close implements io.Closer; it does what you'd expect, mostly. @@ -230,7 +231,7 @@ func (enc *ReEncoder) Close() error { return enc.err } if len(enc.barriers) == 0 { - if err := enc.handleRune(0, internal.RuneTypeError, enc.stackSize()); err != nil { + if err := enc.handleRune(0, jsonparse.RuneTypeError, enc.stackSize()); err != nil { enc.err = &ReEncodeSyntaxError{ Err: err, Offset: enc.inputPos, @@ -274,7 +275,7 @@ rehandle: return enc.written, enc.err } enc.err = enc.handleRune(c, t, enc.stackSize()) - if enc.err == nil && t == internal.RuneTypeEOF { + if enc.err == nil && t == jsonparse.RuneTypeEOF { if enc.AllowMultipleValues && len(enc.barriers) == 0 { enc.par.Reset() goto rehandle @@ -319,7 +320,7 @@ func (enc *ReEncoder) stackSize() int { return sz } -func (enc *ReEncoder) handleRune(c rune, t internal.RuneType, stackSize int) error { +func (enc *ReEncoder) handleRune(c rune, t jsonparse.RuneType, stackSize int) error { if enc.CompactIfUnder == 0 || enc.Compact || enc.Indent == "" { return enc.handleRuneNoSpeculation(c, t) } @@ -327,7 +328,7 @@ func (enc *ReEncoder) handleRune(c rune, t internal.RuneType, stackSize int) err // main if !enc.specu.speculating { // not speculating switch t { - case internal.RuneTypeObjectBeg, internal.RuneTypeArrayBeg: // start speculating + case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeArrayBeg: // start speculating if err, _ := enc.handleRunePre(c, t); err != nil { return err } @@ -385,7 +386,7 @@ func (enc *ReEncoder) handleRune(c rune, t internal.RuneType, stackSize int) err return nil } -func (enc *ReEncoder) handleRuneNoSpeculation(c rune, t internal.RuneType) error { +func (enc *ReEncoder) handleRuneNoSpeculation(c rune, t jsonparse.RuneType) error { err, shouldHandle := enc.handleRunePre(c, t) if err != nil { return err @@ -398,9 +399,9 @@ func (enc *ReEncoder) handleRuneNoSpeculation(c rune, t internal.RuneType) error // handleRunePre handles buffered things that need to happen before // the new rune itself is handled. -func (enc *ReEncoder) handleRunePre(c rune, t internal.RuneType) (error, bool) { +func (enc *ReEncoder) handleRunePre(c rune, t jsonparse.RuneType) (error, bool) { // emit newlines between top-level values - if enc.lastNonSpace == internal.RuneTypeEOF { + if enc.lastNonSpace == jsonparse.RuneTypeEOF { switch { case enc.wasNumber && t.IsNumber(): if err := enc.emitByte('\n'); err != nil { @@ -415,10 +416,10 @@ func (enc *ReEncoder) handleRunePre(c rune, t internal.RuneType) (error, bool) { // shorten numbers switch t { // trim trailing '0's from the fraction-part, but don't remove all digits - case internal.RuneTypeNumberFracDot: + case jsonparse.RuneTypeNumberFracDot: enc.fracZeros = 0 - case internal.RuneTypeNumberFracDig: - if c == '0' && enc.lastNonSpace == internal.RuneTypeNumberFracDig { + case jsonparse.RuneTypeNumberFracDig: + if c == '0' && enc.lastNonSpace == jsonparse.RuneTypeNumberFracDig { enc.fracZeros++ return nil, false } @@ -432,9 +433,9 @@ func (enc *ReEncoder) handleRunePre(c rune, t internal.RuneType) (error, bool) { } } switch t { // trim leading '0's from the exponent-part, but don't remove all digits - case internal.RuneTypeNumberExpE, internal.RuneTypeNumberExpSign: + case jsonparse.RuneTypeNumberExpE, jsonparse.RuneTypeNumberExpSign: enc.expZero = true - case internal.RuneTypeNumberExpDig: + case jsonparse.RuneTypeNumberExpDig: if c == '0' && enc.expZero { return nil, false } @@ -451,18 +452,18 @@ func (enc *ReEncoder) handleRunePre(c rune, t internal.RuneType) (error, bool) { // whitespace switch { case enc.Compact: - if t == internal.RuneTypeSpace { + if t == jsonparse.RuneTypeSpace { return nil, false } case enc.Indent != "": switch t { - case internal.RuneTypeSpace: + case jsonparse.RuneTypeSpace: // let us manage whitespace, don't pass it through return nil, false - case internal.RuneTypeObjectEnd, internal.RuneTypeArrayEnd: + case jsonparse.RuneTypeObjectEnd, jsonparse.RuneTypeArrayEnd: enc.curIndent-- switch enc.lastNonSpace { - case internal.RuneTypeObjectBeg, internal.RuneTypeArrayBeg: + case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeArrayBeg: // collapse default: if err := enc.emitNlIndent(); err != nil { @@ -471,17 +472,17 @@ func (enc *ReEncoder) handleRunePre(c rune, t internal.RuneType) (error, bool) { } default: switch enc.lastNonSpace { - case internal.RuneTypeObjectBeg, internal.RuneTypeObjectComma, internal.RuneTypeArrayBeg, internal.RuneTypeArrayComma: + case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeObjectComma, jsonparse.RuneTypeArrayBeg, jsonparse.RuneTypeArrayComma: if err := enc.emitNlIndent(); err != nil { return err, false } - case internal.RuneTypeObjectColon: + case jsonparse.RuneTypeObjectColon: if err := enc.emitByte(' '); err != nil { return err, false } } switch t { - case internal.RuneTypeObjectBeg, internal.RuneTypeArrayBeg: + case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeArrayBeg: enc.curIndent++ } } @@ -491,15 +492,15 @@ func (enc *ReEncoder) handleRunePre(c rune, t internal.RuneType) (error, bool) { } // handleRuneMain handles the new rune itself, not buffered things. -func (enc *ReEncoder) handleRuneMain(c rune, t internal.RuneType) error { +func (enc *ReEncoder) handleRuneMain(c rune, t jsonparse.RuneType) error { var err error switch t { - case internal.RuneTypeStringChar: + case jsonparse.RuneTypeStringChar: err = enc.emit(writeStringChar(enc.out, c, BackslashEscapeNone, enc.BackslashEscape)) - case internal.RuneTypeStringEsc, internal.RuneTypeStringEscU: + case jsonparse.RuneTypeStringEsc, jsonparse.RuneTypeStringEscU: // do nothing - case internal.RuneTypeStringEsc1: + case jsonparse.RuneTypeStringEsc1: switch c { case '"': err = enc.emit(writeStringChar(enc.out, '"', BackslashEscapeShort, enc.BackslashEscape)) @@ -520,14 +521,14 @@ func (enc *ReEncoder) handleRuneMain(c rune, t internal.RuneType) error { default: panic("should not happen") } - case internal.RuneTypeStringEscUA: - enc.uhex[0], _ = internal.HexToInt(c) - case internal.RuneTypeStringEscUB: - enc.uhex[1], _ = internal.HexToInt(c) - case internal.RuneTypeStringEscUC: - enc.uhex[2], _ = internal.HexToInt(c) - case internal.RuneTypeStringEscUD: - enc.uhex[3], _ = internal.HexToInt(c) + case jsonparse.RuneTypeStringEscUA: + enc.uhex[0], _ = jsonparse.HexToInt(c) + case jsonparse.RuneTypeStringEscUB: + enc.uhex[1], _ = jsonparse.HexToInt(c) + case jsonparse.RuneTypeStringEscUC: + enc.uhex[2], _ = jsonparse.HexToInt(c) + case jsonparse.RuneTypeStringEscUD: + enc.uhex[3], _ = jsonparse.HexToInt(c) c := 0 | rune(enc.uhex[0])<<12 | rune(enc.uhex[1])<<8 | @@ -535,24 +536,24 @@ func (enc *ReEncoder) handleRuneMain(c rune, t internal.RuneType) error { rune(enc.uhex[3])<<0 err = enc.emit(writeStringChar(enc.out, c, BackslashEscapeUnicode, enc.BackslashEscape)) - case internal.RuneTypeError: // EOF explicitly stated by .Close() + case jsonparse.RuneTypeError: // EOF explicitly stated by .Close() fallthrough - case internal.RuneTypeEOF: // EOF implied by the start of the next top-level value + case jsonparse.RuneTypeEOF: // EOF implied by the start of the next top-level value enc.wasNumber = enc.lastNonSpace.IsNumber() switch { case enc.ForceTrailingNewlines && len(enc.barriers) == 0: - t = internal.RuneTypeError // enc.lastNonSpace : an NL isn't needed (we already printed one) + t = jsonparse.RuneTypeError // enc.lastNonSpace : an NL isn't needed (we already printed one) err = enc.emitByte('\n') default: - t = internal.RuneTypeEOF // enc.lastNonSpace : an NL *might* be needed + t = jsonparse.RuneTypeEOF // enc.lastNonSpace : an NL *might* be needed } default: err = enc.emitByte(byte(c)) } - if t != internal.RuneTypeSpace { + if t != jsonparse.RuneTypeSpace { enc.lastNonSpace = t - if t != internal.RuneTypeEOF { + if t != jsonparse.RuneTypeEOF { enc.lastNonSpaceNonEOF = t } } diff --git a/struct.go b/struct.go index 81bc22d..5ccb62f 100644 --- a/struct.go +++ b/struct.go @@ -9,7 +9,7 @@ import ( "git.lukeshu.com/go/typedsync" - "git.lukeshu.com/go/lowmemjson/internal" + "git.lukeshu.com/go/lowmemjson/internal/jsontags" ) type structField struct { @@ -157,7 +157,7 @@ func indexStructInner(typ reflect.Type, byPos *[]structField, byName map[string] if tag == "-" { continue } - tagName, opts := internal.ParseTag(tag) + tagName, opts := jsontags.ParseTag(tag) name := tagName if !isValidTag(name) { name = "" -- cgit v1.2.3-2-g168b From 643cbc4d6e37d07619bec05039da1abb411d28d4 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 12:45:46 -0700 Subject: Move struct-handling to internal/jsonstruct --- borrowed_misc.go | 20 ---- compat/json/compat_test.go | 4 +- decode.go | 11 +- encode.go | 4 +- internal/jsonstruct/borrowed_misc.go | 30 +++++ internal/jsonstruct/borrowed_tags.go | 40 +++++++ internal/jsonstruct/struct.go | 205 +++++++++++++++++++++++++++++++++++ internal/jsontags/borrowed_tags.go | 40 ------- internal/jsontags/tags.go | 7 -- struct.go | 205 ----------------------------------- 10 files changed, 286 insertions(+), 280 deletions(-) create mode 100644 internal/jsonstruct/borrowed_misc.go create mode 100644 internal/jsonstruct/borrowed_tags.go create mode 100644 internal/jsonstruct/struct.go delete mode 100644 internal/jsontags/borrowed_tags.go delete mode 100644 internal/jsontags/tags.go delete mode 100644 struct.go diff --git a/borrowed_misc.go b/borrowed_misc.go index b84158b..59c49aa 100644 --- a/borrowed_misc.go +++ b/borrowed_misc.go @@ -8,8 +8,6 @@ package lowmemjson import ( "reflect" - "strings" - "unicode" ) // isEmptyValue is borrowed from encode.go. @@ -30,21 +28,3 @@ func isEmptyValue(v reflect.Value) bool { } return false } - -// isValidTag is borrowed from encode.go. -func isValidTag(s string) bool { - if s == "" { - return false - } - for _, c := range s { - switch { - case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): - // Backslash and quote chars are reserved, but - // otherwise any punctuation chars are allowed - // in a tag name. - case !unicode.IsLetter(c) && !unicode.IsDigit(c): - return false - } - } - return true -} diff --git a/compat/json/compat_test.go b/compat/json/compat_test.go index 4b167d1..2969107 100644 --- a/compat/json/compat_test.go +++ b/compat/json/compat_test.go @@ -10,11 +10,11 @@ import ( "git.lukeshu.com/go/lowmemjson" "git.lukeshu.com/go/lowmemjson/internal/jsonparse" - "git.lukeshu.com/go/lowmemjson/internal/jsontags" + "git.lukeshu.com/go/lowmemjson/internal/jsonstruct" "git.lukeshu.com/go/lowmemjson/internal/jsontest" ) -var parseTag = jsontags.ParseTag +var parseTag = jsonstruct.ParseTag type scanner = lowmemjson.ReEncoderConfig diff --git a/decode.go b/decode.go index 3a9a4b1..487bce4 100644 --- a/decode.go +++ b/decode.go @@ -26,6 +26,7 @@ import ( "git.lukeshu.com/go/lowmemjson/internal/base64dec" "git.lukeshu.com/go/lowmemjson/internal/fastio" "git.lukeshu.com/go/lowmemjson/internal/jsonparse" + "git.lukeshu.com/go/lowmemjson/internal/jsonstruct" ) // Decodable is the interface implemented by types that can decode a @@ -532,7 +533,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { dec.decodeNull() return } - index := indexStruct(typ) + index := jsonstruct.IndexStruct(typ) var nameBuf strings.Builder dec.decodeObject(typ, func() { dec.posStackPush() @@ -545,10 +546,10 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { name := nameBuf.String() dec.structStackPush(typ, name) defer dec.structStackPop() - idx, ok := index.byName[name] + idx, ok := index.ByName[name] if !ok { - for oidx := range index.byPos { - if strings.EqualFold(name, index.byPos[oidx].Name) { + for oidx := range index.ByPos { + if strings.EqualFold(name, index.ByPos[oidx].Name) { idx = oidx ok = true break @@ -562,7 +563,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) { dec.scan(fastio.Discard) return } - field := index.byPos[idx] + field := index.ByPos[idx] fVal := val for _, idx := range field.Path { if fVal.Kind() == reflect.Pointer { diff --git a/encode.go b/encode.go index ca4e060..fa558b9 100644 --- a/encode.go +++ b/encode.go @@ -16,6 +16,8 @@ import ( "strconv" "strings" "unsafe" + + "git.lukeshu.com/go/lowmemjson/internal/jsonstruct" ) // Encodable is the interface implemented by types that can encode @@ -299,7 +301,7 @@ func encode(w *ReEncoder, val reflect.Value, escaper BackslashEscaper, quote boo return err } empty := true - for _, field := range indexStruct(val.Type()).byPos { + for _, field := range jsonstruct.IndexStruct(val.Type()).ByPos { fVal, err := val.FieldByIndexErr(field.Path) if err != nil { continue diff --git a/internal/jsonstruct/borrowed_misc.go b/internal/jsonstruct/borrowed_misc.go new file mode 100644 index 0000000..3b4181e --- /dev/null +++ b/internal/jsonstruct/borrowed_misc.go @@ -0,0 +1,30 @@ +// 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. +// +// SPDX-License-Identifier: BSD-3-Clause + +package jsonstruct + +import ( + "strings" + "unicode" +) + +// isValidTag is borrowed from encode.go. +func isValidTag(s string) bool { + if s == "" { + return false + } + for _, c := range s { + switch { + case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): + // Backslash and quote chars are reserved, but + // otherwise any punctuation chars are allowed + // in a tag name. + case !unicode.IsLetter(c) && !unicode.IsDigit(c): + return false + } + } + return true +} diff --git a/internal/jsonstruct/borrowed_tags.go b/internal/jsonstruct/borrowed_tags.go new file mode 100644 index 0000000..f2ef71c --- /dev/null +++ b/internal/jsonstruct/borrowed_tags.go @@ -0,0 +1,40 @@ +// Copyright 2011 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. +// +// SPDX-License-Identifier: BSD-3-Clause + +package jsonstruct // MODIFIED: changed package name + +import ( + "strings" +) + +// tagOptions is the string following a comma in a struct field's "json" +// tag, or the empty string. It does not include the leading comma. +type tagOptions string + +// parseTag splits a struct field's json tag into its name and +// comma-separated options. +func parseTag(tag string) (string, tagOptions) { + tag, opt, _ := strings.Cut(tag, ",") + return tag, tagOptions(opt) +} + +// Contains reports whether a comma-separated list of options +// contains a particular substr flag. substr must be surrounded by a +// string boundary or commas. +func (o tagOptions) Contains(optionName string) bool { + if len(o) == 0 { + return false + } + s := string(o) + for s != "" { + var name string + name, s, _ = strings.Cut(s, ",") + if name == optionName { + return true + } + } + return false +} diff --git a/internal/jsonstruct/struct.go b/internal/jsonstruct/struct.go new file mode 100644 index 0000000..830dc80 --- /dev/null +++ b/internal/jsonstruct/struct.go @@ -0,0 +1,205 @@ +// Copyright (C) 2022-2023 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package jsonstruct + +import ( + "reflect" + + "git.lukeshu.com/go/typedsync" +) + +var ParseTag = parseTag + +type StructField struct { + Name string + Path []int + Tagged bool + OmitEmpty bool + Quote bool +} + +// A StructIndex is used by Decoder.Decode() and Encoder.Encode() when +// decoding-to or encoding-from a struct. +type StructIndex struct { + ByPos []StructField + ByName map[string]int +} + +var structIndexCache typedsync.CacheMap[reflect.Type, StructIndex] + +// IndexStruct takes a struct Type, and indexes its fields for use by +// Decoder.Decode() and Encoder.Encode(). indexStruct caches its +// results. +func IndexStruct(typ reflect.Type) StructIndex { + ret, _ := structIndexCache.LoadOrCompute(typ, indexStructReal) + return ret +} + +// indexStructReal is like indexStruct, but is the real indexer, +// bypassing the cache. +func indexStructReal(typ reflect.Type) StructIndex { + var byPos []StructField + byName := make(map[string][]int) + + indexStructInner(typ, &byPos, byName, nil, map[reflect.Type]struct{}{}) + + ret := StructIndex{ + ByName: make(map[string]int), + } + + for curPos, _field := range byPos { + name := _field.Name + fieldPoss := byName[name] + switch len(fieldPoss) { + case 0: + // do nothing + case 1: + ret.ByName[name] = len(ret.ByPos) + ret.ByPos = append(ret.ByPos, _field) + default: + // To quote the encoding/json docs (version 1.18.4): + // + // If there are multiple fields at the same level, and that level is the + // least nested (and would therefore be the nesting level selected by the + // usual Go rules), the following extra rules apply: + // + // 1) Of those fields, if any are JSON-tagged, only tagged fields are + // considered, even if there are multiple untagged fields that would + // otherwise conflict. + // + // 2) If there is exactly one field (tagged or not according to the first + // rule), that is selected. + // + // 3) Otherwise there are multiple fields, and all are ignored; no error + // occurs. + leastLevel := len(byPos[fieldPoss[0]].Path) + for _, fieldPos := range fieldPoss[1:] { + field := byPos[fieldPos] + if len(field.Path) < leastLevel { + leastLevel = len(field.Path) + } + } + var numUntagged, numTagged int + var untaggedPos, taggedPos int + for _, fieldPos := range fieldPoss { + field := byPos[fieldPos] + if len(field.Path) != leastLevel { + continue + } + if field.Tagged { + numTagged++ + taggedPos = fieldPos + if numTagged > 1 { + break // optimization + } + } else { + numUntagged++ + untaggedPos = fieldPos + } + } + switch numTagged { + case 0: + switch numUntagged { + case 0: + // do nothing + case 1: + if curPos == untaggedPos { + ret.ByName[name] = len(ret.ByPos) + ret.ByPos = append(ret.ByPos, byPos[curPos]) + } + } + case 1: + if curPos == taggedPos { + ret.ByName[name] = len(ret.ByPos) + ret.ByPos = append(ret.ByPos, byPos[curPos]) + } + } + } + } + + return ret +} + +// indexStructInner crawls the struct `typ`, storing information on +// all struct fields found in to `byPos` and `byName`. If `typ` +// contains other structs as fields, indexStructInner will recurse and +// call itself; keeping track of stack information with `stackPath` +// (which identifies where we are in the parent struct) and +// `stackSeen` (which is used for detecting loops). +func indexStructInner(typ reflect.Type, byPos *[]StructField, byName map[string][]int, stackPath []int, stackSeen map[reflect.Type]struct{}) { + if _, ok := stackSeen[typ]; ok { + return + } + stackSeen[typ] = struct{}{} + defer delete(stackSeen, typ) + + n := typ.NumField() + for i := 0; i < n; i++ { + stackPath := append(stackPath, i) + + fTyp := typ.Field(i) + var embed bool + if fTyp.Anonymous { + t := fTyp.Type + if t.Kind() == reflect.Pointer { + t = t.Elem() + } + if !fTyp.IsExported() && t.Kind() != reflect.Struct { + continue + } + embed = t.Kind() == reflect.Struct + } else if !fTyp.IsExported() { + continue + } + tag := fTyp.Tag.Get("json") + if tag == "-" { + continue + } + tagName, opts := parseTag(tag) + name := tagName + if !isValidTag(name) { + name = "" + } + if name == "" { + name = fTyp.Name + } + + if embed && tagName == "" { + t := fTyp.Type + if t.Kind() == reflect.Pointer { + t = t.Elem() + } + indexStructInner(t, byPos, byName, stackPath, stackSeen) + } else { + byName[name] = append(byName[name], len(*byPos)) + *byPos = append(*byPos, StructField{ + Name: name, + Path: append([]int(nil), stackPath...), + Tagged: tagName != "", + OmitEmpty: opts.Contains("omitempty"), + Quote: opts.Contains("string") && isQuotable(fTyp.Type), + }) + } + } +} + +// isQuotable returns whether a type is eligible for `json:,string` +// quoting. +func isQuotable(typ reflect.Type) bool { + for typ.Kind() == reflect.Pointer { + typ = typ.Elem() + } + switch typ.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Uintptr, + reflect.Float32, reflect.Float64, + reflect.String: + return true + default: + return false + } +} diff --git a/internal/jsontags/borrowed_tags.go b/internal/jsontags/borrowed_tags.go deleted file mode 100644 index aa94b9b..0000000 --- a/internal/jsontags/borrowed_tags.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2011 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. -// -// SPDX-License-Identifier: BSD-3-Clause - -package jsontags // MODIFIED: changed package name - -import ( - "strings" -) - -// tagOptions is the string following a comma in a struct field's "json" -// tag, or the empty string. It does not include the leading comma. -type tagOptions string - -// parseTag splits a struct field's json tag into its name and -// comma-separated options. -func parseTag(tag string) (string, tagOptions) { - tag, opt, _ := strings.Cut(tag, ",") - return tag, tagOptions(opt) -} - -// Contains reports whether a comma-separated list of options -// contains a particular substr flag. substr must be surrounded by a -// string boundary or commas. -func (o tagOptions) Contains(optionName string) bool { - if len(o) == 0 { - return false - } - s := string(o) - for s != "" { - var name string - name, s, _ = strings.Cut(s, ",") - if name == optionName { - return true - } - } - return false -} diff --git a/internal/jsontags/tags.go b/internal/jsontags/tags.go deleted file mode 100644 index 386824d..0000000 --- a/internal/jsontags/tags.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package jsontags - -var ParseTag = parseTag diff --git a/struct.go b/struct.go deleted file mode 100644 index 5ccb62f..0000000 --- a/struct.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (C) 2022-2023 Luke Shumaker -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package lowmemjson - -import ( - "reflect" - - "git.lukeshu.com/go/typedsync" - - "git.lukeshu.com/go/lowmemjson/internal/jsontags" -) - -type structField struct { - Name string - Path []int - Tagged bool - OmitEmpty bool - Quote bool -} - -// A structIndex is used by Decoder.Decode() and Encoder.Encode() when -// decoding-to or encoding-from a struct. -type structIndex struct { - byPos []structField - byName map[string]int -} - -var structIndexCache typedsync.CacheMap[reflect.Type, structIndex] - -// indexStruct takes a struct Type, and indexes its fields for use by -// Decoder.Decode() and Encoder.Encode(). indexStruct caches its -// results. -func indexStruct(typ reflect.Type) structIndex { - ret, _ := structIndexCache.LoadOrCompute(typ, indexStructReal) - return ret -} - -// indexStructReal is like indexStruct, but is the real indexer, -// bypassing the cache. -func indexStructReal(typ reflect.Type) structIndex { - var byPos []structField - byName := make(map[string][]int) - - indexStructInner(typ, &byPos, byName, nil, map[reflect.Type]struct{}{}) - - ret := structIndex{ - byName: make(map[string]int), - } - - for curPos, _field := range byPos { - name := _field.Name - fieldPoss := byName[name] - switch len(fieldPoss) { - case 0: - // do nothing - case 1: - ret.byName[name] = len(ret.byPos) - ret.byPos = append(ret.byPos, _field) - default: - // To quote the encoding/json docs (version 1.18.4): - // - // If there are multiple fields at the same level, and that level is the - // least nested (and would therefore be the nesting level selected by the - // usual Go rules), the following extra rules apply: - // - // 1) Of those fields, if any are JSON-tagged, only tagged fields are - // considered, even if there are multiple untagged fields that would - // otherwise conflict. - // - // 2) If there is exactly one field (tagged or not according to the first - // rule), that is selected. - // - // 3) Otherwise there are multiple fields, and all are ignored; no error - // occurs. - leastLevel := len(byPos[fieldPoss[0]].Path) - for _, fieldPos := range fieldPoss[1:] { - field := byPos[fieldPos] - if len(field.Path) < leastLevel { - leastLevel = len(field.Path) - } - } - var numUntagged, numTagged int - var untaggedPos, taggedPos int - for _, fieldPos := range fieldPoss { - field := byPos[fieldPos] - if len(field.Path) != leastLevel { - continue - } - if field.Tagged { - numTagged++ - taggedPos = fieldPos - if numTagged > 1 { - break // optimization - } - } else { - numUntagged++ - untaggedPos = fieldPos - } - } - switch numTagged { - case 0: - switch numUntagged { - case 0: - // do nothing - case 1: - if curPos == untaggedPos { - ret.byName[name] = len(ret.byPos) - ret.byPos = append(ret.byPos, byPos[curPos]) - } - } - case 1: - if curPos == taggedPos { - ret.byName[name] = len(ret.byPos) - ret.byPos = append(ret.byPos, byPos[curPos]) - } - } - } - } - - return ret -} - -// indexStructInner crawls the struct `typ`, storing information on -// all struct fields found in to `byPos` and `byName`. If `typ` -// contains other structs as fields, indexStructInner will recurse and -// call itself; keeping track of stack information with `stackPath` -// (which identifies where we are in the parent struct) and -// `stackSeen` (which is used for detecting loops). -func indexStructInner(typ reflect.Type, byPos *[]structField, byName map[string][]int, stackPath []int, stackSeen map[reflect.Type]struct{}) { - if _, ok := stackSeen[typ]; ok { - return - } - stackSeen[typ] = struct{}{} - defer delete(stackSeen, typ) - - n := typ.NumField() - for i := 0; i < n; i++ { - stackPath := append(stackPath, i) - - fTyp := typ.Field(i) - var embed bool - if fTyp.Anonymous { - t := fTyp.Type - if t.Kind() == reflect.Pointer { - t = t.Elem() - } - if !fTyp.IsExported() && t.Kind() != reflect.Struct { - continue - } - embed = t.Kind() == reflect.Struct - } else if !fTyp.IsExported() { - continue - } - tag := fTyp.Tag.Get("json") - if tag == "-" { - continue - } - tagName, opts := jsontags.ParseTag(tag) - name := tagName - if !isValidTag(name) { - name = "" - } - if name == "" { - name = fTyp.Name - } - - if embed && tagName == "" { - t := fTyp.Type - if t.Kind() == reflect.Pointer { - t = t.Elem() - } - indexStructInner(t, byPos, byName, stackPath, stackSeen) - } else { - byName[name] = append(byName[name], len(*byPos)) - *byPos = append(*byPos, structField{ - Name: name, - Path: append([]int(nil), stackPath...), - Tagged: tagName != "", - OmitEmpty: opts.Contains("omitempty"), - Quote: opts.Contains("string") && isQuotable(fTyp.Type), - }) - } - } -} - -// isQuotable returns whether a type is eligible for `json:,string` -// quoting. -func isQuotable(typ reflect.Type) bool { - for typ.Kind() == reflect.Pointer { - typ = typ.Elem() - } - switch typ.Kind() { - case reflect.Bool, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Uintptr, - reflect.Float32, reflect.Float64, - reflect.String: - return true - default: - return false - } -} -- cgit v1.2.3-2-g168b From 47549aa3d10808c063d45dcaa598887dadde59c5 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 7 Feb 2023 12:28:35 -0700 Subject: compat: Enable the cache benchmark This should have been done back in 8aa12d3 (struct.go: Cache structIndexes, 2023-01-26) --- compat/json/borrowed_bench_test.go | 14 ++++++++------ compat/json/compat_test.go | 6 +++++- internal/jsonstruct/struct.go | 4 ++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/compat/json/borrowed_bench_test.go b/compat/json/borrowed_bench_test.go index e2d74ab..443a13d 100644 --- a/compat/json/borrowed_bench_test.go +++ b/compat/json/borrowed_bench_test.go @@ -15,9 +15,13 @@ package json import ( "bytes" "compress/gzip" + "fmt" "io" "os" + "reflect" + "runtime" "strings" + "sync" "testing" ) @@ -325,11 +329,10 @@ func BenchmarkUnmapped(b *testing.B) { }) } -/* // MODIFIED: we don't have a cache func BenchmarkTypeFieldsCache(b *testing.B) { b.ReportAllocs() var maxTypes int = 1e6 - if testenv.Builder() != "" { + if false { // testenv.Builder() != "" { // MODIFIED: disabled maxTypes = 1e3 // restrict cache sizes on builders } @@ -345,9 +348,9 @@ func BenchmarkTypeFieldsCache(b *testing.B) { } // clearClear clears the cache. Other JSON operations, must not be running. - clearCache := func() { - fieldCache = sync.Map{} - } + // clearCache := func() { // MODIFIED: use function from compat_test.go + // fieldCache = sync.Map{} // MODIFIED: use function from compat_test.go + // } // MODIFIED: use function from compat_test.go // MissTypes tests the performance of repeated cache misses. // This measures the time to rebuild a cache of size nt. @@ -389,7 +392,6 @@ func BenchmarkTypeFieldsCache(b *testing.B) { }) } } -*/ // MODIFIED: we don't have a cache func BenchmarkEncodeMarshaler(b *testing.B) { b.ReportAllocs() diff --git a/compat/json/compat_test.go b/compat/json/compat_test.go index 2969107..203594f 100644 --- a/compat/json/compat_test.go +++ b/compat/json/compat_test.go @@ -14,7 +14,11 @@ import ( "git.lukeshu.com/go/lowmemjson/internal/jsontest" ) -var parseTag = jsonstruct.ParseTag +var ( + parseTag = jsonstruct.ParseTag + clearCache = jsonstruct.ClearCache + cachedTypeFields = jsonstruct.IndexStruct +) type scanner = lowmemjson.ReEncoderConfig diff --git a/internal/jsonstruct/struct.go b/internal/jsonstruct/struct.go index 830dc80..16c45de 100644 --- a/internal/jsonstruct/struct.go +++ b/internal/jsonstruct/struct.go @@ -37,6 +37,10 @@ func IndexStruct(typ reflect.Type) StructIndex { return ret } +func ClearCache() { + structIndexCache = typedsync.CacheMap[reflect.Type, StructIndex]{} +} + // indexStructReal is like indexStruct, but is the real indexer, // bypassing the cache. func indexStructReal(typ reflect.Type) StructIndex { -- cgit v1.2.3-2-g168b