migrate go version to 1.17 (#203)
* migrate go version to 1.17 * update contributing
This commit is contained in:
parent
e681aac589
commit
f2e5bedea6
|
@ -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
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
118
go.mod
|
@ -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
110
go.sum
|
@ -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=
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -1,3 +0,0 @@
|
||||||
module github.com/buckket/go-blurhash
|
|
||||||
|
|
||||||
go 1.14
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -1,5 +0,0 @@
|
||||||
module github.com/dsoprea/go-iptc
|
|
||||||
|
|
||||||
go 1.13
|
|
||||||
|
|
||||||
require github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d
|
|
|
@ -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=
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -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
|
|
|
@ -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=
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -1,5 +0,0 @@
|
||||||
module github.com/gin-contrib/sse
|
|
||||||
|
|
||||||
go 1.12
|
|
||||||
|
|
||||||
require github.com/stretchr/testify v1.3.0
|
|
|
@ -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=
|
|
|
@ -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:"
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -26,7 +26,7 @@ var (
|
||||||
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,22 +1166,28 @@ 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),
|
// Done returns nil (chan which will wait forever) when c.Request has no Context.
|
||||||
// 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{} {
|
func (c *Context) Done() <-chan struct{} {
|
||||||
|
if c.Request == nil || c.Request.Context() == nil {
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
return c.Request.Context().Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Err always returns nil, maybe you want to use Request.Context().Err() instead.
|
// Err returns nil when c.Request has no Context.
|
||||||
func (c *Context) Err() error {
|
func (c *Context) Err() error {
|
||||||
|
if c.Request == nil || c.Request.Context() == nil {
|
||||||
return 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
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -41,8 +41,10 @@ var DefaultWriter io.Writer = os.Stdout
|
||||||
// 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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -7,7 +7,7 @@ package render
|
||||||
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.
|
||||||
|
|
|
@ -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 @@ walk: // Outer loop for walking the tree
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@ walk: // Outer loop for walking the tree
|
||||||
|
|
||||||
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 @@ walk: // Outer loop for walking the tree
|
||||||
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 @@ walk: // Outer loop for walking the tree
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@ walk: // Outer loop for walking the tree
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
|
|
@ -1,5 +0,0 @@
|
||||||
module github.com/go-fed/httpsig
|
|
||||||
|
|
||||||
require golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
|
||||||
|
|
||||||
go 1.13
|
|
|
@ -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=
|
|
|
@ -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
|
||||||
|
|
|
@ -176,6 +176,7 @@ const (
|
||||||
MNT
|
MNT
|
||||||
MOP
|
MOP
|
||||||
MRO
|
MRO
|
||||||
|
MRU
|
||||||
MTL
|
MTL
|
||||||
MTP
|
MTP
|
||||||
MUR
|
MUR
|
||||||
|
@ -262,9 +263,11 @@ const (
|
||||||
UYI
|
UYI
|
||||||
UYP
|
UYP
|
||||||
UYU
|
UYU
|
||||||
|
UYW
|
||||||
UZS
|
UZS
|
||||||
VEB
|
VEB
|
||||||
VEF
|
VEF
|
||||||
|
VES
|
||||||
VND
|
VND
|
||||||
VNN
|
VNN
|
||||||
VUV
|
VUV
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
module github.com/go-playground/locales
|
|
||||||
|
|
||||||
go 1.13
|
|
||||||
|
|
||||||
require golang.org/x/text v0.3.2
|
|
|
@ -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=
|
|
|
@ -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
|
|
@ -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:
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
module github.com/go-playground/universal-translator
|
|
||||||
|
|
||||||
go 1.13
|
|
||||||
|
|
||||||
require github.com/go-playground/locales v0.13.0
|
|
|
@ -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=
|
|
|
@ -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":
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
-------
|
-------
|
||||||
|
@ -100,7 +100,7 @@ Baked-in Validations
|
||||||
| hostname_rfc1123 | Hostname RFC 1123 |
|
| hostname_rfc1123 | Hostname RFC 1123 |
|
||||||
| ip | Internet Protocol Address IP |
|
| ip | Internet Protocol Address IP |
|
||||||
| ip4_addr | Internet Protocol Address IPv4 |
|
| ip4_addr | Internet Protocol Address IPv4 |
|
||||||
| ip6_addr |Internet Protocol Address IPv6 |
|
| ip6_addr | Internet Protocol Address IPv6 |
|
||||||
| ip_addr | Internet Protocol Address IP |
|
| ip_addr | Internet Protocol Address IP |
|
||||||
| ipv4 | Internet Protocol Address IPv4 |
|
| ipv4 | Internet Protocol Address IPv4 |
|
||||||
| ipv6 | Internet Protocol Address IPv6 |
|
| ipv6 | Internet Protocol Address IPv6 |
|
||||||
|
@ -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 |
|
||||||
|
@ -178,7 +195,7 @@ Baked-in Validations
|
||||||
| - | - |
|
| - | - |
|
||||||
| eq | Equals |
|
| eq | Equals |
|
||||||
| gt | Greater than|
|
| gt | Greater than|
|
||||||
| gte |Greater than or equal |
|
| gte | Greater than or equal |
|
||||||
| lt | Less Than |
|
| lt | Less Than |
|
||||||
| lte | Less Than or Equal |
|
| lte | Less Than or Equal |
|
||||||
| ne | Not Equal |
|
| ne | Not Equal |
|
||||||
|
@ -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
|
||||||
|
|
|
@ -56,7 +56,7 @@ var (
|
||||||
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 @@ var (
|
||||||
"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 @@ var (
|
||||||
"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 @@ var (
|
||||||
"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 @@ var (
|
||||||
"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()
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
|
@ -7,6 +7,14 @@ and has the ability to dive into arrays and maps of any type.
|
||||||
|
|
||||||
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 @@ This validates that a string value contains unicode alphanumeric characters only
|
||||||
|
|
||||||
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 @@ This validates that a string value is valid JSON
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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=
|
|
|
@ -48,6 +48,7 @@ const (
|
||||||
uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$`
|
uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$`
|
||||||
hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?`
|
hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?`
|
||||||
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 @@ var (
|
||||||
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)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)))
|
|
||||||
}
|
|
|
@ -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),
|
||||||
|
}
|
||||||
|
)
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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++
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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++
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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)
|
||||||
|
}
|
||||||
func encodeDebugRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
|
return vm_indent.Run(ctx, b, codeSet)
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,3 @@ type UnmarshalTypeError = errors.UnmarshalTypeError
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
module github.com/goccy/go-json
|
|
||||||
|
|
||||||
go 1.12
|
|
37
vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go
generated
vendored
Normal file
37
vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go
generated
vendored
Normal 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))
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
28
vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go
generated
vendored
Normal file
28
vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go
generated
vendored
Normal 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
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
|
@ -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)
|
||||||
|
}
|
|
@ -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 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
|
@ -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)
|
||||||
}
|
}
|
|
@ -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++
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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 @@ const (
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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())
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package json
|
package decoder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -6,6 +6,8 @@ import (
|
||||||
"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 @@ RETRY:
|
||||||
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 @@ var (
|
||||||
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
Loading…
Reference in New Issue