migrate go version to 1.17 (#203)

* migrate go version to 1.17

* update contributing
This commit is contained in:
tobi 2021-09-10 14:42:14 +02:00 committed by GitHub
parent e681aac589
commit f2e5bedea6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
282 changed files with 11863 additions and 12600 deletions

View file

@ -13,7 +13,7 @@ steps:
# We use golangci-lint for linting. # We use golangci-lint for linting.
# See: https://golangci-lint.run/ # See: https://golangci-lint.run/
- name: lint - name: lint
image: golangci/golangci-lint:v1.41.1 image: golangci/golangci-lint:v1.42.1
volumes: volumes:
- name: go-build-cache - name: go-build-cache
path: /root/.cache/go-build path: /root/.cache/go-build
@ -27,17 +27,16 @@ steps:
- pull_request - pull_request
- name: test - name: test
image: golang:1.16.4 image: golang:1.17.1
volumes: volumes:
- name: go-build-cache - name: go-build-cache
path: /root/.cache/go-build path: /root/.cache/go-build
environment: environment:
GTS_DB_ADDRESS: postgres GTS_DB_ADDRESS: postgres
commands: commands:
# `-count 1` => run all tests at least once
# `-p 1` => run maximum one test at a time # `-p 1` => run maximum one test at a time
# `./...` => run all tests # `./...` => run all tests
- go test -count 1 -p 1 ./... - go test -p 1 ./...
when: when:
event: event:
include: include:
@ -86,6 +85,6 @@ trigger:
--- ---
kind: signature kind: signature
hmac: 7fa6fa70be0a5c436ecb2f02f4b74bd1be5e90817e2d95a16898e3d29cbadf80 hmac: 268d484fd9c5d14834a3e2a1e39cfe605c3898d601d2969dba5c2e11c1ea2f3b
... ...

View file

@ -4,7 +4,7 @@ Hey! Welcome to the CONTRIBUTING.md for GoToSocial :) Thanks for taking a look,
This document will expand as the project expands, so for now this is basically a stub. This document will expand as the project expands, so for now this is basically a stub.
Contributions are welcome at this point, since the API is fairly stable now and the structure is at least vaguely coherent. Contributions are welcome at this point, since the API is fairly stable now and the structure is somewhat coherent.
Check the [issues](https://github.com/superseriousbusiness/gotosocial/issues) to see if there's anything you fancy jumping in on. Check the [issues](https://github.com/superseriousbusiness/gotosocial/issues) to see if there's anything you fancy jumping in on.
@ -20,11 +20,11 @@ In lieu of a fuller code of conduct, here are a few ground rules.
1. We *DO NOT ACCEPT* PRs from right-wingers, Nazis, transphobes, homophobes, racists, harassers, abusers, white-supremacists, misogynists, tech-bros of questionable ethics. If that's you, politely fuck off somewhere else. 1. We *DO NOT ACCEPT* PRs from right-wingers, Nazis, transphobes, homophobes, racists, harassers, abusers, white-supremacists, misogynists, tech-bros of questionable ethics. If that's you, politely fuck off somewhere else.
2. Any PR that moves GoToSocial in the direction of surveillance capitalism or other bad fediverse behavior will be rejected. 2. Any PR that moves GoToSocial in the direction of surveillance capitalism or other bad fediverse behavior will be rejected.
3. Don't spam the chat too hard. 3. Don't spam the general chat too hard.
## Setting up your development environment ## Setting up your development environment
To get started, you first need to have Go installed. GTS was developed with Go 1.16.4, so you should take that too. See [here](https://golang.org/doc/install). To get started, you first need to have Go installed. GtS is currently using Go 1.17, so you should take that too. See [here](https://golang.org/doc/install).
Once you've got go installed, clone this repository into your Go path. Normally, this should be `~/go/src/github.com/superseriousbusiness/gotosocial`. Once you've got go installed, clone this repository into your Go path. Normally, this should be `~/go/src/github.com/superseriousbusiness/gotosocial`.
@ -70,33 +70,13 @@ In case this post disappears, here are the steps (slightly modified):
GoToSocial provides a [testrig](https://github.com/superseriousbusiness/gotosocial/tree/main/testrig) with a bunch of mock packages you can use in integration tests. GoToSocial provides a [testrig](https://github.com/superseriousbusiness/gotosocial/tree/main/testrig) with a bunch of mock packages you can use in integration tests.
One thing that *isn't* mocked is the Database interface, because it's just easier to use a real Postgres database running on localhost. One thing that *isn't* mocked is the Database interface, because it's just easier to use an in-memory SQLite database than to mock everything out.
You can spin up a Postgres easily using Docker:
```bash
docker run -d --user postgres --network host -e POSTGRES_PASSWORD=postgres postgres
```
If you want a nice interface for peeking at what's in the Postgres database during tests, use PGWeb:
```bash
docker run -d --user postgres --network host sosedoff/pgweb
```
This will launch a pgweb at `http://localhost:8081`.
### Standalone Testrig ### Standalone Testrig
You can also launch a testrig as a standalone server running at localhost, which you can connect to using something like [Pinafore](https://github.com/nolanlawson/pinafore). You can also launch a testrig as a standalone server running at localhost, which you can connect to using something like [Pinafore](https://github.com/nolanlawson/pinafore).
To do this, first build the gotosocial binary with `go build ./cmd/gotosocial`. To do this, first build the gotosocial binary with `./build.sh`.
Then launch a clean Postgres container on localhost:
```bash
docker run -d --user postgres --network host -e POSTGRES_PASSWORD=postgres postgres
```
Then, launch the testrig by invoking the binary as follows: Then, launch the testrig by invoking the binary as follows:
@ -118,19 +98,19 @@ At the login screen, enter the email address `zork@example.org` and password `pa
Note the following constraints: Note the following constraints:
- The testrig data will be destroyed when the testrig is destroyed. It does this by dropping all tables in Postgres on shutdown. As such, you should **NEVER RUN THE TESTRIG AGAINST A DATABASE WITH REAL DATA IN IT** because it will be destroyed. Be especially careful if you're forwarding database ports from a remote instance to your local machine, because you can easily and irreversibly nuke that data if you run the testrig against it. - Since the testrig uses an in-memory database, the database will be destroyed when the testrig is stopped.
- If you stop the testrig and start it again, any tokens or applications you created during your tests will also be removed. As such, you need to log out and in again every time you stop/start the rig. - If you stop the testrig and start it again, any tokens or applications you created during your tests will also be removed. As such, you need to log out and in again every time you stop/start the rig.
- The testrig does not make any actual external http calls, so federation will (obviously) not work from a testrig. - The testrig does not make any actual external http calls, so federation will (obviously) not work from a testrig.
## Running tests ## Running tests
Because the tests use a real Postgres under the hood, you can't run them in parallel, so you need to run tests with the following command: Because the tests use a real SQLite database under the hood, you can't run them in parallel, so you need to run tests with the following command:
```bash ```bash
go test -count 1 -p 1 ./... go test -p 1 ./...
``` ```
The `count` flag means that tests will be run at least once, and the `-p 1` flag means that only 1 test will be run at a time. The `-p 1` flag means that only 1 test will be run at a time.
## Linting ## Linting

View file

@ -1,5 +1,5 @@
# STEP ONE: build the GoToSocial binary # STEP ONE: build the GoToSocial binary
FROM golang:1.16.4-alpine3.13 AS binary_builder FROM golang:1.17.1-alpine3.13 AS binary_builder
RUN apk update && apk upgrade --no-cache RUN apk update && apk upgrade --no-cache
RUN apk add git RUN apk add git

118
go.mod
View file

@ -1,12 +1,52 @@
module github.com/superseriousbusiness/gotosocial module github.com/superseriousbusiness/gotosocial
go 1.16 go 1.17
require ( require (
github.com/ReneKroon/ttlcache v1.7.0 github.com/ReneKroon/ttlcache v1.7.0
github.com/buckket/go-blurhash v1.1.0 github.com/buckket/go-blurhash v1.1.0
github.com/coreos/go-oidc/v3 v3.0.0 github.com/coreos/go-oidc/v3 v3.0.0
github.com/gin-contrib/cors v1.3.1
github.com/gin-contrib/sessions v0.0.3
github.com/gin-gonic/gin v1.7.2-0.20210908033055-3a6f18f32f22
github.com/go-errors/errors v1.4.0 // indirect
github.com/go-fed/activity v1.0.1-0.20210803212804-d866ba75dd0f
github.com/go-fed/httpsig v1.1.0
github.com/go-playground/validator/v10 v10.9.0
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.4.2
github.com/h2non/filetype v1.1.1
github.com/jackc/pgconn v1.10.0
github.com/jackc/pgx/v4 v4.13.0
github.com/microcosm-cc/bluemonday v1.0.15
github.com/mitchellh/mapstructure v1.4.1
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/oklog/ulid v1.3.1
github.com/russross/blackfriday/v2 v2.1.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB
github.com/tdewolff/minify/v2 v2.9.21
github.com/uptrace/bun v1.0.5
github.com/uptrace/bun/dialect/pgdialect v1.0.5
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5
github.com/urfave/cli/v2 v2.3.0
github.com/wagslane/go-password-validator v0.3.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/text v0.3.7
gopkg.in/yaml.v2 v2.4.0
modernc.org/sqlite v1.13.0
mvdan.cc/xurls/v2 v2.3.0
)
require (
github.com/PuerkitoBio/goquery v1.7.1 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b // indirect github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b // indirect
github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b // indirect github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b // indirect
github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 // indirect github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 // indirect
@ -15,54 +55,56 @@ require (
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect
github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d // indirect github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d // indirect
github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e // indirect github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e // indirect
github.com/gin-contrib/cors v1.3.1 github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-contrib/sessions v0.0.3 github.com/go-playground/locales v0.14.0 // indirect
github.com/gin-gonic/gin v1.7.2-0.20210722225815-d4ca9a0fb121 github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-errors/errors v1.4.0 // indirect github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
github.com/go-fed/activity v1.0.1-0.20210803212804-d866ba75dd0f github.com/goccy/go-json v0.7.8 // indirect
github.com/go-fed/httpsig v1.1.0 github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/go-playground/validator/v10 v10.7.0
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect github.com/gorilla/sessions v1.2.1 // indirect
github.com/gorilla/websocket v1.4.2 github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/h2non/filetype v1.1.1 github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgconn v1.10.0 github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgx/v4 v4.13.0 github.com/jackc/pgproto3/v2 v2.1.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.8.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/json-iterator/go v1.1.11 // indirect github.com/json-iterator/go v1.1.11 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/microcosm-cc/bluemonday v1.0.15
github.com/mitchellh/mapstructure v1.4.1
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/oklog/ulid v1.3.1
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect
github.com/russross/blackfriday/v2 v2.1.0 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/sirupsen/logrus v1.8.1 github.com/stretchr/objx v0.2.0 // indirect
github.com/stretchr/testify v1.7.0 github.com/tdewolff/parse/v2 v2.5.19 // indirect
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203 github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB github.com/ugorji/go/codec v1.2.6 // indirect
github.com/tdewolff/minify/v2 v2.9.21 github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect
github.com/tidwall/buntdb v1.2.4 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/uptrace/bun v1.0.4
github.com/uptrace/bun/dialect/pgdialect v0.4.3
github.com/uptrace/bun/dialect/sqlitedialect v0.4.3
github.com/urfave/cli/v2 v2.3.0
github.com/wagslane/go-password-validator v0.3.0
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/mod v0.5.0 // indirect golang.org/x/mod v0.5.0 // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f golang.org/x/net v0.0.0-20210908191846-a5e095526f91 // indirect
golang.org/x/sys v0.0.0-20210908160347-a851e7ddeee0 // indirect golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3 // indirect
golang.org/x/text v0.3.6
golang.org/x/tools v0.1.5 // indirect golang.org/x/tools v0.1.5 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v2 v2.4.0 gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
modernc.org/sqlite v1.13.0 lukechampine.com/uint128 v1.1.1 // indirect
mvdan.cc/xurls/v2 v2.3.0 modernc.org/cc/v3 v3.34.0 // indirect
modernc.org/ccgo/v3 v3.11.2 // indirect
modernc.org/libc v1.11.3 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.0.5 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect
) )

110
go.sum
View file

@ -35,12 +35,16 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/PuerkitoBio/goquery v1.7.1 h1:oE+T06D+1T7LNrn91B4aERsRIeCLJ/oPSa6xB9FPnz4=
github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY=
github.com/ReneKroon/ttlcache v1.7.0 h1:8BkjFfrzVFXyrqnMtezAaJ6AHPSsVV10m6w28N/Fgkk= github.com/ReneKroon/ttlcache v1.7.0 h1:8BkjFfrzVFXyrqnMtezAaJ6AHPSsVV10m6w28N/Fgkk=
github.com/ReneKroon/ttlcache v1.7.0/go.mod h1:8BGGzdumrIjWxdRx8zpK6L3oGMWvIXdvB2GD1cfvd+I= github.com/ReneKroon/ttlcache v1.7.0/go.mod h1:8BGGzdumrIjWxdRx8zpK6L3oGMWvIXdvB2GD1cfvd+I=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4= github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
@ -62,39 +66,49 @@ github.com/coreos/go-oidc/v3 v3.0.0 h1:/mAA0XMgYJw2Uqm7WKGCsKnjitE/+A0FFbOmiRJm7
github.com/coreos/go-oidc/v3 v3.0.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= github.com/coreos/go-oidc/v3 v3.0.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc h1:AuzYp98IFVOi0NU/WcZyGDQ6vAh/zkCjxGD3kt8aLzA=
github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs= github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs=
github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b h1:hoVHc4m/v8Al8mbWyvKJWr4Z37yM4QUSVh/NY6A5Sbc= github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b h1:hoVHc4m/v8Al8mbWyvKJWr4Z37yM4QUSVh/NY6A5Sbc=
github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs= github.com/dsoprea/go-exif v0.0.0-20210625224831-a6301f85c82b/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E= github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 h1:Mg7pY7kxDQD2Bkvr1N+XW4BESSIQ7tTTR7Vv+Gi2CsM=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0= github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b h1:8lVRnnni9zebcpjkrEXrEyxFpRWG/oTpWc2Y3giKomE= github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b h1:8lVRnnni9zebcpjkrEXrEyxFpRWG/oTpWc2Y3giKomE=
github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b/go.mod h1:oKrjk2kb3rAR5NbtSTLUMvMSbc+k8ZosI3MaVH47noc= github.com/dsoprea/go-exif/v2 v2.0.0-20210625224831-a6301f85c82b/go.mod h1:oKrjk2kb3rAR5NbtSTLUMvMSbc+k8ZosI3MaVH47noc=
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8= github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk= github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb h1:gwjJjUr6FY7zAWVEueFPrcRHhd9+IK81TcItbqw2du4=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM= github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 h1:YDRiMEm32T60Kpm35YzOK9ZHgjsS1Qrid+XskNcsdp8= github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 h1:YDRiMEm32T60Kpm35YzOK9ZHgjsS1Qrid+XskNcsdp8=
github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM= github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2 h1:ULCSN6v0WISNbALxomGPXh4dSjRKPW+7+seYoMz8UTc=
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2/go.mod h1:ZoOP3yUG0HD1T4IUjIFsz/2OAB2yB4YX6NSm4K+uJRg= github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2/go.mod h1:ZoOP3yUG0HD1T4IUjIFsz/2OAB2yB4YX6NSm4K+uJRg=
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210512043942-b434301c6836 h1:OHRfKIVRz2XrhZ6A7fJKHLoKky1giN+VUgU2npF0BvE= github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210512043942-b434301c6836 h1:OHRfKIVRz2XrhZ6A7fJKHLoKky1giN+VUgU2npF0BvE=
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210512043942-b434301c6836/go.mod h1:6+tQXZ+I62x13UZ+hemLVoZIuq/usVzvau7bqwUo9P0= github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210512043942-b434301c6836/go.mod h1:6+tQXZ+I62x13UZ+hemLVoZIuq/usVzvau7bqwUo9P0=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA= github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg= github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg=
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c h1:7j5aWACOzROpr+dvMtu8GnI97g9ShLWD72XIELMgn+c=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E= github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d h1:dg6UMHa50VI01WuPWXPbNJpO8QSyvIF5T5n2IZiqX3A= github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d h1:dg6UMHa50VI01WuPWXPbNJpO8QSyvIF5T5n2IZiqX3A=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E= github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82 h1:RdwKOEEe2ND/JmoKh6I/EQlR9idKJTDOMffPFK6vN2M=
github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82/go.mod h1:aDYQkL/5gfRNZkoxiLTSWU4Y8/gV/4MVsy/MU9uwTak= github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82/go.mod h1:aDYQkL/5gfRNZkoxiLTSWU4Y8/gV/4MVsy/MU9uwTak=
github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d h1:8+qI8ant/vZkNSsbwSjIR6XJfWcDVTg/qx/3pRUUZNA= github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d h1:8+qI8ant/vZkNSsbwSjIR6XJfWcDVTg/qx/3pRUUZNA=
github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d/go.mod h1:yTR3tKgyk20phAFg6IE9ulMA5NjEDD2wyx+okRFLVtw= github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d/go.mod h1:yTR3tKgyk20phAFg6IE9ulMA5NjEDD2wyx+okRFLVtw=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 h1:CfXezFYb2STGOd1+n1HshvE191zVx+QX3A1nML5xxME=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8= github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8= github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e h1:ojqYA1mU6LuRm8XzrVOvyfb000y59cbUcu6Wt8sFSAs= github.com/dsoprea/go-utility v0.0.0-20200717064901-2fccff4aa15e h1:ojqYA1mU6LuRm8XzrVOvyfb000y59cbUcu6Wt8sFSAs=
@ -122,8 +136,13 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/gin-gonic/gin v1.7.2-0.20210722225815-d4ca9a0fb121 h1:g8dxLBXSWxnEVZ+YqpDw30A4+bfscDZrqqS+JSt7dsY= github.com/gin-gonic/gin v1.7.2-0.20210722225815-d4ca9a0fb121 h1:g8dxLBXSWxnEVZ+YqpDw30A4+bfscDZrqqS+JSt7dsY=
github.com/gin-gonic/gin v1.7.2-0.20210722225815-d4ca9a0fb121/go.mod h1:0rdnKJhj+oP5aTsm5iFhKbQaPXBz4q/pWndcoMneALE= github.com/gin-gonic/gin v1.7.2-0.20210722225815-d4ca9a0fb121/go.mod h1:0rdnKJhj+oP5aTsm5iFhKbQaPXBz4q/pWndcoMneALE=
github.com/gin-gonic/gin v1.7.2-0.20210908033055-3a6f18f32f22 h1:kWkYy1sC7NJOQJ9d5byxqVYNtDxaHxNfBhxa1x+fncc=
github.com/gin-gonic/gin v1.7.2-0.20210908033055-3a6f18f32f22/go.mod h1:JkzyG2NNK3nIu6mIADW5aYvtWOsqhYbJhXueC0y9Iz8=
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.4.0 h1:2OA7MFw38+e9na72T1xgkomPb6GzZzzxvJ5U630FoRM= github.com/go-errors/errors v1.4.0 h1:2OA7MFw38+e9na72T1xgkomPb6GzZzzxvJ5U630FoRM=
@ -143,12 +162,19 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk= github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
github.com/go-playground/validator/v10 v10.7.0 h1:gLi5ajTBBheLNt0ctewgq7eolXoDALQd5/y90Hh9ZgM= github.com/go-playground/validator/v10 v10.7.0 h1:gLi5ajTBBheLNt0ctewgq7eolXoDALQd5/y90Hh9ZgM=
github.com/go-playground/validator/v10 v10.7.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk= github.com/go-playground/validator/v10 v10.7.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg= github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg=
@ -157,11 +183,16 @@ github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/goccy/go-json v0.5.1 h1:R9UYTOUvo7eIY9aeDMZ4L6OVtHaSr1k2No9W6MKjXrA= github.com/goccy/go-json v0.5.1 h1:R9UYTOUvo7eIY9aeDMZ4L6OVtHaSr1k2No9W6MKjXrA=
github.com/goccy/go-json v0.5.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.5.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.7.8 h1:CvMH7LotYymYuLGEohBM1lTZWX4g6jzWUUl2aLFuBoE=
github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
@ -175,9 +206,8 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -191,6 +221,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@ -234,6 +265,7 @@ github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
@ -298,6 +330,7 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -315,14 +348,19 @@ github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
@ -338,6 +376,7 @@ github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@ -348,9 +387,11 @@ github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSO
github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30= github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@ -372,12 +413,14 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438 h1:jnz/4VenymvySjE+Ez511s0pqVzkUOmr1fwCVytNNWk=
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg= github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc= github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc=
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg= github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
@ -404,6 +447,7 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/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= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@ -422,33 +466,24 @@ github.com/tdewolff/parse/v2 v2.5.19 h1:Kjaj3KQOx/4elIxlBSglus4E2oMfdROphvbq2b+O
github.com/tdewolff/parse/v2 v2.5.19/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= github.com/tdewolff/parse/v2 v2.5.19/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E=
github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8=
github.com/tidwall/btree v0.5.0 h1:IBfCtOj4uOMQcodv3wzYVo0zPqSJObm71mE039/dlXY= github.com/tidwall/buntdb v1.1.2 h1:noCrqQXL9EKMtcdwJcmuVKSEjqu1ua99RHHgbLTEHRo=
github.com/tidwall/btree v0.5.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
github.com/tidwall/buntdb v1.1.2/go.mod h1:xAzi36Hir4FarpSHyfuZ6JzPJdjRZ8QlLZSntE2mqlI= github.com/tidwall/buntdb v1.1.2/go.mod h1:xAzi36Hir4FarpSHyfuZ6JzPJdjRZ8QlLZSntE2mqlI=
github.com/tidwall/buntdb v1.2.4 h1:G0Qz2pV+gdxyXGCa+ARZUAE4TEljz4OaGUl8/7xEMyM=
github.com/tidwall/buntdb v1.2.4/go.mod h1:RLySCmKeFqn8PW6jU4HQ6yLvA++kunwIwjkR9hv5hB8=
github.com/tidwall/gjson v1.3.4/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/gjson v1.3.4/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ= github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb h1:5NSYaAdrnblKByzd7XByQEJVT8+9v0W/tIY0Oo4OwrE=
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb/go.mod h1:lKYYLFIr9OIgdgrtgkZ9zgRxRdvPYsExnYBsEAd8W5M= github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb/go.mod h1:lKYYLFIr9OIgdgrtgkZ9zgRxRdvPYsExnYBsEAd8W5M=
github.com/tidwall/grect v0.1.2 h1:wKVeQVZhjaFCKTTlpkDe3Ex4ko3cMGW3MRKawRe8uQ4= github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/grect v0.1.2/go.mod h1:v+n4ewstPGduVJebcp5Eh2WXBJBumNzyhK8GZt4gHNw=
github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8=
github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e h1:+NL1GDIUOKxVfbp2KoJQD9cTQ6dyP2co9q4yzmT9FZo=
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e/go.mod h1:/h+UnNGt0IhNNJLkGikcdcJqm66zGD/uJGMRxK/9+Ao= github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e/go.mod h1:/h+UnNGt0IhNNJLkGikcdcJqm66zGD/uJGMRxK/9+Ao=
github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 h1:Otn9S136ELckZ3KKDyCkxapfufrqDqwmGjcHfAyXRrE=
github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ= github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ=
github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@ -460,10 +495,16 @@ github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxW
github.com/uptrace/bun v0.4.3/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw= github.com/uptrace/bun v0.4.3/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun v1.0.4 h1:XKkddp+F5rbjyZCfEXPHc9ZEG3RE8VktO4HCcg5nzCQ= github.com/uptrace/bun v1.0.4 h1:XKkddp+F5rbjyZCfEXPHc9ZEG3RE8VktO4HCcg5nzCQ=
github.com/uptrace/bun v1.0.4/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw= github.com/uptrace/bun v1.0.4/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun v1.0.5 h1:bNhNhWt6XNwSWMEQUvYK7iJ3qHrMfeoKY3/w2jkqcBs=
github.com/uptrace/bun v1.0.5/go.mod h1:aL6D9vPw8DXaTQTwGrEPtUderBYXx7ShUmPfnxnqscw=
github.com/uptrace/bun/dialect/pgdialect v0.4.3 h1:lM2IUKpU99110chKkupw3oTfXiOKpB0hTJIe6frqQDo= github.com/uptrace/bun/dialect/pgdialect v0.4.3 h1:lM2IUKpU99110chKkupw3oTfXiOKpB0hTJIe6frqQDo=
github.com/uptrace/bun/dialect/pgdialect v0.4.3/go.mod h1:BaNvWejl32oKUhwpFkw/eNcWldzIlVY4nfw/sNul0s8= github.com/uptrace/bun/dialect/pgdialect v0.4.3/go.mod h1:BaNvWejl32oKUhwpFkw/eNcWldzIlVY4nfw/sNul0s8=
github.com/uptrace/bun/dialect/pgdialect v1.0.5 h1:mq694/aMvs7GwuTar9NIlCLQt/2u4xsF0QMP4I24yHA=
github.com/uptrace/bun/dialect/pgdialect v1.0.5/go.mod h1:MKWjO0PC20ris2oJ3dd6mI/762x24Cjwh8XmbqUhM8A=
github.com/uptrace/bun/dialect/sqlitedialect v0.4.3 h1:h+vqLGCeY22PFrbCOpQqK5+/p1qWCXYIhIUm/D5Vw08= github.com/uptrace/bun/dialect/sqlitedialect v0.4.3 h1:h+vqLGCeY22PFrbCOpQqK5+/p1qWCXYIhIUm/D5Vw08=
github.com/uptrace/bun/dialect/sqlitedialect v0.4.3/go.mod h1:W9zHzVl9lJwWHx038vHs7ddVJ6LbNebseLZ3UGAqeAk= github.com/uptrace/bun/dialect/sqlitedialect v0.4.3/go.mod h1:W9zHzVl9lJwWHx038vHs7ddVJ6LbNebseLZ3UGAqeAk=
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5 h1:6cIj31YVJr4vvA15C2v76soXL+7WtjFdV6WraApc3r0=
github.com/uptrace/bun/dialect/sqlitedialect v1.0.5/go.mod h1:NW2Gctc9ooQXGSD4kYSac2aiF49lo8YJ3ZAr93lH2p8=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@ -494,7 +535,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@ -526,6 +566,8 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -555,10 +597,11 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q= golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -592,9 +635,10 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210908191846-a5e095526f91 h1:E8wdt+zBjoxD3MA65wEc3pl25BsTi7tbkpwc4ANThjc=
golang.org/x/net v0.0.0-20210908191846-a5e095526f91/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -611,7 +655,6 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180525142821-c11f84a56e43/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180525142821-c11f84a56e43/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -653,15 +696,16 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b h1:S7hKs0Flbq0bbc9xgYt4stIEG1zNDFqyrPwAX2Wj/sE=
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908160347-a851e7ddeee0 h1:6xxeVXiyYpF8WCTnKKCbjnEdsrwjZYY8TOuk7xP0chg= golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3 h1:3Ad41xy2WCESpufXwgs7NpDSu+vjxqLt2UFqUV+20bI=
golang.org/x/sys v0.0.0-20210908160347-a851e7ddeee0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -673,6 +717,8 @@ 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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -722,8 +768,8 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/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= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 h1:M8tBwCtWD/cZV9DZpFYRUgaymAYAr+aIUTWzDaM3uPs=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -754,6 +800,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
@ -811,10 +858,12 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
@ -823,6 +872,8 @@ gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWd
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -833,6 +884,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -1,9 +0,0 @@
module github.com/ReneKroon/ttlcache
go 1.14
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/stretchr/testify v1.3.0
go.uber.org/goleak v0.10.0
)

View file

@ -1,11 +0,0 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=

View file

@ -1,3 +0,0 @@
module github.com/buckket/go-blurhash
go 1.14

View file

@ -1,11 +0,0 @@
module github.com/dsoprea/go-exif
go 1.13
require (
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696
github.com/go-errors/errors v1.0.1 // indirect
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
gopkg.in/yaml.v2 v2.2.7
)

View file

@ -1,14 +0,0 @@
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -1,15 +0,0 @@
module github.com/dsoprea/go-exif/v2
go 1.13
// Development only
// replace github.com/dsoprea/go-logging => ../../go-logging
require (
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf // indirect
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d
github.com/jessevdk/go-flags v1.4.0
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 // indirect
gopkg.in/yaml.v2 v2.3.0
)

View file

@ -1,37 +0,0 @@
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200502191043-ec333ec7635f h1:XM9MVftaUNA4CcjV97+4bSy7u9Ns04DEYbZkswUrRtc=
github.com/dsoprea/go-logging v0.0.0-20200502191043-ec333ec7635f/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f h1:FonKAuW3PmNtqk9tOR+Z7bnyQHytmnZBCmm5z1PQMss=
github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf h1:/w4QxepU4AHh3AuO6/g8y/YIIHH5+aKP3Bj8sg5cqhU=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -1,5 +0,0 @@
module github.com/dsoprea/go-iptc
go 1.13
require github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d

View file

@ -1,10 +0,0 @@
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -1,22 +0,0 @@
module github.com/dsoprea/go-jpeg-image-structure
go 1.13
// Development only
// replace github.com/dsoprea/go-utility => ../go-utility
// replace github.com/dsoprea/go-logging => ../go-logging
// replace github.com/dsoprea/go-exif/v2 => ../go-exif/v2
// replace github.com/dsoprea/go-photoshop-info-format => ../go-photoshop-info-format
// replace github.com/dsoprea/go-iptc => ../go-iptc
require (
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e // indirect
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b
github.com/jessevdk/go-flags v1.4.0
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 // indirect
)

View file

@ -1,85 +0,0 @@
github.com/dsoprea/go-exif v0.0.0-20200502203340-6aea10b45f4c h1:PoW4xOq3wUrX8ghNGiJFzem7mwd+mY/Xkgo0Z8AwcNY=
github.com/dsoprea/go-exif v0.0.0-20200516122116-a45cc7cfd55e h1:tTb1WdrhFs8VdnmxiADJEUpDJWKHFUFys0OUyLM9A6o=
github.com/dsoprea/go-exif/v2 v2.0.0-20200113231207-0bbb7a3584f7 h1:+koSu4BOaLu+dy50WEj+ltzEjMzK5evzPawKxgIQerw=
github.com/dsoprea/go-exif/v2 v2.0.0-20200113231207-0bbb7a3584f7/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200502203340-6aea10b45f4c h1:fQNBTLqL4u7yhl5AqW6dGG5RSxGuRhzXLnBVDR2uUuE=
github.com/dsoprea/go-exif/v2 v2.0.0-20200502203340-6aea10b45f4c/go.mod h1:YXOyDqCYjBuHHRw4JIGPgOgMit0IDvVSjjhsqOAFTYQ=
github.com/dsoprea/go-exif/v2 v2.0.0-20200516113213-42546383ce8f h1:WFrUfvt3uESgJ/NwPG/2Vjhp2uOE7X2wENldE+ch1yw=
github.com/dsoprea/go-exif/v2 v2.0.0-20200516113213-42546383ce8f/go.mod h1:YXOyDqCYjBuHHRw4JIGPgOgMit0IDvVSjjhsqOAFTYQ=
github.com/dsoprea/go-exif/v2 v2.0.0-20200516122116-a45cc7cfd55e h1:tPHXVRs63sg0ajoZjdmMa5aZuyjnSAt3Anwh2F4XsJM=
github.com/dsoprea/go-exif/v2 v2.0.0-20200516122116-a45cc7cfd55e/go.mod h1:YXOyDqCYjBuHHRw4JIGPgOgMit0IDvVSjjhsqOAFTYQ=
github.com/dsoprea/go-exif/v2 v2.0.0-20200516213102-7f6eb3d9f38c h1:92aud+9pN3bQjh/iw1+849uOBQfLuAcUC4LJwtfmRBo=
github.com/dsoprea/go-exif/v2 v2.0.0-20200516213102-7f6eb3d9f38c/go.mod h1:YXOyDqCYjBuHHRw4JIGPgOgMit0IDvVSjjhsqOAFTYQ=
github.com/dsoprea/go-exif/v2 v2.0.0-20200517080529-c9be4b30b064 h1:V7CH/kZImE6Lf27H4DS5PG7qzBkf774GIXUuM31vVNA=
github.com/dsoprea/go-exif/v2 v2.0.0-20200517080529-c9be4b30b064/go.mod h1:YXOyDqCYjBuHHRw4JIGPgOgMit0IDvVSjjhsqOAFTYQ=
github.com/dsoprea/go-exif/v2 v2.0.0-20200518001653-d0d0f14dea03 h1:r+aCxLEe6uGDC/NJCpA3WQJ+C7WJ0chzfHKgy173fug=
github.com/dsoprea/go-exif/v2 v2.0.0-20200518001653-d0d0f14dea03/go.mod h1:STKu28lNwOeoO0bieAKJ3zQYkUbZ2hivI6qjjGVW0sc=
github.com/dsoprea/go-exif/v2 v2.0.0-20200520183328-015129a9efd5 h1:iKMxnRjFqQQYKEpdsjFDMV2+VUAncTLT4ofcCiQpDvo=
github.com/dsoprea/go-exif/v2 v2.0.0-20200520183328-015129a9efd5/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v2 v2.0.0-20200527040709-fecb7e81f4be h1:iYHdwTUXN48h6wZd2QQHDyR4QsuWM08PX4wCJuzd7O0=
github.com/dsoprea/go-exif/v2 v2.0.0-20200527040709-fecb7e81f4be/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v2 v2.0.0-20200527042908-2a1e3f0fa19c h1:3uLJ1ub/I1sFM76IEzRi7RjqbhL1WfyPJeSko0tIYMI=
github.com/dsoprea/go-exif/v2 v2.0.0-20200527042908-2a1e3f0fa19c/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v2 v2.0.0-20200527165002-1a62daf3052a h1:Xk487H/DyhmIgYAnbJ5gvOrwI/eJ+FVXIO9Y22m44VI=
github.com/dsoprea/go-exif/v2 v2.0.0-20200527165002-1a62daf3052a/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 h1:Mg7pY7kxDQD2Bkvr1N+XW4BESSIQ7tTTR7Vv+Gi2CsM=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e h1:E4XTSQZF/JtOQWcSaJBJho7t+RNWfdO92W/5skg10Jk=
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb h1:gwjJjUr6FY7zAWVEueFPrcRHhd9+IK81TcItbqw2du4=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f h1:FonKAuW3PmNtqk9tOR+Z7bnyQHytmnZBCmm5z1PQMss=
github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200517222403-5742ce3fc1be h1:k3sHKay8cXGnGHeF8x6U7KtX8Lc7qAiQCNDRGEIPdnU=
github.com/dsoprea/go-logging v0.0.0-20200517222403-5742ce3fc1be/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c h1:7j5aWACOzROpr+dvMtu8GnI97g9ShLWD72XIELMgn+c=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
github.com/dsoprea/go-utility v0.0.0-20200322055224-4dc0f716e7d0 h1:zFSboMDWXX2UX7/k/mCHBjZhHlaFMx0HmtUE37HABsA=
github.com/dsoprea/go-utility v0.0.0-20200322055224-4dc0f716e7d0/go.mod h1:xv8CVgDmI/Shx/X+EUXyXELVnH5lSRUYRija52OHq7E=
github.com/dsoprea/go-utility v0.0.0-20200322154813-27f0b0d142d7 h1:DJhSHW0odJrW5wR9MU6ry5S+PsxuRXA165KFaiB+cZo=
github.com/dsoprea/go-utility v0.0.0-20200322154813-27f0b0d142d7/go.mod h1:xv8CVgDmI/Shx/X+EUXyXELVnH5lSRUYRija52OHq7E=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 h1:CfXezFYb2STGOd1+n1HshvE191zVx+QX3A1nML5xxME=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf h1:/w4QxepU4AHh3AuO6/g8y/YIIHH5+aKP3Bj8sg5cqhU=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbCNrwumIYjDoMOdf4KOSkMC6NJE4s8oRbE7E=
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
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/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -1,8 +0,0 @@
module github.com/dsoprea/go-logging
go 1.13
require (
github.com/go-errors/errors v1.0.2
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5
)

View file

@ -1,8 +0,0 @@
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -1,5 +0,0 @@
module github.com/dsoprea/go-photoshop-info-format
go 1.13
require github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d

View file

@ -1,10 +0,0 @@
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -1,15 +0,0 @@
module github.com/dsoprea/go-png-image-structure
go 1.13
// Development only
// replace github.com/dsoprea/go-utility => ../go-utility
// replace github.com/dsoprea/go-exif/v2 => ../go-exif/v2
require (
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e // indirect
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 // indirect
)

View file

@ -1,67 +0,0 @@
github.com/dsoprea/go-exif v0.0.0-20200502203340-6aea10b45f4c h1:PoW4xOq3wUrX8ghNGiJFzem7mwd+mY/Xkgo0Z8AwcNY=
github.com/dsoprea/go-exif/v2 v2.0.0-20200113184400-90b66e3d1158 h1:DzXu3hw2xqwfd/R0QflKY/ixfrLDbMFk30D/CyJMTAM=
github.com/dsoprea/go-exif/v2 v2.0.0-20200113184400-90b66e3d1158/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200113231207-0bbb7a3584f7 h1:+koSu4BOaLu+dy50WEj+ltzEjMzK5evzPawKxgIQerw=
github.com/dsoprea/go-exif/v2 v2.0.0-20200113231207-0bbb7a3584f7/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4 h1:bVaiYo8amn7Lu93sz6mTlYB3EtLG9aRcMnM1Eps8fmM=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200502203340-6aea10b45f4c h1:fQNBTLqL4u7yhl5AqW6dGG5RSxGuRhzXLnBVDR2uUuE=
github.com/dsoprea/go-exif/v2 v2.0.0-20200502203340-6aea10b45f4c/go.mod h1:YXOyDqCYjBuHHRw4JIGPgOgMit0IDvVSjjhsqOAFTYQ=
github.com/dsoprea/go-exif/v2 v2.0.0-20200517080529-c9be4b30b064 h1:V7CH/kZImE6Lf27H4DS5PG7qzBkf774GIXUuM31vVNA=
github.com/dsoprea/go-exif/v2 v2.0.0-20200517080529-c9be4b30b064/go.mod h1:YXOyDqCYjBuHHRw4JIGPgOgMit0IDvVSjjhsqOAFTYQ=
github.com/dsoprea/go-exif/v2 v2.0.0-20200517234148-29b0ff22564b h1:Uvnq5XTzlscGvQl3IwysBUVdSb1VUmqIvHrOv4x4UCE=
github.com/dsoprea/go-exif/v2 v2.0.0-20200517234148-29b0ff22564b/go.mod h1:STKu28lNwOeoO0bieAKJ3zQYkUbZ2hivI6qjjGVW0sc=
github.com/dsoprea/go-exif/v2 v2.0.0-20200518001653-d0d0f14dea03 h1:r+aCxLEe6uGDC/NJCpA3WQJ+C7WJ0chzfHKgy173fug=
github.com/dsoprea/go-exif/v2 v2.0.0-20200518001653-d0d0f14dea03/go.mod h1:STKu28lNwOeoO0bieAKJ3zQYkUbZ2hivI6qjjGVW0sc=
github.com/dsoprea/go-exif/v2 v2.0.0-20200520183328-015129a9efd5 h1:iKMxnRjFqQQYKEpdsjFDMV2+VUAncTLT4ofcCiQpDvo=
github.com/dsoprea/go-exif/v2 v2.0.0-20200520183328-015129a9efd5/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 h1:Mg7pY7kxDQD2Bkvr1N+XW4BESSIQ7tTTR7Vv+Gi2CsM=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e h1:E4XTSQZF/JtOQWcSaJBJho7t+RNWfdO92W/5skg10Jk=
github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f h1:FonKAuW3PmNtqk9tOR+Z7bnyQHytmnZBCmm5z1PQMss=
github.com/dsoprea/go-logging v0.0.0-20200502201358-170ff607885f/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-utility v0.0.0-20200322055224-4dc0f716e7d0 h1:zFSboMDWXX2UX7/k/mCHBjZhHlaFMx0HmtUE37HABsA=
github.com/dsoprea/go-utility v0.0.0-20200322055224-4dc0f716e7d0/go.mod h1:xv8CVgDmI/Shx/X+EUXyXELVnH5lSRUYRija52OHq7E=
github.com/dsoprea/go-utility v0.0.0-20200322154813-27f0b0d142d7 h1:DJhSHW0odJrW5wR9MU6ry5S+PsxuRXA165KFaiB+cZo=
github.com/dsoprea/go-utility v0.0.0-20200322154813-27f0b0d142d7/go.mod h1:xv8CVgDmI/Shx/X+EUXyXELVnH5lSRUYRija52OHq7E=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 h1:CfXezFYb2STGOd1+n1HshvE191zVx+QX3A1nML5xxME=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf h1:/w4QxepU4AHh3AuO6/g8y/YIIHH5+aKP3Bj8sg5cqhU=
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbCNrwumIYjDoMOdf4KOSkMC6NJE4s8oRbE7E=
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -1,10 +0,0 @@
module github.com/gin-contrib/cors
go 1.13
require (
github.com/gin-gonic/gin v1.5.0
github.com/kr/pretty v0.1.0 // indirect
github.com/stretchr/testify v1.4.0
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)

View file

@ -1,52 +0,0 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -1,17 +0,0 @@
module github.com/gin-contrib/sessions
go 1.12
require (
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1
github.com/gin-gonic/gin v1.5.0
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/gomodule/redigo v2.0.0+incompatible
github.com/gorilla/context v1.1.1
github.com/gorilla/sessions v1.1.3
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b
github.com/memcachier/mc v2.0.1+incompatible
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438
)

View file

@ -1,69 +0,0 @@
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA=
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1 h1:4QHxgr7hM4gVD8uOwrk8T1fjkKRLwaLjmTkU0ibhZKU=
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b h1:TLCm7HR+P9HM2NXaAJaIiHerOUMedtFJeAfaYwZ8YhY=
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/memcachier/mc v2.0.1+incompatible h1:s8EDz0xrJLP8goitwZOoq1vA/sm0fPS4X3KAF0nyhWQ=
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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/quasoft/memstore v0.0.0-20180925164028-84a050167438 h1:jnz/4VenymvySjE+Ez511s0pqVzkUOmr1fwCVytNNWk=
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -1,5 +0,0 @@
module github.com/gin-contrib/sse
go 1.12
require github.com/stretchr/testify v1.3.0

View file

@ -1,7 +0,0 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=

22
vendor/github.com/gin-gonic/gin/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,22 @@
run:
timeout: 5m
linters:
enable:
- gofmt
- misspell
- revive
issues:
exclude-rules:
- linters:
- structcheck
- unused
text: "`data` is unused"
- linters:
- staticcheck
text: "SA1019:"
- linters:
- revive
text: "var-naming:"
- linters:
- revive
text: "exported:"

View file

@ -1,5 +1,11 @@
# Gin ChangeLog # Gin ChangeLog
## Gin v1.7.3
### BUGFIXES
* fix level 1 router match [#2767](https://github.com/gin-gonic/gin/issues/2767), [#2796](https://github.com/gin-gonic/gin/issues/2796)
## Gin v1.7.2 ## Gin v1.7.2
### BUGFIXES ### BUGFIXES

View file

@ -256,14 +256,15 @@ func main() {
// For each matched request Context will hold the route definition // For each matched request Context will hold the route definition
router.POST("/user/:name/*action", func(c *gin.Context) { router.POST("/user/:name/*action", func(c *gin.Context) {
c.FullPath() == "/user/:name/*action" // true b := c.FullPath() == "/user/:name/*action" // true
c.String(http.StatusOK, "%t", b)
}) })
// This handler will add a new router for /user/groups. // This handler will add a new router for /user/groups.
// Exact routes are resolved before param routes, regardless of the order they were defined. // Exact routes are resolved before param routes, regardless of the order they were defined.
// Routes starting with /user/groups are never interpreted as /user/:name/... routes // Routes starting with /user/groups are never interpreted as /user/:name/... routes
router.GET("/user/groups", func(c *gin.Context) { router.GET("/user/groups", func(c *gin.Context) {
c.String(http.StatusOK, "The available groups are [...]", name) c.String(http.StatusOK, "The available groups are [...]")
}) })
router.Run(":8080") router.Run(":8080")

View file

@ -26,7 +26,7 @@
ErrConvertToMapString = errors.New("can not convert to map of strings") ErrConvertToMapString = errors.New("can not convert to map of strings")
) )
func mapUri(ptr interface{}, m map[string][]string) error { func mapURI(ptr interface{}, m map[string][]string) error {
return mapFormByTag(ptr, m, "uri") return mapFormByTag(ptr, m, "uri")
} }
@ -83,7 +83,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
return false, nil return false, nil
} }
var vKind = value.Kind() vKind := value.Kind()
if vKind == reflect.Ptr { if vKind == reflect.Ptr {
var isNew bool var isNew bool
@ -210,7 +210,7 @@ func setWithProperType(val string, value reflect.Value, field reflect.StructFiel
case reflect.Int64: case reflect.Int64:
switch value.Interface().(type) { switch value.Interface().(type) {
case time.Duration: case time.Duration:
return setTimeDuration(val, value, field) return setTimeDuration(val, value)
} }
return setIntField(val, 64, value) return setIntField(val, 64, value)
case reflect.Uint: case reflect.Uint:
@ -310,7 +310,6 @@ func setTimeField(val string, structField reflect.StructField, value reflect.Val
t := time.Unix(tv/int64(d), tv%int64(d)) t := time.Unix(tv/int64(d), tv%int64(d))
value.Set(reflect.ValueOf(t)) value.Set(reflect.ValueOf(t))
return nil return nil
} }
if val == "" { if val == "" {
@ -360,7 +359,7 @@ func setSlice(vals []string, value reflect.Value, field reflect.StructField) err
return nil return nil
} }
func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error { func setTimeDuration(val string, value reflect.Value) error {
d, err := time.ParseDuration(val) d, err := time.ParseDuration(val)
if err != nil { if err != nil {
return err return err

View file

@ -5,10 +5,11 @@
package binding package binding
import ( import (
"errors"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"github.com/golang/protobuf/proto" "google.golang.org/protobuf/proto"
) )
type protobufBinding struct{} type protobufBinding struct{}
@ -26,7 +27,11 @@ func (b protobufBinding) Bind(req *http.Request, obj interface{}) error {
} }
func (protobufBinding) BindBody(body []byte, obj interface{}) error { func (protobufBinding) BindBody(body []byte, obj interface{}) error {
if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil { msg, ok := obj.(proto.Message)
if !ok {
return errors.New("obj is not ProtoMessage")
}
if err := proto.Unmarshal(body, msg); err != nil {
return err return err
} }
// Here it's same to return validate(obj), but util now we can't add // Here it's same to return validate(obj), but util now we can't add

View file

@ -11,7 +11,7 @@ func (uriBinding) Name() string {
} }
func (uriBinding) BindUri(m map[string][]string, obj interface{}) error { func (uriBinding) BindUri(m map[string][]string, obj interface{}) error {
if err := mapUri(obj, m); err != nil { if err := mapURI(obj, m); err != nil {
return err return err
} }
return validate(obj) return validate(obj)

View file

@ -383,6 +383,15 @@ func (c *Context) Param(key string) string {
return c.Params.ByName(key) return c.Params.ByName(key)
} }
// AddParam adds param to context and
// replaces path param key with given value for e2e testing purposes
// Example Route: "/user/:id"
// AddParam("id", 1)
// Result: "/user/1"
func (c *Context) AddParam(key, value string) {
c.Params = append(c.Params, Param{Key: key, Value: value})
}
// Query returns the keyed url query value if it exists, // Query returns the keyed url query value if it exists,
// otherwise it returns an empty string `("")`. // otherwise it returns an empty string `("")`.
// It is shortcut for `c.Request.URL.Query().Get(key)` // It is shortcut for `c.Request.URL.Query().Get(key)`
@ -391,9 +400,9 @@ func (c *Context) Param(key string) string {
// c.Query("name") == "Manu" // c.Query("name") == "Manu"
// c.Query("value") == "" // c.Query("value") == ""
// c.Query("wtf") == "" // c.Query("wtf") == ""
func (c *Context) Query(key string) string { func (c *Context) Query(key string) (value string) {
value, _ := c.GetQuery(key) value, _ = c.GetQuery(key)
return value return
} }
// DefaultQuery returns the keyed url query value if it exists, // DefaultQuery returns the keyed url query value if it exists,
@ -427,9 +436,9 @@ func (c *Context) GetQuery(key string) (string, bool) {
// QueryArray returns a slice of strings for a given query key. // QueryArray returns a slice of strings for a given query key.
// The length of the slice depends on the number of params with the given key. // The length of the slice depends on the number of params with the given key.
func (c *Context) QueryArray(key string) []string { func (c *Context) QueryArray(key string) (values []string) {
values, _ := c.GetQueryArray(key) values, _ = c.GetQueryArray(key)
return values return
} }
func (c *Context) initQueryCache() { func (c *Context) initQueryCache() {
@ -444,18 +453,16 @@ func (c *Context) initQueryCache() {
// GetQueryArray returns a slice of strings for a given query key, plus // GetQueryArray returns a slice of strings for a given query key, plus
// a boolean value whether at least one value exists for the given key. // a boolean value whether at least one value exists for the given key.
func (c *Context) GetQueryArray(key string) ([]string, bool) { func (c *Context) GetQueryArray(key string) (values []string, ok bool) {
c.initQueryCache() c.initQueryCache()
if values, ok := c.queryCache[key]; ok && len(values) > 0 { values, ok = c.queryCache[key]
return values, true return
}
return []string{}, false
} }
// QueryMap returns a map for a given query key. // QueryMap returns a map for a given query key.
func (c *Context) QueryMap(key string) map[string]string { func (c *Context) QueryMap(key string) (dicts map[string]string) {
dicts, _ := c.GetQueryMap(key) dicts, _ = c.GetQueryMap(key)
return dicts return
} }
// GetQueryMap returns a map for a given query key, plus a boolean value // GetQueryMap returns a map for a given query key, plus a boolean value
@ -467,9 +474,9 @@ func (c *Context) GetQueryMap(key string) (map[string]string, bool) {
// PostForm returns the specified key from a POST urlencoded form or multipart form // PostForm returns the specified key from a POST urlencoded form or multipart form
// when it exists, otherwise it returns an empty string `("")`. // when it exists, otherwise it returns an empty string `("")`.
func (c *Context) PostForm(key string) string { func (c *Context) PostForm(key string) (value string) {
value, _ := c.GetPostForm(key) value, _ = c.GetPostForm(key)
return value return
} }
// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
@ -498,9 +505,9 @@ func (c *Context) GetPostForm(key string) (string, bool) {
// PostFormArray returns a slice of strings for a given form key. // PostFormArray returns a slice of strings for a given form key.
// The length of the slice depends on the number of params with the given key. // The length of the slice depends on the number of params with the given key.
func (c *Context) PostFormArray(key string) []string { func (c *Context) PostFormArray(key string) (values []string) {
values, _ := c.GetPostFormArray(key) values, _ = c.GetPostFormArray(key)
return values return
} }
func (c *Context) initFormCache() { func (c *Context) initFormCache() {
@ -518,18 +525,16 @@ func (c *Context) initFormCache() {
// GetPostFormArray returns a slice of strings for a given form key, plus // GetPostFormArray returns a slice of strings for a given form key, plus
// a boolean value whether at least one value exists for the given key. // a boolean value whether at least one value exists for the given key.
func (c *Context) GetPostFormArray(key string) ([]string, bool) { func (c *Context) GetPostFormArray(key string) (values []string, ok bool) {
c.initFormCache() c.initFormCache()
if values := c.formCache[key]; len(values) > 0 { values, ok = c.formCache[key]
return values, true return
}
return []string{}, false
} }
// PostFormMap returns a map for a given form key. // PostFormMap returns a map for a given form key.
func (c *Context) PostFormMap(key string) map[string]string { func (c *Context) PostFormMap(key string) (dicts map[string]string) {
dicts, _ := c.GetPostFormMap(key) dicts, _ = c.GetPostFormMap(key)
return dicts return
} }
// GetPostFormMap returns a map for a given form key, plus a boolean value // GetPostFormMap returns a map for a given form key, plus a boolean value
@ -1161,23 +1166,29 @@ func (c *Context) SetAccepted(formats ...string) {
/***** GOLANG.ORG/X/NET/CONTEXT *****/ /***** GOLANG.ORG/X/NET/CONTEXT *****/
/************************************/ /************************************/
// Deadline always returns that there is no deadline (ok==false), // Deadline returns that there is no deadline (ok==false) when c.Request has no Context.
// maybe you want to use Request.Context().Deadline() instead.
func (c *Context) Deadline() (deadline time.Time, ok bool) { func (c *Context) Deadline() (deadline time.Time, ok bool) {
if c.Request == nil || c.Request.Context() == nil {
return return
} }
return c.Request.Context().Deadline()
// Done always returns nil (chan which will wait forever),
// if you want to abort your work when the connection was closed
// you should use Request.Context().Done() instead.
func (c *Context) Done() <-chan struct{} {
return nil
} }
// Err always returns nil, maybe you want to use Request.Context().Err() instead. // Done returns nil (chan which will wait forever) when c.Request has no Context.
func (c *Context) Err() error { func (c *Context) Done() <-chan struct{} {
if c.Request == nil || c.Request.Context() == nil {
return nil return nil
} }
return c.Request.Context().Done()
}
// Err returns nil when c.Request has no Context.
func (c *Context) Err() error {
if c.Request == nil || c.Request.Context() == nil {
return nil
}
return c.Request.Context().Err()
}
// Value returns the value associated with this context for key, or nil // Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with // if no value is associated with key. Successive calls to Value with

View file

@ -1,15 +0,0 @@
module github.com/gin-gonic/gin
go 1.13
require (
github.com/gin-contrib/sse v0.1.0
github.com/go-playground/validator/v10 v10.6.1
github.com/goccy/go-json v0.5.1
github.com/golang/protobuf v1.3.3
github.com/json-iterator/go v1.1.9
github.com/mattn/go-isatty v0.0.12
github.com/stretchr/testify v1.4.0
github.com/ugorji/go/codec v1.2.6
gopkg.in/yaml.v2 v2.2.8
)

View file

@ -1,55 +0,0 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
github.com/goccy/go-json v0.5.1 h1:R9UYTOUvo7eIY9aeDMZ4L6OVtHaSr1k2No9W6MKjXrA=
github.com/goccy/go-json v0.5.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -41,8 +41,10 @@
// DefaultErrorWriter is the default io.Writer used by Gin to debug errors // DefaultErrorWriter is the default io.Writer used by Gin to debug errors
var DefaultErrorWriter io.Writer = os.Stderr var DefaultErrorWriter io.Writer = os.Stderr
var ginMode = debugCode var (
var modeName = DebugMode ginMode = debugCode
modeName = DebugMode
)
func init() { func init() {
mode := os.Getenv(EnvGinMode) mode := os.Getenv(EnvGinMode)

View file

@ -49,7 +49,7 @@ type PureJSON struct {
var ( var (
jsonContentType = []string{"application/json; charset=utf-8"} jsonContentType = []string{"application/json; charset=utf-8"}
jsonpContentType = []string{"application/javascript; charset=utf-8"} jsonpContentType = []string{"application/javascript; charset=utf-8"}
jsonAsciiContentType = []string{"application/json"} jsonASCIIContentType = []string{"application/json"}
) )
// Render (JSON) writes data with custom ContentType. // Render (JSON) writes data with custom ContentType.
@ -102,8 +102,7 @@ func (r SecureJSON) Render(w http.ResponseWriter) error {
// if the jsonBytes is array values // if the jsonBytes is array values
if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes, if bytes.HasPrefix(jsonBytes, bytesconv.StringToBytes("[")) && bytes.HasSuffix(jsonBytes,
bytesconv.StringToBytes("]")) { bytesconv.StringToBytes("]")) {
_, err = w.Write(bytesconv.StringToBytes(r.Prefix)) if _, err = w.Write(bytesconv.StringToBytes(r.Prefix)); err != nil {
if err != nil {
return err return err
} }
} }
@ -130,20 +129,19 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
} }
callback := template.JSEscapeString(r.Callback) callback := template.JSEscapeString(r.Callback)
_, err = w.Write(bytesconv.StringToBytes(callback)) if _, err = w.Write(bytesconv.StringToBytes(callback)); err != nil {
if err != nil {
return err return err
} }
_, err = w.Write(bytesconv.StringToBytes("("))
if err != nil { if _, err = w.Write(bytesconv.StringToBytes("(")); err != nil {
return err return err
} }
_, err = w.Write(ret)
if err != nil { if _, err = w.Write(ret); err != nil {
return err return err
} }
_, err = w.Write(bytesconv.StringToBytes(");"))
if err != nil { if _, err = w.Write(bytesconv.StringToBytes(");")); err != nil {
return err return err
} }
@ -178,7 +176,7 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
// WriteContentType (AsciiJSON) writes JSON ContentType. // WriteContentType (AsciiJSON) writes JSON ContentType.
func (r AsciiJSON) WriteContentType(w http.ResponseWriter) { func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonAsciiContentType) writeContentType(w, jsonASCIIContentType)
} }
// Render (PureJSON) writes custom ContentType and encodes the given interface object. // Render (PureJSON) writes custom ContentType and encodes the given interface object.

View file

@ -7,7 +7,7 @@
import ( import (
"net/http" "net/http"
"github.com/golang/protobuf/proto" "google.golang.org/protobuf/proto"
) )
// ProtoBuf contains the given interface object. // ProtoBuf contains the given interface object.

View file

@ -101,8 +101,7 @@ func countParams(path string) uint16 {
type nodeType uint8 type nodeType uint8
const ( const (
static nodeType = iota // default root nodeType = iota + 1
root
param param
catchAll catchAll
) )
@ -400,23 +399,10 @@ type nodeValue struct {
// made if a handle exists with an extra (without the) trailing slash for the // made if a handle exists with an extra (without the) trailing slash for the
// given path. // given path.
func (n *node) getValue(path string, params *Params, unescape bool) (value nodeValue) { func (n *node) getValue(path string, params *Params, unescape bool) (value nodeValue) {
// path: /abc/123/def
// level 1 router:abc
// level 2 router:123
// level 3 router:def
var ( var (
skippedPath string skippedPath string
latestNode = n // not found `level 2 router` use latestNode latestNode = n // Caching the latest node
// match '/' count
// matchNum < 1: `level 2 router` not found,the current node needs to be equal to latestNode
// matchNum >= 1: `level (2 or 3 or 4 or ...) router`: Normal handling
matchNum int // each match will accumulate
) )
//if path == "/", no need to look for tree node
if len(path) == 1 {
matchNum = 1
}
walk: // Outer loop for walking the tree walk: // Outer loop for walking the tree
for { for {
@ -444,17 +430,13 @@ func (n *node) getValue(path string, params *Params, unescape bool) (value nodeV
} }
n = n.children[i] n = n.children[i]
// match '/', If this condition is matched, the next route is found
if (len(n.fullPath) != 0 && n.wildChild) || path[len(path)-1] == '/' {
matchNum++
}
continue walk continue walk
} }
} }
// If the path at the end of the loop is not equal to '/' and the current node has no child nodes
// level 2 router not found,the current node needs to be equal to latestNode // the current node needs to be equal to the latest matching node
if matchNum < 1 { matched := path != "/" && !n.wildChild
if matched {
n = latestNode n = latestNode
} }
@ -472,6 +454,16 @@ func (n *node) getValue(path string, params *Params, unescape bool) (value nodeV
switch n.nType { switch n.nType {
case param: case param:
// fix truncate the parameter
// tree_test.go line: 204
if matched {
path = prefix + path
// The saved path is used after the prefix route is intercepted by matching
if n.indices == "/" {
path = skippedPath[1:]
}
}
// Find param end (either '/' or path end) // Find param end (either '/' or path end)
end := 0 end := 0
for end < len(path) && path[end] != '/' { for end < len(path) && path[end] != '/' {
@ -503,18 +495,6 @@ func (n *node) getValue(path string, params *Params, unescape bool) (value nodeV
if len(n.children) > 0 { if len(n.children) > 0 {
path = path[end:] path = path[end:]
n = n.children[0] n = n.children[0]
// next node,the latestNode needs to be equal to currentNode and handle next router
latestNode = n
// not found router in (level 1 router and handle next node),skippedPath cannot execute
// example:
// * /:cc/cc
// call /a/cc expectations:match/200 Actual:match/200
// call /a/dd expectations:unmatch/404 Actual: panic
// call /addr/dd/aa expectations:unmatch/404 Actual: panic
// skippedPath: It can only be executed if the secondary route is not found
// matchNum: Go to the next level of routing tree node search,need add matchNum
skippedPath = ""
matchNum++
continue walk continue walk
} }
@ -567,8 +547,9 @@ func (n *node) getValue(path string, params *Params, unescape bool) (value nodeV
} }
if path == prefix { if path == prefix {
// level 2 router not found and latestNode.wildChild is true // If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
if matchNum < 1 && latestNode.wildChild { // the current node needs to be equal to the latest matching node
if latestNode.wildChild && n.handlers == nil && path != "/" {
n = latestNode.children[len(latestNode.children)-1] n = latestNode.children[len(latestNode.children)-1]
} }
// We should have reached the node containing the handle. // We should have reached the node containing the handle.
@ -600,10 +581,17 @@ func (n *node) getValue(path string, params *Params, unescape bool) (value nodeV
return return
} }
// path != "/" && skippedPath != "" if path != "/" && len(skippedPath) > 0 && strings.HasSuffix(skippedPath, path) {
if len(path) != 1 && len(skippedPath) > 0 && strings.HasSuffix(skippedPath, path) {
path = skippedPath path = skippedPath
n = latestNode // Reduce the number of cycles
n, latestNode = latestNode, n
// skippedPath cannot execute
// example:
// * /:cc/cc
// call /a/cc expectations:match/200 Actual:match/200
// call /a/dd expectations:unmatch/404 Actual: panic
// call /addr/dd/aa expectations:unmatch/404 Actual: panic
// skippedPath: It can only be executed if the secondary route is not found
skippedPath = "" skippedPath = ""
continue walk continue walk
} }

View file

@ -5,4 +5,4 @@
package gin package gin
// Version is the current gin framework's version. // Version is the current gin framework's version.
const Version = "v1.7.2" const Version = "v1.7.3"

View file

@ -1,6 +0,0 @@
module github.com/go-errors/errors
go 1.14
// Was not API-compatible with earlier or later releases.
retract v1.3.0

View file

@ -1,5 +0,0 @@
module github.com/go-fed/httpsig
require golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
go 1.13

View file

@ -1,8 +0,0 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View file

@ -1,5 +1,5 @@
## locales ## locales
<img align="right" src="https://raw.githubusercontent.com/go-playground/locales/master/logo.png">![Project status](https://img.shields.io/badge/version-0.13.0-green.svg) <img align="right" src="https://raw.githubusercontent.com/go-playground/locales/master/logo.png">![Project status](https://img.shields.io/badge/version-0.14.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales) [![Build Status](https://travis-ci.org/go-playground/locales.svg?branch=master)](https://travis-ci.org/go-playground/locales)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/locales)](https://goreportcard.com/report/github.com/go-playground/locales)
[![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales) [![GoDoc](https://godoc.org/github.com/go-playground/locales?status.svg)](https://godoc.org/github.com/go-playground/locales)
@ -11,7 +11,7 @@ an i18n package; these were built for use with, but not exclusive to, [Universal
Features Features
-------- --------
- [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v31.0.1 - [x] Rules generated from the latest [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1
- [x] Contains Cardinal, Ordinal and Range Plural Rules - [x] Contains Cardinal, Ordinal and Range Plural Rules
- [x] Contains Month, Weekday and Timezone translations built in - [x] Contains Month, Weekday and Timezone translations built in
- [x] Contains Date & Time formatting functions - [x] Contains Date & Time formatting functions

View file

@ -176,6 +176,7 @@
MNT MNT
MOP MOP
MRO MRO
MRU
MTL MTL
MTP MTP
MUR MUR
@ -262,9 +263,11 @@
UYI UYI
UYP UYP
UYU UYU
UYW
UZS UZS
VEB VEB
VEF VEF
VES
VND VND
VNN VNN
VUV VUV

View file

@ -1,5 +0,0 @@
module github.com/go-playground/locales
go 1.13
require golang.org/x/text v0.3.2

View file

@ -1,3 +0,0 @@
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View file

@ -0,0 +1,18 @@
GOCMD=GO111MODULE=on go
linters-install:
@golangci-lint --version >/dev/null 2>&1 || { \
echo "installing linting tools..."; \
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \
}
lint: linters-install
golangci-lint run
test:
$(GOCMD) test -cover -race ./...
bench:
$(GOCMD) test -bench=. -benchmem ./...
.PHONY: test lint linters-install

View file

@ -1,5 +1,5 @@
## universal-translator ## universal-translator
<img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">![Project status](https://img.shields.io/badge/version-0.17.0-green.svg) <img align="right" src="https://raw.githubusercontent.com/go-playground/universal-translator/master/logo.png">![Project status](https://img.shields.io/badge/version-0.18.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator) [![Build Status](https://travis-ci.org/go-playground/universal-translator.svg?branch=master)](https://travis-ci.org/go-playground/universal-translator)
[![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator) [![Coverage Status](https://coveralls.io/repos/github/go-playground/universal-translator/badge.svg)](https://coveralls.io/github/go-playground/universal-translator)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/universal-translator)](https://goreportcard.com/report/github.com/go-playground/universal-translator)
@ -18,7 +18,7 @@ use in your applications.
Features Features
-------- --------
- [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v30.0.3 - [x] Rules generated from the [CLDR](http://cldr.unicode.org/index/downloads) data, v36.0.1
- [x] Contains Cardinal, Ordinal and Range Plural Rules - [x] Contains Cardinal, Ordinal and Range Plural Rules
- [x] Contains Month, Weekday and Timezone translations built in - [x] Contains Month, Weekday and Timezone translations built in
- [x] Contains Date & Time formatting functions - [x] Contains Date & Time formatting functions
@ -51,7 +51,7 @@ Please see https://godoc.org/github.com/go-playground/universal-translator for u
File formatting File formatting
-------------- --------------
All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained withing the same file(s); All types, Plain substitution, Cardinal, Ordinal and Range translations can all be contained within the same file(s);
they are only separated for easy viewing. they are only separated for easy viewing.
##### Examples: ##### Examples:

View file

@ -1,5 +0,0 @@
module github.com/go-playground/universal-translator
go 1.13
require github.com/go-playground/locales v0.13.0

View file

@ -1,4 +0,0 @@
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View file

@ -257,6 +257,8 @@ func (t *UniversalTranslator) ImportByReader(format ImportExportFormat, reader i
func stringToPR(s string) locales.PluralRule { func stringToPR(s string) locales.PluralRule {
switch s { switch s {
case "Zero":
return locales.PluralRuleZero
case "One": case "One":
return locales.PluralRuleOne return locales.PluralRuleOne
case "Two": case "Two":

View file

@ -159,13 +159,13 @@ func (t *translator) AddCardinal(key interface{}, text string, rule locales.Plur
} }
} else { } else {
tarr = make([]*transText, 7, 7) tarr = make([]*transText, 7)
t.cardinalTanslations[key] = tarr t.cardinalTanslations[key] = tarr
} }
trans := &transText{ trans := &transText{
text: text, text: text,
indexes: make([]int, 2, 2), indexes: make([]int, 2),
} }
tarr[rule] = trans tarr[rule] = trans
@ -211,13 +211,13 @@ func (t *translator) AddOrdinal(key interface{}, text string, rule locales.Plura
} }
} else { } else {
tarr = make([]*transText, 7, 7) tarr = make([]*transText, 7)
t.ordinalTanslations[key] = tarr t.ordinalTanslations[key] = tarr
} }
trans := &transText{ trans := &transText{
text: text, text: text,
indexes: make([]int, 2, 2), indexes: make([]int, 2),
} }
tarr[rule] = trans tarr[rule] = trans
@ -261,13 +261,13 @@ func (t *translator) AddRange(key interface{}, text string, rule locales.PluralR
} }
} else { } else {
tarr = make([]*transText, 7, 7) tarr = make([]*transText, 7)
t.rangeTanslations[key] = tarr t.rangeTanslations[key] = tarr
} }
trans := &transText{ trans := &transText{
text: text, text: text,
indexes: make([]int, 4, 4), indexes: make([]int, 4),
} }
tarr[rule] = trans tarr[rule] = trans

View file

@ -3,7 +3,7 @@ GOCMD=GO111MODULE=on go
linters-install: linters-install:
@golangci-lint --version >/dev/null 2>&1 || { \ @golangci-lint --version >/dev/null 2>&1 || { \
echo "installing linting tools..."; \ echo "installing linting tools..."; \
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.39.0; \ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v1.41.1; \
} }
lint: linters-install lint: linters-install

View file

@ -1,7 +1,7 @@
Package validator Package validator
================= =================
<img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Project status](https://img.shields.io/badge/version-10.7.0-green.svg) ![Project status](https://img.shields.io/badge/version-10.9.0-green.svg)
[![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator) [![Build Status](https://travis-ci.org/go-playground/validator.svg?branch=master)](https://travis-ci.org/go-playground/validator)
[![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=master&service=github)](https://coveralls.io/github/go-playground/validator?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator)
@ -27,11 +27,11 @@ Installation
Use go get. Use go get.
go get github.com/go-playground/validator go get github.com/go-playground/validator/v10
Then import the validator package into your own code. Then import the validator package into your own code.
import "github.com/go-playground/validator" import "github.com/go-playground/validator/v10"
Error Return Value Error Return Value
------- -------
@ -126,15 +126,21 @@ Baked-in Validations
| alphanumunicode | Alphanumeric Unicode | | alphanumunicode | Alphanumeric Unicode |
| alphaunicode | Alpha Unicode | | alphaunicode | Alpha Unicode |
| ascii | ASCII | | ascii | ASCII |
| boolean | Boolean |
| contains | Contains | | contains | Contains |
| containsany | Contains Any | | containsany | Contains Any |
| containsrune | Contains Rune | | containsrune | Contains Rune |
| endsnotwith | Ends With |
| endswith | Ends With | | endswith | Ends With |
| excludes | Excludes |
| excludesall | Excludes All |
| excludesrune | Excludes Rune |
| lowercase | Lowercase | | lowercase | Lowercase |
| multibyte | Multi-Byte Characters | | multibyte | Multi-Byte Characters |
| number | NOT DOCUMENTED IN doc.go | | number | NOT DOCUMENTED IN doc.go |
| numeric | Numeric | | numeric | Numeric |
| printascii | Printable ASCII | | printascii | Printable ASCII |
| startsnotwith | Starts Not With |
| startswith | Starts With | | startswith | Starts With |
| uppercase | Uppercase | | uppercase | Uppercase |
@ -143,6 +149,8 @@ Baked-in Validations
| - | - | | - | - |
| base64 | Base64 String | | base64 | Base64 String |
| base64url | Base64URL String | | base64url | Base64URL String |
| bic | Business Identifier Code (ISO 9362) |
| bcp47_language_tag | Language tag (BCP 47) |
| btc_addr | Bitcoin Address | | btc_addr | Bitcoin Address |
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
| datetime | Datetime | | datetime | Datetime |
@ -158,12 +166,21 @@ Baked-in Validations
| isbn | International Standard Book Number | | isbn | International Standard Book Number |
| isbn10 | International Standard Book Number 10 | | isbn10 | International Standard Book Number 10 |
| isbn13 | International Standard Book Number 13 | | isbn13 | International Standard Book Number 13 |
| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) |
| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) |
| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) |
| iso3166_2 | Country subdivision code (ISO 3166-2) |
| iso4217 | Currency code (ISO 4217) |
| json | JSON | | json | JSON |
| jwt | JSON Web Token (JWT) |
| latitude | Latitude | | latitude | Latitude |
| longitude | Longitude | | longitude | Longitude |
| postcode_iso3166_alpha2 | Postcode |
| postcode_iso3166_alpha2_field | Postcode |
| rgb | RGB String | | rgb | RGB String |
| rgba | RGBA String | | rgba | RGBA String |
| ssn | Social Security Number SSN | | ssn | Social Security Number SSN |
| timezone | Timezone |
| uuid | Universally Unique Identifier UUID | | uuid | Universally Unique Identifier UUID |
| uuid3 | Universally Unique Identifier UUID v3 | | uuid3 | Universally Unique Identifier UUID v3 |
| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 | | uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 |
@ -187,10 +204,6 @@ Baked-in Validations
| Tag | Description | | Tag | Description |
| - | - | | - | - |
| dir | Directory | | dir | Directory |
| endswith | Ends With |
| excludes | Excludes |
| excludesall | Excludes All |
| excludesrune | Excludes Rune |
| file | File path | | file | File path |
| isdefault | Is Default | | isdefault | Is Default |
| len | Length | | len | Length |
@ -210,6 +223,12 @@ Baked-in Validations
| excluded_without_all | Excluded Without All | | excluded_without_all | Excluded Without All |
| unique | Unique | | unique | Unique |
#### Aliases:
| Tag | Description |
| - | - |
| iscolor | hexcolor\|rgb\|rgba\|hsl\|hsla |
| country_code | iso3166_1_alpha2\|iso3166_1_alpha3\|iso3166_1_alpha_numeric |
Benchmarks Benchmarks
------ ------
###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64 ###### Run on MacBook Pro (15-inch, 2017) go version go1.10.2 darwin/amd64

View file

@ -56,7 +56,7 @@ func wrapFunc(fn Func) FuncCtx {
isdefault: {}, isdefault: {},
} }
// BakedInAliasValidators is a default mapping of a single validation tag that // bakedInAliases is a default mapping of a single validation tag that
// defines a common or complex set of validation(s) to simplify // defines a common or complex set of validation(s) to simplify
// adding validation to structs. // adding validation to structs.
bakedInAliases = map[string]string{ bakedInAliases = map[string]string{
@ -64,7 +64,7 @@ func wrapFunc(fn Func) FuncCtx {
"country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric", "country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric",
} }
// BakedInValidators is the default map of ValidationFunc // bakedInValidators is the default map of ValidationFunc
// you can add, remove or even replace items to suite your needs, // you can add, remove or even replace items to suite your needs,
// or even disregard and use your own map if so desired. // or even disregard and use your own map if so desired.
bakedInValidators = map[string]Func{ bakedInValidators = map[string]Func{
@ -107,6 +107,7 @@ func wrapFunc(fn Func) FuncCtx {
"alphanum": isAlphanum, "alphanum": isAlphanum,
"alphaunicode": isAlphaUnicode, "alphaunicode": isAlphaUnicode,
"alphanumunicode": isAlphanumUnicode, "alphanumunicode": isAlphanumUnicode,
"boolean": isBoolean,
"numeric": isNumeric, "numeric": isNumeric,
"number": isNumber, "number": isNumber,
"hexadecimal": isHexadecimal, "hexadecimal": isHexadecimal,
@ -181,6 +182,7 @@ func wrapFunc(fn Func) FuncCtx {
"url_encoded": isURLEncoded, "url_encoded": isURLEncoded,
"dir": isDir, "dir": isDir,
"json": isJSON, "json": isJSON,
"jwt": isJWT,
"hostname_port": isHostnamePort, "hostname_port": isHostnamePort,
"lowercase": isLowercase, "lowercase": isLowercase,
"uppercase": isUppercase, "uppercase": isUppercase,
@ -190,6 +192,8 @@ func wrapFunc(fn Func) FuncCtx {
"iso3166_1_alpha3": isIso3166Alpha3, "iso3166_1_alpha3": isIso3166Alpha3,
"iso3166_1_alpha_numeric": isIso3166AlphaNumeric, "iso3166_1_alpha_numeric": isIso3166AlphaNumeric,
"iso3166_2": isIso31662, "iso3166_2": isIso31662,
"iso4217": isIso4217,
"iso4217_numeric": isIso4217Numeric,
"bcp47_language_tag": isBCP47LanguageTag, "bcp47_language_tag": isBCP47LanguageTag,
"postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2, "postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2,
"postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field, "postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field,
@ -302,7 +306,7 @@ func isUnique(fl FieldLevel) bool {
} }
} }
// IsMAC is the validation function for validating if the field's value is a valid MAC address. // isMAC is the validation function for validating if the field's value is a valid MAC address.
func isMAC(fl FieldLevel) bool { func isMAC(fl FieldLevel) bool {
_, err := net.ParseMAC(fl.Field().String()) _, err := net.ParseMAC(fl.Field().String())
@ -310,7 +314,7 @@ func isMAC(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address. // isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
func isCIDRv4(fl FieldLevel) bool { func isCIDRv4(fl FieldLevel) bool {
ip, _, err := net.ParseCIDR(fl.Field().String()) ip, _, err := net.ParseCIDR(fl.Field().String())
@ -318,7 +322,7 @@ func isCIDRv4(fl FieldLevel) bool {
return err == nil && ip.To4() != nil return err == nil && ip.To4() != nil
} }
// IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address. // isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
func isCIDRv6(fl FieldLevel) bool { func isCIDRv6(fl FieldLevel) bool {
ip, _, err := net.ParseCIDR(fl.Field().String()) ip, _, err := net.ParseCIDR(fl.Field().String())
@ -326,7 +330,7 @@ func isCIDRv6(fl FieldLevel) bool {
return err == nil && ip.To4() == nil return err == nil && ip.To4() == nil
} }
// IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address. // isCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
func isCIDR(fl FieldLevel) bool { func isCIDR(fl FieldLevel) bool {
_, _, err := net.ParseCIDR(fl.Field().String()) _, _, err := net.ParseCIDR(fl.Field().String())
@ -334,7 +338,7 @@ func isCIDR(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsIPv4 is the validation function for validating if a value is a valid v4 IP address. // isIPv4 is the validation function for validating if a value is a valid v4 IP address.
func isIPv4(fl FieldLevel) bool { func isIPv4(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String()) ip := net.ParseIP(fl.Field().String())
@ -342,7 +346,7 @@ func isIPv4(fl FieldLevel) bool {
return ip != nil && ip.To4() != nil return ip != nil && ip.To4() != nil
} }
// IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address. // isIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
func isIPv6(fl FieldLevel) bool { func isIPv6(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String()) ip := net.ParseIP(fl.Field().String())
@ -350,7 +354,7 @@ func isIPv6(fl FieldLevel) bool {
return ip != nil && ip.To4() == nil return ip != nil && ip.To4() == nil
} }
// IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address. // isIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
func isIP(fl FieldLevel) bool { func isIP(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String()) ip := net.ParseIP(fl.Field().String())
@ -358,7 +362,7 @@ func isIP(fl FieldLevel) bool {
return ip != nil return ip != nil
} }
// IsSSN is the validation function for validating if the field's value is a valid SSN. // isSSN is the validation function for validating if the field's value is a valid SSN.
func isSSN(fl FieldLevel) bool { func isSSN(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -370,7 +374,7 @@ func isSSN(fl FieldLevel) bool {
return sSNRegex.MatchString(field.String()) return sSNRegex.MatchString(field.String())
} }
// IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate. // isLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
func isLongitude(fl FieldLevel) bool { func isLongitude(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -393,7 +397,7 @@ func isLongitude(fl FieldLevel) bool {
return longitudeRegex.MatchString(v) return longitudeRegex.MatchString(v)
} }
// IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate. // isLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
func isLatitude(fl FieldLevel) bool { func isLatitude(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -416,7 +420,7 @@ func isLatitude(fl FieldLevel) bool {
return latitudeRegex.MatchString(v) return latitudeRegex.MatchString(v)
} }
// IsDataURI is the validation function for validating if the field's value is a valid data URI. // isDataURI is the validation function for validating if the field's value is a valid data URI.
func isDataURI(fl FieldLevel) bool { func isDataURI(fl FieldLevel) bool {
uri := strings.SplitN(fl.Field().String(), ",", 2) uri := strings.SplitN(fl.Field().String(), ",", 2)
@ -432,7 +436,7 @@ func isDataURI(fl FieldLevel) bool {
return base64Regex.MatchString(uri[1]) return base64Regex.MatchString(uri[1])
} }
// HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character. // hasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
func hasMultiByteCharacter(fl FieldLevel) bool { func hasMultiByteCharacter(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -444,62 +448,62 @@ func hasMultiByteCharacter(fl FieldLevel) bool {
return multibyteRegex.MatchString(field.String()) return multibyteRegex.MatchString(field.String())
} }
// IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character. // isPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
func isPrintableASCII(fl FieldLevel) bool { func isPrintableASCII(fl FieldLevel) bool {
return printableASCIIRegex.MatchString(fl.Field().String()) return printableASCIIRegex.MatchString(fl.Field().String())
} }
// IsASCII is the validation function for validating if the field's value is a valid ASCII character. // isASCII is the validation function for validating if the field's value is a valid ASCII character.
func isASCII(fl FieldLevel) bool { func isASCII(fl FieldLevel) bool {
return aSCIIRegex.MatchString(fl.Field().String()) return aSCIIRegex.MatchString(fl.Field().String())
} }
// IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID. // isUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
func isUUID5(fl FieldLevel) bool { func isUUID5(fl FieldLevel) bool {
return uUID5Regex.MatchString(fl.Field().String()) return uUID5Regex.MatchString(fl.Field().String())
} }
// IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID. // isUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
func isUUID4(fl FieldLevel) bool { func isUUID4(fl FieldLevel) bool {
return uUID4Regex.MatchString(fl.Field().String()) return uUID4Regex.MatchString(fl.Field().String())
} }
// IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID. // isUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
func isUUID3(fl FieldLevel) bool { func isUUID3(fl FieldLevel) bool {
return uUID3Regex.MatchString(fl.Field().String()) return uUID3Regex.MatchString(fl.Field().String())
} }
// IsUUID is the validation function for validating if the field's value is a valid UUID of any version. // isUUID is the validation function for validating if the field's value is a valid UUID of any version.
func isUUID(fl FieldLevel) bool { func isUUID(fl FieldLevel) bool {
return uUIDRegex.MatchString(fl.Field().String()) return uUIDRegex.MatchString(fl.Field().String())
} }
// IsUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID. // isUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID.
func isUUID5RFC4122(fl FieldLevel) bool { func isUUID5RFC4122(fl FieldLevel) bool {
return uUID5RFC4122Regex.MatchString(fl.Field().String()) return uUID5RFC4122Regex.MatchString(fl.Field().String())
} }
// IsUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID. // isUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID.
func isUUID4RFC4122(fl FieldLevel) bool { func isUUID4RFC4122(fl FieldLevel) bool {
return uUID4RFC4122Regex.MatchString(fl.Field().String()) return uUID4RFC4122Regex.MatchString(fl.Field().String())
} }
// IsUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID. // isUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID.
func isUUID3RFC4122(fl FieldLevel) bool { func isUUID3RFC4122(fl FieldLevel) bool {
return uUID3RFC4122Regex.MatchString(fl.Field().String()) return uUID3RFC4122Regex.MatchString(fl.Field().String())
} }
// IsUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version. // isUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version.
func isUUIDRFC4122(fl FieldLevel) bool { func isUUIDRFC4122(fl FieldLevel) bool {
return uUIDRFC4122Regex.MatchString(fl.Field().String()) return uUIDRFC4122Regex.MatchString(fl.Field().String())
} }
// IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN. // isISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
func isISBN(fl FieldLevel) bool { func isISBN(fl FieldLevel) bool {
return isISBN10(fl) || isISBN13(fl) return isISBN10(fl) || isISBN13(fl)
} }
// IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN. // isISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
func isISBN13(fl FieldLevel) bool { func isISBN13(fl FieldLevel) bool {
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4) s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
@ -520,7 +524,7 @@ func isISBN13(fl FieldLevel) bool {
return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0 return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0
} }
// IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN. // isISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
func isISBN10(fl FieldLevel) bool { func isISBN10(fl FieldLevel) bool {
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3) s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
@ -545,7 +549,7 @@ func isISBN10(fl FieldLevel) bool {
return checksum%11 == 0 return checksum%11 == 0
} }
// IsEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address. // isEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address.
func isEthereumAddress(fl FieldLevel) bool { func isEthereumAddress(fl FieldLevel) bool {
address := fl.Field().String() address := fl.Field().String()
@ -576,7 +580,7 @@ func isEthereumAddress(fl FieldLevel) bool {
return true return true
} }
// IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address // isBitcoinAddress is the validation function for validating if the field's value is a valid btc address
func isBitcoinAddress(fl FieldLevel) bool { func isBitcoinAddress(fl FieldLevel) bool {
address := fl.Field().String() address := fl.Field().String()
@ -613,7 +617,7 @@ func isBitcoinAddress(fl FieldLevel) bool {
return validchecksum == computedchecksum return validchecksum == computedchecksum
} }
// IsBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address // isBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address
func isBitcoinBech32Address(fl FieldLevel) bool { func isBitcoinBech32Address(fl FieldLevel) bool {
address := fl.Field().String() address := fl.Field().String()
@ -693,22 +697,22 @@ func isBitcoinBech32Address(fl FieldLevel) bool {
return true return true
} }
// ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param. // excludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
func excludesRune(fl FieldLevel) bool { func excludesRune(fl FieldLevel) bool {
return !containsRune(fl) return !containsRune(fl)
} }
// ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param. // excludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
func excludesAll(fl FieldLevel) bool { func excludesAll(fl FieldLevel) bool {
return !containsAny(fl) return !containsAny(fl)
} }
// Excludes is the validation function for validating that the field's value does not contain the text specified within the param. // excludes is the validation function for validating that the field's value does not contain the text specified within the param.
func excludes(fl FieldLevel) bool { func excludes(fl FieldLevel) bool {
return !contains(fl) return !contains(fl)
} }
// ContainsRune is the validation function for validating that the field's value contains the rune specified within the param. // containsRune is the validation function for validating that the field's value contains the rune specified within the param.
func containsRune(fl FieldLevel) bool { func containsRune(fl FieldLevel) bool {
r, _ := utf8.DecodeRuneInString(fl.Param()) r, _ := utf8.DecodeRuneInString(fl.Param())
@ -716,37 +720,37 @@ func containsRune(fl FieldLevel) bool {
return strings.ContainsRune(fl.Field().String(), r) return strings.ContainsRune(fl.Field().String(), r)
} }
// ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param. // containsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
func containsAny(fl FieldLevel) bool { func containsAny(fl FieldLevel) bool {
return strings.ContainsAny(fl.Field().String(), fl.Param()) return strings.ContainsAny(fl.Field().String(), fl.Param())
} }
// Contains is the validation function for validating that the field's value contains the text specified within the param. // contains is the validation function for validating that the field's value contains the text specified within the param.
func contains(fl FieldLevel) bool { func contains(fl FieldLevel) bool {
return strings.Contains(fl.Field().String(), fl.Param()) return strings.Contains(fl.Field().String(), fl.Param())
} }
// StartsWith is the validation function for validating that the field's value starts with the text specified within the param. // startsWith is the validation function for validating that the field's value starts with the text specified within the param.
func startsWith(fl FieldLevel) bool { func startsWith(fl FieldLevel) bool {
return strings.HasPrefix(fl.Field().String(), fl.Param()) return strings.HasPrefix(fl.Field().String(), fl.Param())
} }
// EndsWith is the validation function for validating that the field's value ends with the text specified within the param. // endsWith is the validation function for validating that the field's value ends with the text specified within the param.
func endsWith(fl FieldLevel) bool { func endsWith(fl FieldLevel) bool {
return strings.HasSuffix(fl.Field().String(), fl.Param()) return strings.HasSuffix(fl.Field().String(), fl.Param())
} }
// StartsNotWith is the validation function for validating that the field's value does not start with the text specified within the param. // startsNotWith is the validation function for validating that the field's value does not start with the text specified within the param.
func startsNotWith(fl FieldLevel) bool { func startsNotWith(fl FieldLevel) bool {
return !startsWith(fl) return !startsWith(fl)
} }
// EndsNotWith is the validation function for validating that the field's value does not end with the text specified within the param. // endsNotWith is the validation function for validating that the field's value does not end with the text specified within the param.
func endsNotWith(fl FieldLevel) bool { func endsNotWith(fl FieldLevel) bool {
return !endsWith(fl) return !endsWith(fl)
} }
// FieldContains is the validation function for validating if the current field's value contains the field specified by the param's value. // fieldContains is the validation function for validating if the current field's value contains the field specified by the param's value.
func fieldContains(fl FieldLevel) bool { func fieldContains(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -759,7 +763,7 @@ func fieldContains(fl FieldLevel) bool {
return strings.Contains(field.String(), currentField.String()) return strings.Contains(field.String(), currentField.String())
} }
// FieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value. // fieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value.
func fieldExcludes(fl FieldLevel) bool { func fieldExcludes(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -771,7 +775,7 @@ func fieldExcludes(fl FieldLevel) bool {
return !strings.Contains(field.String(), currentField.String()) return !strings.Contains(field.String(), currentField.String())
} }
// IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value. // isNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
func isNeField(fl FieldLevel) bool { func isNeField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -823,12 +827,12 @@ func isNeField(fl FieldLevel) bool {
return field.String() != currentField.String() return field.String() != currentField.String()
} }
// IsNe is the validation function for validating that the field's value does not equal the provided param value. // isNe is the validation function for validating that the field's value does not equal the provided param value.
func isNe(fl FieldLevel) bool { func isNe(fl FieldLevel) bool {
return !isEq(fl) return !isEq(fl)
} }
// IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value. // isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
func isLteCrossStructField(fl FieldLevel) bool { func isLteCrossStructField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -875,7 +879,7 @@ func isLteCrossStructField(fl FieldLevel) bool {
return field.String() <= topField.String() return field.String() <= topField.String()
} }
// IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value. // isLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. // NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
func isLtCrossStructField(fl FieldLevel) bool { func isLtCrossStructField(fl FieldLevel) bool {
@ -923,7 +927,7 @@ func isLtCrossStructField(fl FieldLevel) bool {
return field.String() < topField.String() return field.String() < topField.String()
} }
// IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value. // isGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
func isGteCrossStructField(fl FieldLevel) bool { func isGteCrossStructField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -970,7 +974,7 @@ func isGteCrossStructField(fl FieldLevel) bool {
return field.String() >= topField.String() return field.String() >= topField.String()
} }
// IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value. // isGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
func isGtCrossStructField(fl FieldLevel) bool { func isGtCrossStructField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1017,7 +1021,7 @@ func isGtCrossStructField(fl FieldLevel) bool {
return field.String() > topField.String() return field.String() > topField.String()
} }
// IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value. // isNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
func isNeCrossStructField(fl FieldLevel) bool { func isNeCrossStructField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1067,7 +1071,7 @@ func isNeCrossStructField(fl FieldLevel) bool {
return topField.String() != field.String() return topField.String() != field.String()
} }
// IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value. // isEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
func isEqCrossStructField(fl FieldLevel) bool { func isEqCrossStructField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1117,7 +1121,7 @@ func isEqCrossStructField(fl FieldLevel) bool {
return topField.String() == field.String() return topField.String() == field.String()
} }
// IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value. // isEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
func isEqField(fl FieldLevel) bool { func isEqField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1168,7 +1172,7 @@ func isEqField(fl FieldLevel) bool {
return field.String() == currentField.String() return field.String() == currentField.String()
} }
// IsEq is the validation function for validating if the current field's value is equal to the param's value. // isEq is the validation function for validating if the current field's value is equal to the param's value.
func isEq(fl FieldLevel) bool { func isEq(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1249,17 +1253,17 @@ func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
return reg.MatchString(field.String()) return reg.MatchString(field.String())
} }
// IsBase64 is the validation function for validating if the current field's value is a valid base 64. // isBase64 is the validation function for validating if the current field's value is a valid base 64.
func isBase64(fl FieldLevel) bool { func isBase64(fl FieldLevel) bool {
return base64Regex.MatchString(fl.Field().String()) return base64Regex.MatchString(fl.Field().String())
} }
// IsBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string. // isBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string.
func isBase64URL(fl FieldLevel) bool { func isBase64URL(fl FieldLevel) bool {
return base64URLRegex.MatchString(fl.Field().String()) return base64URLRegex.MatchString(fl.Field().String())
} }
// IsURI is the validation function for validating if the current field's value is a valid URI. // isURI is the validation function for validating if the current field's value is a valid URI.
func isURI(fl FieldLevel) bool { func isURI(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1288,7 +1292,7 @@ func isURI(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// IsURL is the validation function for validating if the current field's value is a valid URL. // isURL is the validation function for validating if the current field's value is a valid URL.
func isURL(fl FieldLevel) bool { func isURL(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1340,7 +1344,7 @@ func isUrnRFC2141(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// IsFile is the validation function for validating if the current field's value is a valid file path. // isFile is the validation function for validating if the current field's value is a valid file path.
func isFile(fl FieldLevel) bool { func isFile(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1357,47 +1361,47 @@ func isFile(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// IsE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number. // isE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number.
func isE164(fl FieldLevel) bool { func isE164(fl FieldLevel) bool {
return e164Regex.MatchString(fl.Field().String()) return e164Regex.MatchString(fl.Field().String())
} }
// IsEmail is the validation function for validating if the current field's value is a valid email address. // isEmail is the validation function for validating if the current field's value is a valid email address.
func isEmail(fl FieldLevel) bool { func isEmail(fl FieldLevel) bool {
return emailRegex.MatchString(fl.Field().String()) return emailRegex.MatchString(fl.Field().String())
} }
// IsHSLA is the validation function for validating if the current field's value is a valid HSLA color. // isHSLA is the validation function for validating if the current field's value is a valid HSLA color.
func isHSLA(fl FieldLevel) bool { func isHSLA(fl FieldLevel) bool {
return hslaRegex.MatchString(fl.Field().String()) return hslaRegex.MatchString(fl.Field().String())
} }
// IsHSL is the validation function for validating if the current field's value is a valid HSL color. // isHSL is the validation function for validating if the current field's value is a valid HSL color.
func isHSL(fl FieldLevel) bool { func isHSL(fl FieldLevel) bool {
return hslRegex.MatchString(fl.Field().String()) return hslRegex.MatchString(fl.Field().String())
} }
// IsRGBA is the validation function for validating if the current field's value is a valid RGBA color. // isRGBA is the validation function for validating if the current field's value is a valid RGBA color.
func isRGBA(fl FieldLevel) bool { func isRGBA(fl FieldLevel) bool {
return rgbaRegex.MatchString(fl.Field().String()) return rgbaRegex.MatchString(fl.Field().String())
} }
// IsRGB is the validation function for validating if the current field's value is a valid RGB color. // isRGB is the validation function for validating if the current field's value is a valid RGB color.
func isRGB(fl FieldLevel) bool { func isRGB(fl FieldLevel) bool {
return rgbRegex.MatchString(fl.Field().String()) return rgbRegex.MatchString(fl.Field().String())
} }
// IsHEXColor is the validation function for validating if the current field's value is a valid HEX color. // isHEXColor is the validation function for validating if the current field's value is a valid HEX color.
func isHEXColor(fl FieldLevel) bool { func isHEXColor(fl FieldLevel) bool {
return hexColorRegex.MatchString(fl.Field().String()) return hexColorRegex.MatchString(fl.Field().String())
} }
// IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal. // isHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
func isHexadecimal(fl FieldLevel) bool { func isHexadecimal(fl FieldLevel) bool {
return hexadecimalRegex.MatchString(fl.Field().String()) return hexadecimalRegex.MatchString(fl.Field().String())
} }
// IsNumber is the validation function for validating if the current field's value is a valid number. // isNumber is the validation function for validating if the current field's value is a valid number.
func isNumber(fl FieldLevel) bool { func isNumber(fl FieldLevel) bool {
switch fl.Field().Kind() { switch fl.Field().Kind() {
case 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: case 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:
@ -1407,7 +1411,7 @@ func isNumber(fl FieldLevel) bool {
} }
} }
// IsNumeric is the validation function for validating if the current field's value is a valid numeric value. // isNumeric is the validation function for validating if the current field's value is a valid numeric value.
func isNumeric(fl FieldLevel) bool { func isNumeric(fl FieldLevel) bool {
switch fl.Field().Kind() { switch fl.Field().Kind() {
case 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: case 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:
@ -1417,32 +1421,38 @@ func isNumeric(fl FieldLevel) bool {
} }
} }
// IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value. // isAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
func isAlphanum(fl FieldLevel) bool { func isAlphanum(fl FieldLevel) bool {
return alphaNumericRegex.MatchString(fl.Field().String()) return alphaNumericRegex.MatchString(fl.Field().String())
} }
// IsAlpha is the validation function for validating if the current field's value is a valid alpha value. // isAlpha is the validation function for validating if the current field's value is a valid alpha value.
func isAlpha(fl FieldLevel) bool { func isAlpha(fl FieldLevel) bool {
return alphaRegex.MatchString(fl.Field().String()) return alphaRegex.MatchString(fl.Field().String())
} }
// IsAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value. // isAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
func isAlphanumUnicode(fl FieldLevel) bool { func isAlphanumUnicode(fl FieldLevel) bool {
return alphaUnicodeNumericRegex.MatchString(fl.Field().String()) return alphaUnicodeNumericRegex.MatchString(fl.Field().String())
} }
// IsAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value. // isAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
func isAlphaUnicode(fl FieldLevel) bool { func isAlphaUnicode(fl FieldLevel) bool {
return alphaUnicodeRegex.MatchString(fl.Field().String()) return alphaUnicodeRegex.MatchString(fl.Field().String())
} }
// isBoolean is the validation function for validating if the current field's value can be safely converted to a boolean.
func isBoolean(fl FieldLevel) bool {
_, err := strconv.ParseBool(fl.Field().String())
return err == nil
}
// isDefault is the opposite of required aka hasValue // isDefault is the opposite of required aka hasValue
func isDefault(fl FieldLevel) bool { func isDefault(fl FieldLevel) bool {
return !hasValue(fl) return !hasValue(fl)
} }
// HasValue is the validation function for validating if the current field's value is not the default static value. // hasValue is the validation function for validating if the current field's value is not the default static value.
func hasValue(fl FieldLevel) bool { func hasValue(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
switch field.Kind() { switch field.Kind() {
@ -1540,7 +1550,7 @@ func requiredUnless(fl FieldLevel) bool {
return hasValue(fl) return hasValue(fl)
} }
// ExcludedWith is the validation function // excludedWith is the validation function
// The field under validation must not be present or is empty if any of the other specified fields are present. // The field under validation must not be present or is empty if any of the other specified fields are present.
func excludedWith(fl FieldLevel) bool { func excludedWith(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
@ -1552,7 +1562,7 @@ func excludedWith(fl FieldLevel) bool {
return true return true
} }
// RequiredWith is the validation function // requiredWith is the validation function
// The field under validation must be present and not empty only if any of the other specified fields are present. // The field under validation must be present and not empty only if any of the other specified fields are present.
func requiredWith(fl FieldLevel) bool { func requiredWith(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
@ -1564,7 +1574,7 @@ func requiredWith(fl FieldLevel) bool {
return true return true
} }
// ExcludedWithAll is the validation function // excludedWithAll is the validation function
// The field under validation must not be present or is empty if all of the other specified fields are present. // The field under validation must not be present or is empty if all of the other specified fields are present.
func excludedWithAll(fl FieldLevel) bool { func excludedWithAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
@ -1576,7 +1586,7 @@ func excludedWithAll(fl FieldLevel) bool {
return !hasValue(fl) return !hasValue(fl)
} }
// RequiredWithAll is the validation function // requiredWithAll is the validation function
// The field under validation must be present and not empty only if all of the other specified fields are present. // The field under validation must be present and not empty only if all of the other specified fields are present.
func requiredWithAll(fl FieldLevel) bool { func requiredWithAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
@ -1588,7 +1598,7 @@ func requiredWithAll(fl FieldLevel) bool {
return hasValue(fl) return hasValue(fl)
} }
// ExcludedWithout is the validation function // excludedWithout is the validation function
// The field under validation must not be present or is empty when any of the other specified fields are not present. // The field under validation must not be present or is empty when any of the other specified fields are not present.
func excludedWithout(fl FieldLevel) bool { func excludedWithout(fl FieldLevel) bool {
if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
@ -1597,7 +1607,7 @@ func excludedWithout(fl FieldLevel) bool {
return true return true
} }
// RequiredWithout is the validation function // requiredWithout is the validation function
// The field under validation must be present and not empty only when any of the other specified fields are not present. // The field under validation must be present and not empty only when any of the other specified fields are not present.
func requiredWithout(fl FieldLevel) bool { func requiredWithout(fl FieldLevel) bool {
if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) { if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
@ -1606,7 +1616,7 @@ func requiredWithout(fl FieldLevel) bool {
return true return true
} }
// ExcludedWithoutAll is the validation function // excludedWithoutAll is the validation function
// The field under validation must not be present or is empty when all of the other specified fields are not present. // The field under validation must not be present or is empty when all of the other specified fields are not present.
func excludedWithoutAll(fl FieldLevel) bool { func excludedWithoutAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
@ -1618,7 +1628,7 @@ func excludedWithoutAll(fl FieldLevel) bool {
return !hasValue(fl) return !hasValue(fl)
} }
// RequiredWithoutAll is the validation function // requiredWithoutAll is the validation function
// The field under validation must be present and not empty only when all of the other specified fields are not present. // The field under validation must be present and not empty only when all of the other specified fields are not present.
func requiredWithoutAll(fl FieldLevel) bool { func requiredWithoutAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param()) params := parseOneOfParam2(fl.Param())
@ -1630,7 +1640,7 @@ func requiredWithoutAll(fl FieldLevel) bool {
return hasValue(fl) return hasValue(fl)
} }
// IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value. // isGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
func isGteField(fl FieldLevel) bool { func isGteField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1677,7 +1687,7 @@ func isGteField(fl FieldLevel) bool {
return len(field.String()) >= len(currentField.String()) return len(field.String()) >= len(currentField.String())
} }
// IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value. // isGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
func isGtField(fl FieldLevel) bool { func isGtField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1724,7 +1734,7 @@ func isGtField(fl FieldLevel) bool {
return len(field.String()) > len(currentField.String()) return len(field.String()) > len(currentField.String())
} }
// IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value. // isGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
func isGte(fl FieldLevel) bool { func isGte(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1771,7 +1781,7 @@ func isGte(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// IsGt is the validation function for validating if the current field's value is greater than the param's value. // isGt is the validation function for validating if the current field's value is greater than the param's value.
func isGt(fl FieldLevel) bool { func isGt(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1814,7 +1824,7 @@ func isGt(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// HasLengthOf is the validation function for validating if the current field's value is equal to the param's value. // hasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
func hasLengthOf(fl FieldLevel) bool { func hasLengthOf(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1851,12 +1861,12 @@ func hasLengthOf(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value. // hasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
func hasMinOf(fl FieldLevel) bool { func hasMinOf(fl FieldLevel) bool {
return isGte(fl) return isGte(fl)
} }
// IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value. // isLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
func isLteField(fl FieldLevel) bool { func isLteField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1903,7 +1913,7 @@ func isLteField(fl FieldLevel) bool {
return len(field.String()) <= len(currentField.String()) return len(field.String()) <= len(currentField.String())
} }
// IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value. // isLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
func isLtField(fl FieldLevel) bool { func isLtField(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1950,7 +1960,7 @@ func isLtField(fl FieldLevel) bool {
return len(field.String()) < len(currentField.String()) return len(field.String()) < len(currentField.String())
} }
// IsLte is the validation function for validating if the current field's value is less than or equal to the param's value. // isLte is the validation function for validating if the current field's value is less than or equal to the param's value.
func isLte(fl FieldLevel) bool { func isLte(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -1997,7 +2007,7 @@ func isLte(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// IsLt is the validation function for validating if the current field's value is less than the param's value. // isLt is the validation function for validating if the current field's value is less than the param's value.
func isLt(fl FieldLevel) bool { func isLt(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -2041,12 +2051,12 @@ func isLt(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value. // hasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
func hasMaxOf(fl FieldLevel) bool { func hasMaxOf(fl FieldLevel) bool {
return isLte(fl) return isLte(fl)
} }
// IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. // isTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
func isTCP4AddrResolvable(fl FieldLevel) bool { func isTCP4AddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) { if !isIP4Addr(fl) {
@ -2057,7 +2067,7 @@ func isTCP4AddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. // isTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
func isTCP6AddrResolvable(fl FieldLevel) bool { func isTCP6AddrResolvable(fl FieldLevel) bool {
if !isIP6Addr(fl) { if !isIP6Addr(fl) {
@ -2069,7 +2079,7 @@ func isTCP6AddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. // isTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
func isTCPAddrResolvable(fl FieldLevel) bool { func isTCPAddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) && !isIP6Addr(fl) { if !isIP4Addr(fl) && !isIP6Addr(fl) {
@ -2081,7 +2091,7 @@ func isTCPAddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. // isUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
func isUDP4AddrResolvable(fl FieldLevel) bool { func isUDP4AddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) { if !isIP4Addr(fl) {
@ -2093,7 +2103,7 @@ func isUDP4AddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. // isUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
func isUDP6AddrResolvable(fl FieldLevel) bool { func isUDP6AddrResolvable(fl FieldLevel) bool {
if !isIP6Addr(fl) { if !isIP6Addr(fl) {
@ -2105,7 +2115,7 @@ func isUDP6AddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. // isUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
func isUDPAddrResolvable(fl FieldLevel) bool { func isUDPAddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) && !isIP6Addr(fl) { if !isIP4Addr(fl) && !isIP6Addr(fl) {
@ -2117,7 +2127,7 @@ func isUDPAddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. // isIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
func isIP4AddrResolvable(fl FieldLevel) bool { func isIP4AddrResolvable(fl FieldLevel) bool {
if !isIPv4(fl) { if !isIPv4(fl) {
@ -2129,7 +2139,7 @@ func isIP4AddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. // isIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
func isIP6AddrResolvable(fl FieldLevel) bool { func isIP6AddrResolvable(fl FieldLevel) bool {
if !isIPv6(fl) { if !isIPv6(fl) {
@ -2141,7 +2151,7 @@ func isIP6AddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. // isIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
func isIPAddrResolvable(fl FieldLevel) bool { func isIPAddrResolvable(fl FieldLevel) bool {
if !isIP(fl) { if !isIP(fl) {
@ -2153,7 +2163,7 @@ func isIPAddrResolvable(fl FieldLevel) bool {
return err == nil return err == nil
} }
// IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. // isUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
func isUnixAddrResolvable(fl FieldLevel) bool { func isUnixAddrResolvable(fl FieldLevel) bool {
_, err := net.ResolveUnixAddr("unix", fl.Field().String()) _, err := net.ResolveUnixAddr("unix", fl.Field().String())
@ -2207,7 +2217,7 @@ func isFQDN(fl FieldLevel) bool {
return fqdnRegexRFC1123.MatchString(val) return fqdnRegexRFC1123.MatchString(val)
} }
// IsDir is the validation function for validating if the current field's value is a valid directory. // isDir is the validation function for validating if the current field's value is a valid directory.
func isDir(fl FieldLevel) bool { func isDir(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()
@ -2235,6 +2245,11 @@ func isJSON(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// isJWT is the validation function for validating if the current field's value is a valid JWT string.
func isJWT(fl FieldLevel) bool {
return jWTRegex.MatchString(fl.Field().String())
}
// isHostnamePort validates a <dns>:<port> combination for fields typically used for socket address. // isHostnamePort validates a <dns>:<port> combination for fields typically used for socket address.
func isHostnamePort(fl FieldLevel) bool { func isHostnamePort(fl FieldLevel) bool {
val := fl.Field().String() val := fl.Field().String()
@ -2352,6 +2367,28 @@ func isIso31662(fl FieldLevel) bool {
return iso3166_2[val] return iso3166_2[val]
} }
// isIso4217 is the validation function for validating if the current field's value is a valid iso4217 currency code.
func isIso4217(fl FieldLevel) bool {
val := fl.Field().String()
return iso4217[val]
}
// isIso4217Numeric is the validation function for validating if the current field's value is a valid iso4217 numeric currency code.
func isIso4217Numeric(fl FieldLevel) bool {
field := fl.Field()
var code int
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
code = int(field.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
code = int(field.Uint())
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
return iso4217_numeric[code]
}
// isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse // isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse
func isBCP47LanguageTag(fl FieldLevel) bool { func isBCP47LanguageTag(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()

View file

@ -0,0 +1,79 @@
package validator
var iso4217 = map[string]bool{
"AFN": true, "EUR": true, "ALL": true, "DZD": true, "USD": true,
"AOA": true, "XCD": true, "ARS": true, "AMD": true, "AWG": true,
"AUD": true, "AZN": true, "BSD": true, "BHD": true, "BDT": true,
"BBD": true, "BYN": true, "BZD": true, "XOF": true, "BMD": true,
"INR": true, "BTN": true, "BOB": true, "BOV": true, "BAM": true,
"BWP": true, "NOK": true, "BRL": true, "BND": true, "BGN": true,
"BIF": true, "CVE": true, "KHR": true, "XAF": true, "CAD": true,
"KYD": true, "CLP": true, "CLF": true, "CNY": true, "COP": true,
"COU": true, "KMF": true, "CDF": true, "NZD": true, "CRC": true,
"HRK": true, "CUP": true, "CUC": true, "ANG": true, "CZK": true,
"DKK": true, "DJF": true, "DOP": true, "EGP": true, "SVC": true,
"ERN": true, "SZL": true, "ETB": true, "FKP": true, "FJD": true,
"XPF": true, "GMD": true, "GEL": true, "GHS": true, "GIP": true,
"GTQ": true, "GBP": true, "GNF": true, "GYD": true, "HTG": true,
"HNL": true, "HKD": true, "HUF": true, "ISK": true, "IDR": true,
"XDR": true, "IRR": true, "IQD": true, "ILS": true, "JMD": true,
"JPY": true, "JOD": true, "KZT": true, "KES": true, "KPW": true,
"KRW": true, "KWD": true, "KGS": true, "LAK": true, "LBP": true,
"LSL": true, "ZAR": true, "LRD": true, "LYD": true, "CHF": true,
"MOP": true, "MKD": true, "MGA": true, "MWK": true, "MYR": true,
"MVR": true, "MRU": true, "MUR": true, "XUA": true, "MXN": true,
"MXV": true, "MDL": true, "MNT": true, "MAD": true, "MZN": true,
"MMK": true, "NAD": true, "NPR": true, "NIO": true, "NGN": true,
"OMR": true, "PKR": true, "PAB": true, "PGK": true, "PYG": true,
"PEN": true, "PHP": true, "PLN": true, "QAR": true, "RON": true,
"RUB": true, "RWF": true, "SHP": true, "WST": true, "STN": true,
"SAR": true, "RSD": true, "SCR": true, "SLL": true, "SGD": true,
"XSU": true, "SBD": true, "SOS": true, "SSP": true, "LKR": true,
"SDG": true, "SRD": true, "SEK": true, "CHE": true, "CHW": true,
"SYP": true, "TWD": true, "TJS": true, "TZS": true, "THB": true,
"TOP": true, "TTD": true, "TND": true, "TRY": true, "TMT": true,
"UGX": true, "UAH": true, "AED": true, "USN": true, "UYU": true,
"UYI": true, "UYW": true, "UZS": true, "VUV": true, "VES": true,
"VND": true, "YER": true, "ZMW": true, "ZWL": true, "XBA": true,
"XBB": true, "XBC": true, "XBD": true, "XTS": true, "XXX": true,
"XAU": true, "XPD": true, "XPT": true, "XAG": true,
}
var iso4217_numeric = map[int]bool{
8: true, 12: true, 32: true, 36: true, 44: true,
48: true, 50: true, 51: true, 52: true, 60: true,
64: true, 68: true, 72: true, 84: true, 90: true,
96: true, 104: true, 108: true, 116: true, 124: true,
132: true, 136: true, 144: true, 152: true, 156: true,
170: true, 174: true, 188: true, 191: true, 192: true,
203: true, 208: true, 214: true, 222: true, 230: true,
232: true, 238: true, 242: true, 262: true, 270: true,
292: true, 320: true, 324: true, 328: true, 332: true,
340: true, 344: true, 348: true, 352: true, 356: true,
360: true, 364: true, 368: true, 376: true, 388: true,
392: true, 398: true, 400: true, 404: true, 408: true,
410: true, 414: true, 417: true, 418: true, 422: true,
426: true, 430: true, 434: true, 446: true, 454: true,
458: true, 462: true, 480: true, 484: true, 496: true,
498: true, 504: true, 512: true, 516: true, 524: true,
532: true, 533: true, 548: true, 554: true, 558: true,
566: true, 578: true, 586: true, 590: true, 598: true,
600: true, 604: true, 608: true, 634: true, 643: true,
646: true, 654: true, 682: true, 690: true, 694: true,
702: true, 704: true, 706: true, 710: true, 728: true,
748: true, 752: true, 756: true, 760: true, 764: true,
776: true, 780: true, 784: true, 788: true, 800: true,
807: true, 818: true, 826: true, 834: true, 840: true,
858: true, 860: true, 882: true, 886: true, 901: true,
927: true, 928: true, 929: true, 930: true, 931: true,
932: true, 933: true, 934: true, 936: true, 938: true,
940: true, 941: true, 943: true, 944: true, 946: true,
947: true, 948: true, 949: true, 950: true, 951: true,
952: true, 953: true, 955: true, 956: true, 957: true,
958: true, 959: true, 960: true, 961: true, 962: true,
963: true, 964: true, 965: true, 967: true, 968: true,
969: true, 970: true, 971: true, 972: true, 973: true,
975: true, 976: true, 977: true, 978: true, 979: true,
980: true, 981: true, 984: true, 985: true, 986: true,
990: true, 994: true, 997: true, 999: true,
}

View file

@ -7,6 +7,14 @@
see more examples https://github.com/go-playground/validator/tree/master/_examples see more examples https://github.com/go-playground/validator/tree/master/_examples
Singleton
Validator is designed to be thread-safe and used as a singleton instance.
It caches information about your struct and validations,
in essence only parsing your validation tags once per struct type.
Using multiple instances neglects the benefit of caching.
The not thread-safe functions are explicitly marked as such in the documentation.
Validation Functions Return Type error Validation Functions Return Type error
Doing things this way is actually the way the standard library does, see the Doing things this way is actually the way the standard library does, see the
@ -726,6 +734,12 @@ type Test struct {
Usage: alphanumunicode Usage: alphanumunicode
Boolean
This validates that a string value can successfully be parsed into a boolean with strconv.ParseBool
Usage: boolean
Number Number
This validates that a string value contains number values only. This validates that a string value contains number values only.
@ -811,6 +825,12 @@ type Test struct {
Usage: json Usage: json
JWT String
This validates that a string value is a valid JWT
Usage: jwt
File path File path
This validates that a string value contains a valid file path and that This validates that a string value contains a valid file path and that

View file

@ -1,12 +0,0 @@
module github.com/go-playground/validator/v10
go 1.13
require (
github.com/go-playground/assert/v2 v2.0.1
github.com/go-playground/locales v0.13.0
github.com/go-playground/universal-translator v0.17.0
github.com/leodido/go-urn v1.2.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/text v0.3.2 // indirect
)

View file

@ -1,33 +0,0 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -48,6 +48,7 @@
uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$` uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$`
hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(&gt)|(&lt)|(&quot)|(&amp)+[;]?` hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(&gt)|(&lt)|(&quot)|(&amp)+[;]?`
hTMLRegexString = `<[/]?([a-zA-Z]+).*?>` hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
splitParamsRegexString = `'[^']*'|\S+` splitParamsRegexString = `'[^']*'|\S+`
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
) )
@ -98,6 +99,7 @@
uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString)
hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString)
hTMLRegex = regexp.MustCompile(hTMLRegexString) hTMLRegex = regexp.MustCompile(hTMLRegexString)
jWTRegex = regexp.MustCompile(jWTRegexString)
splitParamsRegex = regexp.MustCompile(splitParamsRegexString) splitParamsRegex = regexp.MustCompile(splitParamsRegexString)
bicRegex = regexp.MustCompile(bicRegexString) bicRegex = regexp.MustCompile(bicRegexString)
) )

View file

@ -89,6 +89,10 @@ type Validate struct {
} }
// New returns a new instance of 'validate' with sane defaults. // New returns a new instance of 'validate' with sane defaults.
// Validate is designed to be thread-safe and used as a singleton instance.
// It caches information about your struct and validations,
// in essence only parsing your validation tags once per struct type.
// Using multiple instances neglects the benefit of caching.
func New() *Validate { func New() *Validate {
tc := new(tagCache) tc := new(tagCache)
@ -207,11 +211,11 @@ func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationE
func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error { func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilCheckable bool) error {
if len(tag) == 0 { if len(tag) == 0 {
return errors.New("Function Key cannot be empty") return errors.New("function Key cannot be empty")
} }
if fn == nil { if fn == nil {
return errors.New("Function cannot be empty") return errors.New("function cannot be empty")
} }
_, ok := restrictedTags[tag] _, ok := restrictedTags[tag]

View file

@ -28,4 +28,5 @@ comment:
require_changes: no require_changes: no
ignore: ignore:
- internal/encoder/vm_debug - internal/encoder/vm_color
- internal/encoder/vm_color_indent

View file

@ -1,3 +1,118 @@
# v0.7.8 - 2021/09/01
* Fix mapassign_faststr for indirect struct type ( #283 )
* Fix encoding of not empty interface type ( #284 )
* Fix encoding of empty struct interface type ( #286 )
# v0.7.7 - 2021/08/25
* Fix invalid utf8 on stream decoder ( #279 )
* Fix buffer length bug on string stream decoder ( #280 )
Thank you @orisano !!
# v0.7.6 - 2021/08/13
* Fix nil slice assignment ( #276 )
* Improve error message ( #277 )
# v0.7.5 - 2021/08/12
* Fix encoding of embedded struct with tags ( #265 )
* Fix encoding of embedded struct that isn't first field ( #272 )
* Fix decoding of binary type with escaped char ( #273 )
# v0.7.4 - 2021/07/06
* Fix encoding of indirect layout structure ( #264 )
# v0.7.3 - 2021/06/29
* Fix encoding of pointer type in empty interface ( #262 )
# v0.7.2 - 2021/06/26
### Fix decoder
* Add decoder for func type to fix decoding of nil function value ( #257 )
* Fix stream decoding of []byte type ( #258 )
### Performance
* Improve decoding performance of map[string]interface{} type ( use `mapassign_faststr` ) ( #256 )
* Improve encoding performance of empty interface type ( remove recursive calling of `vm.Run` ) ( #259 )
### Benchmark
* Add bytedance/sonic as benchmark target ( #254 )
# v0.7.1 - 2021/06/18
### Fix decoder
* Fix error when unmarshal empty array ( #253 )
# v0.7.0 - 2021/06/12
### Support context for MarshalJSON and UnmarshalJSON ( #248 )
* json.MarshalContext(context.Context, interface{}, ...json.EncodeOption) ([]byte, error)
* json.NewEncoder(io.Writer).EncodeContext(context.Context, interface{}, ...json.EncodeOption) error
* json.UnmarshalContext(context.Context, []byte, interface{}, ...json.DecodeOption) error
* json.NewDecoder(io.Reader).DecodeContext(context.Context, interface{}) error
```go
type MarshalerContext interface {
MarshalJSON(context.Context) ([]byte, error)
}
type UnmarshalerContext interface {
UnmarshalJSON(context.Context, []byte) error
}
```
### Add DecodeFieldPriorityFirstWin option ( #242 )
In the default behavior, go-json, like encoding/json, will reflect the result of the last evaluation when a field with the same name exists. I've added new options to allow you to change this behavior. `json.DecodeFieldPriorityFirstWin` option reflects the result of the first evaluation if a field with the same name exists. This behavior has a performance advantage as it allows the subsequent strings to be skipped if all fields have been evaluated.
### Fix encoder
* Fix indent number contains recursive type ( #249 )
* Fix encoding of using empty interface as map key ( #244 )
### Fix decoder
* Fix decoding fields containing escaped characters ( #237 )
### Refactor
* Move some tests to subdirectory ( #243 )
* Refactor package layout for decoder ( #238 )
# v0.6.1 - 2021/06/02
### Fix encoder
* Fix value of totalLength for encoding ( #236 )
# v0.6.0 - 2021/06/01
### Support Colorize option for encoding (#233)
```go
b, err := json.MarshalWithOption(v, json.Colorize(json.DefaultColorScheme))
if err != nil {
...
}
fmt.Println(string(b)) // print colored json
```
### Refactor
* Fix opcode layout - Adjust memory layout of the opcode to 128 bytes in a 64-bit environment ( #230 )
* Refactor encode option ( #231 )
* Refactor escape string ( #232 )
# v0.5.1 - 2021/5/20 # v0.5.1 - 2021/5/20
### Optimization ### Optimization

View file

@ -1,7 +1,7 @@
PKG := github.com/goccy/go-json PKG := github.com/goccy/go-json
BIN_DIR := $(CURDIR)/bin BIN_DIR := $(CURDIR)/bin
PKGS := $(shell go list ./... | grep -v internal/cmd) PKGS := $(shell go list ./... | grep -v internal/cmd|grep -v test)
COVER_PKGS := $(foreach pkg,$(PKGS),$(subst $(PKG),.,$(pkg))) COVER_PKGS := $(foreach pkg,$(PKGS),$(subst $(PKG),.,$(pkg)))
COMMA := , COMMA := ,
@ -14,7 +14,7 @@ $(BIN_DIR):
.PHONY: cover .PHONY: cover
cover: cover:
go test -coverpkg=$(COVERPKG_OPT) -coverprofile=cover.out . go test -coverpkg=$(COVERPKG_OPT) -coverprofile=cover.out ./...
.PHONY: cover-html .PHONY: cover-html
cover-html: cover cover-html: cover

View file

@ -13,23 +13,26 @@ Fast JSON encoder/decoder compatible with encoding/json for Go
``` ```
* version ( expected release date ) * version ( expected release date )
* v0.5.0 * v0.7.0
|
| refactor all sources for maintainability and improve performance
|
v
* v0.6.0 ( 2021/05 Mid )
| |
| while maintaining compatibility with encoding/json, we will add convenient APIs | while maintaining compatibility with encoding/json, we will add convenient APIs
| |
v v
* v1.0.0 ( 2021/06 Mid ) * v1.0.0
``` ```
We are accepting requests for features that will be implemented between v0.6.0 and v.1.0.0. We are accepting requests for features that will be implemented between v0.7.0 and v.1.0.0.
If you have the API you need, please submit your issue [here](https://github.com/goccy/go-json/issues). If you have the API you need, please submit your issue [here](https://github.com/goccy/go-json/issues).
For example, I'm thinking of supporting `context.Context` of `json.Marshaler` and decoding using JSON Path. For example, I'm thinking of supporting `context.Context` of `json.Marshaler` and decoding using JSON Path.
# Features
- Drop-in replacement of `encoding/json`
- Fast ( See [Benchmark section](https://github.com/goccy/go-json#benchmarks) )
- Flexible customization with options
- Coloring the encoded string
- Can propagate context.Context to `MarshalJSON` or `UnmarshalJSON`
# Installation # Installation
``` ```
@ -53,13 +56,26 @@ Replace import statement from `encoding/json` to `github.com/goccy/go-json`
| [json-iterator/go](https://github.com/json-iterator/go) | yes | yes | partial | | [json-iterator/go](https://github.com/json-iterator/go) | yes | yes | partial |
| [easyjson](https://github.com/mailru/easyjson) | yes | yes | no | | [easyjson](https://github.com/mailru/easyjson) | yes | yes | no |
| [gojay](https://github.com/francoispqt/gojay) | yes | yes | no | | [gojay](https://github.com/francoispqt/gojay) | yes | yes | no |
| [segmentio/encoding/json](https://github.com/segmentio/encoding/tree/master/json) | yes | yes | yes | | [segmentio/encoding/json](https://github.com/segmentio/encoding/tree/master/json) | yes | yes | partial |
| [jettison](https://github.com/wI2L/jettison) | yes | no | no | | [jettison](https://github.com/wI2L/jettison) | yes | no | no |
| [simdjson-go](https://github.com/minio/simdjson-go) | no | yes | no | | [simdjson-go](https://github.com/minio/simdjson-go) | no | yes | no |
| goccy/go-json | yes | yes | yes | | goccy/go-json | yes | yes | yes |
- `json-iterator/go` isn't compatible with `encoding/json` in many ways, but it hasn't been supported for a long time. - `json-iterator/go` isn't compatible with `encoding/json` in many ways (e.g. https://github.com/json-iterator/go/issues/229 ), but it hasn't been supported for a long time.
- `segmentio/encoding/json` is well supported for encoders, but some are not supported for decoder APIs such as `Token` ( streaming decode )
## Other libraries
- [jingo](https://github.com/bet365/jingo)
I tried the benchmark but it didn't work.
Also, it seems to panic when it receives an unexpected value because there is no error handling...
- [ffjson](https://github.com/pquerna/ffjson)
Benchmarking gave very slow results.
It seems that it is assumed that the user will use the buffer pool properly.
Also, development seems to have already stopped
# Benchmarks # Benchmarks
@ -176,7 +192,7 @@ For this reason, to date `reflect.Type` is the same as `*reflect.rtype`.
Therefore, by directly handling `*reflect.rtype`, which is an implementation of `reflect.Type`, it is possible to avoid escaping because it changes from `interface` to using `struct`. Therefore, by directly handling `*reflect.rtype`, which is an implementation of `reflect.Type`, it is possible to avoid escaping because it changes from `interface` to using `struct`.
The technique for working with `*reflect.rtype` directly from `go-json` is implemented at https://github.com/goccy/go-json/blob/master/rtype.go. The technique for working with `*reflect.rtype` directly from `go-json` is implemented at [rtype.go](https://github.com/goccy/go-json/blob/master/internal/runtime/rtype.go)
Also, the same technique is cut out as a library ( https://github.com/goccy/go-reflect ) Also, the same technique is cut out as a library ( https://github.com/goccy/go-reflect )
@ -337,7 +353,7 @@ However, if there is too much type information, it will use a lot of memory, so
If this approach is not available, it will fall back to the `atomic` based process described above. If this approach is not available, it will fall back to the `atomic` based process described above.
If you want to know more, please refer to the implementation [here](https://github.com/goccy/go-json/blob/master/codec.go#L24-L76 ) If you want to know more, please refer to the implementation [here](https://github.com/goccy/go-json/blob/master/internal/runtime/type.go#L36-L100)
## Decoder ## Decoder

View file

@ -1,104 +0,0 @@
package json
import (
"fmt"
"reflect"
"sync/atomic"
"unsafe"
)
const (
maxAcceptableTypeAddrRange = 1024 * 1024 * 2 // 2 Mib
)
var (
cachedDecoder []decoder
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
baseTypeAddr uintptr
maxTypeAddr uintptr
typeAddrShift uintptr
)
//go:linkname typelinks reflect.typelinks
func typelinks() ([]unsafe.Pointer, [][]int32)
//go:linkname rtypeOff reflect.rtypeOff
func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer
func setupCodec() error {
sections, offsets := typelinks()
if len(sections) != 1 {
return fmt.Errorf("failed to get sections")
}
if len(offsets) != 1 {
return fmt.Errorf("failed to get offsets")
}
section := sections[0]
offset := offsets[0]
var (
min uintptr = uintptr(^uint(0))
max uintptr = 0
isAligned64 = true
isAligned32 = true
)
for i := 0; i < len(offset); i++ {
typ := (*rtype)(rtypeOff(section, offset[i]))
addr := uintptr(unsafe.Pointer(typ))
if min > addr {
min = addr
}
if max < addr {
max = addr
}
if typ.Kind() == reflect.Ptr {
addr = uintptr(unsafe.Pointer(typ.Elem()))
if min > addr {
min = addr
}
if max < addr {
max = addr
}
}
// check every address is aligned from the base address
isAligned64 = isAligned64 && (addr-min)&63 == 0
isAligned32 = isAligned32 && (addr-min)&31 == 0
}
addrRange := max - min
if addrRange == 0 {
return fmt.Errorf("failed to get address range of types")
}
if isAligned64 {
typeAddrShift = 6
} else if isAligned32 {
typeAddrShift = 5
}
cacheSize := addrRange >> typeAddrShift
if cacheSize > maxAcceptableTypeAddrRange {
return fmt.Errorf("too big address range %d", addrRange)
}
cachedDecoder = make([]decoder, cacheSize)
baseTypeAddr = min
maxTypeAddr = max
return nil
}
func init() {
_ = setupCodec()
}
func loadDecoderMap() map[uintptr]decoder {
p := atomic.LoadPointer(&cachedDecoderMap)
return *(*map[uintptr]decoder)(unsafe.Pointer(&p))
}
func storeDecoder(typ uintptr, dec decoder, m map[uintptr]decoder) {
newDecoderMap := make(map[uintptr]decoder, len(m)+1)
newDecoderMap[typ] = dec
for k, v := range m {
newDecoderMap[k] = v
}
atomic.StorePointer(&cachedDecoderMap, *(*unsafe.Pointer)(unsafe.Pointer(&newDecoderMap)))
}

68
vendor/github.com/goccy/go-json/color.go generated vendored Normal file
View file

@ -0,0 +1,68 @@
package json
import (
"fmt"
"github.com/goccy/go-json/internal/encoder"
)
type (
ColorFormat = encoder.ColorFormat
ColorScheme = encoder.ColorScheme
)
const escape = "\x1b"
type colorAttr int
//nolint:deadcode,varcheck
const (
fgBlackColor colorAttr = iota + 30
fgRedColor
fgGreenColor
fgYellowColor
fgBlueColor
fgMagentaColor
fgCyanColor
fgWhiteColor
)
//nolint:deadcode,varcheck
const (
fgHiBlackColor colorAttr = iota + 90
fgHiRedColor
fgHiGreenColor
fgHiYellowColor
fgHiBlueColor
fgHiMagentaColor
fgHiCyanColor
fgHiWhiteColor
)
func createColorFormat(attr colorAttr) ColorFormat {
return ColorFormat{
Header: wrapColor(attr),
Footer: resetColor(),
}
}
func wrapColor(attr colorAttr) string {
return fmt.Sprintf("%s[%dm", escape, attr)
}
func resetColor() string {
return wrapColor(colorAttr(0))
}
var (
DefaultColorScheme = &ColorScheme{
Int: createColorFormat(fgHiMagentaColor),
Uint: createColorFormat(fgHiMagentaColor),
Float: createColorFormat(fgHiMagentaColor),
Bool: createColorFormat(fgHiYellowColor),
String: createColorFormat(fgHiGreenColor),
Binary: createColorFormat(fgHiRedColor),
ObjectKey: createColorFormat(fgHiCyanColor),
Null: createColorFormat(fgBlueColor),
}
)

View file

@ -1,34 +1,31 @@
package json package json
import ( import (
"encoding" "context"
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
"strconv"
"unsafe" "unsafe"
)
type decoder interface { "github.com/goccy/go-json/internal/decoder"
decode([]byte, int64, int64, unsafe.Pointer) (int64, error) "github.com/goccy/go-json/internal/errors"
decodeStream(*stream, int64, unsafe.Pointer) error "github.com/goccy/go-json/internal/runtime"
} )
type Decoder struct { type Decoder struct {
s *stream s *decoder.Stream
} }
var (
unmarshalJSONType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
unmarshalTextType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
)
const ( const (
nul = '\000' nul = '\000'
maxDecodeNestingDepth = 10000
) )
func unmarshal(data []byte, v interface{}) error { type emptyInterface struct {
typ *runtime.Type
ptr unsafe.Pointer
}
func unmarshal(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
src := make([]byte, len(data)+1) // append nul byte to the end src := make([]byte, len(data)+1) // append nul byte to the end
copy(src, data) copy(src, data)
@ -37,18 +34,26 @@ func unmarshal(data []byte, v interface{}) error {
if err := validateType(header.typ, uintptr(header.ptr)); err != nil { if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
return err return err
} }
dec, err := decodeCompileToGetDecoder(header.typ) dec, err := decoder.CompileToGetDecoder(header.typ)
if err != nil { if err != nil {
return err return err
} }
cursor, err := dec.decode(src, 0, 0, header.ptr) ctx := decoder.TakeRuntimeContext()
ctx.Buf = src
ctx.Option.Flags = 0
for _, optFunc := range optFuncs {
optFunc(ctx.Option)
}
cursor, err := dec.Decode(ctx, 0, 0, header.ptr)
if err != nil { if err != nil {
decoder.ReleaseRuntimeContext(ctx)
return err return err
} }
decoder.ReleaseRuntimeContext(ctx)
return validateEndBuf(src, cursor) return validateEndBuf(src, cursor)
} }
func unmarshalNoEscape(data []byte, v interface{}) error { func unmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
src := make([]byte, len(data)+1) // append nul byte to the end src := make([]byte, len(data)+1) // append nul byte to the end
copy(src, data) copy(src, data)
@ -57,14 +62,53 @@ func unmarshalNoEscape(data []byte, v interface{}) error {
if err := validateType(header.typ, uintptr(header.ptr)); err != nil { if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
return err return err
} }
dec, err := decodeCompileToGetDecoder(header.typ) dec, err := decoder.CompileToGetDecoder(header.typ)
if err != nil { if err != nil {
return err return err
} }
cursor, err := dec.decode(src, 0, 0, noescape(header.ptr)) rctx := decoder.TakeRuntimeContext()
rctx.Buf = src
rctx.Option.Flags = 0
rctx.Option.Flags |= decoder.ContextOption
rctx.Option.Context = ctx
for _, optFunc := range optFuncs {
optFunc(rctx.Option)
}
cursor, err := dec.Decode(rctx, 0, 0, header.ptr)
if err != nil {
decoder.ReleaseRuntimeContext(rctx)
return err
}
decoder.ReleaseRuntimeContext(rctx)
return validateEndBuf(src, cursor)
}
func unmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
src := make([]byte, len(data)+1) // append nul byte to the end
copy(src, data)
header := (*emptyInterface)(unsafe.Pointer(&v))
if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
return err
}
dec, err := decoder.CompileToGetDecoder(header.typ)
if err != nil { if err != nil {
return err return err
} }
ctx := decoder.TakeRuntimeContext()
ctx.Buf = src
ctx.Option.Flags = 0
for _, optFunc := range optFuncs {
optFunc(ctx.Option)
}
cursor, err := dec.Decode(ctx, 0, 0, noescape(header.ptr))
if err != nil {
decoder.ReleaseRuntimeContext(ctx)
return err
}
decoder.ReleaseRuntimeContext(ctx)
return validateEndBuf(src, cursor) return validateEndBuf(src, cursor)
} }
@ -77,7 +121,7 @@ func validateEndBuf(src []byte, cursor int64) error {
case nul: case nul:
return nil return nil
} }
return errSyntax( return errors.ErrSyntax(
fmt.Sprintf("invalid character '%c' after top-level value", src[cursor]), fmt.Sprintf("invalid character '%c' after top-level value", src[cursor]),
cursor+1, cursor+1,
) )
@ -91,9 +135,9 @@ func noescape(p unsafe.Pointer) unsafe.Pointer {
return unsafe.Pointer(x ^ 0) return unsafe.Pointer(x ^ 0)
} }
func validateType(typ *rtype, p uintptr) error { func validateType(typ *runtime.Type, p uintptr) error {
if typ == nil || typ.Kind() != reflect.Ptr || p == 0 { if typ == nil || typ.Kind() != reflect.Ptr || p == 0 {
return &InvalidUnmarshalError{Type: rtype2type(typ)} return &InvalidUnmarshalError{Type: runtime.RType2Type(typ)}
} }
return nil return nil
} }
@ -103,7 +147,7 @@ func validateType(typ *rtype, p uintptr) error {
// The decoder introduces its own buffering and may // The decoder introduces its own buffering and may
// read data from r beyond the JSON values requested. // read data from r beyond the JSON values requested.
func NewDecoder(r io.Reader) *Decoder { func NewDecoder(r io.Reader) *Decoder {
s := newStream(r) s := decoder.NewStream(r)
return &Decoder{ return &Decoder{
s: s, s: s,
} }
@ -112,28 +156,7 @@ func NewDecoder(r io.Reader) *Decoder {
// Buffered returns a reader of the data remaining in the Decoder's // Buffered returns a reader of the data remaining in the Decoder's
// buffer. The reader is valid until the next call to Decode. // buffer. The reader is valid until the next call to Decode.
func (d *Decoder) Buffered() io.Reader { func (d *Decoder) Buffered() io.Reader {
return d.s.buffered() return d.s.Buffered()
}
func (d *Decoder) prepareForDecode() error {
s := d.s
for {
switch s.char() {
case ' ', '\t', '\r', '\n':
s.cursor++
continue
case ',', ':':
s.cursor++
return nil
case nul:
if s.read() {
continue
}
return io.EOF
}
break
}
return nil
} }
// Decode reads the next JSON-encoded value from its // Decode reads the next JSON-encoded value from its
@ -142,120 +165,68 @@ func (d *Decoder) prepareForDecode() error {
// See the documentation for Unmarshal for details about // See the documentation for Unmarshal for details about
// the conversion of JSON into a Go value. // the conversion of JSON into a Go value.
func (d *Decoder) Decode(v interface{}) error { func (d *Decoder) Decode(v interface{}) error {
return d.DecodeWithOption(v)
}
// DecodeContext reads the next JSON-encoded value from its
// input and stores it in the value pointed to by v with context.Context.
func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
d.s.Option.Flags |= decoder.ContextOption
d.s.Option.Context = ctx
return d.DecodeWithOption(v)
}
func (d *Decoder) DecodeWithOption(v interface{}, optFuncs ...DecodeOptionFunc) error {
header := (*emptyInterface)(unsafe.Pointer(&v)) header := (*emptyInterface)(unsafe.Pointer(&v))
typ := header.typ typ := header.typ
ptr := uintptr(header.ptr) ptr := uintptr(header.ptr)
typeptr := uintptr(unsafe.Pointer(typ)) typeptr := uintptr(unsafe.Pointer(typ))
// noescape trick for header.typ ( reflect.*rtype ) // noescape trick for header.typ ( reflect.*rtype )
copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
if err := validateType(copiedType, ptr); err != nil { if err := validateType(copiedType, ptr); err != nil {
return err return err
} }
dec, err := decodeCompileToGetDecoder(typ) dec, err := decoder.CompileToGetDecoder(typ)
if err != nil { if err != nil {
return err return err
} }
if err := d.prepareForDecode(); err != nil { if err := d.s.PrepareForDecode(); err != nil {
return err return err
} }
s := d.s s := d.s
if err := dec.decodeStream(s, 0, header.ptr); err != nil { for _, optFunc := range optFuncs {
optFunc(s.Option)
}
if err := dec.DecodeStream(s, 0, header.ptr); err != nil {
return err return err
} }
s.reset() s.Reset()
s.bufSize = initBufSize
return nil return nil
} }
func (d *Decoder) More() bool { func (d *Decoder) More() bool {
s := d.s return d.s.More()
for {
switch s.char() {
case ' ', '\n', '\r', '\t':
s.cursor++
continue
case '}', ']':
return false
case nul:
if s.read() {
continue
}
return false
}
break
}
return true
} }
func (d *Decoder) Token() (Token, error) { func (d *Decoder) Token() (Token, error) {
s := d.s return d.s.Token()
for {
c := s.char()
switch c {
case ' ', '\n', '\r', '\t':
s.cursor++
case '{', '[', ']', '}':
s.cursor++
return Delim(c), nil
case ',', ':':
s.cursor++
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
bytes := floatBytes(s)
s := *(*string)(unsafe.Pointer(&bytes))
f64, err := strconv.ParseFloat(s, 64)
if err != nil {
return nil, err
}
return f64, nil
case '"':
bytes, err := stringBytes(s)
if err != nil {
return nil, err
}
return string(bytes), nil
case 't':
if err := trueBytes(s); err != nil {
return nil, err
}
return true, nil
case 'f':
if err := falseBytes(s); err != nil {
return nil, err
}
return false, nil
case 'n':
if err := nullBytes(s); err != nil {
return nil, err
}
return nil, nil
case nul:
if s.read() {
continue
}
goto END
default:
return nil, errInvalidCharacter(s.char(), "token", s.totalOffset())
}
}
END:
return nil, io.EOF
} }
// DisallowUnknownFields causes the Decoder to return an error when the destination // DisallowUnknownFields causes the Decoder to return an error when the destination
// is a struct and the input contains object keys which do not match any // is a struct and the input contains object keys which do not match any
// non-ignored, exported fields in the destination. // non-ignored, exported fields in the destination.
func (d *Decoder) DisallowUnknownFields() { func (d *Decoder) DisallowUnknownFields() {
d.s.disallowUnknownFields = true d.s.DisallowUnknownFields = true
} }
func (d *Decoder) InputOffset() int64 { func (d *Decoder) InputOffset() int64 {
return d.s.totalOffset() return d.s.TotalOffset()
} }
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a // UseNumber causes the Decoder to unmarshal a number into an interface{} as a
// Number instead of as a float64. // Number instead of as a float64.
func (d *Decoder) UseNumber() { func (d *Decoder) UseNumber() {
d.s.useNumber = true d.s.UseNumber = true
} }

View file

@ -1,35 +0,0 @@
package json
import (
"unsafe"
)
type anonymousFieldDecoder struct {
structType *rtype
offset uintptr
dec decoder
}
func newAnonymousFieldDecoder(structType *rtype, offset uintptr, dec decoder) *anonymousFieldDecoder {
return &anonymousFieldDecoder{
structType: structType,
offset: offset,
dec: dec,
}
}
func (d *anonymousFieldDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe_New(d.structType)
}
p = *(*unsafe.Pointer)(p)
return d.dec.decodeStream(s, depth, unsafe.Pointer(uintptr(p)+d.offset))
}
func (d *anonymousFieldDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe_New(d.structType)
}
p = *(*unsafe.Pointer)(p)
return d.dec.decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+d.offset))
}

View file

@ -1,172 +0,0 @@
package json
import (
"encoding/base64"
"unsafe"
)
type bytesDecoder struct {
typ *rtype
sliceDecoder decoder
structName string
fieldName string
}
func byteUnmarshalerSliceDecoder(typ *rtype, structName string, fieldName string) decoder {
var unmarshalDecoder decoder
switch {
case rtype_ptrTo(typ).Implements(unmarshalJSONType):
unmarshalDecoder = newUnmarshalJSONDecoder(rtype_ptrTo(typ), structName, fieldName)
case rtype_ptrTo(typ).Implements(unmarshalTextType):
unmarshalDecoder = newUnmarshalTextDecoder(rtype_ptrTo(typ), structName, fieldName)
}
if unmarshalDecoder == nil {
return nil
}
return newSliceDecoder(unmarshalDecoder, typ, 1, structName, fieldName)
}
func newBytesDecoder(typ *rtype, structName string, fieldName string) *bytesDecoder {
return &bytesDecoder{
typ: typ,
sliceDecoder: byteUnmarshalerSliceDecoder(typ, structName, fieldName),
structName: structName,
fieldName: fieldName,
}
}
func (d *bytesDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error {
bytes, err := d.decodeStreamBinary(s, depth, p)
if err != nil {
return err
}
if bytes == nil {
s.reset()
return nil
}
decodedLen := base64.StdEncoding.DecodedLen(len(bytes))
buf := make([]byte, decodedLen)
if _, err := base64.StdEncoding.Decode(buf, bytes); err != nil {
return err
}
*(*[]byte)(p) = buf
s.reset()
return nil
}
func (d *bytesDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) {
bytes, c, err := d.decodeBinary(buf, cursor, depth, p)
if err != nil {
return 0, err
}
if bytes == nil {
return c, nil
}
cursor = c
decodedLen := base64.StdEncoding.DecodedLen(len(bytes))
b := make([]byte, decodedLen)
n, err := base64.StdEncoding.Decode(b, bytes)
if err != nil {
return 0, err
}
*(*[]byte)(p) = b[:n]
return cursor, nil
}
func binaryBytes(s *stream) ([]byte, error) {
s.cursor++
start := s.cursor
for {
switch s.char() {
case '"':
literal := s.buf[start:s.cursor]
s.cursor++
return literal, nil
case nul:
if s.read() {
continue
}
goto ERROR
}
s.cursor++
}
ERROR:
return nil, errUnexpectedEndOfJSON("[]byte", s.totalOffset())
}
func (d *bytesDecoder) decodeStreamBinary(s *stream, depth int64, p unsafe.Pointer) ([]byte, error) {
for {
switch s.char() {
case ' ', '\n', '\t', '\r':
s.cursor++
continue
case '"':
return binaryBytes(s)
case 'n':
if err := nullBytes(s); err != nil {
return nil, err
}
return nil, nil
case '[':
if d.sliceDecoder == nil {
return nil, &UnmarshalTypeError{
Type: rtype2type(d.typ),
Offset: s.totalOffset(),
}
}
if err := d.sliceDecoder.decodeStream(s, depth, p); err != nil {
return nil, err
}
return nil, nil
case nul:
if s.read() {
continue
}
}
break
}
return nil, errNotAtBeginningOfValue(s.totalOffset())
}
func (d *bytesDecoder) decodeBinary(buf []byte, cursor, depth int64, p unsafe.Pointer) ([]byte, int64, error) {
for {
switch buf[cursor] {
case ' ', '\n', '\t', '\r':
cursor++
case '"':
cursor++
start := cursor
for {
switch buf[cursor] {
case '"':
literal := buf[start:cursor]
cursor++
return literal, cursor, nil
case nul:
return nil, 0, errUnexpectedEndOfJSON("[]byte", cursor)
}
cursor++
}
case '[':
if d.sliceDecoder == nil {
return nil, 0, &UnmarshalTypeError{
Type: rtype2type(d.typ),
Offset: cursor,
}
}
c, err := d.sliceDecoder.decode(buf, cursor, depth, p)
if err != nil {
return nil, 0, err
}
return nil, c, nil
case 'n':
if err := validateNull(buf, cursor); err != nil {
return nil, 0, err
}
cursor += 4
return nil, cursor, nil
default:
return nil, 0, errNotAtBeginningOfValue(cursor)
}
}
}

View file

@ -1,24 +0,0 @@
// +build !race
package json
import "unsafe"
func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
typeptr := uintptr(unsafe.Pointer(typ))
if typeptr > maxTypeAddr {
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
}
index := (typeptr - baseTypeAddr) >> typeAddrShift
if dec := cachedDecoder[index]; dec != nil {
return dec, nil
}
dec, err := decodeCompileHead(typ, map[uintptr]decoder{})
if err != nil {
return nil, err
}
cachedDecoder[index] = dec
return dec, nil
}

View file

@ -1,154 +0,0 @@
package json
import (
"unsafe"
)
type mapDecoder struct {
mapType *rtype
keyType *rtype
valueType *rtype
keyDecoder decoder
valueDecoder decoder
structName string
fieldName string
}
func newMapDecoder(mapType *rtype, keyType *rtype, keyDec decoder, valueType *rtype, valueDec decoder, structName, fieldName string) *mapDecoder {
return &mapDecoder{
mapType: mapType,
keyDecoder: keyDec,
keyType: keyType,
valueType: valueType,
valueDecoder: valueDec,
structName: structName,
fieldName: fieldName,
}
}
//go:linkname makemap reflect.makemap
func makemap(*rtype, int) unsafe.Pointer
//go:linkname mapassign reflect.mapassign
//go:noescape
func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
func (d *mapDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error {
depth++
if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor)
}
s.skipWhiteSpace()
switch s.char() {
case 'n':
if err := nullBytes(s); err != nil {
return err
}
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
return nil
case '{':
default:
return errExpected("{ character for map value", s.totalOffset())
}
s.skipWhiteSpace()
mapValue := *(*unsafe.Pointer)(p)
if mapValue == nil {
mapValue = makemap(d.mapType, 0)
}
if s.buf[s.cursor+1] == '}' {
*(*unsafe.Pointer)(p) = mapValue
s.cursor += 2
return nil
}
for {
s.cursor++
k := unsafe_New(d.keyType)
if err := d.keyDecoder.decodeStream(s, depth, k); err != nil {
return err
}
s.skipWhiteSpace()
if !s.equalChar(':') {
return errExpected("colon after object key", s.totalOffset())
}
s.cursor++
v := unsafe_New(d.valueType)
if err := d.valueDecoder.decodeStream(s, depth, v); err != nil {
return err
}
mapassign(d.mapType, mapValue, k, v)
s.skipWhiteSpace()
if s.equalChar('}') {
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
s.cursor++
return nil
}
if !s.equalChar(',') {
return errExpected("comma after object value", s.totalOffset())
}
}
}
func (d *mapDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) {
depth++
if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor)
}
cursor = skipWhiteSpace(buf, cursor)
buflen := int64(len(buf))
if buflen < 2 {
return 0, errExpected("{} for map", cursor)
}
switch buf[cursor] {
case 'n':
if err := validateNull(buf, cursor); err != nil {
return 0, err
}
cursor += 4
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
return cursor, nil
case '{':
default:
return 0, errExpected("{ character for map value", cursor)
}
cursor++
cursor = skipWhiteSpace(buf, cursor)
mapValue := *(*unsafe.Pointer)(p)
if mapValue == nil {
mapValue = makemap(d.mapType, 0)
}
if buf[cursor] == '}' {
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
cursor++
return cursor, nil
}
for {
k := unsafe_New(d.keyType)
keyCursor, err := d.keyDecoder.decode(buf, cursor, depth, k)
if err != nil {
return 0, err
}
cursor = skipWhiteSpace(buf, keyCursor)
if buf[cursor] != ':' {
return 0, errExpected("colon after object key", cursor)
}
cursor++
v := unsafe_New(d.valueType)
valueCursor, err := d.valueDecoder.decode(buf, cursor, depth, v)
if err != nil {
return 0, err
}
mapassign(d.mapType, mapValue, k, v)
cursor = skipWhiteSpace(buf, valueCursor)
if buf[cursor] == '}' {
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
cursor++
return cursor, nil
}
if buf[cursor] != ',' {
return 0, errExpected("comma after object value", cursor)
}
cursor++
}
}

View file

@ -1,623 +0,0 @@
package json
import (
"fmt"
"math"
"math/bits"
"sort"
"strings"
"unsafe"
)
type structFieldSet struct {
dec decoder
offset uintptr
isTaggedKey bool
key string
keyLen int64
err error
}
type structDecoder struct {
fieldMap map[string]*structFieldSet
stringDecoder *stringDecoder
structName string
fieldName string
isTriedOptimize bool
keyBitmapUint8 [][256]uint8
keyBitmapUint16 [][256]uint16
sortedFieldSets []*structFieldSet
keyDecoder func(*structDecoder, []byte, int64) (int64, *structFieldSet, error)
keyStreamDecoder func(*structDecoder, *stream) (*structFieldSet, string, error)
}
var (
largeToSmallTable [256]byte
)
func init() {
for i := 0; i < 256; i++ {
c := i
if 'A' <= c && c <= 'Z' {
c += 'a' - 'A'
}
largeToSmallTable[i] = byte(c)
}
}
func newStructDecoder(structName, fieldName string, fieldMap map[string]*structFieldSet) *structDecoder {
return &structDecoder{
fieldMap: fieldMap,
stringDecoder: newStringDecoder(structName, fieldName),
structName: structName,
fieldName: fieldName,
keyDecoder: decodeKey,
keyStreamDecoder: decodeKeyStream,
}
}
const (
allowOptimizeMaxKeyLen = 64
allowOptimizeMaxFieldLen = 16
)
func (d *structDecoder) tryOptimize() {
if d.isTriedOptimize {
return
}
fieldMap := map[string]*structFieldSet{}
conflicted := map[string]struct{}{}
for k, v := range d.fieldMap {
key := strings.ToLower(k)
if key != k {
// already exists same key (e.g. Hello and HELLO has same lower case key
if _, exists := conflicted[key]; exists {
d.isTriedOptimize = true
return
}
conflicted[key] = struct{}{}
}
if field, exists := fieldMap[key]; exists {
if field != v {
d.isTriedOptimize = true
return
}
}
fieldMap[key] = v
}
if len(fieldMap) > allowOptimizeMaxFieldLen {
d.isTriedOptimize = true
return
}
var maxKeyLen int
sortedKeys := []string{}
for key := range fieldMap {
keyLen := len(key)
if keyLen > allowOptimizeMaxKeyLen {
d.isTriedOptimize = true
return
}
if maxKeyLen < keyLen {
maxKeyLen = keyLen
}
sortedKeys = append(sortedKeys, key)
}
sort.Strings(sortedKeys)
// By allocating one extra capacity than `maxKeyLen`,
// it is possible to avoid the process of comparing the index of the key with the length of the bitmap each time.
bitmapLen := maxKeyLen + 1
if len(sortedKeys) <= 8 {
keyBitmap := make([][256]uint8, bitmapLen)
for i, key := range sortedKeys {
for j := 0; j < len(key); j++ {
c := key[j]
keyBitmap[j][c] |= (1 << uint(i))
}
d.sortedFieldSets = append(d.sortedFieldSets, fieldMap[key])
}
d.keyBitmapUint8 = keyBitmap
d.keyDecoder = decodeKeyByBitmapUint8
d.keyStreamDecoder = decodeKeyByBitmapUint8Stream
} else {
keyBitmap := make([][256]uint16, bitmapLen)
for i, key := range sortedKeys {
for j := 0; j < len(key); j++ {
c := key[j]
keyBitmap[j][c] |= (1 << uint(i))
}
d.sortedFieldSets = append(d.sortedFieldSets, fieldMap[key])
}
d.keyBitmapUint16 = keyBitmap
d.keyDecoder = decodeKeyByBitmapUint16
d.keyStreamDecoder = decodeKeyByBitmapUint16Stream
}
}
func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) {
var (
field *structFieldSet
curBit uint8 = math.MaxUint8
)
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
for {
switch char(b, cursor) {
case ' ', '\n', '\t', '\r':
cursor++
case '"':
cursor++
c := char(b, cursor)
switch c {
case '"':
cursor++
return cursor, field, nil
case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
}
keyIdx := 0
bitmap := d.keyBitmapUint8
start := cursor
for {
c := char(b, cursor)
switch c {
case '"':
fieldSetIndex := bits.TrailingZeros8(curBit)
field = d.sortedFieldSets[fieldSetIndex]
keyLen := cursor - start
cursor++
if keyLen < field.keyLen {
// early match
return cursor, nil, nil
}
return cursor, field, nil
case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
default:
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
if curBit == 0 {
for {
cursor++
switch char(b, cursor) {
case '"':
cursor++
return cursor, field, nil
case '\\':
cursor++
if char(b, cursor) == nul {
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
}
case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
}
}
}
keyIdx++
}
cursor++
}
default:
return cursor, nil, errNotAtBeginningOfValue(cursor)
}
}
}
func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) {
var (
field *structFieldSet
curBit uint16 = math.MaxUint16
)
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
for {
switch char(b, cursor) {
case ' ', '\n', '\t', '\r':
cursor++
case '"':
cursor++
c := char(b, cursor)
switch c {
case '"':
cursor++
return cursor, field, nil
case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
}
keyIdx := 0
bitmap := d.keyBitmapUint16
start := cursor
for {
c := char(b, cursor)
switch c {
case '"':
fieldSetIndex := bits.TrailingZeros16(curBit)
field = d.sortedFieldSets[fieldSetIndex]
keyLen := cursor - start
cursor++
if keyLen < field.keyLen {
// early match
return cursor, nil, nil
}
return cursor, field, nil
case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
default:
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
if curBit == 0 {
for {
cursor++
switch char(b, cursor) {
case '"':
cursor++
return cursor, field, nil
case '\\':
cursor++
if char(b, cursor) == nul {
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
}
case nul:
return 0, nil, errUnexpectedEndOfJSON("string", cursor)
}
}
}
keyIdx++
}
cursor++
}
default:
return cursor, nil, errNotAtBeginningOfValue(cursor)
}
}
}
func decodeKey(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) {
key, c, err := d.stringDecoder.decodeByte(buf, cursor)
if err != nil {
return 0, nil, err
}
cursor = c
k := *(*string)(unsafe.Pointer(&key))
field, exists := d.fieldMap[k]
if !exists {
return cursor, nil, nil
}
return cursor, field, nil
}
func decodeKeyByBitmapUint8Stream(d *structDecoder, s *stream) (*structFieldSet, string, error) {
var (
field *structFieldSet
curBit uint8 = math.MaxUint8
)
buf, cursor, p := s.stat()
for {
switch char(p, cursor) {
case ' ', '\n', '\t', '\r':
cursor++
case nul:
s.cursor = cursor
if s.read() {
buf, cursor, p = s.stat()
continue
}
return nil, "", errNotAtBeginningOfValue(s.totalOffset())
case '"':
cursor++
FIRST_CHAR:
start := cursor
switch char(p, cursor) {
case '"':
cursor++
s.cursor = cursor
return field, "", nil
case nul:
s.cursor = cursor
if s.read() {
buf, cursor, p = s.stat()
goto FIRST_CHAR
}
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
}
keyIdx := 0
bitmap := d.keyBitmapUint8
for {
c := char(p, cursor)
switch c {
case '"':
fieldSetIndex := bits.TrailingZeros8(curBit)
field = d.sortedFieldSets[fieldSetIndex]
keyLen := cursor - start
cursor++
s.cursor = cursor
if keyLen < field.keyLen {
// early match
return nil, field.key, nil
}
return field, field.key, nil
case nul:
s.cursor = cursor
if s.read() {
buf, cursor, p = s.stat()
continue
}
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
default:
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
if curBit == 0 {
for {
cursor++
switch char(p, cursor) {
case '"':
b := buf[start:cursor]
key := *(*string)(unsafe.Pointer(&b))
cursor++
s.cursor = cursor
return field, key, nil
case '\\':
cursor++
if char(p, cursor) == nul {
s.cursor = cursor
if !s.read() {
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
}
buf, cursor, p = s.statForRetry()
}
case nul:
s.cursor = cursor
if !s.read() {
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
}
buf, cursor, p = s.statForRetry()
}
}
}
keyIdx++
}
cursor++
}
default:
return nil, "", errNotAtBeginningOfValue(s.totalOffset())
}
}
}
func decodeKeyByBitmapUint16Stream(d *structDecoder, s *stream) (*structFieldSet, string, error) {
var (
field *structFieldSet
curBit uint16 = math.MaxUint16
)
buf, cursor, p := s.stat()
for {
switch char(p, cursor) {
case ' ', '\n', '\t', '\r':
cursor++
case nul:
s.cursor = cursor
if s.read() {
buf, cursor, p = s.stat()
continue
}
return nil, "", errNotAtBeginningOfValue(s.totalOffset())
case '"':
cursor++
FIRST_CHAR:
start := cursor
switch char(p, cursor) {
case '"':
cursor++
s.cursor = cursor
return field, "", nil
case nul:
s.cursor = cursor
if s.read() {
buf, cursor, p = s.stat()
goto FIRST_CHAR
}
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
}
keyIdx := 0
bitmap := d.keyBitmapUint16
for {
c := char(p, cursor)
switch c {
case '"':
fieldSetIndex := bits.TrailingZeros16(curBit)
field = d.sortedFieldSets[fieldSetIndex]
keyLen := cursor - start
cursor++
s.cursor = cursor
if keyLen < field.keyLen {
// early match
return nil, field.key, nil
}
return field, field.key, nil
case nul:
s.cursor = cursor
if s.read() {
buf, cursor, p = s.stat()
continue
}
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
default:
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
if curBit == 0 {
for {
cursor++
switch char(p, cursor) {
case '"':
b := buf[start:cursor]
key := *(*string)(unsafe.Pointer(&b))
cursor++
s.cursor = cursor
return field, key, nil
case '\\':
cursor++
if char(p, cursor) == nul {
s.cursor = cursor
if !s.read() {
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
}
buf, cursor, p = s.statForRetry()
}
case nul:
s.cursor = cursor
if !s.read() {
return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset())
}
buf, cursor, p = s.statForRetry()
}
}
}
keyIdx++
}
cursor++
}
default:
return nil, "", errNotAtBeginningOfValue(s.totalOffset())
}
}
}
func decodeKeyStream(d *structDecoder, s *stream) (*structFieldSet, string, error) {
key, err := d.stringDecoder.decodeStreamByte(s)
if err != nil {
return nil, "", err
}
k := *(*string)(unsafe.Pointer(&key))
return d.fieldMap[k], k, nil
}
func (d *structDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error {
depth++
if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor)
}
s.skipWhiteSpace()
switch s.char() {
case 'n':
if err := nullBytes(s); err != nil {
return err
}
return nil
case nul:
s.read()
default:
if s.char() != '{' {
return errNotAtBeginningOfValue(s.totalOffset())
}
}
s.cursor++
s.skipWhiteSpace()
if s.char() == '}' {
s.cursor++
return nil
}
for {
s.reset()
field, key, err := d.keyStreamDecoder(d, s)
if err != nil {
return err
}
s.skipWhiteSpace()
if s.char() != ':' {
return errExpected("colon after object key", s.totalOffset())
}
s.cursor++
if s.char() == nul {
if !s.read() {
return errExpected("object value after colon", s.totalOffset())
}
}
if field != nil {
if field.err != nil {
return field.err
}
if err := field.dec.decodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
return err
}
} else if s.disallowUnknownFields {
return fmt.Errorf("json: unknown field %q", key)
} else {
if err := s.skipValue(depth); err != nil {
return err
}
}
s.skipWhiteSpace()
c := s.char()
if c == '}' {
s.cursor++
return nil
}
if c != ',' {
return errExpected("comma after object element", s.totalOffset())
}
s.cursor++
}
}
func (d *structDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) {
depth++
if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor)
}
buflen := int64(len(buf))
cursor = skipWhiteSpace(buf, cursor)
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
switch char(b, cursor) {
case 'n':
if err := validateNull(buf, cursor); err != nil {
return 0, err
}
cursor += 4
return cursor, nil
case '{':
default:
return 0, errNotAtBeginningOfValue(cursor)
}
cursor++
cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == '}' {
cursor++
return cursor, nil
}
for {
c, field, err := d.keyDecoder(d, buf, cursor)
if err != nil {
return 0, err
}
cursor = skipWhiteSpace(buf, c)
if char(b, cursor) != ':' {
return 0, errExpected("colon after object key", cursor)
}
cursor++
if cursor >= buflen {
return 0, errExpected("object value after colon", cursor)
}
if field != nil {
if field.err != nil {
return 0, field.err
}
c, err := field.dec.decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+field.offset))
if err != nil {
return 0, err
}
cursor = c
} else {
c, err := skipValue(buf, cursor, depth)
if err != nil {
return 0, err
}
cursor = c
}
cursor = skipWhiteSpace(buf, cursor)
if char(b, cursor) == '}' {
cursor++
return cursor, nil
}
if char(b, cursor) != ',' {
return 0, errExpected("comma after object element", cursor)
}
cursor++
}
}

View file

@ -1,72 +0,0 @@
package json
import (
"unsafe"
)
type unmarshalJSONDecoder struct {
typ *rtype
structName string
fieldName string
}
func newUnmarshalJSONDecoder(typ *rtype, structName, fieldName string) *unmarshalJSONDecoder {
return &unmarshalJSONDecoder{
typ: typ,
structName: structName,
fieldName: fieldName,
}
}
func (d *unmarshalJSONDecoder) annotateError(cursor int64, err error) {
switch e := err.(type) {
case *UnmarshalTypeError:
e.Struct = d.structName
e.Field = d.fieldName
case *SyntaxError:
e.Offset = cursor
}
}
func (d *unmarshalJSONDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error {
s.skipWhiteSpace()
start := s.cursor
if err := s.skipValue(depth); err != nil {
return err
}
src := s.buf[start:s.cursor]
dst := make([]byte, len(src))
copy(dst, src)
v := *(*interface{})(unsafe.Pointer(&emptyInterface{
typ: d.typ,
ptr: p,
}))
if err := v.(Unmarshaler).UnmarshalJSON(dst); err != nil {
d.annotateError(s.cursor, err)
return err
}
return nil
}
func (d *unmarshalJSONDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) {
cursor = skipWhiteSpace(buf, cursor)
start := cursor
end, err := skipValue(buf, cursor, depth)
if err != nil {
return 0, err
}
src := buf[start:end]
dst := make([]byte, len(src))
copy(dst, src)
v := *(*interface{})(unsafe.Pointer(&emptyInterface{
typ: d.typ,
ptr: p,
}))
if err := v.(Unmarshaler).UnmarshalJSON(dst); err != nil {
d.annotateError(cursor, err)
return 0, err
}
return end, nil
}

View file

@ -1,13 +1,14 @@
package json package json
import ( import (
"context"
"io" "io"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/encoder" "github.com/goccy/go-json/internal/encoder"
"github.com/goccy/go-json/internal/encoder/vm" "github.com/goccy/go-json/internal/encoder/vm"
"github.com/goccy/go-json/internal/encoder/vm_escaped" "github.com/goccy/go-json/internal/encoder/vm_color"
"github.com/goccy/go-json/internal/encoder/vm_escaped_indent" "github.com/goccy/go-json/internal/encoder/vm_color_indent"
"github.com/goccy/go-json/internal/encoder/vm_indent" "github.com/goccy/go-json/internal/encoder/vm_indent"
) )
@ -20,15 +21,6 @@ type Encoder struct {
indentStr string indentStr string
} }
type EncodeOption int
const (
EncodeOptionHTMLEscape EncodeOption = 1 << iota
EncodeOptionIndent
EncodeOptionUnorderedMap
EncodeOptionDebug
)
// NewEncoder returns a new encoder that writes to w. // NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder { func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w, enabledHTMLEscape: true} return &Encoder{w: w, enabledHTMLEscape: true}
@ -44,6 +36,7 @@ func (e *Encoder) Encode(v interface{}) error {
// EncodeWithOption call Encode with EncodeOption. // EncodeWithOption call Encode with EncodeOption.
func (e *Encoder) EncodeWithOption(v interface{}, optFuncs ...EncodeOptionFunc) error { func (e *Encoder) EncodeWithOption(v interface{}, optFuncs ...EncodeOptionFunc) error {
ctx := encoder.TakeRuntimeContext() ctx := encoder.TakeRuntimeContext()
ctx.Option.Flag = 0
err := e.encodeWithOption(ctx, v, optFuncs...) err := e.encodeWithOption(ctx, v, optFuncs...)
@ -51,22 +44,34 @@ func (e *Encoder) EncodeWithOption(v interface{}, optFuncs ...EncodeOptionFunc)
return err return err
} }
// EncodeContext call Encode with context.Context and EncodeOption.
func (e *Encoder) EncodeContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) error {
rctx := encoder.TakeRuntimeContext()
rctx.Option.Flag = 0
rctx.Option.Flag |= encoder.ContextOption
rctx.Option.Context = ctx
err := e.encodeWithOption(rctx, v, optFuncs...)
encoder.ReleaseRuntimeContext(rctx)
return err
}
func (e *Encoder) encodeWithOption(ctx *encoder.RuntimeContext, v interface{}, optFuncs ...EncodeOptionFunc) error { func (e *Encoder) encodeWithOption(ctx *encoder.RuntimeContext, v interface{}, optFuncs ...EncodeOptionFunc) error {
var opt EncodeOption
if e.enabledHTMLEscape { if e.enabledHTMLEscape {
opt |= EncodeOptionHTMLEscape ctx.Option.Flag |= encoder.HTMLEscapeOption
} }
for _, optFunc := range optFuncs { for _, optFunc := range optFuncs {
opt = optFunc(opt) optFunc(ctx.Option)
} }
var ( var (
buf []byte buf []byte
err error err error
) )
if e.enabledIndent { if e.enabledIndent {
buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr, opt) buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr)
} else { } else {
buf, err = encode(ctx, v, opt) buf, err = encode(ctx, v)
} }
if err != nil { if err != nil {
return err return err
@ -103,10 +108,43 @@ func (e *Encoder) SetIndent(prefix, indent string) {
e.enabledIndent = true e.enabledIndent = true
} }
func marshal(v interface{}, opt EncodeOption) ([]byte, error) { func marshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
rctx := encoder.TakeRuntimeContext()
rctx.Option.Flag = 0
rctx.Option.Flag = encoder.HTMLEscapeOption | encoder.ContextOption
rctx.Option.Context = ctx
for _, optFunc := range optFuncs {
optFunc(rctx.Option)
}
buf, err := encode(rctx, v)
if err != nil {
encoder.ReleaseRuntimeContext(rctx)
return nil, err
}
// this line exists to escape call of `runtime.makeslicecopy` .
// if use `make([]byte, len(buf)-1)` and `copy(copied, buf)`,
// dst buffer size and src buffer size are differrent.
// in this case, compiler uses `runtime.makeslicecopy`, but it is slow.
buf = buf[:len(buf)-1]
copied := make([]byte, len(buf))
copy(copied, buf)
encoder.ReleaseRuntimeContext(rctx)
return copied, nil
}
func marshal(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
ctx := encoder.TakeRuntimeContext() ctx := encoder.TakeRuntimeContext()
buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape) ctx.Option.Flag = 0
ctx.Option.Flag |= encoder.HTMLEscapeOption
for _, optFunc := range optFuncs {
optFunc(ctx.Option)
}
buf, err := encode(ctx, v)
if err != nil { if err != nil {
encoder.ReleaseRuntimeContext(ctx) encoder.ReleaseRuntimeContext(ctx)
return nil, err return nil, err
@ -124,10 +162,13 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
return copied, nil return copied, nil
} }
func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) { func marshalNoEscape(v interface{}) ([]byte, error) {
ctx := encoder.TakeRuntimeContext() ctx := encoder.TakeRuntimeContext()
buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape) ctx.Option.Flag = 0
ctx.Option.Flag |= encoder.HTMLEscapeOption
buf, err := encodeNoEscape(ctx, v)
if err != nil { if err != nil {
encoder.ReleaseRuntimeContext(ctx) encoder.ReleaseRuntimeContext(ctx)
return nil, err return nil, err
@ -145,10 +186,16 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
return copied, nil return copied, nil
} }
func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) { func marshalIndent(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) {
ctx := encoder.TakeRuntimeContext() ctx := encoder.TakeRuntimeContext()
buf, err := encodeIndent(ctx, v, prefix, indent, opt|EncodeOptionHTMLEscape) ctx.Option.Flag = 0
ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.IndentOption)
for _, optFunc := range optFuncs {
optFunc(ctx.Option)
}
buf, err := encodeIndent(ctx, v, prefix, indent)
if err != nil { if err != nil {
encoder.ReleaseRuntimeContext(ctx) encoder.ReleaseRuntimeContext(ctx)
return nil, err return nil, err
@ -162,11 +209,11 @@ func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]by
return copied, nil return copied, nil
} }
func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { func encode(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
b := ctx.Buf[:0] b := ctx.Buf[:0]
if v == nil { if v == nil {
b = encoder.AppendNull(b) b = encoder.AppendNull(ctx, b)
b = encoder.AppendComma(b) b = encoder.AppendComma(ctx, b)
return b, nil return b, nil
} }
header := (*emptyInterface)(unsafe.Pointer(&v)) header := (*emptyInterface)(unsafe.Pointer(&v))
@ -182,7 +229,7 @@ func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byt
ctx.Init(p, codeSet.CodeLength) ctx.Init(p, codeSet.CodeLength)
ctx.KeepRefs = append(ctx.KeepRefs, header.ptr) ctx.KeepRefs = append(ctx.KeepRefs, header.ptr)
buf, err := encodeRunCode(ctx, b, codeSet, opt) buf, err := encodeRunCode(ctx, b, codeSet)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -190,11 +237,11 @@ func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byt
return buf, nil return buf, nil
} }
func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) { func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
b := ctx.Buf[:0] b := ctx.Buf[:0]
if v == nil { if v == nil {
b = encoder.AppendNull(b) b = encoder.AppendNull(ctx, b)
b = encoder.AppendComma(b) b = encoder.AppendComma(ctx, b)
return b, nil return b, nil
} }
header := (*emptyInterface)(unsafe.Pointer(&v)) header := (*emptyInterface)(unsafe.Pointer(&v))
@ -208,7 +255,7 @@ func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption
p := uintptr(header.ptr) p := uintptr(header.ptr)
ctx.Init(p, codeSet.CodeLength) ctx.Init(p, codeSet.CodeLength)
buf, err := encodeRunCode(ctx, b, codeSet, opt) buf, err := encodeRunCode(ctx, b, codeSet)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -217,11 +264,11 @@ func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption
return buf, nil return buf, nil
} }
func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent string, opt EncodeOption) ([]byte, error) { func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent string) ([]byte, error) {
b := ctx.Buf[:0] b := ctx.Buf[:0]
if v == nil { if v == nil {
b = encoder.AppendNull(b) b = encoder.AppendNull(ctx, b)
b = encoder.AppendCommaIndent(b) b = encoder.AppendCommaIndent(ctx, b)
return b, nil return b, nil
} }
header := (*emptyInterface)(unsafe.Pointer(&v)) header := (*emptyInterface)(unsafe.Pointer(&v))
@ -235,7 +282,7 @@ func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent str
p := uintptr(header.ptr) p := uintptr(header.ptr)
ctx.Init(p, codeSet.CodeLength) ctx.Init(p, codeSet.CodeLength)
buf, err := encodeRunIndentCode(ctx, b, codeSet, prefix, indent, opt) buf, err := encodeRunIndentCode(ctx, b, codeSet, prefix, indent)
ctx.KeepRefs = append(ctx.KeepRefs, header.ptr) ctx.KeepRefs = append(ctx.KeepRefs, header.ptr)
@ -247,38 +294,30 @@ func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent str
return buf, nil return buf, nil
} }
func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) { func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
if (opt & EncodeOptionDebug) != 0 { if (ctx.Option.Flag & encoder.DebugOption) != 0 {
return encodeDebugRunCode(ctx, b, codeSet, opt) if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
return vm_color.DebugRun(ctx, b, codeSet)
} }
if (opt & EncodeOptionHTMLEscape) != 0 { return vm.DebugRun(ctx, b, codeSet)
return vm_escaped.Run(ctx, b, codeSet, encoder.Option(opt))
} }
return vm.Run(ctx, b, codeSet, encoder.Option(opt)) if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
return vm_color.Run(ctx, b, codeSet)
}
return vm.Run(ctx, b, codeSet)
} }
func encodeDebugRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) { func encodeRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, prefix, indent string) ([]byte, error) {
if (opt & EncodeOptionHTMLEscape) != 0 {
return vm_escaped.DebugRun(ctx, b, codeSet, encoder.Option(opt))
}
return vm.DebugRun(ctx, b, codeSet, encoder.Option(opt))
}
func encodeRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, prefix, indent string, opt EncodeOption) ([]byte, error) {
ctx.Prefix = []byte(prefix) ctx.Prefix = []byte(prefix)
ctx.IndentStr = []byte(indent) ctx.IndentStr = []byte(indent)
if (opt & EncodeOptionDebug) != 0 { if (ctx.Option.Flag & encoder.DebugOption) != 0 {
return encodeDebugRunIndentCode(ctx, b, codeSet, opt) if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
return vm_color_indent.DebugRun(ctx, b, codeSet)
} }
if (opt & EncodeOptionHTMLEscape) != 0 { return vm_indent.DebugRun(ctx, b, codeSet)
return vm_escaped_indent.Run(ctx, b, codeSet, encoder.Option(opt))
} }
return vm_indent.Run(ctx, b, codeSet, encoder.Option(opt)) if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
return vm_color_indent.Run(ctx, b, codeSet)
} }
return vm_indent.Run(ctx, b, codeSet)
func encodeDebugRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
if (opt & EncodeOptionHTMLEscape) != 0 {
return vm_escaped_indent.DebugRun(ctx, b, codeSet, encoder.Option(opt))
}
return vm_indent.DebugRun(ctx, b, codeSet, encoder.Option(opt))
} }

View file

@ -37,13 +37,3 @@
type UnsupportedTypeError = errors.UnsupportedTypeError type UnsupportedTypeError = errors.UnsupportedTypeError
type UnsupportedValueError = errors.UnsupportedValueError type UnsupportedValueError = errors.UnsupportedValueError
var (
errExceededMaxDepth = errors.ErrExceededMaxDepth
errNotAtBeginningOfValue = errors.ErrNotAtBeginningOfValue
errUnexpectedEndOfJSON = errors.ErrUnexpectedEndOfJSON
errExpected = errors.ErrExpected
errInvalidCharacter = errors.ErrInvalidCharacter
errSyntax = errors.ErrSyntax
errMarshaler = errors.ErrMarshaler
)

View file

@ -1,3 +0,0 @@
module github.com/goccy/go-json
go 1.12

View file

View file

@ -0,0 +1,37 @@
package decoder
import (
"unsafe"
"github.com/goccy/go-json/internal/runtime"
)
type anonymousFieldDecoder struct {
structType *runtime.Type
offset uintptr
dec Decoder
}
func newAnonymousFieldDecoder(structType *runtime.Type, offset uintptr, dec Decoder) *anonymousFieldDecoder {
return &anonymousFieldDecoder{
structType: structType,
offset: offset,
dec: dec,
}
}
func (d *anonymousFieldDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe_New(d.structType)
}
p = *(*unsafe.Pointer)(p)
return d.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+d.offset))
}
func (d *anonymousFieldDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe_New(d.structType)
}
p = *(*unsafe.Pointer)(p)
return d.dec.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+d.offset))
}

View file

@ -1,20 +1,23 @@
package json package decoder
import ( import (
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
) )
type arrayDecoder struct { type arrayDecoder struct {
elemType *rtype elemType *runtime.Type
size uintptr size uintptr
valueDecoder decoder valueDecoder Decoder
alen int alen int
structName string structName string
fieldName string fieldName string
zeroValue unsafe.Pointer zeroValue unsafe.Pointer
} }
func newArrayDecoder(dec decoder, elemType *rtype, alen int, structName, fieldName string) *arrayDecoder { func newArrayDecoder(dec Decoder, elemType *runtime.Type, alen int, structName, fieldName string) *arrayDecoder {
zeroValue := *(*unsafe.Pointer)(unsafe_New(elemType)) zeroValue := *(*unsafe.Pointer)(unsafe_New(elemType))
return &arrayDecoder{ return &arrayDecoder{
valueDecoder: dec, valueDecoder: dec,
@ -27,10 +30,10 @@ func newArrayDecoder(dec decoder, elemType *rtype, alen int, structName, fieldNa
} }
} }
func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *arrayDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor) return errors.ErrExceededMaxDepth(s.char(), s.cursor)
} }
for { for {
@ -43,10 +46,18 @@ func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
return nil return nil
case '[': case '[':
idx := 0 idx := 0
for {
s.cursor++ s.cursor++
if s.skipWhiteSpace() == ']' {
for idx < d.alen {
*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
idx++
}
s.cursor++
return nil
}
for {
if idx < d.alen { if idx < d.alen {
if err := d.valueDecoder.decodeStream(s, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)); err != nil { if err := d.valueDecoder.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)); err != nil {
return err return err
} }
} else { } else {
@ -55,8 +66,7 @@ func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
} }
} }
idx++ idx++
s.skipWhiteSpace() switch s.skipWhiteSpace() {
switch s.char() {
case ']': case ']':
for idx < d.alen { for idx < d.alen {
*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue *(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
@ -65,9 +75,11 @@ func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
s.cursor++ s.cursor++
return nil return nil
case ',': case ',':
s.cursor++
continue continue
case nul: case nul:
if s.read() { if s.read() {
s.cursor++
continue continue
} }
goto ERROR goto ERROR
@ -86,13 +98,14 @@ func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
s.cursor++ s.cursor++
} }
ERROR: ERROR:
return errUnexpectedEndOfJSON("array", s.totalOffset()) return errors.ErrUnexpectedEndOfJSON("array", s.totalOffset())
} }
func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *arrayDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor) return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
} }
for { for {
@ -108,10 +121,19 @@ func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
return cursor, nil return cursor, nil
case '[': case '[':
idx := 0 idx := 0
for {
cursor++ cursor++
cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == ']' {
for idx < d.alen {
*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
idx++
}
cursor++
return cursor, nil
}
for {
if idx < d.alen { if idx < d.alen {
c, err := d.valueDecoder.decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)) c, err := d.valueDecoder.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size))
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -134,13 +156,14 @@ func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
cursor++ cursor++
return cursor, nil return cursor, nil
case ',': case ',':
cursor++
continue continue
default: default:
return 0, errInvalidCharacter(buf[cursor], "array", cursor) return 0, errors.ErrInvalidCharacter(buf[cursor], "array", cursor)
} }
} }
default: default:
return 0, errUnexpectedEndOfJSON("array", cursor) return 0, errors.ErrUnexpectedEndOfJSON("array", cursor)
} }
} }
} }

View file

@ -1,7 +1,9 @@
package json package decoder
import ( import (
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
) )
type boolDecoder struct { type boolDecoder struct {
@ -13,10 +15,10 @@ func newBoolDecoder(structName, fieldName string) *boolDecoder {
return &boolDecoder{structName: structName, fieldName: fieldName} return &boolDecoder{structName: structName, fieldName: fieldName}
} }
func (d *boolDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *boolDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
s.skipWhiteSpace() c := s.skipWhiteSpace()
for { for {
switch s.char() { switch c {
case 't': case 't':
if err := trueBytes(s); err != nil { if err := trueBytes(s); err != nil {
return err return err
@ -36,6 +38,7 @@ func (d *boolDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) err
return nil return nil
case nul: case nul:
if s.read() { if s.read() {
c = s.char()
continue continue
} }
goto ERROR goto ERROR
@ -43,10 +46,11 @@ func (d *boolDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) err
break break
} }
ERROR: ERROR:
return errUnexpectedEndOfJSON("bool", s.totalOffset()) return errors.ErrUnexpectedEndOfJSON("bool", s.totalOffset())
} }
func (d *boolDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *boolDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
switch buf[cursor] { switch buf[cursor] {
case 't': case 't':
@ -70,5 +74,5 @@ func (d *boolDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
cursor += 4 cursor += 4
return cursor, nil return cursor, nil
} }
return 0, errUnexpectedEndOfJSON("bool", cursor) return 0, errors.ErrUnexpectedEndOfJSON("bool", cursor)
} }

View file

@ -0,0 +1,114 @@
package decoder
import (
"encoding/base64"
"unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
)
type bytesDecoder struct {
typ *runtime.Type
sliceDecoder Decoder
stringDecoder *stringDecoder
structName string
fieldName string
}
func byteUnmarshalerSliceDecoder(typ *runtime.Type, structName string, fieldName string) Decoder {
var unmarshalDecoder Decoder
switch {
case runtime.PtrTo(typ).Implements(unmarshalJSONType):
unmarshalDecoder = newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName)
case runtime.PtrTo(typ).Implements(unmarshalTextType):
unmarshalDecoder = newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName)
}
if unmarshalDecoder == nil {
return nil
}
return newSliceDecoder(unmarshalDecoder, typ, 1, structName, fieldName)
}
func newBytesDecoder(typ *runtime.Type, structName string, fieldName string) *bytesDecoder {
return &bytesDecoder{
typ: typ,
sliceDecoder: byteUnmarshalerSliceDecoder(typ, structName, fieldName),
stringDecoder: newStringDecoder(structName, fieldName),
structName: structName,
fieldName: fieldName,
}
}
func (d *bytesDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
bytes, err := d.decodeStreamBinary(s, depth, p)
if err != nil {
return err
}
if bytes == nil {
s.reset()
return nil
}
decodedLen := base64.StdEncoding.DecodedLen(len(bytes))
buf := make([]byte, decodedLen)
n, err := base64.StdEncoding.Decode(buf, bytes)
if err != nil {
return err
}
*(*[]byte)(p) = buf[:n]
s.reset()
return nil
}
func (d *bytesDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
bytes, c, err := d.decodeBinary(ctx, cursor, depth, p)
if err != nil {
return 0, err
}
if bytes == nil {
return c, nil
}
cursor = c
decodedLen := base64.StdEncoding.DecodedLen(len(bytes))
b := make([]byte, decodedLen)
n, err := base64.StdEncoding.Decode(b, bytes)
if err != nil {
return 0, err
}
*(*[]byte)(p) = b[:n]
return cursor, nil
}
func (d *bytesDecoder) decodeStreamBinary(s *Stream, depth int64, p unsafe.Pointer) ([]byte, error) {
c := s.skipWhiteSpace()
if c == '[' {
if d.sliceDecoder == nil {
return nil, &errors.UnmarshalTypeError{
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
}
}
err := d.sliceDecoder.DecodeStream(s, depth, p)
return nil, err
}
return d.stringDecoder.decodeStreamByte(s)
}
func (d *bytesDecoder) decodeBinary(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) ([]byte, int64, error) {
buf := ctx.Buf
cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == '[' {
if d.sliceDecoder == nil {
return nil, 0, &errors.UnmarshalTypeError{
Type: runtime.RType2Type(d.typ),
Offset: cursor,
}
}
c, err := d.sliceDecoder.Decode(ctx, cursor, depth, p)
if err != nil {
return nil, 0, err
}
return nil, c, nil
}
return d.stringDecoder.decodeByte(buf, cursor)
}

View file

@ -1,27 +1,56 @@
package json package decoder
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
"sync/atomic"
"unicode" "unicode"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime" "github.com/goccy/go-json/internal/runtime"
) )
var ( var (
jsonNumberType = reflect.TypeOf(json.Number("")) jsonNumberType = reflect.TypeOf(json.Number(""))
typeAddr *runtime.TypeAddr
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
cachedDecoder []Decoder
) )
func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, error) { func init() {
typeAddr = runtime.AnalyzeTypeAddr()
if typeAddr == nil {
typeAddr = &runtime.TypeAddr{}
}
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift)
}
func loadDecoderMap() map[uintptr]Decoder {
p := atomic.LoadPointer(&cachedDecoderMap)
return *(*map[uintptr]Decoder)(unsafe.Pointer(&p))
}
func storeDecoder(typ uintptr, dec Decoder, m map[uintptr]Decoder) {
newDecoderMap := make(map[uintptr]Decoder, len(m)+1)
newDecoderMap[typ] = dec
for k, v := range m {
newDecoderMap[k] = v
}
atomic.StorePointer(&cachedDecoderMap, *(*unsafe.Pointer)(unsafe.Pointer(&newDecoderMap)))
}
func compileToGetDecoderSlowPath(typeptr uintptr, typ *runtime.Type) (Decoder, error) {
decoderMap := loadDecoderMap() decoderMap := loadDecoderMap()
if dec, exists := decoderMap[typeptr]; exists { if dec, exists := decoderMap[typeptr]; exists {
return dec, nil return dec, nil
} }
dec, err := decodeCompileHead(typ, map[uintptr]decoder{}) dec, err := compileHead(typ, map[uintptr]Decoder{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -29,84 +58,88 @@ func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, er
return dec, nil return dec, nil
} }
func decodeCompileHead(typ *rtype, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compileHead(typ *runtime.Type, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
switch { switch {
case rtype_ptrTo(typ).Implements(unmarshalJSONType): case implementsUnmarshalJSONType(runtime.PtrTo(typ)):
return newUnmarshalJSONDecoder(rtype_ptrTo(typ), "", ""), nil return newUnmarshalJSONDecoder(runtime.PtrTo(typ), "", ""), nil
case rtype_ptrTo(typ).Implements(unmarshalTextType): case runtime.PtrTo(typ).Implements(unmarshalTextType):
return newUnmarshalTextDecoder(rtype_ptrTo(typ), "", ""), nil return newUnmarshalTextDecoder(runtime.PtrTo(typ), "", ""), nil
} }
return decodeCompile(typ.Elem(), "", "", structTypeToDecoder) return compile(typ.Elem(), "", "", structTypeToDecoder)
} }
func decodeCompile(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compile(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
switch { switch {
case rtype_ptrTo(typ).Implements(unmarshalJSONType): case implementsUnmarshalJSONType(runtime.PtrTo(typ)):
return newUnmarshalJSONDecoder(rtype_ptrTo(typ), structName, fieldName), nil return newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName), nil
case rtype_ptrTo(typ).Implements(unmarshalTextType): case runtime.PtrTo(typ).Implements(unmarshalTextType):
return newUnmarshalTextDecoder(rtype_ptrTo(typ), structName, fieldName), nil return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil
} }
switch typ.Kind() { switch typ.Kind() {
case reflect.Ptr: case reflect.Ptr:
return decodeCompilePtr(typ, structName, fieldName, structTypeToDecoder) return compilePtr(typ, structName, fieldName, structTypeToDecoder)
case reflect.Struct: case reflect.Struct:
return decodeCompileStruct(typ, structName, fieldName, structTypeToDecoder) return compileStruct(typ, structName, fieldName, structTypeToDecoder)
case reflect.Slice: case reflect.Slice:
elem := typ.Elem() elem := typ.Elem()
if elem.Kind() == reflect.Uint8 { if elem.Kind() == reflect.Uint8 {
return decodeCompileBytes(elem, structName, fieldName) return compileBytes(elem, structName, fieldName)
} }
return decodeCompileSlice(typ, structName, fieldName, structTypeToDecoder) return compileSlice(typ, structName, fieldName, structTypeToDecoder)
case reflect.Array: case reflect.Array:
return decodeCompileArray(typ, structName, fieldName, structTypeToDecoder) return compileArray(typ, structName, fieldName, structTypeToDecoder)
case reflect.Map: case reflect.Map:
return decodeCompileMap(typ, structName, fieldName, structTypeToDecoder) return compileMap(typ, structName, fieldName, structTypeToDecoder)
case reflect.Interface: case reflect.Interface:
return decodeCompileInterface(typ, structName, fieldName) return compileInterface(typ, structName, fieldName)
case reflect.Uintptr: case reflect.Uintptr:
return decodeCompileUint(typ, structName, fieldName) return compileUint(typ, structName, fieldName)
case reflect.Int: case reflect.Int:
return decodeCompileInt(typ, structName, fieldName) return compileInt(typ, structName, fieldName)
case reflect.Int8: case reflect.Int8:
return decodeCompileInt8(typ, structName, fieldName) return compileInt8(typ, structName, fieldName)
case reflect.Int16: case reflect.Int16:
return decodeCompileInt16(typ, structName, fieldName) return compileInt16(typ, structName, fieldName)
case reflect.Int32: case reflect.Int32:
return decodeCompileInt32(typ, structName, fieldName) return compileInt32(typ, structName, fieldName)
case reflect.Int64: case reflect.Int64:
return decodeCompileInt64(typ, structName, fieldName) return compileInt64(typ, structName, fieldName)
case reflect.Uint: case reflect.Uint:
return decodeCompileUint(typ, structName, fieldName) return compileUint(typ, structName, fieldName)
case reflect.Uint8: case reflect.Uint8:
return decodeCompileUint8(typ, structName, fieldName) return compileUint8(typ, structName, fieldName)
case reflect.Uint16: case reflect.Uint16:
return decodeCompileUint16(typ, structName, fieldName) return compileUint16(typ, structName, fieldName)
case reflect.Uint32: case reflect.Uint32:
return decodeCompileUint32(typ, structName, fieldName) return compileUint32(typ, structName, fieldName)
case reflect.Uint64: case reflect.Uint64:
return decodeCompileUint64(typ, structName, fieldName) return compileUint64(typ, structName, fieldName)
case reflect.String: case reflect.String:
return decodeCompileString(typ, structName, fieldName) return compileString(typ, structName, fieldName)
case reflect.Bool: case reflect.Bool:
return decodeCompileBool(structName, fieldName) return compileBool(structName, fieldName)
case reflect.Float32: case reflect.Float32:
return decodeCompileFloat32(structName, fieldName) return compileFloat32(structName, fieldName)
case reflect.Float64: case reflect.Float64:
return decodeCompileFloat64(structName, fieldName) return compileFloat64(structName, fieldName)
case reflect.Func:
return compileFunc(typ, structName, fieldName)
} }
return nil, &UnmarshalTypeError{ return nil, &errors.UnmarshalTypeError{
Value: "object", Value: "object",
Type: rtype2type(typ), Type: runtime.RType2Type(typ),
Offset: 0, Offset: 0,
Struct: structName,
Field: fieldName,
} }
} }
func isStringTagSupportedType(typ *rtype) bool { func isStringTagSupportedType(typ *runtime.Type) bool {
switch { switch {
case rtype_ptrTo(typ).Implements(unmarshalJSONType): case implementsUnmarshalJSONType(runtime.PtrTo(typ)):
return false return false
case rtype_ptrTo(typ).Implements(unmarshalTextType): case runtime.PtrTo(typ).Implements(unmarshalTextType):
return false return false
} }
switch typ.Kind() { switch typ.Kind() {
@ -124,11 +157,11 @@ func isStringTagSupportedType(typ *rtype) bool {
return true return true
} }
func decodeCompileMapKey(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compileMapKey(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
if rtype_ptrTo(typ).Implements(unmarshalTextType) { if runtime.PtrTo(typ).Implements(unmarshalTextType) {
return newUnmarshalTextDecoder(rtype_ptrTo(typ), structName, fieldName), nil return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil
} }
dec, err := decodeCompile(typ, structName, fieldName, structTypeToDecoder) dec, err := compile(typ, structName, fieldName, structTypeToDecoder)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -145,145 +178,151 @@ func decodeCompileMapKey(typ *rtype, structName, fieldName string, structTypeToD
} }
} }
ERROR: ERROR:
return nil, &UnmarshalTypeError{ return nil, &errors.UnmarshalTypeError{
Value: "object", Value: "object",
Type: rtype2type(typ), Type: runtime.RType2Type(typ),
Offset: 0, Offset: 0,
Struct: structName,
Field: fieldName,
} }
} }
func decodeCompilePtr(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compilePtr(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
dec, err := decodeCompile(typ.Elem(), structName, fieldName, structTypeToDecoder) dec, err := compile(typ.Elem(), structName, fieldName, structTypeToDecoder)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newPtrDecoder(dec, typ.Elem(), structName, fieldName), nil return newPtrDecoder(dec, typ.Elem(), structName, fieldName), nil
} }
func decodeCompileInt(typ *rtype, structName, fieldName string) (decoder, error) { func compileInt(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
*(*int)(p) = int(v) *(*int)(p) = int(v)
}), nil }), nil
} }
func decodeCompileInt8(typ *rtype, structName, fieldName string) (decoder, error) { func compileInt8(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
*(*int8)(p) = int8(v) *(*int8)(p) = int8(v)
}), nil }), nil
} }
func decodeCompileInt16(typ *rtype, structName, fieldName string) (decoder, error) { func compileInt16(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
*(*int16)(p) = int16(v) *(*int16)(p) = int16(v)
}), nil }), nil
} }
func decodeCompileInt32(typ *rtype, structName, fieldName string) (decoder, error) { func compileInt32(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
*(*int32)(p) = int32(v) *(*int32)(p) = int32(v)
}), nil }), nil
} }
func decodeCompileInt64(typ *rtype, structName, fieldName string) (decoder, error) { func compileInt64(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
*(*int64)(p) = v *(*int64)(p) = v
}), nil }), nil
} }
func decodeCompileUint(typ *rtype, structName, fieldName string) (decoder, error) { func compileUint(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
*(*uint)(p) = uint(v) *(*uint)(p) = uint(v)
}), nil }), nil
} }
func decodeCompileUint8(typ *rtype, structName, fieldName string) (decoder, error) { func compileUint8(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
*(*uint8)(p) = uint8(v) *(*uint8)(p) = uint8(v)
}), nil }), nil
} }
func decodeCompileUint16(typ *rtype, structName, fieldName string) (decoder, error) { func compileUint16(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
*(*uint16)(p) = uint16(v) *(*uint16)(p) = uint16(v)
}), nil }), nil
} }
func decodeCompileUint32(typ *rtype, structName, fieldName string) (decoder, error) { func compileUint32(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
*(*uint32)(p) = uint32(v) *(*uint32)(p) = uint32(v)
}), nil }), nil
} }
func decodeCompileUint64(typ *rtype, structName, fieldName string) (decoder, error) { func compileUint64(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
*(*uint64)(p) = v *(*uint64)(p) = v
}), nil }), nil
} }
func decodeCompileFloat32(structName, fieldName string) (decoder, error) { func compileFloat32(structName, fieldName string) (Decoder, error) {
return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
*(*float32)(p) = float32(v) *(*float32)(p) = float32(v)
}), nil }), nil
} }
func decodeCompileFloat64(structName, fieldName string) (decoder, error) { func compileFloat64(structName, fieldName string) (Decoder, error) {
return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
*(*float64)(p) = v *(*float64)(p) = v
}), nil }), nil
} }
func decodeCompileString(typ *rtype, structName, fieldName string) (decoder, error) { func compileString(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
if typ == type2rtype(jsonNumberType) { if typ == runtime.Type2RType(jsonNumberType) {
return newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v Number) { return newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
*(*Number)(p) = v *(*json.Number)(p) = v
}), nil }), nil
} }
return newStringDecoder(structName, fieldName), nil return newStringDecoder(structName, fieldName), nil
} }
func decodeCompileBool(structName, fieldName string) (decoder, error) { func compileBool(structName, fieldName string) (Decoder, error) {
return newBoolDecoder(structName, fieldName), nil return newBoolDecoder(structName, fieldName), nil
} }
func decodeCompileBytes(typ *rtype, structName, fieldName string) (decoder, error) { func compileBytes(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newBytesDecoder(typ, structName, fieldName), nil return newBytesDecoder(typ, structName, fieldName), nil
} }
func decodeCompileSlice(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compileSlice(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
elem := typ.Elem() elem := typ.Elem()
decoder, err := decodeCompile(elem, structName, fieldName, structTypeToDecoder) decoder, err := compile(elem, structName, fieldName, structTypeToDecoder)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newSliceDecoder(decoder, elem, elem.Size(), structName, fieldName), nil return newSliceDecoder(decoder, elem, elem.Size(), structName, fieldName), nil
} }
func decodeCompileArray(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compileArray(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
elem := typ.Elem() elem := typ.Elem()
decoder, err := decodeCompile(elem, structName, fieldName, structTypeToDecoder) decoder, err := compile(elem, structName, fieldName, structTypeToDecoder)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newArrayDecoder(decoder, elem, typ.Len(), structName, fieldName), nil return newArrayDecoder(decoder, elem, typ.Len(), structName, fieldName), nil
} }
func decodeCompileMap(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compileMap(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
keyDec, err := decodeCompileMapKey(typ.Key(), structName, fieldName, structTypeToDecoder) keyDec, err := compileMapKey(typ.Key(), structName, fieldName, structTypeToDecoder)
if err != nil { if err != nil {
return nil, err return nil, err
} }
valueDec, err := decodeCompile(typ.Elem(), structName, fieldName, structTypeToDecoder) valueDec, err := compile(typ.Elem(), structName, fieldName, structTypeToDecoder)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newMapDecoder(typ, typ.Key(), keyDec, typ.Elem(), valueDec, structName, fieldName), nil return newMapDecoder(typ, typ.Key(), keyDec, typ.Elem(), valueDec, structName, fieldName), nil
} }
func decodeCompileInterface(typ *rtype, structName, fieldName string) (decoder, error) { func compileInterface(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
return newInterfaceDecoder(typ, structName, fieldName), nil return newInterfaceDecoder(typ, structName, fieldName), nil
} }
func decodeRemoveConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, field reflect.StructField) { func compileFunc(typ *runtime.Type, strutName, fieldName string) (Decoder, error) {
return newFuncDecoder(typ, strutName, fieldName), nil
}
func removeConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, field reflect.StructField) {
for k, v := range dec.fieldMap { for k, v := range dec.fieldMap {
if _, exists := conflictedMap[k]; exists { if _, exists := conflictedMap[k]; exists {
// already conflicted key // already conflicted key
@ -338,7 +377,7 @@ func decodeRemoveConflictFields(fieldMap map[string]*structFieldSet, conflictedM
} }
} }
func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
fieldNum := typ.NumField() fieldNum := typ.NumField()
conflictedMap := map[string]struct{}{} conflictedMap := map[string]struct{}{}
fieldMap := map[string]*structFieldSet{} fieldMap := map[string]*structFieldSet{}
@ -356,17 +395,17 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD
} }
isUnexportedField := unicode.IsLower([]rune(field.Name)[0]) isUnexportedField := unicode.IsLower([]rune(field.Name)[0])
tag := runtime.StructTagFromField(field) tag := runtime.StructTagFromField(field)
dec, err := decodeCompile(type2rtype(field.Type), structName, field.Name, structTypeToDecoder) dec, err := compile(runtime.Type2RType(field.Type), structName, field.Name, structTypeToDecoder)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if field.Anonymous && !tag.IsTaggedKey { if field.Anonymous && !tag.IsTaggedKey {
if stDec, ok := dec.(*structDecoder); ok { if stDec, ok := dec.(*structDecoder); ok {
if type2rtype(field.Type) == typ { if runtime.Type2RType(field.Type) == typ {
// recursive definition // recursive definition
continue continue
} }
decodeRemoveConflictFields(fieldMap, conflictedMap, stDec, field) removeConflictFields(fieldMap, conflictedMap, stDec, field)
} else if pdec, ok := dec.(*ptrDecoder); ok { } else if pdec, ok := dec.(*ptrDecoder); ok {
contentDec := pdec.contentDecoder() contentDec := pdec.contentDecoder()
if pdec.typ == typ { if pdec.typ == typ {
@ -438,8 +477,8 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD
} }
} }
} else { } else {
if tag.IsString && isStringTagSupportedType(type2rtype(field.Type)) { if tag.IsString && isStringTagSupportedType(runtime.Type2RType(field.Type)) {
dec = newWrappedStringDecoder(type2rtype(field.Type), dec, structName, field.Name) dec = newWrappedStringDecoder(runtime.Type2RType(field.Type), dec, structName, field.Name)
} }
var key string var key string
if tag.Key != "" { if tag.Key != "" {
@ -465,3 +504,7 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD
structDec.tryOptimize() structDec.tryOptimize()
return structDec, nil return structDec, nil
} }
func implementsUnmarshalJSONType(typ *runtime.Type) bool {
return typ.Implements(unmarshalJSONType) || typ.Implements(unmarshalJSONContextType)
}

View file

@ -0,0 +1,28 @@
// +build !race
package decoder
import (
"unsafe"
"github.com/goccy/go-json/internal/runtime"
)
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
typeptr := uintptr(unsafe.Pointer(typ))
if typeptr > typeAddr.MaxTypeAddr {
return compileToGetDecoderSlowPath(typeptr, typ)
}
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
if dec := cachedDecoder[index]; dec != nil {
return dec, nil
}
dec, err := compileHead(typ, map[uintptr]Decoder{})
if err != nil {
return nil, err
}
cachedDecoder[index] = dec
return dec, nil
}

View file

@ -1,21 +1,23 @@
// +build race // +build race
package json package decoder
import ( import (
"sync" "sync"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/runtime"
) )
var decMu sync.RWMutex var decMu sync.RWMutex
func decodeCompileToGetDecoder(typ *rtype) (decoder, error) { func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
typeptr := uintptr(unsafe.Pointer(typ)) typeptr := uintptr(unsafe.Pointer(typ))
if typeptr > maxTypeAddr { if typeptr > typeAddr.MaxTypeAddr {
return decodeCompileToGetDecoderSlowPath(typeptr, typ) return compileToGetDecoderSlowPath(typeptr, typ)
} }
index := (typeptr - baseTypeAddr) >> typeAddrShift index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
decMu.RLock() decMu.RLock()
if dec := cachedDecoder[index]; dec != nil { if dec := cachedDecoder[index]; dec != nil {
decMu.RUnlock() decMu.RUnlock()
@ -23,7 +25,7 @@ func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
} }
decMu.RUnlock() decMu.RUnlock()
dec, err := decodeCompileHead(typ, map[uintptr]decoder{}) dec, err := compileHead(typ, map[uintptr]Decoder{})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1,9 +1,35 @@
package json package decoder
import ( import (
"sync"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
) )
type RuntimeContext struct {
Buf []byte
Option *Option
}
var (
runtimeContextPool = sync.Pool{
New: func() interface{} {
return &RuntimeContext{
Option: &Option{},
}
},
}
)
func TakeRuntimeContext() *RuntimeContext {
return runtimeContextPool.Get().(*RuntimeContext)
}
func ReleaseRuntimeContext(ctx *RuntimeContext) {
runtimeContextPool.Put(ctx)
}
var ( var (
isWhiteSpace = [256]bool{} isWhiteSpace = [256]bool{}
) )
@ -34,7 +60,7 @@ func skipObject(buf []byte, cursor, depth int64) (int64, error) {
braceCount++ braceCount++
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor) return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
} }
case '}': case '}':
depth-- depth--
@ -45,7 +71,7 @@ func skipObject(buf []byte, cursor, depth int64) (int64, error) {
case '[': case '[':
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor) return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
} }
case ']': case ']':
depth-- depth--
@ -56,16 +82,16 @@ func skipObject(buf []byte, cursor, depth int64) (int64, error) {
case '\\': case '\\':
cursor++ cursor++
if buf[cursor] == nul { if buf[cursor] == nul {
return 0, errUnexpectedEndOfJSON("string of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
case '"': case '"':
goto SWITCH_OUT goto SWITCH_OUT
case nul: case nul:
return 0, errUnexpectedEndOfJSON("string of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
} }
case nul: case nul:
return 0, errUnexpectedEndOfJSON("object of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("object of object", cursor)
} }
SWITCH_OUT: SWITCH_OUT:
cursor++ cursor++
@ -80,7 +106,7 @@ func skipArray(buf []byte, cursor, depth int64) (int64, error) {
bracketCount++ bracketCount++
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor) return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
} }
case ']': case ']':
bracketCount-- bracketCount--
@ -91,7 +117,7 @@ func skipArray(buf []byte, cursor, depth int64) (int64, error) {
case '{': case '{':
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor) return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
} }
case '}': case '}':
depth-- depth--
@ -102,16 +128,16 @@ func skipArray(buf []byte, cursor, depth int64) (int64, error) {
case '\\': case '\\':
cursor++ cursor++
if buf[cursor] == nul { if buf[cursor] == nul {
return 0, errUnexpectedEndOfJSON("string of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
case '"': case '"':
goto SWITCH_OUT goto SWITCH_OUT
case nul: case nul:
return 0, errUnexpectedEndOfJSON("string of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
} }
case nul: case nul:
return 0, errUnexpectedEndOfJSON("array of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("array of object", cursor)
} }
SWITCH_OUT: SWITCH_OUT:
cursor++ cursor++
@ -135,12 +161,12 @@ func skipValue(buf []byte, cursor, depth int64) (int64, error) {
case '\\': case '\\':
cursor++ cursor++
if buf[cursor] == nul { if buf[cursor] == nul {
return 0, errUnexpectedEndOfJSON("string of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
case '"': case '"':
return cursor + 1, nil return cursor + 1, nil
case nul: case nul:
return 0, errUnexpectedEndOfJSON("string of object", cursor) return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
} }
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
@ -171,58 +197,58 @@ func skipValue(buf []byte, cursor, depth int64) (int64, error) {
cursor += 4 cursor += 4
return cursor, nil return cursor, nil
default: default:
return cursor, errUnexpectedEndOfJSON("null", cursor) return cursor, errors.ErrUnexpectedEndOfJSON("null", cursor)
} }
} }
} }
func validateTrue(buf []byte, cursor int64) error { func validateTrue(buf []byte, cursor int64) error {
if cursor+3 >= int64(len(buf)) { if cursor+3 >= int64(len(buf)) {
return errUnexpectedEndOfJSON("true", cursor) return errors.ErrUnexpectedEndOfJSON("true", cursor)
} }
if buf[cursor+1] != 'r' { if buf[cursor+1] != 'r' {
return errInvalidCharacter(buf[cursor+1], "true", cursor) return errors.ErrInvalidCharacter(buf[cursor+1], "true", cursor)
} }
if buf[cursor+2] != 'u' { if buf[cursor+2] != 'u' {
return errInvalidCharacter(buf[cursor+2], "true", cursor) return errors.ErrInvalidCharacter(buf[cursor+2], "true", cursor)
} }
if buf[cursor+3] != 'e' { if buf[cursor+3] != 'e' {
return errInvalidCharacter(buf[cursor+3], "true", cursor) return errors.ErrInvalidCharacter(buf[cursor+3], "true", cursor)
} }
return nil return nil
} }
func validateFalse(buf []byte, cursor int64) error { func validateFalse(buf []byte, cursor int64) error {
if cursor+4 >= int64(len(buf)) { if cursor+4 >= int64(len(buf)) {
return errUnexpectedEndOfJSON("false", cursor) return errors.ErrUnexpectedEndOfJSON("false", cursor)
} }
if buf[cursor+1] != 'a' { if buf[cursor+1] != 'a' {
return errInvalidCharacter(buf[cursor+1], "false", cursor) return errors.ErrInvalidCharacter(buf[cursor+1], "false", cursor)
} }
if buf[cursor+2] != 'l' { if buf[cursor+2] != 'l' {
return errInvalidCharacter(buf[cursor+2], "false", cursor) return errors.ErrInvalidCharacter(buf[cursor+2], "false", cursor)
} }
if buf[cursor+3] != 's' { if buf[cursor+3] != 's' {
return errInvalidCharacter(buf[cursor+3], "false", cursor) return errors.ErrInvalidCharacter(buf[cursor+3], "false", cursor)
} }
if buf[cursor+4] != 'e' { if buf[cursor+4] != 'e' {
return errInvalidCharacter(buf[cursor+4], "false", cursor) return errors.ErrInvalidCharacter(buf[cursor+4], "false", cursor)
} }
return nil return nil
} }
func validateNull(buf []byte, cursor int64) error { func validateNull(buf []byte, cursor int64) error {
if cursor+3 >= int64(len(buf)) { if cursor+3 >= int64(len(buf)) {
return errUnexpectedEndOfJSON("null", cursor) return errors.ErrUnexpectedEndOfJSON("null", cursor)
} }
if buf[cursor+1] != 'u' { if buf[cursor+1] != 'u' {
return errInvalidCharacter(buf[cursor+1], "null", cursor) return errors.ErrInvalidCharacter(buf[cursor+1], "null", cursor)
} }
if buf[cursor+2] != 'l' { if buf[cursor+2] != 'l' {
return errInvalidCharacter(buf[cursor+2], "null", cursor) return errors.ErrInvalidCharacter(buf[cursor+2], "null", cursor)
} }
if buf[cursor+3] != 'l' { if buf[cursor+3] != 'l' {
return errInvalidCharacter(buf[cursor+3], "null", cursor) return errors.ErrInvalidCharacter(buf[cursor+3], "null", cursor)
} }
return nil return nil
} }

View file

@ -1,8 +1,10 @@
package json package decoder
import ( import (
"strconv" "strconv"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
) )
type floatDecoder struct { type floatDecoder struct {
@ -47,7 +49,7 @@ func newFloatDecoder(structName, fieldName string, op func(unsafe.Pointer, float
} }
) )
func floatBytes(s *stream) []byte { func floatBytes(s *Stream) []byte {
start := s.cursor start := s.cursor
for { for {
s.cursor++ s.cursor++
@ -64,7 +66,7 @@ func floatBytes(s *stream) []byte {
return s.buf[start:s.cursor] return s.buf[start:s.cursor]
} }
func (d *floatDecoder) decodeStreamByte(s *stream) ([]byte, error) { func (d *floatDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
for { for {
switch s.char() { switch s.char() {
case ' ', '\n', '\t', '\r': case ' ', '\n', '\t', '\r':
@ -87,7 +89,7 @@ func (d *floatDecoder) decodeStreamByte(s *stream) ([]byte, error) {
} }
} }
ERROR: ERROR:
return nil, errUnexpectedEndOfJSON("float", s.totalOffset()) return nil, errors.ErrUnexpectedEndOfJSON("float", s.totalOffset())
} }
func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
@ -111,12 +113,12 @@ func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, erro
cursor += 4 cursor += 4
return nil, cursor, nil return nil, cursor, nil
default: default:
return nil, 0, errUnexpectedEndOfJSON("float", cursor) return nil, 0, errors.ErrUnexpectedEndOfJSON("float", cursor)
} }
} }
} }
func (d *floatDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *floatDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
bytes, err := d.decodeStreamByte(s) bytes, err := d.decodeStreamByte(s)
if err != nil { if err != nil {
return err return err
@ -127,13 +129,14 @@ func (d *floatDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
str := *(*string)(unsafe.Pointer(&bytes)) str := *(*string)(unsafe.Pointer(&bytes))
f64, err := strconv.ParseFloat(str, 64) f64, err := strconv.ParseFloat(str, 64)
if err != nil { if err != nil {
return errSyntax(err.Error(), s.totalOffset()) return errors.ErrSyntax(err.Error(), s.totalOffset())
} }
d.op(p, f64) d.op(p, f64)
return nil return nil
} }
func (d *floatDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *floatDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
bytes, c, err := d.decodeByte(buf, cursor) bytes, c, err := d.decodeByte(buf, cursor)
if err != nil { if err != nil {
return 0, err return 0, err
@ -143,12 +146,12 @@ func (d *floatDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
} }
cursor = c cursor = c
if !validEndNumberChar[buf[cursor]] { if !validEndNumberChar[buf[cursor]] {
return 0, errUnexpectedEndOfJSON("float", cursor) return 0, errors.ErrUnexpectedEndOfJSON("float", cursor)
} }
s := *(*string)(unsafe.Pointer(&bytes)) s := *(*string)(unsafe.Pointer(&bytes))
f64, err := strconv.ParseFloat(s, 64) f64, err := strconv.ParseFloat(s, 64)
if err != nil { if err != nil {
return 0, errSyntax(err.Error(), cursor) return 0, errors.ErrSyntax(err.Error(), cursor)
} }
d.op(p, f64) d.op(p, f64)
return cursor, nil return cursor, nil

View file

@ -0,0 +1,141 @@
package decoder
import (
"bytes"
"unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
)
type funcDecoder struct {
typ *runtime.Type
structName string
fieldName string
}
func newFuncDecoder(typ *runtime.Type, structName, fieldName string) *funcDecoder {
fnDecoder := &funcDecoder{typ, structName, fieldName}
return fnDecoder
}
func (d *funcDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
s.skipWhiteSpace()
start := s.cursor
if err := s.skipValue(depth); err != nil {
return err
}
src := s.buf[start:s.cursor]
if len(src) > 0 {
switch src[0] {
case '"':
return &errors.UnmarshalTypeError{
Value: "string",
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
}
case '[':
return &errors.UnmarshalTypeError{
Value: "array",
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
}
case '{':
return &errors.UnmarshalTypeError{
Value: "object",
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
}
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return &errors.UnmarshalTypeError{
Value: "number",
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
}
case 'n':
if err := nullBytes(s); err != nil {
return err
}
*(*unsafe.Pointer)(p) = nil
return nil
case 't':
if err := trueBytes(s); err == nil {
return &errors.UnmarshalTypeError{
Value: "boolean",
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
}
}
case 'f':
if err := falseBytes(s); err == nil {
return &errors.UnmarshalTypeError{
Value: "boolean",
Type: runtime.RType2Type(d.typ),
Offset: s.totalOffset(),
}
}
}
}
return errors.ErrInvalidBeginningOfValue(s.buf[s.cursor], s.totalOffset())
}
func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
cursor = skipWhiteSpace(buf, cursor)
start := cursor
end, err := skipValue(buf, cursor, depth)
if err != nil {
return 0, err
}
src := buf[start:end]
if len(src) > 0 {
switch src[0] {
case '"':
return 0, &errors.UnmarshalTypeError{
Value: "string",
Type: runtime.RType2Type(d.typ),
Offset: start,
}
case '[':
return 0, &errors.UnmarshalTypeError{
Value: "array",
Type: runtime.RType2Type(d.typ),
Offset: start,
}
case '{':
return 0, &errors.UnmarshalTypeError{
Value: "object",
Type: runtime.RType2Type(d.typ),
Offset: start,
}
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return 0, &errors.UnmarshalTypeError{
Value: "number",
Type: runtime.RType2Type(d.typ),
Offset: start,
}
case 'n':
if bytes.Equal(src, nullbytes) {
*(*unsafe.Pointer)(p) = nil
return end, nil
}
case 't':
if err := validateTrue(buf, start); err == nil {
return 0, &errors.UnmarshalTypeError{
Value: "boolean",
Type: runtime.RType2Type(d.typ),
Offset: start,
}
}
case 'f':
if err := validateFalse(buf, start); err == nil {
return 0, &errors.UnmarshalTypeError{
Value: "boolean",
Type: runtime.RType2Type(d.typ),
Offset: start,
}
}
}
}
return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor)
}

View file

@ -1,20 +1,23 @@
package json package decoder
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
) )
type intDecoder struct { type intDecoder struct {
typ *rtype typ *runtime.Type
kind reflect.Kind kind reflect.Kind
op func(unsafe.Pointer, int64) op func(unsafe.Pointer, int64)
structName string structName string
fieldName string fieldName string
} }
func newIntDecoder(typ *rtype, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder { func newIntDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder {
return &intDecoder{ return &intDecoder{
typ: typ, typ: typ,
kind: typ.Kind(), kind: typ.Kind(),
@ -24,10 +27,10 @@ func newIntDecoder(typ *rtype, structName, fieldName string, op func(unsafe.Poin
} }
} }
func (d *intDecoder) typeError(buf []byte, offset int64) *UnmarshalTypeError { func (d *intDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError {
return &UnmarshalTypeError{ return &errors.UnmarshalTypeError{
Value: fmt.Sprintf("number %s", string(buf)), Value: fmt.Sprintf("number %s", string(buf)),
Type: rtype2type(d.typ), Type: runtime.RType2Type(d.typ),
Struct: d.structName, Struct: d.structName,
Field: d.fieldName, Field: d.fieldName,
Offset: offset, Offset: offset,
@ -79,7 +82,11 @@ func (d *intDecoder) parseInt(b []byte) (int64, error) {
} }
) )
func (d *intDecoder) decodeStreamByte(s *stream) ([]byte, error) { var (
numZeroBuf = []byte{'0'}
)
func (d *intDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
for { for {
switch s.char() { switch s.char() {
case ' ', '\n', '\t', '\r': case ' ', '\n', '\t', '\r':
@ -106,7 +113,7 @@ func (d *intDecoder) decodeStreamByte(s *stream) ([]byte, error) {
return num, nil return num, nil
case '0': case '0':
s.cursor++ s.cursor++
return []byte{'0'}, nil return numZeroBuf, nil
case '1', '2', '3', '4', '5', '6', '7', '8', '9': case '1', '2', '3', '4', '5', '6', '7', '8', '9':
start := s.cursor start := s.cursor
for { for {
@ -138,7 +145,7 @@ func (d *intDecoder) decodeStreamByte(s *stream) ([]byte, error) {
} }
} }
ERROR: ERROR:
return nil, errUnexpectedEndOfJSON("number(integer)", s.totalOffset()) return nil, errors.ErrUnexpectedEndOfJSON("number(integer)", s.totalOffset())
} }
func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
@ -150,7 +157,7 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error)
continue continue
case '0': case '0':
cursor++ cursor++
return []byte{'0'}, cursor, nil return numZeroBuf, cursor, nil
case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9':
start := cursor start := cursor
cursor++ cursor++
@ -171,7 +178,7 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error)
} }
} }
func (d *intDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
bytes, err := d.decodeStreamByte(s) bytes, err := d.decodeStreamByte(s)
if err != nil { if err != nil {
return err return err
@ -202,8 +209,8 @@ func (d *intDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) erro
return nil return nil
} }
func (d *intDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
bytes, c, err := d.decodeByte(buf, cursor) bytes, c, err := d.decodeByte(ctx.Buf, cursor)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View file

@ -1,14 +1,18 @@
package json package decoder
import ( import (
"bytes" "bytes"
"encoding" "encoding"
"encoding/json"
"reflect" "reflect"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
) )
type interfaceDecoder struct { type interfaceDecoder struct {
typ *rtype typ *runtime.Type
structName string structName string
fieldName string fieldName string
sliceDecoder *sliceDecoder sliceDecoder *sliceDecoder
@ -26,7 +30,7 @@ func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder {
floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v Number) { numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
stringDecoder: newStringDecoder(structName, fieldName), stringDecoder: newStringDecoder(structName, fieldName),
@ -49,7 +53,7 @@ func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder {
return ifaceDecoder return ifaceDecoder
} }
func newInterfaceDecoder(typ *rtype, structName, fieldName string) *interfaceDecoder { func newInterfaceDecoder(typ *runtime.Type, structName, fieldName string) *interfaceDecoder {
emptyIfaceDecoder := newEmptyInterfaceDecoder(structName, fieldName) emptyIfaceDecoder := newEmptyInterfaceDecoder(structName, fieldName)
stringDecoder := newStringDecoder(structName, fieldName) stringDecoder := newStringDecoder(structName, fieldName)
return &interfaceDecoder{ return &interfaceDecoder{
@ -74,31 +78,31 @@ func newInterfaceDecoder(typ *rtype, structName, fieldName string) *interfaceDec
floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v Number) { numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
stringDecoder: stringDecoder, stringDecoder: stringDecoder,
} }
} }
func (d *interfaceDecoder) numDecoder(s *stream) decoder { func (d *interfaceDecoder) numDecoder(s *Stream) Decoder {
if s.useNumber { if s.UseNumber {
return d.numberDecoder return d.numberDecoder
} }
return d.floatDecoder return d.floatDecoder
} }
var ( var (
emptyInterfaceType = type2rtype(reflect.TypeOf((*interface{})(nil)).Elem()) emptyInterfaceType = runtime.Type2RType(reflect.TypeOf((*interface{})(nil)).Elem())
interfaceMapType = type2rtype( interfaceMapType = runtime.Type2RType(
reflect.TypeOf((*map[string]interface{})(nil)).Elem(), reflect.TypeOf((*map[string]interface{})(nil)).Elem(),
) )
stringType = type2rtype( stringType = runtime.Type2RType(
reflect.TypeOf(""), reflect.TypeOf(""),
) )
) )
func decodeStreamUnmarshaler(s *stream, depth int64, unmarshaler Unmarshaler) error { func decodeStreamUnmarshaler(s *Stream, depth int64, unmarshaler json.Unmarshaler) error {
start := s.cursor start := s.cursor
if err := s.skipValue(depth); err != nil { if err := s.skipValue(depth); err != nil {
return err return err
@ -113,7 +117,22 @@ func decodeStreamUnmarshaler(s *stream, depth int64, unmarshaler Unmarshaler) er
return nil return nil
} }
func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler Unmarshaler) (int64, error) { func decodeStreamUnmarshalerContext(s *Stream, depth int64, unmarshaler unmarshalerContext) error {
start := s.cursor
if err := s.skipValue(depth); err != nil {
return err
}
src := s.buf[start:s.cursor]
dst := make([]byte, len(src))
copy(dst, src)
if err := unmarshaler.UnmarshalJSON(s.Option.Context, dst); err != nil {
return err
}
return nil
}
func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler json.Unmarshaler) (int64, error) {
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
start := cursor start := cursor
end, err := skipValue(buf, cursor, depth) end, err := skipValue(buf, cursor, depth)
@ -130,7 +149,24 @@ func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler Unmarshaler)
return end, nil return end, nil
} }
func decodeStreamTextUnmarshaler(s *stream, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) error { func decodeUnmarshalerContext(ctx *RuntimeContext, buf []byte, cursor, depth int64, unmarshaler unmarshalerContext) (int64, error) {
cursor = skipWhiteSpace(buf, cursor)
start := cursor
end, err := skipValue(buf, cursor, depth)
if err != nil {
return 0, err
}
src := buf[start:end]
dst := make([]byte, len(src))
copy(dst, src)
if err := unmarshaler.UnmarshalJSON(ctx.Option.Context, dst); err != nil {
return 0, err
}
return end, nil
}
func decodeStreamTextUnmarshaler(s *Stream, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) error {
start := s.cursor start := s.cursor
if err := s.skipValue(depth); err != nil { if err := s.skipValue(depth); err != nil {
return err return err
@ -171,14 +207,14 @@ func decodeTextUnmarshaler(buf []byte, cursor, depth int64, unmarshaler encoding
return end, nil return end, nil
} }
func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p unsafe.Pointer) error { func (d *interfaceDecoder) decodeStreamEmptyInterface(s *Stream, depth int64, p unsafe.Pointer) error {
s.skipWhiteSpace() c := s.skipWhiteSpace()
for { for {
switch s.char() { switch c {
case '{': case '{':
var v map[string]interface{} var v map[string]interface{}
ptr := unsafe.Pointer(&v) ptr := unsafe.Pointer(&v)
if err := d.mapDecoder.decodeStream(s, depth, ptr); err != nil { if err := d.mapDecoder.DecodeStream(s, depth, ptr); err != nil {
return err return err
} }
*(*interface{})(p) = v *(*interface{})(p) = v
@ -186,20 +222,20 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p
case '[': case '[':
var v []interface{} var v []interface{}
ptr := unsafe.Pointer(&v) ptr := unsafe.Pointer(&v)
if err := d.sliceDecoder.decodeStream(s, depth, ptr); err != nil { if err := d.sliceDecoder.DecodeStream(s, depth, ptr); err != nil {
return err return err
} }
*(*interface{})(p) = v *(*interface{})(p) = v
return nil return nil
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return d.numDecoder(s).decodeStream(s, depth, p) return d.numDecoder(s).DecodeStream(s, depth, p)
case '"': case '"':
s.cursor++ s.cursor++
start := s.cursor start := s.cursor
for { for {
switch s.char() { switch s.char() {
case '\\': case '\\':
if err := decodeEscapeString(s); err != nil { if _, err := decodeEscapeString(s, nil); err != nil {
return err return err
} }
case '"': case '"':
@ -211,7 +247,7 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p
if s.read() { if s.read() {
continue continue
} }
return errUnexpectedEndOfJSON("string", s.totalOffset()) return errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
} }
s.cursor++ s.cursor++
} }
@ -235,29 +271,37 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p
return nil return nil
case nul: case nul:
if s.read() { if s.read() {
c = s.char()
continue continue
} }
} }
break break
} }
return errNotAtBeginningOfValue(s.totalOffset()) return errors.ErrInvalidBeginningOfValue(c, s.totalOffset())
} }
func (d *interfaceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { type emptyInterface struct {
typ *runtime.Type
ptr unsafe.Pointer
}
func (d *interfaceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{
typ: d.typ, typ: d.typ,
ptr: p, ptr: p,
})) }))
rv := reflect.ValueOf(runtimeInterfaceValue) rv := reflect.ValueOf(runtimeInterfaceValue)
if rv.NumMethod() > 0 && rv.CanInterface() { if rv.NumMethod() > 0 && rv.CanInterface() {
if u, ok := rv.Interface().(Unmarshaler); ok { if u, ok := rv.Interface().(unmarshalerContext); ok {
return decodeStreamUnmarshalerContext(s, depth, u)
}
if u, ok := rv.Interface().(json.Unmarshaler); ok {
return decodeStreamUnmarshaler(s, depth, u) return decodeStreamUnmarshaler(s, depth, u)
} }
if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
return decodeStreamTextUnmarshaler(s, depth, u, p) return decodeStreamTextUnmarshaler(s, depth, u, p)
} }
s.skipWhiteSpace() if s.skipWhiteSpace() == 'n' {
if s.char() == 'n' {
if err := nullBytes(s); err != nil { if err := nullBytes(s); err != nil {
return err return err
} }
@ -276,23 +320,22 @@ func (d *interfaceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer
if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr { if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr {
return d.decodeStreamEmptyInterface(s, depth, p) return d.decodeStreamEmptyInterface(s, depth, p)
} }
s.skipWhiteSpace() if s.skipWhiteSpace() == 'n' {
if s.char() == 'n' {
if err := nullBytes(s); err != nil { if err := nullBytes(s); err != nil {
return err return err
} }
*(*interface{})(p) = nil *(*interface{})(p) = nil
return nil return nil
} }
decoder, err := decodeCompileToGetDecoder(typ) decoder, err := CompileToGetDecoder(typ)
if err != nil { if err != nil {
return err return err
} }
return decoder.decodeStream(s, depth, ifaceHeader.ptr) return decoder.DecodeStream(s, depth, ifaceHeader.ptr)
} }
func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *UnmarshalTypeError { func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *errors.UnmarshalTypeError {
return &UnmarshalTypeError{ return &errors.UnmarshalTypeError{
Value: typ.String(), Value: typ.String(),
Type: typ, Type: typ,
Offset: offset, Offset: offset,
@ -301,14 +344,18 @@ func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *Unm
} }
} }
func (d *interfaceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *interfaceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{
typ: d.typ, typ: d.typ,
ptr: p, ptr: p,
})) }))
rv := reflect.ValueOf(runtimeInterfaceValue) rv := reflect.ValueOf(runtimeInterfaceValue)
if rv.NumMethod() > 0 && rv.CanInterface() { if rv.NumMethod() > 0 && rv.CanInterface() {
if u, ok := rv.Interface().(Unmarshaler); ok { if u, ok := rv.Interface().(unmarshalerContext); ok {
return decodeUnmarshalerContext(ctx, buf, cursor, depth, u)
}
if u, ok := rv.Interface().(json.Unmarshaler); ok {
return decodeUnmarshaler(buf, cursor, depth, u) return decodeUnmarshaler(buf, cursor, depth, u)
} }
if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
@ -331,10 +378,10 @@ func (d *interfaceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Poin
typ := ifaceHeader.typ typ := ifaceHeader.typ
if ifaceHeader.ptr == nil || d.typ == typ || typ == nil { if ifaceHeader.ptr == nil || d.typ == typ || typ == nil {
// concrete type is empty interface // concrete type is empty interface
return d.decodeEmptyInterface(buf, cursor, depth, p) return d.decodeEmptyInterface(ctx, cursor, depth, p)
} }
if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr { if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr {
return d.decodeEmptyInterface(buf, cursor, depth, p) return d.decodeEmptyInterface(ctx, cursor, depth, p)
} }
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == 'n' { if buf[cursor] == 'n' {
@ -345,20 +392,21 @@ func (d *interfaceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Poin
**(**interface{})(unsafe.Pointer(&p)) = nil **(**interface{})(unsafe.Pointer(&p)) = nil
return cursor, nil return cursor, nil
} }
decoder, err := decodeCompileToGetDecoder(typ) decoder, err := CompileToGetDecoder(typ)
if err != nil { if err != nil {
return 0, err return 0, err
} }
return decoder.decode(buf, cursor, depth, ifaceHeader.ptr) return decoder.Decode(ctx, cursor, depth, ifaceHeader.ptr)
} }
func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *interfaceDecoder) decodeEmptyInterface(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
switch buf[cursor] { switch buf[cursor] {
case '{': case '{':
var v map[string]interface{} var v map[string]interface{}
ptr := unsafe.Pointer(&v) ptr := unsafe.Pointer(&v)
cursor, err := d.mapDecoder.decode(buf, cursor, depth, ptr) cursor, err := d.mapDecoder.Decode(ctx, cursor, depth, ptr)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -367,18 +415,18 @@ func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64,
case '[': case '[':
var v []interface{} var v []interface{}
ptr := unsafe.Pointer(&v) ptr := unsafe.Pointer(&v)
cursor, err := d.sliceDecoder.decode(buf, cursor, depth, ptr) cursor, err := d.sliceDecoder.Decode(ctx, cursor, depth, ptr)
if err != nil { if err != nil {
return 0, err return 0, err
} }
**(**interface{})(unsafe.Pointer(&p)) = v **(**interface{})(unsafe.Pointer(&p)) = v
return cursor, nil return cursor, nil
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return d.floatDecoder.decode(buf, cursor, depth, p) return d.floatDecoder.Decode(ctx, cursor, depth, p)
case '"': case '"':
var v string var v string
ptr := unsafe.Pointer(&v) ptr := unsafe.Pointer(&v)
cursor, err := d.stringDecoder.decode(buf, cursor, depth, ptr) cursor, err := d.stringDecoder.Decode(ctx, cursor, depth, ptr)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -406,5 +454,5 @@ func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64,
**(**interface{})(unsafe.Pointer(&p)) = nil **(**interface{})(unsafe.Pointer(&p)) = nil
return cursor, nil return cursor, nil
} }
return cursor, errNotAtBeginningOfValue(cursor) return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor)
} }

186
vendor/github.com/goccy/go-json/internal/decoder/map.go generated vendored Normal file
View file

@ -0,0 +1,186 @@
package decoder
import (
"reflect"
"unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
)
type mapDecoder struct {
mapType *runtime.Type
keyType *runtime.Type
valueType *runtime.Type
canUseAssignFaststrType bool
keyDecoder Decoder
valueDecoder Decoder
structName string
fieldName string
}
func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder {
return &mapDecoder{
mapType: mapType,
keyDecoder: keyDec,
keyType: keyType,
canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType),
valueType: valueType,
valueDecoder: valueDec,
structName: structName,
fieldName: fieldName,
}
}
const (
mapMaxElemSize = 128
)
// See detail: https://github.com/goccy/go-json/pull/283
func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool {
indirectElem := value.Size() > mapMaxElemSize
if indirectElem {
return false
}
return key.Kind() == reflect.String
}
//go:linkname makemap reflect.makemap
func makemap(*runtime.Type, int) unsafe.Pointer
//nolint:golint
//go:linkname mapassign_faststr runtime.mapassign_faststr
//go:noescape
func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Pointer
//go:linkname mapassign reflect.mapassign
//go:noescape
func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer)
func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) {
if d.canUseAssignFaststrType {
mapV := mapassign_faststr(t, m, *(*string)(k))
typedmemmove(d.valueType, mapV, v)
} else {
mapassign(t, m, k, v)
}
}
func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
depth++
if depth > maxDecodeNestingDepth {
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
}
switch s.skipWhiteSpace() {
case 'n':
if err := nullBytes(s); err != nil {
return err
}
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
return nil
case '{':
default:
return errors.ErrExpected("{ character for map value", s.totalOffset())
}
mapValue := *(*unsafe.Pointer)(p)
if mapValue == nil {
mapValue = makemap(d.mapType, 0)
}
if s.buf[s.cursor+1] == '}' {
*(*unsafe.Pointer)(p) = mapValue
s.cursor += 2
return nil
}
for {
s.cursor++
k := unsafe_New(d.keyType)
if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil {
return err
}
s.skipWhiteSpace()
if !s.equalChar(':') {
return errors.ErrExpected("colon after object key", s.totalOffset())
}
s.cursor++
v := unsafe_New(d.valueType)
if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil {
return err
}
d.mapassign(d.mapType, mapValue, k, v)
s.skipWhiteSpace()
if s.equalChar('}') {
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
s.cursor++
return nil
}
if !s.equalChar(',') {
return errors.ErrExpected("comma after object value", s.totalOffset())
}
}
}
func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
depth++
if depth > maxDecodeNestingDepth {
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
}
cursor = skipWhiteSpace(buf, cursor)
buflen := int64(len(buf))
if buflen < 2 {
return 0, errors.ErrExpected("{} for map", cursor)
}
switch buf[cursor] {
case 'n':
if err := validateNull(buf, cursor); err != nil {
return 0, err
}
cursor += 4
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
return cursor, nil
case '{':
default:
return 0, errors.ErrExpected("{ character for map value", cursor)
}
cursor++
cursor = skipWhiteSpace(buf, cursor)
mapValue := *(*unsafe.Pointer)(p)
if mapValue == nil {
mapValue = makemap(d.mapType, 0)
}
if buf[cursor] == '}' {
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
cursor++
return cursor, nil
}
for {
k := unsafe_New(d.keyType)
keyCursor, err := d.keyDecoder.Decode(ctx, cursor, depth, k)
if err != nil {
return 0, err
}
cursor = skipWhiteSpace(buf, keyCursor)
if buf[cursor] != ':' {
return 0, errors.ErrExpected("colon after object key", cursor)
}
cursor++
v := unsafe_New(d.valueType)
valueCursor, err := d.valueDecoder.Decode(ctx, cursor, depth, v)
if err != nil {
return 0, err
}
d.mapassign(d.mapType, mapValue, k, v)
cursor = skipWhiteSpace(buf, valueCursor)
if buf[cursor] == '}' {
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
cursor++
return cursor, nil
}
if buf[cursor] != ',' {
return 0, errors.ErrExpected("comma after object value", cursor)
}
cursor++
}
}

View file

@ -1,18 +1,21 @@
package json package decoder
import ( import (
"encoding/json"
"strconv" "strconv"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
) )
type numberDecoder struct { type numberDecoder struct {
stringDecoder *stringDecoder stringDecoder *stringDecoder
op func(unsafe.Pointer, Number) op func(unsafe.Pointer, json.Number)
structName string structName string
fieldName string fieldName string
} }
func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, Number)) *numberDecoder { func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, json.Number)) *numberDecoder {
return &numberDecoder{ return &numberDecoder{
stringDecoder: newStringDecoder(structName, fieldName), stringDecoder: newStringDecoder(structName, fieldName),
op: op, op: op,
@ -21,34 +24,35 @@ func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, Numb
} }
} }
func (d *numberDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *numberDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
bytes, err := d.decodeStreamByte(s) bytes, err := d.decodeStreamByte(s)
if err != nil { if err != nil {
return err return err
} }
if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil { if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil {
return errSyntax(err.Error(), s.totalOffset()) return errors.ErrSyntax(err.Error(), s.totalOffset())
} }
d.op(p, Number(string(bytes))) d.op(p, json.Number(string(bytes)))
s.reset() s.reset()
return nil return nil
} }
func (d *numberDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *numberDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
bytes, c, err := d.decodeByte(buf, cursor) bytes, c, err := d.decodeByte(ctx.Buf, cursor)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil { if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil {
return 0, errSyntax(err.Error(), c) return 0, errors.ErrSyntax(err.Error(), c)
} }
cursor = c cursor = c
s := *(*string)(unsafe.Pointer(&bytes)) s := *(*string)(unsafe.Pointer(&bytes))
d.op(p, Number(s)) d.op(p, json.Number(s))
return cursor, nil return cursor, nil
} }
func (d *numberDecoder) decodeStreamByte(s *stream) ([]byte, error) { func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
start := s.cursor
for { for {
switch s.char() { switch s.char() {
case ' ', '\n', '\t', '\r': case ' ', '\n', '\t', '\r':
@ -73,7 +77,10 @@ func (d *numberDecoder) decodeStreamByte(s *stream) ([]byte, error) {
} }
} }
ERROR: ERROR:
return nil, errUnexpectedEndOfJSON("json.Number", s.totalOffset()) if s.cursor == start {
return nil, errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset())
}
return nil, errors.ErrUnexpectedEndOfJSON("json.Number", s.totalOffset())
} }
func (d *numberDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { func (d *numberDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
@ -99,7 +106,7 @@ func (d *numberDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
case '"': case '"':
return d.stringDecoder.decodeByte(buf, cursor) return d.stringDecoder.decodeByte(buf, cursor)
default: default:
return nil, 0, errUnexpectedEndOfJSON("json.Number", cursor) return nil, 0, errors.ErrUnexpectedEndOfJSON("json.Number", cursor)
} }
} }
} }

View file

@ -0,0 +1,15 @@
package decoder
import "context"
type OptionFlags uint8
const (
FirstWinOption OptionFlags = 1 << iota
ContextOption
)
type Option struct {
Flags OptionFlags
Context context.Context
}

View file

@ -1,17 +1,19 @@
package json package decoder
import ( import (
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/runtime"
) )
type ptrDecoder struct { type ptrDecoder struct {
dec decoder dec Decoder
typ *rtype typ *runtime.Type
structName string structName string
fieldName string fieldName string
} }
func newPtrDecoder(dec decoder, typ *rtype, structName, fieldName string) *ptrDecoder { func newPtrDecoder(dec Decoder, typ *runtime.Type, structName, fieldName string) *ptrDecoder {
return &ptrDecoder{ return &ptrDecoder{
dec: dec, dec: dec,
typ: typ, typ: typ,
@ -20,7 +22,7 @@ func newPtrDecoder(dec decoder, typ *rtype, structName, fieldName string) *ptrDe
} }
} }
func (d *ptrDecoder) contentDecoder() decoder { func (d *ptrDecoder) contentDecoder() Decoder {
dec, ok := d.dec.(*ptrDecoder) dec, ok := d.dec.(*ptrDecoder)
if !ok { if !ok {
return d.dec return d.dec
@ -30,11 +32,10 @@ func (d *ptrDecoder) contentDecoder() decoder {
//nolint:golint //nolint:golint
//go:linkname unsafe_New reflect.unsafe_New //go:linkname unsafe_New reflect.unsafe_New
func unsafe_New(*rtype) unsafe.Pointer func unsafe_New(*runtime.Type) unsafe.Pointer
func (d *ptrDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *ptrDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
s.skipWhiteSpace() if s.skipWhiteSpace() == nul {
if s.char() == nul {
s.read() s.read()
} }
if s.char() == 'n' { if s.char() == 'n' {
@ -51,13 +52,14 @@ func (d *ptrDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) erro
} else { } else {
newptr = *(*unsafe.Pointer)(p) newptr = *(*unsafe.Pointer)(p)
} }
if err := d.dec.decodeStream(s, depth, newptr); err != nil { if err := d.dec.DecodeStream(s, depth, newptr); err != nil {
return err return err
} }
return nil return nil
} }
func (d *ptrDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *ptrDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == 'n' { if buf[cursor] == 'n' {
if err := validateNull(buf, cursor); err != nil { if err := validateNull(buf, cursor); err != nil {
@ -76,7 +78,7 @@ func (d *ptrDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (
} else { } else {
newptr = *(*unsafe.Pointer)(p) newptr = *(*unsafe.Pointer)(p)
} }
c, err := d.dec.decode(buf, cursor, depth, newptr) c, err := d.dec.Decode(ctx, cursor, depth, newptr)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View file

@ -1,15 +1,25 @@
package json package decoder
import ( import (
"reflect" "reflect"
"sync" "sync"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
"github.com/goccy/go-json/internal/runtime"
)
var (
sliceType = runtime.Type2RType(
reflect.TypeOf((*sliceHeader)(nil)).Elem(),
)
nilSlice = unsafe.Pointer(&sliceHeader{})
) )
type sliceDecoder struct { type sliceDecoder struct {
elemType *rtype elemType *runtime.Type
isElemPointerType bool isElemPointerType bool
valueDecoder decoder valueDecoder Decoder
size uintptr size uintptr
arrayPool sync.Pool arrayPool sync.Pool
structName string structName string
@ -29,7 +39,7 @@ type sliceHeader struct {
defaultSliceCapacity = 2 defaultSliceCapacity = 2
) )
func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fieldName string) *sliceDecoder { func newSliceDecoder(dec Decoder, elemType *runtime.Type, size uintptr, structName, fieldName string) *sliceDecoder {
return &sliceDecoder{ return &sliceDecoder{
valueDecoder: dec, valueDecoder: dec,
elemType: elemType, elemType: elemType,
@ -71,28 +81,28 @@ func (d *sliceDecoder) releaseSlice(p *sliceHeader) {
} }
//go:linkname copySlice reflect.typedslicecopy //go:linkname copySlice reflect.typedslicecopy
func copySlice(elemType *rtype, dst, src sliceHeader) int func copySlice(elemType *runtime.Type, dst, src sliceHeader) int
//go:linkname newArray reflect.unsafe_NewArray //go:linkname newArray reflect.unsafe_NewArray
func newArray(*rtype, int) unsafe.Pointer func newArray(*runtime.Type, int) unsafe.Pointer
//go:linkname typedmemmove reflect.typedmemmove //go:linkname typedmemmove reflect.typedmemmove
func typedmemmove(t *rtype, dst, src unsafe.Pointer) func typedmemmove(t *runtime.Type, dst, src unsafe.Pointer)
func (d *sliceDecoder) errNumber(offset int64) *UnmarshalTypeError { func (d *sliceDecoder) errNumber(offset int64) *errors.UnmarshalTypeError {
return &UnmarshalTypeError{ return &errors.UnmarshalTypeError{
Value: "number", Value: "number",
Type: reflect.SliceOf(rtype2type(d.elemType)), Type: reflect.SliceOf(runtime.RType2Type(d.elemType)),
Struct: d.structName, Struct: d.structName,
Field: d.fieldName, Field: d.fieldName,
Offset: offset, Offset: offset,
} }
} }
func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *sliceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor) return errors.ErrExceededMaxDepth(s.char(), s.cursor)
} }
for { for {
@ -104,12 +114,11 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
if err := nullBytes(s); err != nil { if err := nullBytes(s); err != nil {
return err return err
} }
*(*unsafe.Pointer)(p) = nil typedmemmove(sliceType, p, nilSlice)
return nil return nil
case '[': case '[':
s.cursor++ s.cursor++
s.skipWhiteSpace() if s.skipWhiteSpace() == ']' {
if s.char() == ']' {
dst := (*sliceHeader)(p) dst := (*sliceHeader)(p)
if dst.data == nil { if dst.data == nil {
dst.data = newArray(d.elemType, 0) dst.data = newArray(d.elemType, 0)
@ -144,7 +153,7 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
} }
} }
if err := d.valueDecoder.decodeStream(s, depth, ep); err != nil { if err := d.valueDecoder.DecodeStream(s, depth, ep); err != nil {
return err return err
} }
s.skipWhiteSpace() s.skipWhiteSpace()
@ -194,13 +203,14 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er
} }
} }
ERROR: ERROR:
return errUnexpectedEndOfJSON("slice", s.totalOffset()) return errors.ErrUnexpectedEndOfJSON("slice", s.totalOffset())
} }
func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *sliceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
buf := ctx.Buf
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return 0, errExceededMaxDepth(buf[cursor], cursor) return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
} }
for { for {
@ -213,7 +223,7 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
return 0, err return 0, err
} }
cursor += 4 cursor += 4
*(*unsafe.Pointer)(p) = nil typedmemmove(sliceType, p, nilSlice)
return cursor, nil return cursor, nil
case '[': case '[':
cursor++ cursor++
@ -251,7 +261,7 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) typedmemmove(d.elemType, ep, unsafe_New(d.elemType))
} }
} }
c, err := d.valueDecoder.decode(buf, cursor, depth, ep) c, err := d.valueDecoder.Decode(ctx, cursor, depth, ep)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -278,14 +288,14 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer)
slice.cap = capacity slice.cap = capacity
slice.data = data slice.data = data
d.releaseSlice(slice) d.releaseSlice(slice)
return 0, errInvalidCharacter(buf[cursor], "slice", cursor) return 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor)
} }
cursor++ cursor++
} }
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return 0, d.errNumber(cursor) return 0, d.errNumber(cursor)
default: default:
return 0, errUnexpectedEndOfJSON("slice", cursor) return 0, errors.ErrUnexpectedEndOfJSON("slice", cursor)
} }
} }
} }

View file

@ -1,16 +1,20 @@
package json package decoder
import ( import (
"bytes" "bytes"
"encoding/json"
"io" "io"
"strconv"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
) )
const ( const (
initBufSize = 512 initBufSize = 512
) )
type stream struct { type Stream struct {
buf []byte buf []byte
bufSize int64 bufSize int64
length int64 length int64
@ -19,19 +23,25 @@ type stream struct {
cursor int64 cursor int64
filledBuffer bool filledBuffer bool
allRead bool allRead bool
useNumber bool UseNumber bool
disallowUnknownFields bool DisallowUnknownFields bool
Option *Option
} }
func newStream(r io.Reader) *stream { func NewStream(r io.Reader) *Stream {
return &stream{ return &Stream{
r: r, r: r,
bufSize: initBufSize, bufSize: initBufSize,
buf: []byte{nul}, buf: make([]byte, initBufSize),
Option: &Option{},
} }
} }
func (s *stream) buffered() io.Reader { func (s *Stream) TotalOffset() int64 {
return s.totalOffset()
}
func (s *Stream) Buffered() io.Reader {
buflen := int64(len(s.buf)) buflen := int64(len(s.buf))
for i := s.cursor; i < buflen; i++ { for i := s.cursor; i < buflen; i++ {
if s.buf[i] == nul { if s.buf[i] == nul {
@ -41,15 +51,35 @@ func (s *stream) buffered() io.Reader {
return bytes.NewReader(s.buf[s.cursor:]) return bytes.NewReader(s.buf[s.cursor:])
} }
func (s *stream) totalOffset() int64 { func (s *Stream) PrepareForDecode() error {
for {
switch s.char() {
case ' ', '\t', '\r', '\n':
s.cursor++
continue
case ',', ':':
s.cursor++
return nil
case nul:
if s.read() {
continue
}
return io.EOF
}
break
}
return nil
}
func (s *Stream) totalOffset() int64 {
return s.offset + s.cursor return s.offset + s.cursor
} }
func (s *stream) char() byte { func (s *Stream) char() byte {
return s.buf[s.cursor] return s.buf[s.cursor]
} }
func (s *stream) equalChar(c byte) bool { func (s *Stream) equalChar(c byte) bool {
cur := s.buf[s.cursor] cur := s.buf[s.cursor]
if cur == nul { if cur == nul {
s.read() s.read()
@ -58,23 +88,104 @@ func (s *stream) equalChar(c byte) bool {
return cur == c return cur == c
} }
func (s *stream) stat() ([]byte, int64, unsafe.Pointer) { func (s *Stream) stat() ([]byte, int64, unsafe.Pointer) {
return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
} }
func (s *stream) statForRetry() ([]byte, int64, unsafe.Pointer) { func (s *Stream) bufptr() unsafe.Pointer {
return (*sliceHeader)(unsafe.Pointer(&s.buf)).data
}
func (s *Stream) statForRetry() ([]byte, int64, unsafe.Pointer) {
s.cursor-- // for retry ( because caller progress cursor position in each loop ) s.cursor-- // for retry ( because caller progress cursor position in each loop )
return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
} }
func (s *stream) reset() { func (s *Stream) Reset() {
s.reset()
s.bufSize = initBufSize
}
func (s *Stream) More() bool {
for {
switch s.char() {
case ' ', '\n', '\r', '\t':
s.cursor++
continue
case '}', ']':
return false
case nul:
if s.read() {
continue
}
return false
}
break
}
return true
}
func (s *Stream) Token() (interface{}, error) {
for {
c := s.char()
switch c {
case ' ', '\n', '\r', '\t':
s.cursor++
case '{', '[', ']', '}':
s.cursor++
return json.Delim(c), nil
case ',', ':':
s.cursor++
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
bytes := floatBytes(s)
s := *(*string)(unsafe.Pointer(&bytes))
f64, err := strconv.ParseFloat(s, 64)
if err != nil {
return nil, err
}
return f64, nil
case '"':
bytes, err := stringBytes(s)
if err != nil {
return nil, err
}
return string(bytes), nil
case 't':
if err := trueBytes(s); err != nil {
return nil, err
}
return true, nil
case 'f':
if err := falseBytes(s); err != nil {
return nil, err
}
return false, nil
case 'n':
if err := nullBytes(s); err != nil {
return nil, err
}
return nil, nil
case nul:
if s.read() {
continue
}
goto END
default:
return nil, errors.ErrInvalidCharacter(s.char(), "token", s.totalOffset())
}
}
END:
return nil, io.EOF
}
func (s *Stream) reset() {
s.offset += s.cursor s.offset += s.cursor
s.buf = s.buf[s.cursor:] s.buf = s.buf[s.cursor:]
s.length -= s.cursor s.length -= s.cursor
s.cursor = 0 s.cursor = 0
} }
func (s *stream) readBuf() []byte { func (s *Stream) readBuf() []byte {
if s.filledBuffer { if s.filledBuffer {
s.bufSize *= 2 s.bufSize *= 2
remainBuf := s.buf remainBuf := s.buf
@ -89,10 +200,11 @@ func (s *stream) readBuf() []byte {
} }
remainNotNulCharNum++ remainNotNulCharNum++
} }
s.length = s.cursor + remainNotNulCharNum
return s.buf[s.cursor+remainNotNulCharNum:] return s.buf[s.cursor+remainNotNulCharNum:]
} }
func (s *stream) read() bool { func (s *Stream) read() bool {
if s.allRead { if s.allRead {
return false return false
} }
@ -100,7 +212,7 @@ func (s *stream) read() bool {
last := len(buf) - 1 last := len(buf) - 1
buf[last] = nul buf[last] = nul
n, err := s.r.Read(buf[:last]) n, err := s.r.Read(buf[:last])
s.length = s.cursor + int64(n) s.length += int64(n)
if n == last { if n == last {
s.filledBuffer = true s.filledBuffer = true
} else { } else {
@ -114,20 +226,24 @@ func (s *stream) read() bool {
return true return true
} }
func (s *stream) skipWhiteSpace() { func (s *Stream) skipWhiteSpace() byte {
p := s.bufptr()
LOOP: LOOP:
switch s.char() { c := char(p, s.cursor)
switch c {
case ' ', '\n', '\t', '\r': case ' ', '\n', '\t', '\r':
s.cursor++ s.cursor++
goto LOOP goto LOOP
case nul: case nul:
if s.read() { if s.read() {
p = s.bufptr()
goto LOOP goto LOOP
} }
} }
return c
} }
func (s *stream) skipObject(depth int64) error { func (s *Stream) skipObject(depth int64) error {
braceCount := 1 braceCount := 1
_, cursor, p := s.stat() _, cursor, p := s.stat()
for { for {
@ -136,7 +252,7 @@ func (s *stream) skipObject(depth int64) error {
braceCount++ braceCount++
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor) return errors.ErrExceededMaxDepth(s.char(), s.cursor)
} }
case '}': case '}':
braceCount-- braceCount--
@ -148,7 +264,7 @@ func (s *stream) skipObject(depth int64) error {
case '[': case '[':
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor) return errors.ErrExceededMaxDepth(s.char(), s.cursor)
} }
case ']': case ']':
depth-- depth--
@ -164,7 +280,7 @@ func (s *stream) skipObject(depth int64) error {
_, cursor, p = s.statForRetry() _, cursor, p = s.statForRetry()
continue continue
} }
return errUnexpectedEndOfJSON("string of object", cursor) return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
case '"': case '"':
goto SWITCH_OUT goto SWITCH_OUT
@ -174,7 +290,7 @@ func (s *stream) skipObject(depth int64) error {
_, cursor, p = s.statForRetry() _, cursor, p = s.statForRetry()
continue continue
} }
return errUnexpectedEndOfJSON("string of object", cursor) return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
} }
case nul: case nul:
@ -183,14 +299,14 @@ func (s *stream) skipObject(depth int64) error {
_, cursor, p = s.stat() _, cursor, p = s.stat()
continue continue
} }
return errUnexpectedEndOfJSON("object of object", cursor) return errors.ErrUnexpectedEndOfJSON("object of object", cursor)
} }
SWITCH_OUT: SWITCH_OUT:
cursor++ cursor++
} }
} }
func (s *stream) skipArray(depth int64) error { func (s *Stream) skipArray(depth int64) error {
bracketCount := 1 bracketCount := 1
_, cursor, p := s.stat() _, cursor, p := s.stat()
for { for {
@ -199,7 +315,7 @@ func (s *stream) skipArray(depth int64) error {
bracketCount++ bracketCount++
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor) return errors.ErrExceededMaxDepth(s.char(), s.cursor)
} }
case ']': case ']':
bracketCount-- bracketCount--
@ -211,7 +327,7 @@ func (s *stream) skipArray(depth int64) error {
case '{': case '{':
depth++ depth++
if depth > maxDecodeNestingDepth { if depth > maxDecodeNestingDepth {
return errExceededMaxDepth(s.char(), s.cursor) return errors.ErrExceededMaxDepth(s.char(), s.cursor)
} }
case '}': case '}':
depth-- depth--
@ -227,7 +343,7 @@ func (s *stream) skipArray(depth int64) error {
_, cursor, p = s.statForRetry() _, cursor, p = s.statForRetry()
continue continue
} }
return errUnexpectedEndOfJSON("string of object", cursor) return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
case '"': case '"':
goto SWITCH_OUT goto SWITCH_OUT
@ -237,7 +353,7 @@ func (s *stream) skipArray(depth int64) error {
_, cursor, p = s.statForRetry() _, cursor, p = s.statForRetry()
continue continue
} }
return errUnexpectedEndOfJSON("string of object", cursor) return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
} }
} }
case nul: case nul:
@ -246,14 +362,14 @@ func (s *stream) skipArray(depth int64) error {
_, cursor, p = s.stat() _, cursor, p = s.stat()
continue continue
} }
return errUnexpectedEndOfJSON("array of object", cursor) return errors.ErrUnexpectedEndOfJSON("array of object", cursor)
} }
SWITCH_OUT: SWITCH_OUT:
cursor++ cursor++
} }
} }
func (s *stream) skipValue(depth int64) error { func (s *Stream) skipValue(depth int64) error {
_, cursor, p := s.stat() _, cursor, p := s.stat()
for { for {
switch char(p, cursor) { switch char(p, cursor) {
@ -266,7 +382,7 @@ func (s *stream) skipValue(depth int64) error {
_, cursor, p = s.stat() _, cursor, p = s.stat()
continue continue
} }
return errUnexpectedEndOfJSON("value of object", s.totalOffset()) return errors.ErrUnexpectedEndOfJSON("value of object", s.totalOffset())
case '{': case '{':
s.cursor = cursor + 1 s.cursor = cursor + 1
return s.skipObject(depth + 1) return s.skipObject(depth + 1)
@ -285,7 +401,7 @@ func (s *stream) skipValue(depth int64) error {
_, cursor, p = s.statForRetry() _, cursor, p = s.statForRetry()
continue continue
} }
return errUnexpectedEndOfJSON("value of string", s.totalOffset()) return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
} }
case '"': case '"':
s.cursor = cursor + 1 s.cursor = cursor + 1
@ -296,7 +412,7 @@ func (s *stream) skipValue(depth int64) error {
_, cursor, p = s.statForRetry() _, cursor, p = s.statForRetry()
continue continue
} }
return errUnexpectedEndOfJSON("value of string", s.totalOffset()) return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
} }
} }
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
@ -338,7 +454,7 @@ func (s *stream) skipValue(depth int64) error {
} }
} }
func nullBytes(s *stream) error { func nullBytes(s *Stream) error {
// current cursor's character is 'n' // current cursor's character is 'n'
s.cursor++ s.cursor++
if s.char() != 'u' { if s.char() != 'u' {
@ -362,14 +478,14 @@ func nullBytes(s *stream) error {
return nil return nil
} }
func retryReadNull(s *stream) error { func retryReadNull(s *Stream) error {
if s.char() == nul && s.read() { if s.char() == nul && s.read() {
return nil return nil
} }
return errInvalidCharacter(s.char(), "null", s.totalOffset()) return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset())
} }
func trueBytes(s *stream) error { func trueBytes(s *Stream) error {
// current cursor's character is 't' // current cursor's character is 't'
s.cursor++ s.cursor++
if s.char() != 'r' { if s.char() != 'r' {
@ -393,14 +509,14 @@ func trueBytes(s *stream) error {
return nil return nil
} }
func retryReadTrue(s *stream) error { func retryReadTrue(s *Stream) error {
if s.char() == nul && s.read() { if s.char() == nul && s.read() {
return nil return nil
} }
return errInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset())
} }
func falseBytes(s *stream) error { func falseBytes(s *Stream) error {
// current cursor's character is 'f' // current cursor's character is 'f'
s.cursor++ s.cursor++
if s.char() != 'a' { if s.char() != 'a' {
@ -430,9 +546,9 @@ func falseBytes(s *stream) error {
return nil return nil
} }
func retryReadFalse(s *stream) error { func retryReadFalse(s *Stream) error {
if s.char() == nul && s.read() { if s.char() == nul && s.read() {
return nil return nil
} }
return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset())
} }

View file

@ -1,4 +1,4 @@
package json package decoder
import ( import (
"reflect" "reflect"
@ -6,6 +6,8 @@
"unicode/utf16" "unicode/utf16"
"unicode/utf8" "unicode/utf8"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors"
) )
type stringDecoder struct { type stringDecoder struct {
@ -20,8 +22,8 @@ func newStringDecoder(structName, fieldName string) *stringDecoder {
} }
} }
func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *UnmarshalTypeError { func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *errors.UnmarshalTypeError {
return &UnmarshalTypeError{ return &errors.UnmarshalTypeError{
Value: typeName, Value: typeName,
Type: reflect.TypeOf(""), Type: reflect.TypeOf(""),
Offset: offset, Offset: offset,
@ -30,7 +32,7 @@ func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *Unmarsh
} }
} }
func (d *stringDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { func (d *stringDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
bytes, err := d.decodeStreamByte(s) bytes, err := d.decodeStreamByte(s)
if err != nil { if err != nil {
return err return err
@ -43,8 +45,8 @@ func (d *stringDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) e
return nil return nil
} }
func (d *stringDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { func (d *stringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
bytes, c, err := d.decodeByte(buf, cursor) bytes, c, err := d.decodeByte(ctx.Buf, cursor)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -91,38 +93,40 @@ func unicodeToRune(code []byte) rune {
return r return r
} }
func decodeUnicodeRune(s *stream) (rune, int64, error) { func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) {
const defaultOffset = 5 const defaultOffset = 5
const surrogateOffset = 11 const surrogateOffset = 11
if s.cursor+defaultOffset >= s.length { if s.cursor+defaultOffset >= s.length {
if !s.read() { if !s.read() {
return rune(0), 0, errInvalidCharacter(s.char(), "escaped string", s.totalOffset()) return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
} }
p = s.bufptr()
} }
r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset]) r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset])
if utf16.IsSurrogate(r) { if utf16.IsSurrogate(r) {
if s.cursor+surrogateOffset >= s.length { if s.cursor+surrogateOffset >= s.length {
s.read() s.read()
p = s.bufptr()
} }
if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' { if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
return unicode.ReplacementChar, defaultOffset, nil return unicode.ReplacementChar, defaultOffset, p, nil
} }
r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset]) r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset])
if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar { if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar {
return r, surrogateOffset, nil return r, surrogateOffset, p, nil
} }
} }
return r, defaultOffset, nil return r, defaultOffset, p, nil
} }
func decodeUnicode(s *stream) error { func decodeUnicode(s *Stream, p unsafe.Pointer) (unsafe.Pointer, error) {
const backSlashAndULen = 2 // length of \u const backSlashAndULen = 2 // length of \u
r, offset, err := decodeUnicodeRune(s) r, offset, pp, err := decodeUnicodeRune(s, p)
if err != nil { if err != nil {
return err return nil, err
} }
unicode := []byte(string(r)) unicode := []byte(string(r))
unicodeLen := int64(len(unicode)) unicodeLen := int64(len(unicode))
@ -130,10 +134,10 @@ func decodeUnicode(s *stream) error {
unicodeOrgLen := offset - 1 unicodeOrgLen := offset - 1
s.length = s.length - (backSlashAndULen + (unicodeOrgLen - unicodeLen)) s.length = s.length - (backSlashAndULen + (unicodeOrgLen - unicodeLen))
s.cursor = s.cursor - backSlashAndULen + unicodeLen s.cursor = s.cursor - backSlashAndULen + unicodeLen
return nil return pp, nil
} }
func decodeEscapeString(s *stream) error { func decodeEscapeString(s *Stream, p unsafe.Pointer) (unsafe.Pointer, error) {
s.cursor++ s.cursor++
RETRY: RETRY:
switch s.buf[s.cursor] { switch s.buf[s.cursor] {
@ -154,19 +158,20 @@ func decodeEscapeString(s *stream) error {
case 't': case 't':
s.buf[s.cursor] = '\t' s.buf[s.cursor] = '\t'
case 'u': case 'u':
return decodeUnicode(s) return decodeUnicode(s, p)
case nul: case nul:
if !s.read() { if !s.read() {
return errInvalidCharacter(s.char(), "escaped string", s.totalOffset()) return nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
} }
goto RETRY goto RETRY
default: default:
return errUnexpectedEndOfJSON("string", s.totalOffset()) return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
} }
s.buf = append(s.buf[:s.cursor-1], s.buf[s.cursor:]...) s.buf = append(s.buf[:s.cursor-1], s.buf[s.cursor:]...)
s.length-- s.length--
s.cursor-- s.cursor--
return nil p = s.bufptr()
return p, nil
} }
var ( var (
@ -174,7 +179,7 @@ func decodeEscapeString(s *stream) error {
runeErrBytesLen = int64(len(runeErrBytes)) runeErrBytesLen = int64(len(runeErrBytes))
) )
func stringBytes(s *stream) ([]byte, error) { func stringBytes(s *Stream) ([]byte, error) {
_, cursor, p := s.stat() _, cursor, p := s.stat()
cursor++ // skip double quote char cursor++ // skip double quote char
start := cursor start := cursor
@ -182,9 +187,11 @@ func stringBytes(s *stream) ([]byte, error) {
switch char(p, cursor) { switch char(p, cursor) {
case '\\': case '\\':
s.cursor = cursor s.cursor = cursor
if err := decodeEscapeString(s); err != nil { pp, err := decodeEscapeString(s, p)
if err != nil {
return nil, err return nil, err
} }
p = pp
cursor = s.cursor cursor = s.cursor
case '"': case '"':
literal := s.buf[start:cursor] literal := s.buf[start:cursor]
@ -232,23 +239,32 @@ func stringBytes(s *stream) ([]byte, error) {
fallthrough fallthrough
default: default:
// multi bytes character // multi bytes character
r, _ := utf8.DecodeRune(s.buf[cursor:]) if !utf8.FullRune(s.buf[cursor : len(s.buf)-1]) {
b := []byte(string(r)) s.cursor = cursor
if r == utf8.RuneError { if s.read() {
s.buf = append(append(append([]byte{}, s.buf[:cursor]...), b...), s.buf[cursor+1:]...) _, cursor, p = s.stat()
_, _, p = s.stat() continue
}
goto ERROR
}
r, size := utf8.DecodeRune(s.buf[cursor:])
if r == utf8.RuneError {
s.buf = append(append(append([]byte{}, s.buf[:cursor]...), runeErrBytes...), s.buf[cursor+1:]...)
cursor += runeErrBytesLen
s.length += runeErrBytesLen
_, _, p = s.stat()
} else {
cursor += int64(size)
} }
cursor += int64(len(b))
s.length += int64(len(b))
continue continue
} }
cursor++ cursor++
} }
ERROR: ERROR:
return nil, errUnexpectedEndOfJSON("string", s.totalOffset()) return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
} }
func (d *stringDecoder) decodeStreamByte(s *stream) ([]byte, error) { func (d *stringDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
for { for {
switch s.char() { switch s.char() {
case ' ', '\n', '\t', '\r': case ' ', '\n', '\t', '\r':
@ -274,7 +290,7 @@ func (d *stringDecoder) decodeStreamByte(s *stream) ([]byte, error) {
} }
break break
} }
return nil, errNotAtBeginningOfValue(s.totalOffset()) return nil, errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset())
} }
func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
@ -324,13 +340,13 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
case 'u': case 'u':
buflen := int64(len(buf)) buflen := int64(len(buf))
if cursor+5 >= buflen { if cursor+5 >= buflen {
return nil, 0, errUnexpectedEndOfJSON("escaped string", cursor) return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
} }
code := unicodeToRune(buf[cursor+1 : cursor+5]) code := unicodeToRune(buf[cursor+1 : cursor+5])
unicode := []byte(string(code)) unicode := []byte(string(code))
buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...) buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...)
default: default:
return nil, 0, errUnexpectedEndOfJSON("escaped string", cursor) return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
} }
continue continue
case '"': case '"':
@ -338,7 +354,7 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
cursor++ cursor++
return literal, cursor, nil return literal, cursor, nil
case nul: case nul:
return nil, 0, errUnexpectedEndOfJSON("string", cursor) return nil, 0, errors.ErrUnexpectedEndOfJSON("string", cursor)
} }
cursor++ cursor++
} }
@ -349,7 +365,7 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err
cursor += 4 cursor += 4
return nil, cursor, nil return nil, cursor, nil
default: default:
return nil, 0, errNotAtBeginningOfValue(cursor) return nil, 0, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor)
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show more