initial commit for ipbl
This commit is contained in:
commit
e3dbfa30e5
144
.drone.yml
Normal file
144
.drone.yml
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: cleanup-before
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: clean
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- rm -rf /build/*
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /build
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/ipbl/build
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default-linux-amd64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
|
image: golang
|
||||||
|
commands:
|
||||||
|
- ./ci-build.sh build
|
||||||
|
environment:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: amd64
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /build
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/ipbl/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- cleanup-before
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: default-linux-arm64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build
|
||||||
|
image: golang
|
||||||
|
commands:
|
||||||
|
- ./ci-build.sh build
|
||||||
|
environment:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: arm64
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /build
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/ipbl/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- cleanup-before
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: gitea-release
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: move
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- mv build/* ./
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /drone/src/build
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
- name: release
|
||||||
|
image: plugins/gitea-release
|
||||||
|
settings:
|
||||||
|
base_url: https://git.paulbsd.com
|
||||||
|
api_key:
|
||||||
|
from_secret: gitea_token
|
||||||
|
files: "*.tar.gz"
|
||||||
|
checksum:
|
||||||
|
- sha256
|
||||||
|
- sha512
|
||||||
|
title: VERSION
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /drone/src/build
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
- name: ls
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- find .
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /drone/src/build
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/ipbl/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- default-linux-amd64
|
||||||
|
- default-linux-arm64
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: cleanup-after
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: clean
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- rm -rf /build/*
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
path: /build
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: build
|
||||||
|
host:
|
||||||
|
path: /tmp/ipbl/build
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- gitea-release
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/ipbl
|
||||||
|
*.ini
|
||||||
|
/test
|
18
Makefile
Normal file
18
Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# ipbl Makefile
|
||||||
|
|
||||||
|
GOCMD=go
|
||||||
|
GOBUILDCMD=${GOCMD} build
|
||||||
|
GOOPTIONS=-mod=vendor -ldflags="-s -w"
|
||||||
|
|
||||||
|
RMCMD=rm
|
||||||
|
BINNAME=ipbl
|
||||||
|
|
||||||
|
SRCFILES=cmd/ipbl/*.go
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
${GOBUILDCMD} ${GOOPTIONS} ${SRCFILES}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
${RMCMD} -f ${BINNAME}
|
62
README.md
Normal file
62
README.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# ipbl
|
||||||
|
[![Build Status](https://drone.paulbsd.com/api/badges/paulbsd/ipbl/status.svg)](https://drone.paulbsd.com/paulbsd/ipbl)
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
ipbl is ...
|
||||||
|
|
||||||
|
## Howto
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sample config in ipbl.ini
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[ipbl]
|
||||||
|
db_hostname="hostname"
|
||||||
|
db_name="database"
|
||||||
|
db_username="username"
|
||||||
|
db_password="password"
|
||||||
|
db_table="ipbl_test"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./ipbl -configfile ipbl.ini -port 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
```text
|
||||||
|
Copyright (c) 2020, 2021 PaulBSD
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
The views and conclusions contained in the software and documentation are those
|
||||||
|
of the authors and should not be interpreted as representing official policies,
|
||||||
|
either expressed or implied, of this project.
|
||||||
|
```
|
62
ci-build.sh
Executable file
62
ci-build.sh
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PROJECTNAME=ipbl
|
||||||
|
RELEASENAME=${PROJECTNAME}
|
||||||
|
VERSION="0"
|
||||||
|
|
||||||
|
GOOPTIONS="-mod=vendor"
|
||||||
|
SRCFILES=cmd/${PROJECTNAME}/*.go
|
||||||
|
|
||||||
|
build() {
|
||||||
|
echo "Begin of build"
|
||||||
|
if [[ ! -z $DRONE_TAG ]]
|
||||||
|
then
|
||||||
|
echo "Drone tag set, let's do a release"
|
||||||
|
VERSION=$DRONE_TAG
|
||||||
|
echo "${PROJECTNAME} ${VERSION}" > /build/VERSION
|
||||||
|
elif [[ ! -z $DRONE_TAG ]]
|
||||||
|
then
|
||||||
|
echo "Drone not set, let's only do a build"
|
||||||
|
VERSION=$DRONE_COMMIT
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -z $VERSION && ! -z $GOOS && ! -z $GOARCH ]]
|
||||||
|
then
|
||||||
|
echo "Let's set a release name"
|
||||||
|
RELEASENAME=${PROJECTNAME}-${VERSION}-${GOOS}-${GOARCH}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building project"
|
||||||
|
go build -o ${PROJECTNAME} ${GOOPTIONS} ${SRCFILES}
|
||||||
|
|
||||||
|
if [[ ! -z $DRONE_TAG ]]
|
||||||
|
then
|
||||||
|
echo "Let's make archives"
|
||||||
|
mkdir -p /build
|
||||||
|
tar -czvf /build/${RELEASENAME}.tar.gz ${PROJECTNAME}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Removing binary file"
|
||||||
|
rm ${PROJECTNAME}
|
||||||
|
|
||||||
|
echo "End of build"
|
||||||
|
}
|
||||||
|
|
||||||
|
clean() {
|
||||||
|
rm -rf $RELEASEDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
"build")
|
||||||
|
build
|
||||||
|
;;
|
||||||
|
"clean")
|
||||||
|
clean
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "No options choosen"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
57
cmd/ipbl/ipbl.go
Normal file
57
cmd/ipbl/ipbl.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/config"
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/database"
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/ipbl"
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/ipblws"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
//var version string
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var ipblCtx ipbl.IP
|
||||||
|
|
||||||
|
var cfg config.Config
|
||||||
|
cfg.GetConfig()
|
||||||
|
//cfg.Options.Version = version
|
||||||
|
|
||||||
|
// Initialize database app context
|
||||||
|
err := database.Init(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
defer cfg.Db.Close()
|
||||||
|
|
||||||
|
// Initialize ipbl app context
|
||||||
|
err = ipblCtx.Init(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var orphans = []ipbl.IP{}
|
||||||
|
cfg.Db.Where("rdns IS NULL").Asc("ip").Find(&orphans)
|
||||||
|
for _, i := range orphans {
|
||||||
|
reverse := i.UpdateRDNS()
|
||||||
|
if reverse == "" {
|
||||||
|
fmt.Printf("Set \"none\" rdns to IP %s\n", i.IP)
|
||||||
|
i.Rdns = "none"
|
||||||
|
cfg.Db.ID(i.ID).Cols("rdns").Update(&i)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s %s\n", i.IP, reverse)
|
||||||
|
i.Rdns = reverse
|
||||||
|
cfg.Db.ID(i.ID).Cols("rdns").Update(&i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("end")
|
||||||
|
|
||||||
|
// Run the ipbl web service
|
||||||
|
err = ipblws.RunServer(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
32
go.mod
Normal file
32
go.mod
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
module git.paulbsd.com/paulbsd/ipbl
|
||||||
|
|
||||||
|
go 1.17
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/labstack/echo/v4 v4.6.1
|
||||||
|
github.com/lib/pq v1.10.3
|
||||||
|
gopkg.in/ini.v1 v1.63.2
|
||||||
|
xorm.io/xorm v1.2.5
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/goccy/go-json v0.7.8 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.11 // indirect
|
||||||
|
github.com/labstack/gommon v0.3.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||||
|
github.com/onsi/gomega v1.14.0 // indirect
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20210913180222-943fd674d43e // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
|
xorm.io/builder v0.3.9 // indirect
|
||||||
|
)
|
610
go.sum
Normal file
610
go.sum
Normal file
@ -0,0 +1,610 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||||
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
|
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||||
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
|
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||||
|
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||||
|
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||||
|
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/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/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
|
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/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||||
|
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/goccy/go-json v0.7.4/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 v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||||
|
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
|
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||||
|
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||||
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||||
|
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||||
|
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
|
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
|
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||||
|
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||||
|
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||||
|
github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk=
|
||||||
|
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||||
|
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||||
|
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||||
|
github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g=
|
||||||
|
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||||
|
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||||
|
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||||
|
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||||
|
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||||
|
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||||
|
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||||
|
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||||
|
github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0=
|
||||||
|
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
|
||||||
|
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
|
||||||
|
github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE=
|
||||||
|
github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE=
|
||||||
|
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||||
|
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||||
|
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||||
|
github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA=
|
||||||
|
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
|
||||||
|
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
|
||||||
|
github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc=
|
||||||
|
github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60=
|
||||||
|
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
|
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
|
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
|
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
|
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.8/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/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
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/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/labstack/echo/v4 v4.6.1 h1:OMVsrnNFzYlGSdaiYGHbgWQnr+JM7NG+B9suCPie14M=
|
||||||
|
github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k=
|
||||||
|
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||||
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
|
||||||
|
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||||
|
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||||
|
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
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.8/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.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/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||||
|
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||||
|
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||||
|
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||||
|
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||||
|
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||||
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||||
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||||
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
|
github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI=
|
||||||
|
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||||
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||||
|
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||||
|
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||||
|
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
|
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||||
|
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||||
|
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||||
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
|
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||||
|
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
|
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
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/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
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.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
|
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||||
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
|
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||||
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
|
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
|
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
|
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||||
|
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
|
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||||
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||||
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/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/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
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/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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
|
golang.org/x/net v0.0.0-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8=
|
||||||
|
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 h1:xrCZDmdtoloIiooiA9q0OQb9r8HejIHYoHGhGCe1pGg=
|
||||||
|
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/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-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
|
||||||
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
|
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/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||||
|
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||||
|
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
|
||||||
|
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
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/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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
|
||||||
|
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||||
|
modernc.org/cc/v3 v3.33.6 h1:r63dgSzVzRxUpAJFPQWHy1QeZeY1ydNENUDaBx1GqYc=
|
||||||
|
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||||
|
modernc.org/ccgo/v3 v3.9.5 h1:dEuUSf8WN51rDkprFuAqjfchKEzN0WttP/Py3enBwjk=
|
||||||
|
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
|
||||||
|
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||||
|
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||||
|
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||||
|
modernc.org/libc v1.9.11 h1:QUxZMs48Ahg2F7SN41aERvMfGLY2HU/ADnB9DC4Yts8=
|
||||||
|
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
|
||||||
|
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
modernc.org/mathutil v1.4.0 h1:GCjoRaBew8ECCKINQA2nYjzvufFW9YiEuuB+rQ9bn2E=
|
||||||
|
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
|
||||||
|
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
|
||||||
|
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
|
||||||
|
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/sqlite v1.11.2 h1:ShWQpeD3ag/bmx6TqidBlIWonWmQaSQKls3aenCbt+w=
|
||||||
|
modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A=
|
||||||
|
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
|
||||||
|
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||||
|
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI=
|
||||||
|
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
||||||
|
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
|
||||||
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
|
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||||
|
xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=
|
||||||
|
xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||||
|
xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo=
|
||||||
|
xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0=
|
5
ipbl.ini.sample
Normal file
5
ipbl.ini.sample
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[ipbl]
|
||||||
|
db_hostname="hostname"
|
||||||
|
db_name="database"
|
||||||
|
db_username="username"
|
||||||
|
db_password="password"
|
75
src/config/main.go
Normal file
75
src/config/main.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/utils"
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetConfig fetch configuration
|
||||||
|
func (cfg *Config) GetConfig() error {
|
||||||
|
var configfile string
|
||||||
|
var debug bool
|
||||||
|
var drop bool
|
||||||
|
var port int
|
||||||
|
var init bool
|
||||||
|
|
||||||
|
flag.Usage = utils.Usage
|
||||||
|
|
||||||
|
flag.StringVar(&configfile, "configfile", "ipbl.ini", "Configuration file to use with ipbl section")
|
||||||
|
flag.IntVar(&port, "port", 8095, "Web service port to use")
|
||||||
|
flag.BoolVar(&debug, "debug", false, "If debug logging must be enabled")
|
||||||
|
flag.BoolVar(&drop, "drop", false, "If dropping tables must occur")
|
||||||
|
flag.BoolVar(&init, "init", false, "If init of database must be done")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
cfg.Switchs.Port = port
|
||||||
|
cfg.Switchs.Debug = debug
|
||||||
|
cfg.Switchs.Drop = drop
|
||||||
|
cfg.Switchs.Init = init
|
||||||
|
|
||||||
|
inicfg, err := ini.Load(configfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ipblsection := inicfg.Section("ipbl")
|
||||||
|
|
||||||
|
cfg.DbParams.DbHostname = ipblsection.Key("db_hostname").MustString("localhost")
|
||||||
|
cfg.DbParams.DbName = ipblsection.Key("db_name").MustString("database")
|
||||||
|
cfg.DbParams.DbUsername = ipblsection.Key("db_username").MustString("username")
|
||||||
|
cfg.DbParams.DbPassword = ipblsection.Key("db_password").MustString("password")
|
||||||
|
cfg.Options.HideBanner = ipblsection.Key("hidebanner").MustBool(false)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is the global config
|
||||||
|
type Config struct {
|
||||||
|
Db *xorm.Engine `json:"-"`
|
||||||
|
DbParams struct {
|
||||||
|
DbHostname string `json:"dbhostname"`
|
||||||
|
DbName string `json:"dbname"`
|
||||||
|
DbUsername string `json:"dbusername"`
|
||||||
|
DbPassword string `json:"dbpassword"`
|
||||||
|
} `json:"dbparams"`
|
||||||
|
Options struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
HideBanner bool `json:"hidebanner"`
|
||||||
|
} `json:"-"`
|
||||||
|
Switchs struct {
|
||||||
|
Port int `json:"port"`
|
||||||
|
NoFeed bool `json:"nofeed"`
|
||||||
|
Debug bool `json:"debug"`
|
||||||
|
Drop bool `json:"drop"`
|
||||||
|
Init bool `json:"init"`
|
||||||
|
} `json:"-"`
|
||||||
|
Init struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
} `json:"-"`
|
||||||
|
}
|
47
src/database/main.go
Normal file
47
src/database/main.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/config"
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/ipbl"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
"xorm.io/xorm/names"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init creates connection to database and exec Schema
|
||||||
|
func Init(cfg *config.Config) (err error) {
|
||||||
|
databaseEngine := "postgres"
|
||||||
|
tables := []interface{}{ipbl.IP{}}
|
||||||
|
|
||||||
|
cfg.Db, err = xorm.NewEngine(databaseEngine,
|
||||||
|
fmt.Sprintf("%s://%s:%s@%s/%s",
|
||||||
|
databaseEngine,
|
||||||
|
cfg.DbParams.DbUsername,
|
||||||
|
cfg.DbParams.DbPassword,
|
||||||
|
cfg.DbParams.DbHostname,
|
||||||
|
cfg.DbParams.DbName))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
cfg.Db.SetMapper(names.GonicMapper{})
|
||||||
|
cfg.Db.ShowSQL(cfg.Switchs.Debug)
|
||||||
|
|
||||||
|
if cfg.Switchs.Drop {
|
||||||
|
for _, table := range tables {
|
||||||
|
cfg.Db.DropTables(table)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Syncing tables")
|
||||||
|
for _, table := range tables {
|
||||||
|
cfg.Db.CreateTables(table)
|
||||||
|
err = cfg.Db.Sync2(table)
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
30
src/ipbl/ip.go
Normal file
30
src/ipbl/ip.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package ipbl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i *IP) Init(*config.Config) (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IP) UpdateRDNS() (result string) {
|
||||||
|
res, err := net.LookupAddr(i.IP)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return res[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// User describe accounts
|
||||||
|
type IP struct {
|
||||||
|
ID int `xorm:"pk autoincr" json:"-"`
|
||||||
|
IP string `xorm:"text notnull unique(ipsrc)" json:"ip"`
|
||||||
|
Rdns string `xorm:"text default" json:"rdns"`
|
||||||
|
Src string `xorm:"text notnull unique(ipsrc)" json:"src"`
|
||||||
|
Created time.Time `xorm:"created notnull" json:"-"`
|
||||||
|
Updated time.Time `xorm:"updated notnull" json:"-"`
|
||||||
|
}
|
50
src/ipblws/server.go
Normal file
50
src/ipblws/server.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package ipblws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/config"
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/ipbl"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RunServer runs the main echo HTTP server
|
||||||
|
func RunServer(cfg *config.Config) (err error) {
|
||||||
|
e := echo.New()
|
||||||
|
|
||||||
|
e.HideBanner = cfg.Options.HideBanner
|
||||||
|
|
||||||
|
e.GET("/", func(c echo.Context) error {
|
||||||
|
return c.String(http.StatusOK, "Welcome to ipbl software (https://git.paulbsd.com/paulbsd/ipbl)")
|
||||||
|
})
|
||||||
|
e.GET("/ip/:ip", func(c echo.Context) (err error) {
|
||||||
|
var ip = ipbl.IP{IP: c.Param("ip")}
|
||||||
|
res, _ := cfg.Db.Get(&ip)
|
||||||
|
if res {
|
||||||
|
return c.JSON(http.StatusOK, ip)
|
||||||
|
}
|
||||||
|
return c.String(http.StatusNotFound, "IP not found")
|
||||||
|
})
|
||||||
|
e.GET("/ips", func(c echo.Context) (err error) {
|
||||||
|
var ips = []ipbl.IP{}
|
||||||
|
var limit int = 50
|
||||||
|
if c.QueryParam("limit") != "" {
|
||||||
|
limit, err = strconv.Atoi(c.QueryParam("limit"))
|
||||||
|
if err != nil {
|
||||||
|
limit = 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfg.Db.Limit(limit).Desc("created").Find(&ips)
|
||||||
|
return c.JSON(http.StatusOK, ips)
|
||||||
|
})
|
||||||
|
|
||||||
|
e.Logger.Fatal(
|
||||||
|
e.Start(
|
||||||
|
fmt.Sprintf(":%d",
|
||||||
|
cfg.Switchs.Port)))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
1
src/ipblws/serverhandle.go
Normal file
1
src/ipblws/serverhandle.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package ipblws
|
17
src/ipblws/utils.go
Normal file
17
src/ipblws/utils.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package ipblws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.paulbsd.com/paulbsd/ipbl/src/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigAccess make ip authorization to configuration
|
||||||
|
func ConfigAccess(cfg config.Config, ip string) (ret bool) {
|
||||||
|
switch ip {
|
||||||
|
case "127.0.0.1":
|
||||||
|
return true
|
||||||
|
case "::1":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
21
utils/main.go
Normal file
21
utils/main.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Usage displays possible arguments
|
||||||
|
func Usage() {
|
||||||
|
flag.PrintDefaults()
|
||||||
|
log.Fatal()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advice displays possible arguments with warning advices
|
||||||
|
func Advice(advice string) {
|
||||||
|
flag.PrintDefaults()
|
||||||
|
if advice != "" {
|
||||||
|
log.Fatalln(advice)
|
||||||
|
}
|
||||||
|
log.Fatal()
|
||||||
|
}
|
32
vendor/github.com/goccy/go-json/.codecov.yml
generated
vendored
Normal file
32
vendor/github.com/goccy/go-json/.codecov.yml
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
codecov:
|
||||||
|
require_ci_to_pass: yes
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
precision: 2
|
||||||
|
round: down
|
||||||
|
range: "70...100"
|
||||||
|
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
target: 70%
|
||||||
|
threshold: 2%
|
||||||
|
patch: off
|
||||||
|
changes: no
|
||||||
|
|
||||||
|
parsers:
|
||||||
|
gcov:
|
||||||
|
branch_detection:
|
||||||
|
conditional: yes
|
||||||
|
loop: yes
|
||||||
|
method: no
|
||||||
|
macro: no
|
||||||
|
|
||||||
|
comment:
|
||||||
|
layout: "header,diff"
|
||||||
|
behavior: default
|
||||||
|
require_changes: no
|
||||||
|
|
||||||
|
ignore:
|
||||||
|
- internal/encoder/vm_color
|
||||||
|
- internal/encoder/vm_color_indent
|
2
vendor/github.com/goccy/go-json/.gitignore
generated
vendored
Normal file
2
vendor/github.com/goccy/go-json/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
cover.html
|
||||||
|
cover.out
|
75
vendor/github.com/goccy/go-json/.golangci.yml
generated
vendored
Normal file
75
vendor/github.com/goccy/go-json/.golangci.yml
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
run:
|
||||||
|
skip-files:
|
||||||
|
- encode_optype.go
|
||||||
|
- ".*_test\\.go$"
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
govet:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- shadow
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- exhaustive
|
||||||
|
- exhaustivestruct
|
||||||
|
- errorlint
|
||||||
|
- forbidigo
|
||||||
|
- funlen
|
||||||
|
- gci
|
||||||
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
|
- gocognit
|
||||||
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- godot
|
||||||
|
- godox
|
||||||
|
- goerr113
|
||||||
|
- gofumpt
|
||||||
|
- gomnd
|
||||||
|
- gosec
|
||||||
|
- ifshort
|
||||||
|
- lll
|
||||||
|
- makezero
|
||||||
|
- nakedret
|
||||||
|
- nestif
|
||||||
|
- nlreturn
|
||||||
|
- paralleltest
|
||||||
|
- testpackage
|
||||||
|
- thelper
|
||||||
|
- wrapcheck
|
||||||
|
- interfacer
|
||||||
|
- lll
|
||||||
|
- nakedret
|
||||||
|
- nestif
|
||||||
|
- nlreturn
|
||||||
|
- testpackage
|
||||||
|
- wsl
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exclude-rules:
|
||||||
|
# not needed
|
||||||
|
- path: /*.go
|
||||||
|
text: "ST1003: should not use underscores in package names"
|
||||||
|
linters:
|
||||||
|
- stylecheck
|
||||||
|
- path: /*.go
|
||||||
|
text: "don't use an underscore in package name"
|
||||||
|
linters:
|
||||||
|
- golint
|
||||||
|
- path: rtype.go
|
||||||
|
linters:
|
||||||
|
- golint
|
||||||
|
- stylecheck
|
||||||
|
- path: error.go
|
||||||
|
linters:
|
||||||
|
- staticcheck
|
||||||
|
|
||||||
|
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
|
||||||
|
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||||
|
max-same-issues: 0
|
260
vendor/github.com/goccy/go-json/CHANGELOG.md
generated
vendored
Normal file
260
vendor/github.com/goccy/go-json/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
### Optimization
|
||||||
|
|
||||||
|
* Add type addrShift to enable bigger encoder/decoder cache ( #213 )
|
||||||
|
|
||||||
|
### Fix decoder
|
||||||
|
|
||||||
|
* Keep original reference of slice element ( #229 )
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
* Refactor Debug mode for encoding ( #226 )
|
||||||
|
* Generate VM sources for encoding ( #227 )
|
||||||
|
* Refactor validator for null/true/false for decoding ( #221 )
|
||||||
|
|
||||||
|
# v0.5.0 - 2021/5/9
|
||||||
|
|
||||||
|
### Supports using omitempty and string tags at the same time ( #216 )
|
||||||
|
|
||||||
|
### Fix decoder
|
||||||
|
|
||||||
|
* Fix stream decoder for unicode char ( #215 )
|
||||||
|
* Fix decoding of slice element ( #219 )
|
||||||
|
* Fix calculating of buffer length for stream decoder ( #220 )
|
||||||
|
|
||||||
|
### Refactor
|
||||||
|
|
||||||
|
* replace skipWhiteSpace goto by loop ( #212 )
|
||||||
|
|
||||||
|
# v0.4.14 - 2021/5/4
|
||||||
|
|
||||||
|
### Benchmark
|
||||||
|
|
||||||
|
* Add valyala/fastjson to benchmark ( #193 )
|
||||||
|
* Add benchmark task for CI ( #211 )
|
||||||
|
|
||||||
|
### Fix decoder
|
||||||
|
|
||||||
|
* Fix decoding of slice with unmarshal json type ( #198 )
|
||||||
|
* Fix decoding of null value for interface type that does not implement Unmarshaler ( #205 )
|
||||||
|
* Fix decoding of null value to []byte by json.Unmarshal ( #206 )
|
||||||
|
* Fix decoding of backslash char at the end of string ( #207 )
|
||||||
|
* Fix stream decoder for null/true/false value ( #208 )
|
||||||
|
* Fix stream decoder for slow reader ( #211 )
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
* If cap of slice is enough, reuse slice data for compatibility with encoding/json ( #200 )
|
||||||
|
|
||||||
|
# v0.4.13 - 2021/4/20
|
||||||
|
|
||||||
|
### Fix json.Compact and json.Indent
|
||||||
|
|
||||||
|
* Support validation the input buffer for json.Compact and json.Indent ( #189 )
|
||||||
|
* Optimize json.Compact and json.Indent ( improve memory footprint ) ( #190 )
|
||||||
|
|
||||||
|
# v0.4.12 - 2021/4/15
|
||||||
|
|
||||||
|
### Fix encoder
|
||||||
|
|
||||||
|
* Fix unnecessary indent for empty slice type ( #181 )
|
||||||
|
* Fix encoding of omitempty feature for the slice or interface type ( #183 )
|
||||||
|
* Fix encoding custom types zero values with omitempty when marshaller exists ( #187 )
|
||||||
|
|
||||||
|
### Fix decoder
|
||||||
|
|
||||||
|
* Fix decoder for invalid top level value ( #184 )
|
||||||
|
* Fix decoder for invalid number value ( #185 )
|
||||||
|
|
||||||
|
# v0.4.11 - 2021/4/3
|
||||||
|
|
||||||
|
* Improve decoder performance for interface type
|
||||||
|
|
||||||
|
# v0.4.10 - 2021/4/2
|
||||||
|
|
||||||
|
### Fix encoder
|
||||||
|
|
||||||
|
* Fixed a bug when encoding slice and map containing recursive structures
|
||||||
|
* Fixed a logic to determine if indirect reference
|
||||||
|
|
||||||
|
# v0.4.9 - 2021/3/29
|
||||||
|
|
||||||
|
### Add debug mode
|
||||||
|
|
||||||
|
If you use `json.MarshalWithOption(v, json.Debug())` and `panic` occurred in `go-json`, produces debug information to console.
|
||||||
|
|
||||||
|
### Support a new feature to compatible with encoding/json
|
||||||
|
|
||||||
|
- invalid UTF-8 is coerced to valid UTF-8 ( without performance down )
|
||||||
|
|
||||||
|
### Fix encoder
|
||||||
|
|
||||||
|
- Fixed handling of MarshalJSON of function type
|
||||||
|
|
||||||
|
### Fix decoding of slice of pointer type
|
||||||
|
|
||||||
|
If there is a pointer value, go-json will use it. (This behavior is necessary to achieve the ability to prioritize pre-filled values). However, since slices are reused internally, there was a bug that referred to the previous pointer value. Therefore, it is not necessary to refer to the pointer value in advance for the slice element, so we explicitly initialize slice element by `nil`.
|
||||||
|
|
||||||
|
# v0.4.8 - 2021/3/21
|
||||||
|
|
||||||
|
### Reduce memory usage at compile time
|
||||||
|
|
||||||
|
* go-json have used about 2GB of memory at compile time, but now it can compile with about less than 550MB.
|
||||||
|
|
||||||
|
### Fix any encoder's bug
|
||||||
|
|
||||||
|
* Add many test cases for encoder
|
||||||
|
* Fix composite type ( slice/array/map )
|
||||||
|
* Fix pointer types
|
||||||
|
* Fix encoding of MarshalJSON or MarshalText or json.Number type
|
||||||
|
|
||||||
|
### Refactor encoder
|
||||||
|
|
||||||
|
* Change package layout for reducing memory usage at compile
|
||||||
|
* Remove anonymous and only operation
|
||||||
|
* Remove root property from encodeCompileContext and opcode
|
||||||
|
|
||||||
|
### Fix CI
|
||||||
|
|
||||||
|
* Add Go 1.16
|
||||||
|
* Remove Go 1.13
|
||||||
|
* Fix `make cover` task
|
||||||
|
|
||||||
|
### Number/Delim/Token/RawMessage use the types defined in encoding/json by type alias
|
||||||
|
|
||||||
|
# v0.4.7 - 2021/02/22
|
||||||
|
|
||||||
|
### Fix decoder
|
||||||
|
|
||||||
|
* Fix decoding of deep recursive structure
|
||||||
|
* Fix decoding of embedded unexported pointer field
|
||||||
|
* Fix invalid test case
|
||||||
|
* Fix decoding of invalid value
|
||||||
|
* Fix decoding of prefilled value
|
||||||
|
* Fix not being able to return UnmarshalTypeError when it should be returned
|
||||||
|
* Fix decoding of null value
|
||||||
|
* Fix decoding of type of null string
|
||||||
|
* Use pre allocated pointer if exists it at decoding
|
||||||
|
|
||||||
|
### Reduce memory usage at compile
|
||||||
|
|
||||||
|
* Integrate int/int8/int16/int32/int64 and uint/uint8/uint16/uint32/uint64 operation to reduce memory usage at compile
|
||||||
|
|
||||||
|
### Remove unnecessary optype
|
21
vendor/github.com/goccy/go-json/LICENSE
generated
vendored
Normal file
21
vendor/github.com/goccy/go-json/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Masaaki Goshima
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
39
vendor/github.com/goccy/go-json/Makefile
generated
vendored
Normal file
39
vendor/github.com/goccy/go-json/Makefile
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
PKG := github.com/goccy/go-json
|
||||||
|
|
||||||
|
BIN_DIR := $(CURDIR)/bin
|
||||||
|
PKGS := $(shell go list ./... | grep -v internal/cmd|grep -v test)
|
||||||
|
COVER_PKGS := $(foreach pkg,$(PKGS),$(subst $(PKG),.,$(pkg)))
|
||||||
|
|
||||||
|
COMMA := ,
|
||||||
|
EMPTY :=
|
||||||
|
SPACE := $(EMPTY) $(EMPTY)
|
||||||
|
COVERPKG_OPT := $(subst $(SPACE),$(COMMA),$(COVER_PKGS))
|
||||||
|
|
||||||
|
$(BIN_DIR):
|
||||||
|
@mkdir -p $(BIN_DIR)
|
||||||
|
|
||||||
|
.PHONY: cover
|
||||||
|
cover:
|
||||||
|
go test -coverpkg=$(COVERPKG_OPT) -coverprofile=cover.out ./...
|
||||||
|
|
||||||
|
.PHONY: cover-html
|
||||||
|
cover-html: cover
|
||||||
|
go tool cover -html=cover.out
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: golangci-lint
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
golangci-lint: | $(BIN_DIR)
|
||||||
|
@{ \
|
||||||
|
set -e; \
|
||||||
|
GOLANGCI_LINT_TMP_DIR=$$(mktemp -d); \
|
||||||
|
cd $$GOLANGCI_LINT_TMP_DIR; \
|
||||||
|
go mod init tmp; \
|
||||||
|
GOBIN=$(BIN_DIR) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.36.0; \
|
||||||
|
rm -rf $$GOLANGCI_LINT_TMP_DIR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
.PHONY: generate
|
||||||
|
generate:
|
||||||
|
go generate ./internal/...
|
529
vendor/github.com/goccy/go-json/README.md
generated
vendored
Normal file
529
vendor/github.com/goccy/go-json/README.md
generated
vendored
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
# go-json
|
||||||
|
|
||||||
|
![Go](https://github.com/goccy/go-json/workflows/Go/badge.svg)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/goccy/go-json?status.svg)](https://pkg.go.dev/github.com/goccy/go-json?tab=doc)
|
||||||
|
[![codecov](https://codecov.io/gh/goccy/go-json/branch/master/graph/badge.svg)](https://codecov.io/gh/goccy/go-json)
|
||||||
|
|
||||||
|
Fast JSON encoder/decoder compatible with encoding/json for Go
|
||||||
|
|
||||||
|
<img width="400px" src="https://user-images.githubusercontent.com/209884/92572337-42b42900-f2bf-11ea-973a-c74a359553a5.png"></img>
|
||||||
|
|
||||||
|
# Roadmap
|
||||||
|
|
||||||
|
```
|
||||||
|
* version ( expected release date )
|
||||||
|
|
||||||
|
* v0.7.0
|
||||||
|
|
|
||||||
|
| while maintaining compatibility with encoding/json, we will add convenient APIs
|
||||||
|
|
|
||||||
|
v
|
||||||
|
* v1.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).
|
||||||
|
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
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/goccy/go-json
|
||||||
|
```
|
||||||
|
|
||||||
|
# How to use
|
||||||
|
|
||||||
|
Replace import statement from `encoding/json` to `github.com/goccy/go-json`
|
||||||
|
|
||||||
|
```
|
||||||
|
-import "encoding/json"
|
||||||
|
+import "github.com/goccy/go-json"
|
||||||
|
```
|
||||||
|
|
||||||
|
# JSON library comparison
|
||||||
|
|
||||||
|
| name | encoder | decoder | compatible with `encoding/json` |
|
||||||
|
| :----: | :------: | :-----: | :-----------------------------: |
|
||||||
|
| encoding/json | yes | yes | N/A |
|
||||||
|
| [json-iterator/go](https://github.com/json-iterator/go) | yes | yes | partial |
|
||||||
|
| [easyjson](https://github.com/mailru/easyjson) | 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 | partial |
|
||||||
|
| [jettison](https://github.com/wI2L/jettison) | yes | no | no |
|
||||||
|
| [simdjson-go](https://github.com/minio/simdjson-go) | no | yes | no |
|
||||||
|
| goccy/go-json | yes | yes | yes |
|
||||||
|
|
||||||
|
- `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
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd benchmarks
|
||||||
|
$ go test -bench .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encode
|
||||||
|
|
||||||
|
<img width="700px" src="https://user-images.githubusercontent.com/209884/107126758-0845cb00-68f5-11eb-8db7-086fcf9bcfaa.png"></img>
|
||||||
|
<img width="700px" src="https://user-images.githubusercontent.com/209884/107126757-07ad3480-68f5-11eb-87aa-858cc5eacfcb.png"></img>
|
||||||
|
|
||||||
|
## Decode
|
||||||
|
|
||||||
|
<img width="700" alt="" src="https://user-images.githubusercontent.com/209884/107979944-bd1d6d80-7002-11eb-944b-9d17b6674e3f.png">
|
||||||
|
<img width="700" alt="" src="https://user-images.githubusercontent.com/209884/107979931-b989e680-7002-11eb-87a0-66fc22d90dd4.png">
|
||||||
|
<img width="700" alt="" src="https://user-images.githubusercontent.com/209884/107979940-bc84d700-7002-11eb-9647-869bbc25c9d9.png">
|
||||||
|
|
||||||
|
|
||||||
|
# Fuzzing
|
||||||
|
|
||||||
|
[go-json-fuzz](https://github.com/goccy/go-json-fuzz) is the repository for fuzzing tests.
|
||||||
|
If you run the test in this repository and find a bug, please commit to corpus to go-json-fuzz and report the issue to [go-json](https://github.com/goccy/go-json/issues).
|
||||||
|
|
||||||
|
# How it works
|
||||||
|
|
||||||
|
`go-json` is very fast in both encoding and decoding compared to other libraries.
|
||||||
|
It's easier to implement by using automatic code generation for performance or by using a dedicated interface, but `go-json` dares to stick to compatibility with `encoding/json` and is the simple interface. Despite this, we are developing with the aim of being the fastest library.
|
||||||
|
|
||||||
|
Here, we explain the various speed-up techniques implemented by `go-json`.
|
||||||
|
|
||||||
|
## Basic technique
|
||||||
|
|
||||||
|
The techniques listed here are the ones used by most of the libraries listed above.
|
||||||
|
|
||||||
|
### Buffer reuse
|
||||||
|
|
||||||
|
Since the only value required for the result of `json.Marshal(interface{}) ([]byte, error)` is `[]byte`, the only value that must be allocated during encoding is the return value `[]byte` .
|
||||||
|
|
||||||
|
Also, as the number of allocations increases, the performance will be affected, so the number of allocations should be kept as low as possible when creating `[]byte`.
|
||||||
|
|
||||||
|
Therefore, there is a technique to reduce the number of times a new buffer must be allocated by reusing the buffer used for the previous encoding by using `sync.Pool`.
|
||||||
|
|
||||||
|
Finally, you allocate a buffer that is as long as the resulting buffer and copy the contents into it, you only need to allocate the buffer once in theory.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type buffer struct {
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &buffer{data: make([]byte, 0, 1024)}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bufPool.Get().(*buffer)
|
||||||
|
data := encode(buf.data) // reuse buf.data
|
||||||
|
|
||||||
|
newBuf := make([]byte, len(data))
|
||||||
|
copy(newBuf, buf)
|
||||||
|
|
||||||
|
buf.data = data
|
||||||
|
bufPool.Put(buf)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Elimination of reflection
|
||||||
|
|
||||||
|
As you know, the reflection operation is very slow.
|
||||||
|
|
||||||
|
Therefore, using the fact that the address position where the type information is stored is fixed for each binary ( we call this `typeptr` ),
|
||||||
|
we can use the address in the type information to call a pre-built optimized process.
|
||||||
|
|
||||||
|
For example, you can get the address to the type information from `interface{}` as follows and you can use that information to call a process that does not have reflection.
|
||||||
|
|
||||||
|
To process without reflection, pass a pointer (`unsafe.Pointer`) to the value is stored.
|
||||||
|
|
||||||
|
```go
|
||||||
|
|
||||||
|
type emptyInterface struct {
|
||||||
|
typ unsafe.Pointer
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeToEncoder = map[uintptr]func(unsafe.Pointer)([]byte, error){}
|
||||||
|
|
||||||
|
func Marshal(v interface{}) ([]byte, error) {
|
||||||
|
iface := (*emptyInterface)(unsafe.Pointer(&v)
|
||||||
|
typeptr := uintptr(iface.typ)
|
||||||
|
if enc, exists := typeToEncoder[typeptr]; exists {
|
||||||
|
return enc(iface.ptr)
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
※ In reality, `typeToEncoder` can be referenced by multiple goroutines, so exclusive control is required.
|
||||||
|
|
||||||
|
## Unique speed-up technique
|
||||||
|
|
||||||
|
## Encoder
|
||||||
|
|
||||||
|
### Do not escape arguments of `Marshal`
|
||||||
|
|
||||||
|
`json.Marshal` and `json.Unmarshal` receive `interface{}` value and they perform type determination dynamically to process.
|
||||||
|
In normal case, you need to use the `reflect` library to determine the type dynamically, but since `reflect.Type` is defined as `interface`, when you call the method of `reflect.Type`, The reflect's argument is escaped.
|
||||||
|
|
||||||
|
Therefore, the arguments for `Marshal` and `Unmarshal` are always escape to the heap.
|
||||||
|
However, `go-json` can use the feature of `reflect.Type` while avoiding escaping.
|
||||||
|
|
||||||
|
`reflect.Type` is defined as `interface`, but in reality `reflect.Type` is implemented only by the structure `rtype` defined in the `reflect` package.
|
||||||
|
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`.
|
||||||
|
|
||||||
|
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 )
|
||||||
|
|
||||||
|
Initially this feature was the default behavior of `go-json`.
|
||||||
|
But after careful testing, I found that I passed a large value to `json.Marshal()` and if the argument could not be assigned to the stack, it could not be properly escaped to the heap (a bug in the Go compiler).
|
||||||
|
|
||||||
|
Therefore, this feature will be provided as an **optional** until this issue is resolved.
|
||||||
|
|
||||||
|
To use it, add `NoEscape` like `MarshalNoEscape()`
|
||||||
|
|
||||||
|
### Encoding using opcode sequence
|
||||||
|
|
||||||
|
I explained that you can use `typeptr` to call a pre-built process from type information.
|
||||||
|
|
||||||
|
In other libraries, this dedicated process is processed by making it an function calling like anonymous function, but function calls are inherently slow processes and should be avoided as much as possible.
|
||||||
|
|
||||||
|
Therefore, `go-json` adopted the Instruction-based execution processing system, which is also used to implement virtual machines for programming language.
|
||||||
|
|
||||||
|
If it is the first type to encode, create the opcode ( instruction ) sequence required for encoding.
|
||||||
|
From the second time onward, use `typeptr` to get the cached pre-built opcode sequence and encode it based on it. An example of the opcode sequence is shown below.
|
||||||
|
|
||||||
|
```go
|
||||||
|
json.Marshal(struct{
|
||||||
|
X int `json:"x"`
|
||||||
|
Y string `json:"y"`
|
||||||
|
}{X: 1, Y: "hello"})
|
||||||
|
```
|
||||||
|
|
||||||
|
When encoding a structure like the one above, create a sequence of opcodes like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
- opStructFieldHead ( `{` )
|
||||||
|
- opStructFieldInt ( `"x": 1,` )
|
||||||
|
- opStructFieldString ( `"y": "hello"` )
|
||||||
|
- opStructEnd ( `}` )
|
||||||
|
- opEnd
|
||||||
|
```
|
||||||
|
|
||||||
|
※ When processing each operation, write the letters on the right.
|
||||||
|
|
||||||
|
In addition, each opcode is managed by the following structure (
|
||||||
|
Pseudo code ).
|
||||||
|
|
||||||
|
```go
|
||||||
|
type opType int
|
||||||
|
const (
|
||||||
|
opStructFieldHead opType = iota
|
||||||
|
opStructFieldInt
|
||||||
|
opStructFieldStirng
|
||||||
|
opStructEnd
|
||||||
|
opEnd
|
||||||
|
)
|
||||||
|
type opcode struct {
|
||||||
|
op opType
|
||||||
|
key []byte
|
||||||
|
next *opcode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The process of encoding using the opcode sequence is roughly implemented as follows.
|
||||||
|
|
||||||
|
```go
|
||||||
|
func encode(code *opcode, b []byte, p unsafe.Pointer) ([]byte, error) {
|
||||||
|
for {
|
||||||
|
switch code.op {
|
||||||
|
case opStructFieldHead:
|
||||||
|
b = append(b, '{')
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldInt:
|
||||||
|
b = append(b, code.key...)
|
||||||
|
b = appendInt((*int)(unsafe.Pointer(uintptr(p)+code.offset)))
|
||||||
|
code = code.next
|
||||||
|
case opStructFieldString:
|
||||||
|
b = append(b, code.key...)
|
||||||
|
b = appendString((*string)(unsafe.Pointer(uintptr(p)+code.offset)))
|
||||||
|
code = code.next
|
||||||
|
case opStructEnd:
|
||||||
|
b = append(b, '}')
|
||||||
|
code = code.next
|
||||||
|
case opEnd:
|
||||||
|
goto END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END:
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this way, the huge `switch-case` is used to encode by manipulating the linked list opcodes to avoid unnecessary function calls.
|
||||||
|
|
||||||
|
### Opcode sequence optimization
|
||||||
|
|
||||||
|
One of the advantages of encoding using the opcode sequence is the ease of optimization.
|
||||||
|
The opcode sequence mentioned above is actually converted into the following optimized operations and used.
|
||||||
|
|
||||||
|
```
|
||||||
|
- opStructFieldHeadInt ( `{"x": 1,` )
|
||||||
|
- opStructEndString ( `"y": "hello"}` )
|
||||||
|
- opEnd
|
||||||
|
```
|
||||||
|
|
||||||
|
It has been reduced from 5 opcodes to 3 opcodes !
|
||||||
|
Reducing the number of opcodees means reducing the number of branches with `switch-case`.
|
||||||
|
In other words, the closer the number of operations is to 1, the faster the processing can be performed.
|
||||||
|
|
||||||
|
In `go-json`, optimization to reduce the number of opcodes itself like the above and it speeds up by preparing opcodes with optimized paths.
|
||||||
|
|
||||||
|
### Change recursive call from CALL to JMP
|
||||||
|
|
||||||
|
Recursive processing is required during encoding if the type is defined recursively as follows:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type T struct {
|
||||||
|
X int
|
||||||
|
U *U
|
||||||
|
}
|
||||||
|
|
||||||
|
type U struct {
|
||||||
|
T *T
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(&T{
|
||||||
|
X: 1,
|
||||||
|
U: &U{
|
||||||
|
T: &T{
|
||||||
|
X: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
fmt.Println(string(b)) // {"X":1,"U":{"T":{"X":2,"U":null}}}
|
||||||
|
```
|
||||||
|
|
||||||
|
In `go-json`, recursive processing is processed by the operation type of ` opStructFieldRecursive`.
|
||||||
|
|
||||||
|
In this operation, after acquiring the opcode sequence used for recursive processing, the function is **not** called recursively as it is, but the necessary values are saved by itself and implemented by moving to the next operation.
|
||||||
|
|
||||||
|
The technique of implementing recursive processing with the `JMP` operation while avoiding the `CALL` operation is a famous technique for implementing a high-speed virtual machine.
|
||||||
|
|
||||||
|
For more details, please refer to [the article](https://engineering.mercari.com/blog/entry/1599563768-081104c850) ( but Japanese only ).
|
||||||
|
|
||||||
|
### Dispatch by typeptr from map to slice
|
||||||
|
|
||||||
|
When retrieving the data cached from the type information by `typeptr`, we usually use map.
|
||||||
|
Map requires exclusive control, so use `sync.Map` for a naive implementation.
|
||||||
|
|
||||||
|
However, this is slow, so it's a good idea to use the `atomic` package for exclusive control as implemented by `segmentio/encoding/json` ( https://github.com/segmentio/encoding/blob/master/json/codec.go#L41-L55 ).
|
||||||
|
|
||||||
|
This implementation slows down the set instead of speeding up the get, but it works well because of the nature of the library, it encodes much more for the same type.
|
||||||
|
|
||||||
|
However, as a result of profiling, I noticed that `runtime.mapaccess2` accounts for a significant percentage of the execution time. So I thought if I could change the lookup from map to slice.
|
||||||
|
|
||||||
|
There is an API named `typelinks` defined in the `runtime` package that the `reflect` package uses internally.
|
||||||
|
This allows you to get all the type information defined in the binary at runtime.
|
||||||
|
|
||||||
|
The fact that all type information can be acquired means that by constructing slices in advance with the acquired total number of type information, it is possible to look up with the value of `typeptr` without worrying about out-of-range access.
|
||||||
|
|
||||||
|
However, if there is too much type information, it will use a lot of memory, so by default we will only use this optimization if the slice size fits within **2Mib** .
|
||||||
|
|
||||||
|
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/internal/runtime/type.go#L36-L100)
|
||||||
|
|
||||||
|
## Decoder
|
||||||
|
|
||||||
|
### Dispatch by typeptr from map to slice
|
||||||
|
|
||||||
|
Like the encoder, the decoder also uses typeptr to call the dedicated process.
|
||||||
|
|
||||||
|
### Faster termination character inspection using NUL character
|
||||||
|
|
||||||
|
In order to decode, you have to traverse the input buffer character by position.
|
||||||
|
At that time, if you check whether the buffer has reached the end, it will be very slow.
|
||||||
|
|
||||||
|
`buf` : `[]byte` type variable. holds the string passed to the decoder
|
||||||
|
`cursor` : `int64` type variable. holds the current read position
|
||||||
|
|
||||||
|
```go
|
||||||
|
buflen := len(buf)
|
||||||
|
for ; cursor < buflen; cursor++ { // compare cursor and buflen at all times, it is so slow.
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\r', '\t':
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Therefore, by adding the `NUL` (`\000`) character to the end of the read buffer as shown below, it is possible to check the termination character at the same time as other characters.
|
||||||
|
|
||||||
|
```go
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\r', '\t':
|
||||||
|
case '\000':
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Boundary Check Elimination
|
||||||
|
|
||||||
|
Due to the `NUL` character optimization, the Go compiler does a boundary check every time, even though `buf[cursor]` does not cause out-of-range access.
|
||||||
|
|
||||||
|
Therefore, `go-json` eliminates boundary check by fetching characters for hotspot by pointer operation. For example, the following code.
|
||||||
|
|
||||||
|
```go
|
||||||
|
func char(ptr unsafe.Pointer, offset int64) byte {
|
||||||
|
return *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(offset)))
|
||||||
|
}
|
||||||
|
|
||||||
|
p := (*sliceHeader)(&unsafe.Pointer(buf)).data
|
||||||
|
for {
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case ' ', '\n', '\r', '\t':
|
||||||
|
case '\000':
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Checking the existence of fields of struct using Bitmaps
|
||||||
|
|
||||||
|
I found by the profiling result, in the struct decode, lookup process for field was taking a long time.
|
||||||
|
|
||||||
|
For example, consider decoding a string like `{"a":1,"b":2,"c":3}` into the following structure:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type T struct {
|
||||||
|
A int `json:"a"`
|
||||||
|
B int `json:"b"`
|
||||||
|
C int `json:"c"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
At this time, it was found that it takes a lot of time to acquire the decoding process corresponding to the field from the field name as shown below during the decoding process.
|
||||||
|
|
||||||
|
```go
|
||||||
|
fieldName := decodeKey(buf, cursor) // "a" or "b" or "c"
|
||||||
|
decoder, exists := fieldToDecoderMap[fieldName] // so slow
|
||||||
|
if exists {
|
||||||
|
decoder(buf, cursor)
|
||||||
|
} else {
|
||||||
|
skipValue(buf, cursor)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To improve this process, `json-iterator/go` is optimized so that it can be branched by switch-case when the number of fields in the structure is 10 or less (switch-case is faster than map). However, there is a risk of hash collision because the value hashed by the FNV algorithm is used for conditional branching. Also, `gojay` processes this part at high speed by letting the library user yourself write `switch-case`.
|
||||||
|
|
||||||
|
|
||||||
|
`go-json` considers and implements a new approach that is different from these. I call this **bitmap field optimization**.
|
||||||
|
|
||||||
|
The range of values per character can be represented by `[256]byte`. Also, if the number of fields in the structure is 8 or less, `int8` type can represent the state of each field.
|
||||||
|
In other words, it has the following structure.
|
||||||
|
|
||||||
|
- Base ( 8bit ): `00000000`
|
||||||
|
- Key "a": `00000001` ( assign key "a" to the first bit )
|
||||||
|
- Key "b": `00000010` ( assign key "b" to the second bit )
|
||||||
|
- Key "c": `00000100` ( assign key "c" to the third bit )
|
||||||
|
|
||||||
|
Bitmap structure is the following
|
||||||
|
|
||||||
|
```
|
||||||
|
| key index(0) |
|
||||||
|
------------------------
|
||||||
|
0 | 00000000 |
|
||||||
|
1 | 00000000 |
|
||||||
|
~~ | |
|
||||||
|
97 (a) | 00000001 |
|
||||||
|
98 (b) | 00000010 |
|
||||||
|
99 (c) | 00000100 |
|
||||||
|
~~ | |
|
||||||
|
255 | 00000000 |
|
||||||
|
```
|
||||||
|
|
||||||
|
You can think of this as a Bitmap with a height of `256` and a width of the maximum string length in the field name.
|
||||||
|
In other words, it can be represented by the following type .
|
||||||
|
|
||||||
|
```go
|
||||||
|
[maxFieldKeyLength][256]int8
|
||||||
|
```
|
||||||
|
|
||||||
|
When decoding a field character, check whether the corresponding character exists by referring to the pre-built bitmap like the following.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var curBit int8 = math.MaxInt8 // 11111111
|
||||||
|
|
||||||
|
c := char(buf, cursor)
|
||||||
|
bit := bitmap[keyIdx][c]
|
||||||
|
curBit &= bit
|
||||||
|
if curBit == 0 {
|
||||||
|
// not found field
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If `curBit` is not `0` until the end of the field string, then the string is
|
||||||
|
You may have hit one of the fields.
|
||||||
|
But the possibility is that if the decoded string is shorter than the field string, you will get a false hit.
|
||||||
|
|
||||||
|
- input: `{"a":1}`
|
||||||
|
```go
|
||||||
|
type T struct {
|
||||||
|
X int `json:"abc"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
※ Since `a` is shorter than `abc`, it can decode to the end of the field character without `curBit` being 0.
|
||||||
|
|
||||||
|
Rest assured. In this case, it doesn't matter because you can tell if you hit by comparing the string length of `a` with the string length of `abc`.
|
||||||
|
|
||||||
|
Finally, calculate the position of the bit where `1` is set and get the corresponding value, and you're done.
|
||||||
|
|
||||||
|
Using this technique, field lookups are possible with only bitwise operations and access to slices.
|
||||||
|
|
||||||
|
`go-json` uses a similar technique for fields with 9 or more and 16 or less fields. At this time, Bitmap is constructed as `[maxKeyLen][256]int16` type.
|
||||||
|
|
||||||
|
Currently, this optimization is not performed when the maximum length of the field name is long (specifically, 64 bytes or more) in addition to the limitation of the number of fields from the viewpoint of saving memory usage.
|
||||||
|
|
||||||
|
### Others
|
||||||
|
|
||||||
|
I have done a lot of other optimizations. I will find time to write about them. If you have any questions about what's written here or other optimizations, please visit the `#go-json` channel on `gophers.slack.com` .
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
Regarding the story of go-json, there are the following articles in Japanese only.
|
||||||
|
|
||||||
|
- https://speakerdeck.com/goccy/zui-su-falsejsonraiburariwoqiu-mete
|
||||||
|
- https://engineering.mercari.com/blog/entry/1599563768-081104c850/
|
||||||
|
|
||||||
|
# Looking for Sponsors
|
||||||
|
|
||||||
|
I'm looking for sponsors this library. This library is being developed as a personal project in my spare time. If you want a quick response or problem resolution when using this library in your project, please register as a [sponsor](https://github.com/sponsors/goccy). I will cooperate as much as possible. Of course, this library is developed as an MIT license, so you can use it freely for free.
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
MIT
|
68
vendor/github.com/goccy/go-json/color.go
generated
vendored
Normal file
68
vendor/github.com/goccy/go-json/color.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ColorFormat = encoder.ColorFormat
|
||||||
|
ColorScheme = encoder.ColorScheme
|
||||||
|
)
|
||||||
|
|
||||||
|
const escape = "\x1b"
|
||||||
|
|
||||||
|
type colorAttr int
|
||||||
|
|
||||||
|
//nolint:deadcode,varcheck
|
||||||
|
const (
|
||||||
|
fgBlackColor colorAttr = iota + 30
|
||||||
|
fgRedColor
|
||||||
|
fgGreenColor
|
||||||
|
fgYellowColor
|
||||||
|
fgBlueColor
|
||||||
|
fgMagentaColor
|
||||||
|
fgCyanColor
|
||||||
|
fgWhiteColor
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:deadcode,varcheck
|
||||||
|
const (
|
||||||
|
fgHiBlackColor colorAttr = iota + 90
|
||||||
|
fgHiRedColor
|
||||||
|
fgHiGreenColor
|
||||||
|
fgHiYellowColor
|
||||||
|
fgHiBlueColor
|
||||||
|
fgHiMagentaColor
|
||||||
|
fgHiCyanColor
|
||||||
|
fgHiWhiteColor
|
||||||
|
)
|
||||||
|
|
||||||
|
func createColorFormat(attr colorAttr) ColorFormat {
|
||||||
|
return ColorFormat{
|
||||||
|
Header: wrapColor(attr),
|
||||||
|
Footer: resetColor(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapColor(attr colorAttr) string {
|
||||||
|
return fmt.Sprintf("%s[%dm", escape, attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetColor() string {
|
||||||
|
return wrapColor(colorAttr(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultColorScheme = &ColorScheme{
|
||||||
|
Int: createColorFormat(fgHiMagentaColor),
|
||||||
|
Uint: createColorFormat(fgHiMagentaColor),
|
||||||
|
Float: createColorFormat(fgHiMagentaColor),
|
||||||
|
Bool: createColorFormat(fgHiYellowColor),
|
||||||
|
String: createColorFormat(fgHiGreenColor),
|
||||||
|
Binary: createColorFormat(fgHiRedColor),
|
||||||
|
ObjectKey: createColorFormat(fgHiCyanColor),
|
||||||
|
Null: createColorFormat(fgBlueColor),
|
||||||
|
}
|
||||||
|
)
|
232
vendor/github.com/goccy/go-json/decode.go
generated
vendored
Normal file
232
vendor/github.com/goccy/go-json/decode.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/decoder"
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Decoder struct {
|
||||||
|
s *decoder.Stream
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
nul = '\000'
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
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 {
|
||||||
|
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, header.ptr)
|
||||||
|
if err != nil {
|
||||||
|
decoder.ReleaseRuntimeContext(ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
decoder.ReleaseRuntimeContext(ctx)
|
||||||
|
return validateEndBuf(src, cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalContext(ctx context.Context, 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 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEndBuf(src []byte, cursor int64) error {
|
||||||
|
for {
|
||||||
|
switch src[cursor] {
|
||||||
|
case ' ', '\t', '\n', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case nul:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.ErrSyntax(
|
||||||
|
fmt.Sprintf("invalid character '%c' after top-level value", src[cursor]),
|
||||||
|
cursor+1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:staticcheck
|
||||||
|
//go:nosplit
|
||||||
|
func noescape(p unsafe.Pointer) unsafe.Pointer {
|
||||||
|
x := uintptr(p)
|
||||||
|
return unsafe.Pointer(x ^ 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateType(typ *runtime.Type, p uintptr) error {
|
||||||
|
if typ == nil || typ.Kind() != reflect.Ptr || p == 0 {
|
||||||
|
return &InvalidUnmarshalError{Type: runtime.RType2Type(typ)}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a new decoder that reads from r.
|
||||||
|
//
|
||||||
|
// The decoder introduces its own buffering and may
|
||||||
|
// read data from r beyond the JSON values requested.
|
||||||
|
func NewDecoder(r io.Reader) *Decoder {
|
||||||
|
s := decoder.NewStream(r)
|
||||||
|
return &Decoder{
|
||||||
|
s: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffered returns a reader of the data remaining in the Decoder's
|
||||||
|
// buffer. The reader is valid until the next call to Decode.
|
||||||
|
func (d *Decoder) Buffered() io.Reader {
|
||||||
|
return d.s.Buffered()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode reads the next JSON-encoded value from its
|
||||||
|
// input and stores it in the value pointed to by v.
|
||||||
|
//
|
||||||
|
// See the documentation for Unmarshal for details about
|
||||||
|
// the conversion of JSON into a Go value.
|
||||||
|
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))
|
||||||
|
typ := header.typ
|
||||||
|
ptr := uintptr(header.ptr)
|
||||||
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
|
// noescape trick for header.typ ( reflect.*rtype )
|
||||||
|
copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
|
||||||
|
|
||||||
|
if err := validateType(copiedType, ptr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dec, err := decoder.CompileToGetDecoder(typ)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := d.s.PrepareForDecode(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s := d.s
|
||||||
|
for _, optFunc := range optFuncs {
|
||||||
|
optFunc(s.Option)
|
||||||
|
}
|
||||||
|
if err := dec.DecodeStream(s, 0, header.ptr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Reset()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) More() bool {
|
||||||
|
return d.s.More()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Token() (Token, error) {
|
||||||
|
return d.s.Token()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisallowUnknownFields causes the Decoder to return an error when the destination
|
||||||
|
// is a struct and the input contains object keys which do not match any
|
||||||
|
// non-ignored, exported fields in the destination.
|
||||||
|
func (d *Decoder) DisallowUnknownFields() {
|
||||||
|
d.s.DisallowUnknownFields = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) InputOffset() int64 {
|
||||||
|
return d.s.TotalOffset()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
|
||||||
|
// Number instead of as a float64.
|
||||||
|
func (d *Decoder) UseNumber() {
|
||||||
|
d.s.UseNumber = true
|
||||||
|
}
|
13
vendor/github.com/goccy/go-json/docker-compose.yml
generated
vendored
Normal file
13
vendor/github.com/goccy/go-json/docker-compose.yml
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
version: '2'
|
||||||
|
services:
|
||||||
|
go-json:
|
||||||
|
image: golang:1.16
|
||||||
|
volumes:
|
||||||
|
- '.:/go/src/go-json'
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 620M
|
||||||
|
working_dir: /go/src/go-json
|
||||||
|
command: |
|
||||||
|
sh -c "go test -c . && ls go-json.test"
|
323
vendor/github.com/goccy/go-json/encode.go
generated
vendored
Normal file
323
vendor/github.com/goccy/go-json/encode.go
generated
vendored
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
"github.com/goccy/go-json/internal/encoder/vm"
|
||||||
|
"github.com/goccy/go-json/internal/encoder/vm_color"
|
||||||
|
"github.com/goccy/go-json/internal/encoder/vm_color_indent"
|
||||||
|
"github.com/goccy/go-json/internal/encoder/vm_indent"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An Encoder writes JSON values to an output stream.
|
||||||
|
type Encoder struct {
|
||||||
|
w io.Writer
|
||||||
|
enabledIndent bool
|
||||||
|
enabledHTMLEscape bool
|
||||||
|
prefix string
|
||||||
|
indentStr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a new encoder that writes to w.
|
||||||
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
|
return &Encoder{w: w, enabledHTMLEscape: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode writes the JSON encoding of v to the stream, followed by a newline character.
|
||||||
|
//
|
||||||
|
// See the documentation for Marshal for details about the conversion of Go values to JSON.
|
||||||
|
func (e *Encoder) Encode(v interface{}) error {
|
||||||
|
return e.EncodeWithOption(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeWithOption call Encode with EncodeOption.
|
||||||
|
func (e *Encoder) EncodeWithOption(v interface{}, optFuncs ...EncodeOptionFunc) error {
|
||||||
|
ctx := encoder.TakeRuntimeContext()
|
||||||
|
ctx.Option.Flag = 0
|
||||||
|
|
||||||
|
err := e.encodeWithOption(ctx, v, optFuncs...)
|
||||||
|
|
||||||
|
encoder.ReleaseRuntimeContext(ctx)
|
||||||
|
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 {
|
||||||
|
if e.enabledHTMLEscape {
|
||||||
|
ctx.Option.Flag |= encoder.HTMLEscapeOption
|
||||||
|
}
|
||||||
|
for _, optFunc := range optFuncs {
|
||||||
|
optFunc(ctx.Option)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
buf []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if e.enabledIndent {
|
||||||
|
buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr)
|
||||||
|
} else {
|
||||||
|
buf, err = encode(ctx, v)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.enabledIndent {
|
||||||
|
buf = buf[:len(buf)-2]
|
||||||
|
} else {
|
||||||
|
buf = buf[:len(buf)-1]
|
||||||
|
}
|
||||||
|
buf = append(buf, '\n')
|
||||||
|
if _, err := e.w.Write(buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEscapeHTML specifies whether problematic HTML characters should be escaped inside JSON quoted strings.
|
||||||
|
// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e to avoid certain safety problems that can arise when embedding JSON in HTML.
|
||||||
|
//
|
||||||
|
// In non-HTML settings where the escaping interferes with the readability of the output, SetEscapeHTML(false) disables this behavior.
|
||||||
|
func (e *Encoder) SetEscapeHTML(on bool) {
|
||||||
|
e.enabledHTMLEscape = on
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIndent instructs the encoder to format each subsequent encoded value as if indented by the package-level function Indent(dst, src, prefix, indent).
|
||||||
|
// Calling SetIndent("", "") disables indentation.
|
||||||
|
func (e *Encoder) SetIndent(prefix, indent string) {
|
||||||
|
if prefix == "" && indent == "" {
|
||||||
|
e.enabledIndent = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.prefix = prefix
|
||||||
|
e.indentStr = indent
|
||||||
|
e.enabledIndent = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Option.Flag = 0
|
||||||
|
ctx.Option.Flag |= encoder.HTMLEscapeOption
|
||||||
|
for _, optFunc := range optFuncs {
|
||||||
|
optFunc(ctx.Option)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := encode(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
encoder.ReleaseRuntimeContext(ctx)
|
||||||
|
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(ctx)
|
||||||
|
return copied, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalNoEscape(v interface{}) ([]byte, error) {
|
||||||
|
ctx := encoder.TakeRuntimeContext()
|
||||||
|
|
||||||
|
ctx.Option.Flag = 0
|
||||||
|
ctx.Option.Flag |= encoder.HTMLEscapeOption
|
||||||
|
|
||||||
|
buf, err := encodeNoEscape(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
encoder.ReleaseRuntimeContext(ctx)
|
||||||
|
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(ctx)
|
||||||
|
return copied, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalIndent(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||||
|
ctx := encoder.TakeRuntimeContext()
|
||||||
|
|
||||||
|
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 {
|
||||||
|
encoder.ReleaseRuntimeContext(ctx)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = buf[:len(buf)-2]
|
||||||
|
copied := make([]byte, len(buf))
|
||||||
|
copy(copied, buf)
|
||||||
|
|
||||||
|
encoder.ReleaseRuntimeContext(ctx)
|
||||||
|
return copied, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
|
||||||
|
b := ctx.Buf[:0]
|
||||||
|
if v == nil {
|
||||||
|
b = encoder.AppendNull(ctx, b)
|
||||||
|
b = encoder.AppendComma(ctx, b)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
header := (*emptyInterface)(unsafe.Pointer(&v))
|
||||||
|
typ := header.typ
|
||||||
|
|
||||||
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
|
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p := uintptr(header.ptr)
|
||||||
|
ctx.Init(p, codeSet.CodeLength)
|
||||||
|
ctx.KeepRefs = append(ctx.KeepRefs, header.ptr)
|
||||||
|
|
||||||
|
buf, err := encodeRunCode(ctx, b, codeSet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ctx.Buf = buf
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) {
|
||||||
|
b := ctx.Buf[:0]
|
||||||
|
if v == nil {
|
||||||
|
b = encoder.AppendNull(ctx, b)
|
||||||
|
b = encoder.AppendComma(ctx, b)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
header := (*emptyInterface)(unsafe.Pointer(&v))
|
||||||
|
typ := header.typ
|
||||||
|
|
||||||
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
|
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p := uintptr(header.ptr)
|
||||||
|
ctx.Init(p, codeSet.CodeLength)
|
||||||
|
buf, err := encodeRunCode(ctx, b, codeSet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Buf = buf
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent string) ([]byte, error) {
|
||||||
|
b := ctx.Buf[:0]
|
||||||
|
if v == nil {
|
||||||
|
b = encoder.AppendNull(ctx, b)
|
||||||
|
b = encoder.AppendCommaIndent(ctx, b)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
header := (*emptyInterface)(unsafe.Pointer(&v))
|
||||||
|
typ := header.typ
|
||||||
|
|
||||||
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
|
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p := uintptr(header.ptr)
|
||||||
|
ctx.Init(p, codeSet.CodeLength)
|
||||||
|
buf, err := encodeRunIndentCode(ctx, b, codeSet, prefix, indent)
|
||||||
|
|
||||||
|
ctx.KeepRefs = append(ctx.KeepRefs, header.ptr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Buf = buf
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||||
|
if (ctx.Option.Flag & encoder.DebugOption) != 0 {
|
||||||
|
if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
|
||||||
|
return vm_color.DebugRun(ctx, b, codeSet)
|
||||||
|
}
|
||||||
|
return vm.DebugRun(ctx, b, codeSet)
|
||||||
|
}
|
||||||
|
if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
|
||||||
|
return vm_color.Run(ctx, b, codeSet)
|
||||||
|
}
|
||||||
|
return vm.Run(ctx, b, codeSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, prefix, indent string) ([]byte, error) {
|
||||||
|
ctx.Prefix = []byte(prefix)
|
||||||
|
ctx.IndentStr = []byte(indent)
|
||||||
|
if (ctx.Option.Flag & encoder.DebugOption) != 0 {
|
||||||
|
if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
|
||||||
|
return vm_color_indent.DebugRun(ctx, b, codeSet)
|
||||||
|
}
|
||||||
|
return vm_indent.DebugRun(ctx, b, codeSet)
|
||||||
|
}
|
||||||
|
if (ctx.Option.Flag & encoder.ColorizeOption) != 0 {
|
||||||
|
return vm_color_indent.Run(ctx, b, codeSet)
|
||||||
|
}
|
||||||
|
return vm_indent.Run(ctx, b, codeSet)
|
||||||
|
}
|
39
vendor/github.com/goccy/go-json/error.go
generated
vendored
Normal file
39
vendor/github.com/goccy/go-json/error.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when
|
||||||
|
// attempting to encode a string value with invalid UTF-8 sequences.
|
||||||
|
// As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by
|
||||||
|
// replacing invalid bytes with the Unicode replacement rune U+FFFD.
|
||||||
|
//
|
||||||
|
// Deprecated: No longer used; kept for compatibility.
|
||||||
|
type InvalidUTF8Error = errors.InvalidUTF8Error
|
||||||
|
|
||||||
|
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
|
||||||
|
// (The argument to Unmarshal must be a non-nil pointer.)
|
||||||
|
type InvalidUnmarshalError = errors.InvalidUnmarshalError
|
||||||
|
|
||||||
|
// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method.
|
||||||
|
type MarshalerError = errors.MarshalerError
|
||||||
|
|
||||||
|
// A SyntaxError is a description of a JSON syntax error.
|
||||||
|
type SyntaxError = errors.SyntaxError
|
||||||
|
|
||||||
|
// An UnmarshalFieldError describes a JSON object key that
|
||||||
|
// led to an unexported (and therefore unwritable) struct field.
|
||||||
|
//
|
||||||
|
// Deprecated: No longer used; kept for compatibility.
|
||||||
|
type UnmarshalFieldError = errors.UnmarshalFieldError
|
||||||
|
|
||||||
|
// An UnmarshalTypeError describes a JSON value that was
|
||||||
|
// not appropriate for a value of a specific Go type.
|
||||||
|
type UnmarshalTypeError = errors.UnmarshalTypeError
|
||||||
|
|
||||||
|
// An UnsupportedTypeError is returned by Marshal when attempting
|
||||||
|
// to encode an unsupported value type.
|
||||||
|
type UnsupportedTypeError = errors.UnsupportedTypeError
|
||||||
|
|
||||||
|
type UnsupportedValueError = errors.UnsupportedValueError
|
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))
|
||||||
|
}
|
169
vendor/github.com/goccy/go-json/internal/decoder/array.go
generated
vendored
Normal file
169
vendor/github.com/goccy/go-json/internal/decoder/array.go
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrayDecoder struct {
|
||||||
|
elemType *runtime.Type
|
||||||
|
size uintptr
|
||||||
|
valueDecoder Decoder
|
||||||
|
alen int
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
zeroValue unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayDecoder(dec Decoder, elemType *runtime.Type, alen int, structName, fieldName string) *arrayDecoder {
|
||||||
|
zeroValue := *(*unsafe.Pointer)(unsafe_New(elemType))
|
||||||
|
return &arrayDecoder{
|
||||||
|
valueDecoder: dec,
|
||||||
|
elemType: elemType,
|
||||||
|
size: elemType.Size(),
|
||||||
|
alen: alen,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
zeroValue: zeroValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *arrayDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case '[':
|
||||||
|
idx := 0
|
||||||
|
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 err := d.valueDecoder.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := s.skipValue(depth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
switch s.skipWhiteSpace() {
|
||||||
|
case ']':
|
||||||
|
for idx < d.alen {
|
||||||
|
*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
case ',':
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
default:
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
default:
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("array", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *arrayDecoder) 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return cursor, nil
|
||||||
|
case '[':
|
||||||
|
idx := 0
|
||||||
|
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 {
|
||||||
|
c, err := d.valueDecoder.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
} else {
|
||||||
|
c, err := skipValue(buf, cursor, depth)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ']':
|
||||||
|
for idx < d.alen {
|
||||||
|
*(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
return cursor, nil
|
||||||
|
case ',':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
return 0, errors.ErrInvalidCharacter(buf[cursor], "array", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("array", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
vendor/github.com/goccy/go-json/internal/decoder/bool.go
generated
vendored
Normal file
78
vendor/github.com/goccy/go-json/internal/decoder/bool.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type boolDecoder struct {
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBoolDecoder(structName, fieldName string) *boolDecoder {
|
||||||
|
return &boolDecoder{structName: structName, fieldName: fieldName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *boolDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
c := s.skipWhiteSpace()
|
||||||
|
for {
|
||||||
|
switch c {
|
||||||
|
case 't':
|
||||||
|
if err := trueBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
**(**bool)(unsafe.Pointer(&p)) = true
|
||||||
|
return nil
|
||||||
|
case 'f':
|
||||||
|
if err := falseBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
**(**bool)(unsafe.Pointer(&p)) = false
|
||||||
|
return nil
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
c = s.char()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("bool", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *boolDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
switch buf[cursor] {
|
||||||
|
case 't':
|
||||||
|
if err := validateTrue(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
**(**bool)(unsafe.Pointer(&p)) = true
|
||||||
|
return cursor, nil
|
||||||
|
case 'f':
|
||||||
|
if err := validateFalse(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 5
|
||||||
|
**(**bool)(unsafe.Pointer(&p)) = false
|
||||||
|
return cursor, nil
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("bool", cursor)
|
||||||
|
}
|
114
vendor/github.com/goccy/go-json/internal/decoder/bytes.go
generated
vendored
Normal file
114
vendor/github.com/goccy/go-json/internal/decoder/bytes.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bytesDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
sliceDecoder Decoder
|
||||||
|
stringDecoder *stringDecoder
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func byteUnmarshalerSliceDecoder(typ *runtime.Type, structName string, fieldName string) Decoder {
|
||||||
|
var unmarshalDecoder Decoder
|
||||||
|
switch {
|
||||||
|
case runtime.PtrTo(typ).Implements(unmarshalJSONType):
|
||||||
|
unmarshalDecoder = newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName)
|
||||||
|
case runtime.PtrTo(typ).Implements(unmarshalTextType):
|
||||||
|
unmarshalDecoder = newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName)
|
||||||
|
}
|
||||||
|
if unmarshalDecoder == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return newSliceDecoder(unmarshalDecoder, typ, 1, structName, fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBytesDecoder(typ *runtime.Type, structName string, fieldName string) *bytesDecoder {
|
||||||
|
return &bytesDecoder{
|
||||||
|
typ: typ,
|
||||||
|
sliceDecoder: byteUnmarshalerSliceDecoder(typ, structName, fieldName),
|
||||||
|
stringDecoder: newStringDecoder(structName, fieldName),
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *bytesDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
bytes, err := d.decodeStreamBinary(s, depth, p)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
s.reset()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
decodedLen := base64.StdEncoding.DecodedLen(len(bytes))
|
||||||
|
buf := make([]byte, decodedLen)
|
||||||
|
n, err := base64.StdEncoding.Decode(buf, bytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*[]byte)(p) = buf[:n]
|
||||||
|
s.reset()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *bytesDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
bytes, c, err := d.decodeBinary(ctx, cursor, depth, p)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
decodedLen := base64.StdEncoding.DecodedLen(len(bytes))
|
||||||
|
b := make([]byte, decodedLen)
|
||||||
|
n, err := base64.StdEncoding.Decode(b, bytes)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
*(*[]byte)(p) = b[:n]
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *bytesDecoder) decodeStreamBinary(s *Stream, depth int64, p unsafe.Pointer) ([]byte, error) {
|
||||||
|
c := s.skipWhiteSpace()
|
||||||
|
if c == '[' {
|
||||||
|
if d.sliceDecoder == nil {
|
||||||
|
return nil, &errors.UnmarshalTypeError{
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: s.totalOffset(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := d.sliceDecoder.DecodeStream(s, depth, p)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.stringDecoder.decodeStreamByte(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *bytesDecoder) decodeBinary(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) ([]byte, int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
if buf[cursor] == '[' {
|
||||||
|
if d.sliceDecoder == nil {
|
||||||
|
return nil, 0, &errors.UnmarshalTypeError{
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: cursor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c, err := d.sliceDecoder.Decode(ctx, cursor, depth, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return nil, c, nil
|
||||||
|
}
|
||||||
|
return d.stringDecoder.decodeByte(buf, cursor)
|
||||||
|
}
|
510
vendor/github.com/goccy/go-json/internal/decoder/compile.go
generated
vendored
Normal file
510
vendor/github.com/goccy/go-json/internal/decoder/compile.go
generated
vendored
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
"unicode"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||||
|
typeAddr *runtime.TypeAddr
|
||||||
|
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
||||||
|
cachedDecoder []Decoder
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
if dec, exists := decoderMap[typeptr]; exists {
|
||||||
|
return dec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dec, err := compileHead(typ, map[uintptr]Decoder{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
storeDecoder(typeptr, dec, decoderMap)
|
||||||
|
return dec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileHead(typ *runtime.Type, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
switch {
|
||||||
|
case implementsUnmarshalJSONType(runtime.PtrTo(typ)):
|
||||||
|
return newUnmarshalJSONDecoder(runtime.PtrTo(typ), "", ""), nil
|
||||||
|
case runtime.PtrTo(typ).Implements(unmarshalTextType):
|
||||||
|
return newUnmarshalTextDecoder(runtime.PtrTo(typ), "", ""), nil
|
||||||
|
}
|
||||||
|
return compile(typ.Elem(), "", "", structTypeToDecoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compile(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
switch {
|
||||||
|
case implementsUnmarshalJSONType(runtime.PtrTo(typ)):
|
||||||
|
return newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName), nil
|
||||||
|
case runtime.PtrTo(typ).Implements(unmarshalTextType):
|
||||||
|
return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
return compilePtr(typ, structName, fieldName, structTypeToDecoder)
|
||||||
|
case reflect.Struct:
|
||||||
|
return compileStruct(typ, structName, fieldName, structTypeToDecoder)
|
||||||
|
case reflect.Slice:
|
||||||
|
elem := typ.Elem()
|
||||||
|
if elem.Kind() == reflect.Uint8 {
|
||||||
|
return compileBytes(elem, structName, fieldName)
|
||||||
|
}
|
||||||
|
return compileSlice(typ, structName, fieldName, structTypeToDecoder)
|
||||||
|
case reflect.Array:
|
||||||
|
return compileArray(typ, structName, fieldName, structTypeToDecoder)
|
||||||
|
case reflect.Map:
|
||||||
|
return compileMap(typ, structName, fieldName, structTypeToDecoder)
|
||||||
|
case reflect.Interface:
|
||||||
|
return compileInterface(typ, structName, fieldName)
|
||||||
|
case reflect.Uintptr:
|
||||||
|
return compileUint(typ, structName, fieldName)
|
||||||
|
case reflect.Int:
|
||||||
|
return compileInt(typ, structName, fieldName)
|
||||||
|
case reflect.Int8:
|
||||||
|
return compileInt8(typ, structName, fieldName)
|
||||||
|
case reflect.Int16:
|
||||||
|
return compileInt16(typ, structName, fieldName)
|
||||||
|
case reflect.Int32:
|
||||||
|
return compileInt32(typ, structName, fieldName)
|
||||||
|
case reflect.Int64:
|
||||||
|
return compileInt64(typ, structName, fieldName)
|
||||||
|
case reflect.Uint:
|
||||||
|
return compileUint(typ, structName, fieldName)
|
||||||
|
case reflect.Uint8:
|
||||||
|
return compileUint8(typ, structName, fieldName)
|
||||||
|
case reflect.Uint16:
|
||||||
|
return compileUint16(typ, structName, fieldName)
|
||||||
|
case reflect.Uint32:
|
||||||
|
return compileUint32(typ, structName, fieldName)
|
||||||
|
case reflect.Uint64:
|
||||||
|
return compileUint64(typ, structName, fieldName)
|
||||||
|
case reflect.String:
|
||||||
|
return compileString(typ, structName, fieldName)
|
||||||
|
case reflect.Bool:
|
||||||
|
return compileBool(structName, fieldName)
|
||||||
|
case reflect.Float32:
|
||||||
|
return compileFloat32(structName, fieldName)
|
||||||
|
case reflect.Float64:
|
||||||
|
return compileFloat64(structName, fieldName)
|
||||||
|
case reflect.Func:
|
||||||
|
return compileFunc(typ, structName, fieldName)
|
||||||
|
}
|
||||||
|
return nil, &errors.UnmarshalTypeError{
|
||||||
|
Value: "object",
|
||||||
|
Type: runtime.RType2Type(typ),
|
||||||
|
Offset: 0,
|
||||||
|
Struct: structName,
|
||||||
|
Field: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStringTagSupportedType(typ *runtime.Type) bool {
|
||||||
|
switch {
|
||||||
|
case implementsUnmarshalJSONType(runtime.PtrTo(typ)):
|
||||||
|
return false
|
||||||
|
case runtime.PtrTo(typ).Implements(unmarshalTextType):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch typ.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
return false
|
||||||
|
case reflect.Slice:
|
||||||
|
return false
|
||||||
|
case reflect.Array:
|
||||||
|
return false
|
||||||
|
case reflect.Struct:
|
||||||
|
return false
|
||||||
|
case reflect.Interface:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileMapKey(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
if runtime.PtrTo(typ).Implements(unmarshalTextType) {
|
||||||
|
return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil
|
||||||
|
}
|
||||||
|
dec, err := compile(typ, structName, fieldName, structTypeToDecoder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
switch t := dec.(type) {
|
||||||
|
case *stringDecoder, *interfaceDecoder:
|
||||||
|
return dec, nil
|
||||||
|
case *boolDecoder, *intDecoder, *uintDecoder, *numberDecoder:
|
||||||
|
return newWrappedStringDecoder(typ, dec, structName, fieldName), nil
|
||||||
|
case *ptrDecoder:
|
||||||
|
dec = t.dec
|
||||||
|
default:
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
return nil, &errors.UnmarshalTypeError{
|
||||||
|
Value: "object",
|
||||||
|
Type: runtime.RType2Type(typ),
|
||||||
|
Offset: 0,
|
||||||
|
Struct: structName,
|
||||||
|
Field: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compilePtr(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
dec, err := compile(typ.Elem(), structName, fieldName, structTypeToDecoder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newPtrDecoder(dec, typ.Elem(), structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
|
||||||
|
*(*int)(p) = int(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt8(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
|
||||||
|
*(*int8)(p) = int8(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt16(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
|
||||||
|
*(*int16)(p) = int16(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt32(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
|
||||||
|
*(*int32)(p) = int32(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInt64(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) {
|
||||||
|
*(*int64)(p) = v
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
|
||||||
|
*(*uint)(p) = uint(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint8(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
|
||||||
|
*(*uint8)(p) = uint8(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint16(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
|
||||||
|
*(*uint16)(p) = uint16(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint32(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
|
||||||
|
*(*uint32)(p) = uint32(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileUint64(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) {
|
||||||
|
*(*uint64)(p) = v
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileFloat32(structName, fieldName string) (Decoder, error) {
|
||||||
|
return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
|
||||||
|
*(*float32)(p) = float32(v)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileFloat64(structName, fieldName string) (Decoder, error) {
|
||||||
|
return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
|
||||||
|
*(*float64)(p) = v
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileString(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
if typ == runtime.Type2RType(jsonNumberType) {
|
||||||
|
return newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
|
||||||
|
*(*json.Number)(p) = v
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
return newStringDecoder(structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileBool(structName, fieldName string) (Decoder, error) {
|
||||||
|
return newBoolDecoder(structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileBytes(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newBytesDecoder(typ, structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileSlice(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
elem := typ.Elem()
|
||||||
|
decoder, err := compile(elem, structName, fieldName, structTypeToDecoder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newSliceDecoder(decoder, elem, elem.Size(), structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileArray(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
elem := typ.Elem()
|
||||||
|
decoder, err := compile(elem, structName, fieldName, structTypeToDecoder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newArrayDecoder(decoder, elem, typ.Len(), structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileMap(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
keyDec, err := compileMapKey(typ.Key(), structName, fieldName, structTypeToDecoder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
valueDec, err := compile(typ.Elem(), structName, fieldName, structTypeToDecoder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newMapDecoder(typ, typ.Key(), keyDec, typ.Elem(), valueDec, structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileInterface(typ *runtime.Type, structName, fieldName string) (Decoder, error) {
|
||||||
|
return newInterfaceDecoder(typ, structName, fieldName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if _, exists := conflictedMap[k]; exists {
|
||||||
|
// already conflicted key
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set, exists := fieldMap[k]
|
||||||
|
if !exists {
|
||||||
|
fieldSet := &structFieldSet{
|
||||||
|
dec: v.dec,
|
||||||
|
offset: field.Offset + v.offset,
|
||||||
|
isTaggedKey: v.isTaggedKey,
|
||||||
|
key: k,
|
||||||
|
keyLen: int64(len(k)),
|
||||||
|
}
|
||||||
|
fieldMap[k] = fieldSet
|
||||||
|
lower := strings.ToLower(k)
|
||||||
|
if _, exists := fieldMap[lower]; !exists {
|
||||||
|
fieldMap[lower] = fieldSet
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if set.isTaggedKey {
|
||||||
|
if v.isTaggedKey {
|
||||||
|
// conflict tag key
|
||||||
|
delete(fieldMap, k)
|
||||||
|
delete(fieldMap, strings.ToLower(k))
|
||||||
|
conflictedMap[k] = struct{}{}
|
||||||
|
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if v.isTaggedKey {
|
||||||
|
fieldSet := &structFieldSet{
|
||||||
|
dec: v.dec,
|
||||||
|
offset: field.Offset + v.offset,
|
||||||
|
isTaggedKey: v.isTaggedKey,
|
||||||
|
key: k,
|
||||||
|
keyLen: int64(len(k)),
|
||||||
|
}
|
||||||
|
fieldMap[k] = fieldSet
|
||||||
|
lower := strings.ToLower(k)
|
||||||
|
if _, exists := fieldMap[lower]; !exists {
|
||||||
|
fieldMap[lower] = fieldSet
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// conflict tag key
|
||||||
|
delete(fieldMap, k)
|
||||||
|
delete(fieldMap, strings.ToLower(k))
|
||||||
|
conflictedMap[k] = struct{}{}
|
||||||
|
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) {
|
||||||
|
fieldNum := typ.NumField()
|
||||||
|
conflictedMap := map[string]struct{}{}
|
||||||
|
fieldMap := map[string]*structFieldSet{}
|
||||||
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
|
if dec, exists := structTypeToDecoder[typeptr]; exists {
|
||||||
|
return dec, nil
|
||||||
|
}
|
||||||
|
structDec := newStructDecoder(structName, fieldName, fieldMap)
|
||||||
|
structTypeToDecoder[typeptr] = structDec
|
||||||
|
structName = typ.Name()
|
||||||
|
for i := 0; i < fieldNum; i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
if runtime.IsIgnoredStructField(field) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isUnexportedField := unicode.IsLower([]rune(field.Name)[0])
|
||||||
|
tag := runtime.StructTagFromField(field)
|
||||||
|
dec, err := compile(runtime.Type2RType(field.Type), structName, field.Name, structTypeToDecoder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if field.Anonymous && !tag.IsTaggedKey {
|
||||||
|
if stDec, ok := dec.(*structDecoder); ok {
|
||||||
|
if runtime.Type2RType(field.Type) == typ {
|
||||||
|
// recursive definition
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
removeConflictFields(fieldMap, conflictedMap, stDec, field)
|
||||||
|
} else if pdec, ok := dec.(*ptrDecoder); ok {
|
||||||
|
contentDec := pdec.contentDecoder()
|
||||||
|
if pdec.typ == typ {
|
||||||
|
// recursive definition
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var fieldSetErr error
|
||||||
|
if isUnexportedField {
|
||||||
|
fieldSetErr = fmt.Errorf(
|
||||||
|
"json: cannot set embedded pointer to unexported struct: %v",
|
||||||
|
field.Type.Elem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if dec, ok := contentDec.(*structDecoder); ok {
|
||||||
|
for k, v := range dec.fieldMap {
|
||||||
|
if _, exists := conflictedMap[k]; exists {
|
||||||
|
// already conflicted key
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set, exists := fieldMap[k]
|
||||||
|
if !exists {
|
||||||
|
fieldSet := &structFieldSet{
|
||||||
|
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
|
||||||
|
offset: field.Offset,
|
||||||
|
isTaggedKey: v.isTaggedKey,
|
||||||
|
key: k,
|
||||||
|
keyLen: int64(len(k)),
|
||||||
|
err: fieldSetErr,
|
||||||
|
}
|
||||||
|
fieldMap[k] = fieldSet
|
||||||
|
lower := strings.ToLower(k)
|
||||||
|
if _, exists := fieldMap[lower]; !exists {
|
||||||
|
fieldMap[lower] = fieldSet
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if set.isTaggedKey {
|
||||||
|
if v.isTaggedKey {
|
||||||
|
// conflict tag key
|
||||||
|
delete(fieldMap, k)
|
||||||
|
delete(fieldMap, strings.ToLower(k))
|
||||||
|
conflictedMap[k] = struct{}{}
|
||||||
|
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if v.isTaggedKey {
|
||||||
|
fieldSet := &structFieldSet{
|
||||||
|
dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec),
|
||||||
|
offset: field.Offset,
|
||||||
|
isTaggedKey: v.isTaggedKey,
|
||||||
|
key: k,
|
||||||
|
keyLen: int64(len(k)),
|
||||||
|
err: fieldSetErr,
|
||||||
|
}
|
||||||
|
fieldMap[k] = fieldSet
|
||||||
|
lower := strings.ToLower(k)
|
||||||
|
if _, exists := fieldMap[lower]; !exists {
|
||||||
|
fieldMap[lower] = fieldSet
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// conflict tag key
|
||||||
|
delete(fieldMap, k)
|
||||||
|
delete(fieldMap, strings.ToLower(k))
|
||||||
|
conflictedMap[k] = struct{}{}
|
||||||
|
conflictedMap[strings.ToLower(k)] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if tag.IsString && isStringTagSupportedType(runtime.Type2RType(field.Type)) {
|
||||||
|
dec = newWrappedStringDecoder(runtime.Type2RType(field.Type), dec, structName, field.Name)
|
||||||
|
}
|
||||||
|
var key string
|
||||||
|
if tag.Key != "" {
|
||||||
|
key = tag.Key
|
||||||
|
} else {
|
||||||
|
key = field.Name
|
||||||
|
}
|
||||||
|
fieldSet := &structFieldSet{
|
||||||
|
dec: dec,
|
||||||
|
offset: field.Offset,
|
||||||
|
isTaggedKey: tag.IsTaggedKey,
|
||||||
|
key: key,
|
||||||
|
keyLen: int64(len(key)),
|
||||||
|
}
|
||||||
|
fieldMap[key] = fieldSet
|
||||||
|
lower := strings.ToLower(key)
|
||||||
|
if _, exists := fieldMap[lower]; !exists {
|
||||||
|
fieldMap[lower] = fieldSet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(structTypeToDecoder, typeptr)
|
||||||
|
structDec.tryOptimize()
|
||||||
|
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
|
||||||
|
}
|
36
vendor/github.com/goccy/go-json/internal/decoder/compile_race.go
generated
vendored
Normal file
36
vendor/github.com/goccy/go-json/internal/decoder/compile_race.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// +build race
|
||||||
|
|
||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var decMu sync.RWMutex
|
||||||
|
|
||||||
|
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
|
||||||
|
decMu.RLock()
|
||||||
|
if dec := cachedDecoder[index]; dec != nil {
|
||||||
|
decMu.RUnlock()
|
||||||
|
return dec, nil
|
||||||
|
}
|
||||||
|
decMu.RUnlock()
|
||||||
|
|
||||||
|
dec, err := compileHead(typ, map[uintptr]Decoder{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
decMu.Lock()
|
||||||
|
cachedDecoder[index] = dec
|
||||||
|
decMu.Unlock()
|
||||||
|
return dec, nil
|
||||||
|
}
|
254
vendor/github.com/goccy/go-json/internal/decoder/context.go
generated
vendored
Normal file
254
vendor/github.com/goccy/go-json/internal/decoder/context.go
generated
vendored
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"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 (
|
||||||
|
isWhiteSpace = [256]bool{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
isWhiteSpace[' '] = true
|
||||||
|
isWhiteSpace['\n'] = true
|
||||||
|
isWhiteSpace['\t'] = true
|
||||||
|
isWhiteSpace['\r'] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func char(ptr unsafe.Pointer, offset int64) byte {
|
||||||
|
return *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(offset)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipWhiteSpace(buf []byte, cursor int64) int64 {
|
||||||
|
for isWhiteSpace[buf[cursor]] {
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
return cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipObject(buf []byte, cursor, depth int64) (int64, error) {
|
||||||
|
braceCount := 1
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case '{':
|
||||||
|
braceCount++
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
||||||
|
}
|
||||||
|
case '}':
|
||||||
|
depth--
|
||||||
|
braceCount--
|
||||||
|
if braceCount == 0 {
|
||||||
|
return cursor + 1, nil
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
||||||
|
}
|
||||||
|
case ']':
|
||||||
|
depth--
|
||||||
|
case '"':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch buf[cursor] {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if buf[cursor] == nul {
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
goto SWITCH_OUT
|
||||||
|
case nul:
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nul:
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("object of object", cursor)
|
||||||
|
}
|
||||||
|
SWITCH_OUT:
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipArray(buf []byte, cursor, depth int64) (int64, error) {
|
||||||
|
bracketCount := 1
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case '[':
|
||||||
|
bracketCount++
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
||||||
|
}
|
||||||
|
case ']':
|
||||||
|
bracketCount--
|
||||||
|
depth--
|
||||||
|
if bracketCount == 0 {
|
||||||
|
return cursor + 1, nil
|
||||||
|
}
|
||||||
|
case '{':
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
||||||
|
}
|
||||||
|
case '}':
|
||||||
|
depth--
|
||||||
|
case '"':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch buf[cursor] {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if buf[cursor] == nul {
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
goto SWITCH_OUT
|
||||||
|
case nul:
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nul:
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("array of object", cursor)
|
||||||
|
}
|
||||||
|
SWITCH_OUT:
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipValue(buf []byte, cursor, depth int64) (int64, error) {
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\t', '\n', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case '{':
|
||||||
|
return skipObject(buf, cursor+1, depth+1)
|
||||||
|
case '[':
|
||||||
|
return skipArray(buf, cursor+1, depth+1)
|
||||||
|
case '"':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch buf[cursor] {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if buf[cursor] == nul {
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
return cursor + 1, nil
|
||||||
|
case nul:
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
if floatTable[buf[cursor]] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return cursor, nil
|
||||||
|
case 't':
|
||||||
|
if err := validateTrue(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return cursor, nil
|
||||||
|
case 'f':
|
||||||
|
if err := validateFalse(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 5
|
||||||
|
return cursor, nil
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return cursor, nil
|
||||||
|
default:
|
||||||
|
return cursor, errors.ErrUnexpectedEndOfJSON("null", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateTrue(buf []byte, cursor int64) error {
|
||||||
|
if cursor+3 >= int64(len(buf)) {
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("true", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+1] != 'r' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+1], "true", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+2] != 'u' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+2], "true", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+3] != 'e' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+3], "true", cursor)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateFalse(buf []byte, cursor int64) error {
|
||||||
|
if cursor+4 >= int64(len(buf)) {
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("false", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+1] != 'a' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+1], "false", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+2] != 'l' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+2], "false", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+3] != 's' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+3], "false", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+4] != 'e' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+4], "false", cursor)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateNull(buf []byte, cursor int64) error {
|
||||||
|
if cursor+3 >= int64(len(buf)) {
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("null", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+1] != 'u' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+1], "null", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+2] != 'l' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+2], "null", cursor)
|
||||||
|
}
|
||||||
|
if buf[cursor+3] != 'l' {
|
||||||
|
return errors.ErrInvalidCharacter(buf[cursor+3], "null", cursor)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
158
vendor/github.com/goccy/go-json/internal/decoder/float.go
generated
vendored
Normal file
158
vendor/github.com/goccy/go-json/internal/decoder/float.go
generated
vendored
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type floatDecoder struct {
|
||||||
|
op func(unsafe.Pointer, float64)
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFloatDecoder(structName, fieldName string, op func(unsafe.Pointer, float64)) *floatDecoder {
|
||||||
|
return &floatDecoder{op: op, structName: structName, fieldName: fieldName}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
floatTable = [256]bool{
|
||||||
|
'0': true,
|
||||||
|
'1': true,
|
||||||
|
'2': true,
|
||||||
|
'3': true,
|
||||||
|
'4': true,
|
||||||
|
'5': true,
|
||||||
|
'6': true,
|
||||||
|
'7': true,
|
||||||
|
'8': true,
|
||||||
|
'9': true,
|
||||||
|
'.': true,
|
||||||
|
'e': true,
|
||||||
|
'E': true,
|
||||||
|
'+': true,
|
||||||
|
'-': true,
|
||||||
|
}
|
||||||
|
|
||||||
|
validEndNumberChar = [256]bool{
|
||||||
|
nul: true,
|
||||||
|
' ': true,
|
||||||
|
'\t': true,
|
||||||
|
'\r': true,
|
||||||
|
'\n': true,
|
||||||
|
',': true,
|
||||||
|
':': true,
|
||||||
|
'}': true,
|
||||||
|
']': true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func floatBytes(s *Stream) []byte {
|
||||||
|
start := s.cursor
|
||||||
|
for {
|
||||||
|
s.cursor++
|
||||||
|
if floatTable[s.char()] {
|
||||||
|
continue
|
||||||
|
} else if s.char() == nul {
|
||||||
|
if s.read() {
|
||||||
|
s.cursor-- // for retry current character
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return s.buf[start:s.cursor]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *floatDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return floatBytes(s), nil
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
default:
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
return nil, errors.ErrUnexpectedEndOfJSON("float", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
start := cursor
|
||||||
|
cursor++
|
||||||
|
for floatTable[buf[cursor]] {
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
num := buf[start:cursor]
|
||||||
|
return num, cursor, nil
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return nil, cursor, nil
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("float", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *floatDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
bytes, err := d.decodeStreamByte(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
str := *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
f64, err := strconv.ParseFloat(str, 64)
|
||||||
|
if err != nil {
|
||||||
|
return errors.ErrSyntax(err.Error(), s.totalOffset())
|
||||||
|
}
|
||||||
|
d.op(p, f64)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *floatDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
bytes, c, err := d.decodeByte(buf, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
if !validEndNumberChar[buf[cursor]] {
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("float", cursor)
|
||||||
|
}
|
||||||
|
s := *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
f64, err := strconv.ParseFloat(s, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.ErrSyntax(err.Error(), cursor)
|
||||||
|
}
|
||||||
|
d.op(p, f64)
|
||||||
|
return cursor, nil
|
||||||
|
}
|
141
vendor/github.com/goccy/go-json/internal/decoder/func.go
generated
vendored
Normal file
141
vendor/github.com/goccy/go-json/internal/decoder/func.go
generated
vendored
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type funcDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFuncDecoder(typ *runtime.Type, structName, fieldName string) *funcDecoder {
|
||||||
|
fnDecoder := &funcDecoder{typ, structName, fieldName}
|
||||||
|
return fnDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *funcDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
s.skipWhiteSpace()
|
||||||
|
start := s.cursor
|
||||||
|
if err := s.skipValue(depth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
src := s.buf[start:s.cursor]
|
||||||
|
if len(src) > 0 {
|
||||||
|
switch src[0] {
|
||||||
|
case '"':
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: "string",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: s.totalOffset(),
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: "array",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: s.totalOffset(),
|
||||||
|
}
|
||||||
|
case '{':
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: "object",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: s.totalOffset(),
|
||||||
|
}
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: "number",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: s.totalOffset(),
|
||||||
|
}
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
return nil
|
||||||
|
case 't':
|
||||||
|
if err := trueBytes(s); err == nil {
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: "boolean",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: s.totalOffset(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'f':
|
||||||
|
if err := falseBytes(s); err == nil {
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: "boolean",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: s.totalOffset(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.ErrInvalidBeginningOfValue(s.buf[s.cursor], s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
start := cursor
|
||||||
|
end, err := skipValue(buf, cursor, depth)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
src := buf[start:end]
|
||||||
|
if len(src) > 0 {
|
||||||
|
switch src[0] {
|
||||||
|
case '"':
|
||||||
|
return 0, &errors.UnmarshalTypeError{
|
||||||
|
Value: "string",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: start,
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
return 0, &errors.UnmarshalTypeError{
|
||||||
|
Value: "array",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: start,
|
||||||
|
}
|
||||||
|
case '{':
|
||||||
|
return 0, &errors.UnmarshalTypeError{
|
||||||
|
Value: "object",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: start,
|
||||||
|
}
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return 0, &errors.UnmarshalTypeError{
|
||||||
|
Value: "number",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: start,
|
||||||
|
}
|
||||||
|
case 'n':
|
||||||
|
if bytes.Equal(src, nullbytes) {
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
return end, nil
|
||||||
|
}
|
||||||
|
case 't':
|
||||||
|
if err := validateTrue(buf, start); err == nil {
|
||||||
|
return 0, &errors.UnmarshalTypeError{
|
||||||
|
Value: "boolean",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'f':
|
||||||
|
if err := validateFalse(buf, start); err == nil {
|
||||||
|
return 0, &errors.UnmarshalTypeError{
|
||||||
|
Value: "boolean",
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor)
|
||||||
|
}
|
242
vendor/github.com/goccy/go-json/internal/decoder/int.go
generated
vendored
Normal file
242
vendor/github.com/goccy/go-json/internal/decoder/int.go
generated
vendored
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type intDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
kind reflect.Kind
|
||||||
|
op func(unsafe.Pointer, int64)
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIntDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder {
|
||||||
|
return &intDecoder{
|
||||||
|
typ: typ,
|
||||||
|
kind: typ.Kind(),
|
||||||
|
op: op,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *intDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError {
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: fmt.Sprintf("number %s", string(buf)),
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Struct: d.structName,
|
||||||
|
Field: d.fieldName,
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pow10i64 = [...]int64{
|
||||||
|
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
|
||||||
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18,
|
||||||
|
}
|
||||||
|
pow10i64Len = len(pow10i64)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *intDecoder) parseInt(b []byte) (int64, error) {
|
||||||
|
isNegative := false
|
||||||
|
if b[0] == '-' {
|
||||||
|
b = b[1:]
|
||||||
|
isNegative = true
|
||||||
|
}
|
||||||
|
maxDigit := len(b)
|
||||||
|
if maxDigit > pow10i64Len {
|
||||||
|
return 0, fmt.Errorf("invalid length of number")
|
||||||
|
}
|
||||||
|
sum := int64(0)
|
||||||
|
for i := 0; i < maxDigit; i++ {
|
||||||
|
c := int64(b[i]) - 48
|
||||||
|
digitValue := pow10i64[maxDigit-i-1]
|
||||||
|
sum += c * digitValue
|
||||||
|
}
|
||||||
|
if isNegative {
|
||||||
|
return -1 * sum, nil
|
||||||
|
}
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
numTable = [256]bool{
|
||||||
|
'0': true,
|
||||||
|
'1': true,
|
||||||
|
'2': true,
|
||||||
|
'3': true,
|
||||||
|
'4': true,
|
||||||
|
'5': true,
|
||||||
|
'6': true,
|
||||||
|
'7': true,
|
||||||
|
'8': true,
|
||||||
|
'9': true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
numZeroBuf = []byte{'0'}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *intDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
case '-':
|
||||||
|
start := s.cursor
|
||||||
|
for {
|
||||||
|
s.cursor++
|
||||||
|
if numTable[s.char()] {
|
||||||
|
continue
|
||||||
|
} else if s.char() == nul {
|
||||||
|
if s.read() {
|
||||||
|
s.cursor-- // for retry current character
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
num := s.buf[start:s.cursor]
|
||||||
|
if len(num) < 2 {
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
return num, nil
|
||||||
|
case '0':
|
||||||
|
s.cursor++
|
||||||
|
return numZeroBuf, nil
|
||||||
|
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
start := s.cursor
|
||||||
|
for {
|
||||||
|
s.cursor++
|
||||||
|
if numTable[s.char()] {
|
||||||
|
continue
|
||||||
|
} else if s.char() == nul {
|
||||||
|
if s.read() {
|
||||||
|
s.cursor-- // for retry current character
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
num := s.buf[start:s.cursor]
|
||||||
|
return num, nil
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
default:
|
||||||
|
return nil, d.typeError([]byte{s.char()}, s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
return nil, errors.ErrUnexpectedEndOfJSON("number(integer)", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
|
||||||
|
for {
|
||||||
|
switch char(b, cursor) {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case '0':
|
||||||
|
cursor++
|
||||||
|
return numZeroBuf, cursor, nil
|
||||||
|
case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
start := cursor
|
||||||
|
cursor++
|
||||||
|
for numTable[char(b, cursor)] {
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
num := buf[start:cursor]
|
||||||
|
return num, cursor, nil
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return nil, cursor, nil
|
||||||
|
default:
|
||||||
|
return nil, 0, d.typeError([]byte{char(b, cursor)}, cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
bytes, err := d.decodeStreamByte(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
i64, err := d.parseInt(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
switch d.kind {
|
||||||
|
case reflect.Int8:
|
||||||
|
if i64 <= -1*(1<<7) || (1<<7) <= i64 {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
case reflect.Int16:
|
||||||
|
if i64 <= -1*(1<<15) || (1<<15) <= i64 {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
if i64 <= -1*(1<<31) || (1<<31) <= i64 {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.op(p, i64)
|
||||||
|
s.reset()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
bytes, c, err := d.decodeByte(ctx.Buf, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
|
||||||
|
i64, err := d.parseInt(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
switch d.kind {
|
||||||
|
case reflect.Int8:
|
||||||
|
if i64 <= -1*(1<<7) || (1<<7) <= i64 {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
case reflect.Int16:
|
||||||
|
if i64 <= -1*(1<<15) || (1<<15) <= i64 {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
if i64 <= -1*(1<<31) || (1<<31) <= i64 {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.op(p, i64)
|
||||||
|
return cursor, nil
|
||||||
|
}
|
458
vendor/github.com/goccy/go-json/internal/decoder/interface.go
generated
vendored
Normal file
458
vendor/github.com/goccy/go-json/internal/decoder/interface.go
generated
vendored
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding"
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type interfaceDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
sliceDecoder *sliceDecoder
|
||||||
|
mapDecoder *mapDecoder
|
||||||
|
floatDecoder *floatDecoder
|
||||||
|
numberDecoder *numberDecoder
|
||||||
|
stringDecoder *stringDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder {
|
||||||
|
ifaceDecoder := &interfaceDecoder{
|
||||||
|
typ: emptyInterfaceType,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
|
||||||
|
*(*interface{})(p) = v
|
||||||
|
}),
|
||||||
|
numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
|
||||||
|
*(*interface{})(p) = v
|
||||||
|
}),
|
||||||
|
stringDecoder: newStringDecoder(structName, fieldName),
|
||||||
|
}
|
||||||
|
ifaceDecoder.sliceDecoder = newSliceDecoder(
|
||||||
|
ifaceDecoder,
|
||||||
|
emptyInterfaceType,
|
||||||
|
emptyInterfaceType.Size(),
|
||||||
|
structName, fieldName,
|
||||||
|
)
|
||||||
|
ifaceDecoder.mapDecoder = newMapDecoder(
|
||||||
|
interfaceMapType,
|
||||||
|
stringType,
|
||||||
|
ifaceDecoder.stringDecoder,
|
||||||
|
interfaceMapType.Elem(),
|
||||||
|
ifaceDecoder,
|
||||||
|
structName,
|
||||||
|
fieldName,
|
||||||
|
)
|
||||||
|
return ifaceDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInterfaceDecoder(typ *runtime.Type, structName, fieldName string) *interfaceDecoder {
|
||||||
|
emptyIfaceDecoder := newEmptyInterfaceDecoder(structName, fieldName)
|
||||||
|
stringDecoder := newStringDecoder(structName, fieldName)
|
||||||
|
return &interfaceDecoder{
|
||||||
|
typ: typ,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
sliceDecoder: newSliceDecoder(
|
||||||
|
emptyIfaceDecoder,
|
||||||
|
emptyInterfaceType,
|
||||||
|
emptyInterfaceType.Size(),
|
||||||
|
structName, fieldName,
|
||||||
|
),
|
||||||
|
mapDecoder: newMapDecoder(
|
||||||
|
interfaceMapType,
|
||||||
|
stringType,
|
||||||
|
stringDecoder,
|
||||||
|
interfaceMapType.Elem(),
|
||||||
|
emptyIfaceDecoder,
|
||||||
|
structName,
|
||||||
|
fieldName,
|
||||||
|
),
|
||||||
|
floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
|
||||||
|
*(*interface{})(p) = v
|
||||||
|
}),
|
||||||
|
numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
|
||||||
|
*(*interface{})(p) = v
|
||||||
|
}),
|
||||||
|
stringDecoder: stringDecoder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *interfaceDecoder) numDecoder(s *Stream) Decoder {
|
||||||
|
if s.UseNumber {
|
||||||
|
return d.numberDecoder
|
||||||
|
}
|
||||||
|
return d.floatDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
emptyInterfaceType = runtime.Type2RType(reflect.TypeOf((*interface{})(nil)).Elem())
|
||||||
|
interfaceMapType = runtime.Type2RType(
|
||||||
|
reflect.TypeOf((*map[string]interface{})(nil)).Elem(),
|
||||||
|
)
|
||||||
|
stringType = runtime.Type2RType(
|
||||||
|
reflect.TypeOf(""),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func decodeStreamUnmarshaler(s *Stream, depth int64, unmarshaler json.Unmarshaler) 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(dst); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
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(dst); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return end, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if err := s.skipValue(depth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
src := s.buf[start:s.cursor]
|
||||||
|
if bytes.Equal(src, nullbytes) {
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := make([]byte, len(src))
|
||||||
|
copy(dst, src)
|
||||||
|
|
||||||
|
if err := unmarshaler.UnmarshalText(dst); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeTextUnmarshaler(buf []byte, cursor, depth int64, unmarshaler encoding.TextUnmarshaler, 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]
|
||||||
|
if bytes.Equal(src, nullbytes) {
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
return end, nil
|
||||||
|
}
|
||||||
|
if s, ok := unquoteBytes(src); ok {
|
||||||
|
src = s
|
||||||
|
}
|
||||||
|
if err := unmarshaler.UnmarshalText(src); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return end, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *interfaceDecoder) decodeStreamEmptyInterface(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
c := s.skipWhiteSpace()
|
||||||
|
for {
|
||||||
|
switch c {
|
||||||
|
case '{':
|
||||||
|
var v map[string]interface{}
|
||||||
|
ptr := unsafe.Pointer(&v)
|
||||||
|
if err := d.mapDecoder.DecodeStream(s, depth, ptr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*interface{})(p) = v
|
||||||
|
return nil
|
||||||
|
case '[':
|
||||||
|
var v []interface{}
|
||||||
|
ptr := unsafe.Pointer(&v)
|
||||||
|
if err := d.sliceDecoder.DecodeStream(s, depth, ptr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*interface{})(p) = v
|
||||||
|
return nil
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return d.numDecoder(s).DecodeStream(s, depth, p)
|
||||||
|
case '"':
|
||||||
|
s.cursor++
|
||||||
|
start := s.cursor
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case '\\':
|
||||||
|
if _, err := decodeEscapeString(s, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
literal := s.buf[start:s.cursor]
|
||||||
|
s.cursor++
|
||||||
|
*(*interface{})(p) = string(literal)
|
||||||
|
return nil
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
}
|
||||||
|
case 't':
|
||||||
|
if err := trueBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = true
|
||||||
|
return nil
|
||||||
|
case 'f':
|
||||||
|
if err := falseBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = false
|
||||||
|
return nil
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*interface{})(p) = nil
|
||||||
|
return nil
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
c = s.char()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return errors.ErrInvalidBeginningOfValue(c, s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
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{
|
||||||
|
typ: d.typ,
|
||||||
|
ptr: p,
|
||||||
|
}))
|
||||||
|
rv := reflect.ValueOf(runtimeInterfaceValue)
|
||||||
|
if rv.NumMethod() > 0 && rv.CanInterface() {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
|
||||||
|
return decodeStreamTextUnmarshaler(s, depth, u, p)
|
||||||
|
}
|
||||||
|
if s.skipWhiteSpace() == 'n' {
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*interface{})(p) = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return d.errUnmarshalType(rv.Type(), s.totalOffset())
|
||||||
|
}
|
||||||
|
iface := rv.Interface()
|
||||||
|
ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface))
|
||||||
|
typ := ifaceHeader.typ
|
||||||
|
if ifaceHeader.ptr == nil || d.typ == typ || typ == nil {
|
||||||
|
// concrete type is empty interface
|
||||||
|
return d.decodeStreamEmptyInterface(s, depth, p)
|
||||||
|
}
|
||||||
|
if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr {
|
||||||
|
return d.decodeStreamEmptyInterface(s, depth, p)
|
||||||
|
}
|
||||||
|
if s.skipWhiteSpace() == 'n' {
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*interface{})(p) = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
decoder, err := CompileToGetDecoder(typ)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return decoder.DecodeStream(s, depth, ifaceHeader.ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *errors.UnmarshalTypeError {
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: typ.String(),
|
||||||
|
Type: typ,
|
||||||
|
Offset: offset,
|
||||||
|
Struct: d.structName,
|
||||||
|
Field: d.fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *interfaceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: d.typ,
|
||||||
|
ptr: p,
|
||||||
|
}))
|
||||||
|
rv := reflect.ValueOf(runtimeInterfaceValue)
|
||||||
|
if rv.NumMethod() > 0 && rv.CanInterface() {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
|
||||||
|
return decodeTextUnmarshaler(buf, cursor, depth, u, p)
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
if buf[cursor] == 'n' {
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = nil
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
return 0, d.errUnmarshalType(rv.Type(), cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
iface := rv.Interface()
|
||||||
|
ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface))
|
||||||
|
typ := ifaceHeader.typ
|
||||||
|
if ifaceHeader.ptr == nil || d.typ == typ || typ == nil {
|
||||||
|
// concrete type is empty interface
|
||||||
|
return d.decodeEmptyInterface(ctx, cursor, depth, p)
|
||||||
|
}
|
||||||
|
if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr {
|
||||||
|
return d.decodeEmptyInterface(ctx, cursor, depth, p)
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
if buf[cursor] == 'n' {
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = nil
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
decoder, err := CompileToGetDecoder(typ)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return decoder.Decode(ctx, cursor, depth, ifaceHeader.ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *interfaceDecoder) decodeEmptyInterface(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
switch buf[cursor] {
|
||||||
|
case '{':
|
||||||
|
var v map[string]interface{}
|
||||||
|
ptr := unsafe.Pointer(&v)
|
||||||
|
cursor, err := d.mapDecoder.Decode(ctx, cursor, depth, ptr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = v
|
||||||
|
return cursor, nil
|
||||||
|
case '[':
|
||||||
|
var v []interface{}
|
||||||
|
ptr := unsafe.Pointer(&v)
|
||||||
|
cursor, err := d.sliceDecoder.Decode(ctx, cursor, depth, ptr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = v
|
||||||
|
return cursor, nil
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return d.floatDecoder.Decode(ctx, cursor, depth, p)
|
||||||
|
case '"':
|
||||||
|
var v string
|
||||||
|
ptr := unsafe.Pointer(&v)
|
||||||
|
cursor, err := d.stringDecoder.Decode(ctx, cursor, depth, ptr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = v
|
||||||
|
return cursor, nil
|
||||||
|
case 't':
|
||||||
|
if err := validateTrue(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = true
|
||||||
|
return cursor, nil
|
||||||
|
case 'f':
|
||||||
|
if err := validateFalse(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 5
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = false
|
||||||
|
return cursor, nil
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
**(**interface{})(unsafe.Pointer(&p)) = nil
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor)
|
||||||
|
}
|
186
vendor/github.com/goccy/go-json/internal/decoder/map.go
generated
vendored
Normal file
186
vendor/github.com/goccy/go-json/internal/decoder/map.go
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mapDecoder struct {
|
||||||
|
mapType *runtime.Type
|
||||||
|
keyType *runtime.Type
|
||||||
|
valueType *runtime.Type
|
||||||
|
canUseAssignFaststrType bool
|
||||||
|
keyDecoder Decoder
|
||||||
|
valueDecoder Decoder
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder {
|
||||||
|
return &mapDecoder{
|
||||||
|
mapType: mapType,
|
||||||
|
keyDecoder: keyDec,
|
||||||
|
keyType: keyType,
|
||||||
|
canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType),
|
||||||
|
valueType: valueType,
|
||||||
|
valueDecoder: valueDec,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
mapMaxElemSize = 128
|
||||||
|
)
|
||||||
|
|
||||||
|
// See detail: https://github.com/goccy/go-json/pull/283
|
||||||
|
func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool {
|
||||||
|
indirectElem := value.Size() > mapMaxElemSize
|
||||||
|
if indirectElem {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return key.Kind() == reflect.String
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname makemap reflect.makemap
|
||||||
|
func makemap(*runtime.Type, int) unsafe.Pointer
|
||||||
|
|
||||||
|
//nolint:golint
|
||||||
|
//go:linkname mapassign_faststr runtime.mapassign_faststr
|
||||||
|
//go:noescape
|
||||||
|
func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname mapassign reflect.mapassign
|
||||||
|
//go:noescape
|
||||||
|
func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer)
|
||||||
|
|
||||||
|
func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) {
|
||||||
|
if d.canUseAssignFaststrType {
|
||||||
|
mapV := mapassign_faststr(t, m, *(*string)(k))
|
||||||
|
typedmemmove(d.valueType, mapV, v)
|
||||||
|
} else {
|
||||||
|
mapassign(t, m, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s.skipWhiteSpace() {
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
|
||||||
|
return nil
|
||||||
|
case '{':
|
||||||
|
default:
|
||||||
|
return errors.ErrExpected("{ character for map value", s.totalOffset())
|
||||||
|
}
|
||||||
|
mapValue := *(*unsafe.Pointer)(p)
|
||||||
|
if mapValue == nil {
|
||||||
|
mapValue = makemap(d.mapType, 0)
|
||||||
|
}
|
||||||
|
if s.buf[s.cursor+1] == '}' {
|
||||||
|
*(*unsafe.Pointer)(p) = mapValue
|
||||||
|
s.cursor += 2
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
s.cursor++
|
||||||
|
k := unsafe_New(d.keyType)
|
||||||
|
if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.skipWhiteSpace()
|
||||||
|
if !s.equalChar(':') {
|
||||||
|
return errors.ErrExpected("colon after object key", s.totalOffset())
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
v := unsafe_New(d.valueType)
|
||||||
|
if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.mapassign(d.mapType, mapValue, k, v)
|
||||||
|
s.skipWhiteSpace()
|
||||||
|
if s.equalChar('}') {
|
||||||
|
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !s.equalChar(',') {
|
||||||
|
return errors.ErrExpected("comma after object value", s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
buflen := int64(len(buf))
|
||||||
|
if buflen < 2 {
|
||||||
|
return 0, errors.ErrExpected("{} for map", cursor)
|
||||||
|
}
|
||||||
|
switch buf[cursor] {
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
|
||||||
|
return cursor, nil
|
||||||
|
case '{':
|
||||||
|
default:
|
||||||
|
return 0, errors.ErrExpected("{ character for map value", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
mapValue := *(*unsafe.Pointer)(p)
|
||||||
|
if mapValue == nil {
|
||||||
|
mapValue = makemap(d.mapType, 0)
|
||||||
|
}
|
||||||
|
if buf[cursor] == '}' {
|
||||||
|
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
|
||||||
|
cursor++
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
k := unsafe_New(d.keyType)
|
||||||
|
keyCursor, err := d.keyDecoder.Decode(ctx, cursor, depth, k)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(buf, keyCursor)
|
||||||
|
if buf[cursor] != ':' {
|
||||||
|
return 0, errors.ErrExpected("colon after object key", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
v := unsafe_New(d.valueType)
|
||||||
|
valueCursor, err := d.valueDecoder.Decode(ctx, cursor, depth, v)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
d.mapassign(d.mapType, mapValue, k, v)
|
||||||
|
cursor = skipWhiteSpace(buf, valueCursor)
|
||||||
|
if buf[cursor] == '}' {
|
||||||
|
**(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
|
||||||
|
cursor++
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
if buf[cursor] != ',' {
|
||||||
|
return 0, errors.ErrExpected("comma after object value", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
112
vendor/github.com/goccy/go-json/internal/decoder/number.go
generated
vendored
Normal file
112
vendor/github.com/goccy/go-json/internal/decoder/number.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type numberDecoder struct {
|
||||||
|
stringDecoder *stringDecoder
|
||||||
|
op func(unsafe.Pointer, json.Number)
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, json.Number)) *numberDecoder {
|
||||||
|
return &numberDecoder{
|
||||||
|
stringDecoder: newStringDecoder(structName, fieldName),
|
||||||
|
op: op,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *numberDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
bytes, err := d.decodeStreamByte(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil {
|
||||||
|
return errors.ErrSyntax(err.Error(), s.totalOffset())
|
||||||
|
}
|
||||||
|
d.op(p, json.Number(string(bytes)))
|
||||||
|
s.reset()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *numberDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
bytes, c, err := d.decodeByte(ctx.Buf, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil {
|
||||||
|
return 0, errors.ErrSyntax(err.Error(), c)
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
s := *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
d.op(p, json.Number(s))
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
|
||||||
|
start := s.cursor
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return floatBytes(s), nil
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
case '"':
|
||||||
|
return d.stringDecoder.decodeStreamByte(s)
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
default:
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
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) {
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
start := cursor
|
||||||
|
cursor++
|
||||||
|
for floatTable[buf[cursor]] {
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
num := buf[start:cursor]
|
||||||
|
return num, cursor, nil
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return nil, cursor, nil
|
||||||
|
case '"':
|
||||||
|
return d.stringDecoder.decodeByte(buf, cursor)
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("json.Number", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
vendor/github.com/goccy/go-json/internal/decoder/option.go
generated
vendored
Normal file
15
vendor/github.com/goccy/go-json/internal/decoder/option.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type OptionFlags uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
FirstWinOption OptionFlags = 1 << iota
|
||||||
|
ContextOption
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option struct {
|
||||||
|
Flags OptionFlags
|
||||||
|
Context context.Context
|
||||||
|
}
|
87
vendor/github.com/goccy/go-json/internal/decoder/ptr.go
generated
vendored
Normal file
87
vendor/github.com/goccy/go-json/internal/decoder/ptr.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ptrDecoder struct {
|
||||||
|
dec Decoder
|
||||||
|
typ *runtime.Type
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPtrDecoder(dec Decoder, typ *runtime.Type, structName, fieldName string) *ptrDecoder {
|
||||||
|
return &ptrDecoder{
|
||||||
|
dec: dec,
|
||||||
|
typ: typ,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ptrDecoder) contentDecoder() Decoder {
|
||||||
|
dec, ok := d.dec.(*ptrDecoder)
|
||||||
|
if !ok {
|
||||||
|
return d.dec
|
||||||
|
}
|
||||||
|
return dec.contentDecoder()
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:golint
|
||||||
|
//go:linkname unsafe_New reflect.unsafe_New
|
||||||
|
func unsafe_New(*runtime.Type) unsafe.Pointer
|
||||||
|
|
||||||
|
func (d *ptrDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
if s.skipWhiteSpace() == nul {
|
||||||
|
s.read()
|
||||||
|
}
|
||||||
|
if s.char() == 'n' {
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var newptr unsafe.Pointer
|
||||||
|
if *(*unsafe.Pointer)(p) == nil {
|
||||||
|
newptr = unsafe_New(d.typ)
|
||||||
|
*(*unsafe.Pointer)(p) = newptr
|
||||||
|
} else {
|
||||||
|
newptr = *(*unsafe.Pointer)(p)
|
||||||
|
}
|
||||||
|
if err := d.dec.DecodeStream(s, depth, newptr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ptrDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
buf := ctx.Buf
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
if buf[cursor] == 'n' {
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if p != nil {
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
var newptr unsafe.Pointer
|
||||||
|
if *(*unsafe.Pointer)(p) == nil {
|
||||||
|
newptr = unsafe_New(d.typ)
|
||||||
|
*(*unsafe.Pointer)(p) = newptr
|
||||||
|
} else {
|
||||||
|
newptr = *(*unsafe.Pointer)(p)
|
||||||
|
}
|
||||||
|
c, err := d.dec.Decode(ctx, cursor, depth, newptr)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
return cursor, nil
|
||||||
|
}
|
301
vendor/github.com/goccy/go-json/internal/decoder/slice.go
generated
vendored
Normal file
301
vendor/github.com/goccy/go-json/internal/decoder/slice.go
generated
vendored
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
"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 {
|
||||||
|
elemType *runtime.Type
|
||||||
|
isElemPointerType bool
|
||||||
|
valueDecoder Decoder
|
||||||
|
size uintptr
|
||||||
|
arrayPool sync.Pool
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// If use reflect.SliceHeader, data type is uintptr.
|
||||||
|
// In this case, Go compiler cannot trace reference created by newArray().
|
||||||
|
// So, define using unsafe.Pointer as data type
|
||||||
|
type sliceHeader struct {
|
||||||
|
data unsafe.Pointer
|
||||||
|
len int
|
||||||
|
cap int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultSliceCapacity = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
func newSliceDecoder(dec Decoder, elemType *runtime.Type, size uintptr, structName, fieldName string) *sliceDecoder {
|
||||||
|
return &sliceDecoder{
|
||||||
|
valueDecoder: dec,
|
||||||
|
elemType: elemType,
|
||||||
|
isElemPointerType: elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Map,
|
||||||
|
size: size,
|
||||||
|
arrayPool: sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &sliceHeader{
|
||||||
|
data: newArray(elemType, defaultSliceCapacity),
|
||||||
|
len: 0,
|
||||||
|
cap: defaultSliceCapacity,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *sliceDecoder) newSlice(src *sliceHeader) *sliceHeader {
|
||||||
|
slice := d.arrayPool.Get().(*sliceHeader)
|
||||||
|
if src.len > 0 {
|
||||||
|
// copy original elem
|
||||||
|
if slice.cap < src.cap {
|
||||||
|
data := newArray(d.elemType, src.cap)
|
||||||
|
slice = &sliceHeader{data: data, len: src.len, cap: src.cap}
|
||||||
|
} else {
|
||||||
|
slice.len = src.len
|
||||||
|
}
|
||||||
|
copySlice(d.elemType, *slice, *src)
|
||||||
|
} else {
|
||||||
|
slice.len = 0
|
||||||
|
}
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *sliceDecoder) releaseSlice(p *sliceHeader) {
|
||||||
|
d.arrayPool.Put(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname copySlice reflect.typedslicecopy
|
||||||
|
func copySlice(elemType *runtime.Type, dst, src sliceHeader) int
|
||||||
|
|
||||||
|
//go:linkname newArray reflect.unsafe_NewArray
|
||||||
|
func newArray(*runtime.Type, int) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname typedmemmove reflect.typedmemmove
|
||||||
|
func typedmemmove(t *runtime.Type, dst, src unsafe.Pointer)
|
||||||
|
|
||||||
|
func (d *sliceDecoder) errNumber(offset int64) *errors.UnmarshalTypeError {
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: "number",
|
||||||
|
Type: reflect.SliceOf(runtime.RType2Type(d.elemType)),
|
||||||
|
Struct: d.structName,
|
||||||
|
Field: d.fieldName,
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *sliceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
typedmemmove(sliceType, p, nilSlice)
|
||||||
|
return nil
|
||||||
|
case '[':
|
||||||
|
s.cursor++
|
||||||
|
if s.skipWhiteSpace() == ']' {
|
||||||
|
dst := (*sliceHeader)(p)
|
||||||
|
if dst.data == nil {
|
||||||
|
dst.data = newArray(d.elemType, 0)
|
||||||
|
} else {
|
||||||
|
dst.len = 0
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
idx := 0
|
||||||
|
slice := d.newSlice((*sliceHeader)(p))
|
||||||
|
srcLen := slice.len
|
||||||
|
capacity := slice.cap
|
||||||
|
data := slice.data
|
||||||
|
for {
|
||||||
|
if capacity <= idx {
|
||||||
|
src := sliceHeader{data: data, len: idx, cap: capacity}
|
||||||
|
capacity *= 2
|
||||||
|
data = newArray(d.elemType, capacity)
|
||||||
|
dst := sliceHeader{data: data, len: idx, cap: capacity}
|
||||||
|
copySlice(d.elemType, dst, src)
|
||||||
|
}
|
||||||
|
ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size)
|
||||||
|
|
||||||
|
// if srcLen is greater than idx, keep the original reference
|
||||||
|
if srcLen <= idx {
|
||||||
|
if d.isElemPointerType {
|
||||||
|
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer
|
||||||
|
} else {
|
||||||
|
// assign new element to the slice
|
||||||
|
typedmemmove(d.elemType, ep, unsafe_New(d.elemType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.valueDecoder.DecodeStream(s, depth, ep); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.skipWhiteSpace()
|
||||||
|
RETRY:
|
||||||
|
switch s.char() {
|
||||||
|
case ']':
|
||||||
|
slice.cap = capacity
|
||||||
|
slice.len = idx + 1
|
||||||
|
slice.data = data
|
||||||
|
dst := (*sliceHeader)(p)
|
||||||
|
dst.len = idx + 1
|
||||||
|
if dst.len > dst.cap {
|
||||||
|
dst.data = newArray(d.elemType, dst.len)
|
||||||
|
dst.cap = dst.len
|
||||||
|
}
|
||||||
|
copySlice(d.elemType, *dst, *slice)
|
||||||
|
d.releaseSlice(slice)
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
case ',':
|
||||||
|
idx++
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
goto RETRY
|
||||||
|
}
|
||||||
|
slice.cap = capacity
|
||||||
|
slice.data = data
|
||||||
|
d.releaseSlice(slice)
|
||||||
|
goto ERROR
|
||||||
|
default:
|
||||||
|
slice.cap = capacity
|
||||||
|
slice.data = data
|
||||||
|
d.releaseSlice(slice)
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
}
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return d.errNumber(s.totalOffset())
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
default:
|
||||||
|
goto ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("slice", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *sliceDecoder) 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
typedmemmove(sliceType, p, nilSlice)
|
||||||
|
return cursor, nil
|
||||||
|
case '[':
|
||||||
|
cursor++
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
if buf[cursor] == ']' {
|
||||||
|
dst := (*sliceHeader)(p)
|
||||||
|
if dst.data == nil {
|
||||||
|
dst.data = newArray(d.elemType, 0)
|
||||||
|
} else {
|
||||||
|
dst.len = 0
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
idx := 0
|
||||||
|
slice := d.newSlice((*sliceHeader)(p))
|
||||||
|
srcLen := slice.len
|
||||||
|
capacity := slice.cap
|
||||||
|
data := slice.data
|
||||||
|
for {
|
||||||
|
if capacity <= idx {
|
||||||
|
src := sliceHeader{data: data, len: idx, cap: capacity}
|
||||||
|
capacity *= 2
|
||||||
|
data = newArray(d.elemType, capacity)
|
||||||
|
dst := sliceHeader{data: data, len: idx, cap: capacity}
|
||||||
|
copySlice(d.elemType, dst, src)
|
||||||
|
}
|
||||||
|
ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size)
|
||||||
|
// if srcLen is greater than idx, keep the original reference
|
||||||
|
if srcLen <= idx {
|
||||||
|
if d.isElemPointerType {
|
||||||
|
**(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer
|
||||||
|
} else {
|
||||||
|
// assign new element to the slice
|
||||||
|
typedmemmove(d.elemType, ep, unsafe_New(d.elemType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c, err := d.valueDecoder.Decode(ctx, cursor, depth, ep)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ']':
|
||||||
|
slice.cap = capacity
|
||||||
|
slice.len = idx + 1
|
||||||
|
slice.data = data
|
||||||
|
dst := (*sliceHeader)(p)
|
||||||
|
dst.len = idx + 1
|
||||||
|
if dst.len > dst.cap {
|
||||||
|
dst.data = newArray(d.elemType, dst.len)
|
||||||
|
dst.cap = dst.len
|
||||||
|
}
|
||||||
|
copySlice(d.elemType, *dst, *slice)
|
||||||
|
d.releaseSlice(slice)
|
||||||
|
cursor++
|
||||||
|
return cursor, nil
|
||||||
|
case ',':
|
||||||
|
idx++
|
||||||
|
default:
|
||||||
|
slice.cap = capacity
|
||||||
|
slice.data = data
|
||||||
|
d.releaseSlice(slice)
|
||||||
|
return 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return 0, d.errNumber(cursor)
|
||||||
|
default:
|
||||||
|
return 0, errors.ErrUnexpectedEndOfJSON("slice", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
554
vendor/github.com/goccy/go-json/internal/decoder/stream.go
generated
vendored
Normal file
554
vendor/github.com/goccy/go-json/internal/decoder/stream.go
generated
vendored
Normal file
@ -0,0 +1,554 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
initBufSize = 512
|
||||||
|
)
|
||||||
|
|
||||||
|
type Stream struct {
|
||||||
|
buf []byte
|
||||||
|
bufSize int64
|
||||||
|
length int64
|
||||||
|
r io.Reader
|
||||||
|
offset int64
|
||||||
|
cursor int64
|
||||||
|
filledBuffer bool
|
||||||
|
allRead bool
|
||||||
|
UseNumber bool
|
||||||
|
DisallowUnknownFields bool
|
||||||
|
Option *Option
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStream(r io.Reader) *Stream {
|
||||||
|
return &Stream{
|
||||||
|
r: r,
|
||||||
|
bufSize: initBufSize,
|
||||||
|
buf: make([]byte, initBufSize),
|
||||||
|
Option: &Option{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) TotalOffset() int64 {
|
||||||
|
return s.totalOffset()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) Buffered() io.Reader {
|
||||||
|
buflen := int64(len(s.buf))
|
||||||
|
for i := s.cursor; i < buflen; i++ {
|
||||||
|
if s.buf[i] == nul {
|
||||||
|
return bytes.NewReader(s.buf[s.cursor:i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes.NewReader(s.buf[s.cursor:])
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) char() byte {
|
||||||
|
return s.buf[s.cursor]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) equalChar(c byte) bool {
|
||||||
|
cur := s.buf[s.cursor]
|
||||||
|
if cur == nul {
|
||||||
|
s.read()
|
||||||
|
cur = s.buf[s.cursor]
|
||||||
|
}
|
||||||
|
return cur == c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) stat() ([]byte, int64, unsafe.Pointer) {
|
||||||
|
return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
|
||||||
|
}
|
||||||
|
|
||||||
|
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 )
|
||||||
|
return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data
|
||||||
|
}
|
||||||
|
|
||||||
|
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.buf = s.buf[s.cursor:]
|
||||||
|
s.length -= s.cursor
|
||||||
|
s.cursor = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) readBuf() []byte {
|
||||||
|
if s.filledBuffer {
|
||||||
|
s.bufSize *= 2
|
||||||
|
remainBuf := s.buf
|
||||||
|
s.buf = make([]byte, s.bufSize)
|
||||||
|
copy(s.buf, remainBuf)
|
||||||
|
}
|
||||||
|
remainLen := s.length - s.cursor
|
||||||
|
remainNotNulCharNum := int64(0)
|
||||||
|
for i := int64(0); i < remainLen; i++ {
|
||||||
|
if s.buf[s.cursor+i] == nul {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
remainNotNulCharNum++
|
||||||
|
}
|
||||||
|
s.length = s.cursor + remainNotNulCharNum
|
||||||
|
return s.buf[s.cursor+remainNotNulCharNum:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) read() bool {
|
||||||
|
if s.allRead {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
buf := s.readBuf()
|
||||||
|
last := len(buf) - 1
|
||||||
|
buf[last] = nul
|
||||||
|
n, err := s.r.Read(buf[:last])
|
||||||
|
s.length += int64(n)
|
||||||
|
if n == last {
|
||||||
|
s.filledBuffer = true
|
||||||
|
} else {
|
||||||
|
s.filledBuffer = false
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
s.allRead = true
|
||||||
|
} else if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) skipWhiteSpace() byte {
|
||||||
|
p := s.bufptr()
|
||||||
|
LOOP:
|
||||||
|
c := char(p, s.cursor)
|
||||||
|
switch c {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
s.cursor++
|
||||||
|
goto LOOP
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
p = s.bufptr()
|
||||||
|
goto LOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) skipObject(depth int64) error {
|
||||||
|
braceCount := 1
|
||||||
|
_, cursor, p := s.stat()
|
||||||
|
for {
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '{':
|
||||||
|
braceCount++
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
case '}':
|
||||||
|
braceCount--
|
||||||
|
depth--
|
||||||
|
if braceCount == 0 {
|
||||||
|
s.cursor = cursor + 1
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case '[':
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
case ']':
|
||||||
|
depth--
|
||||||
|
case '"':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if char(p, cursor) == nul {
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.statForRetry()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
goto SWITCH_OUT
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.statForRetry()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("object of object", cursor)
|
||||||
|
}
|
||||||
|
SWITCH_OUT:
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) skipArray(depth int64) error {
|
||||||
|
bracketCount := 1
|
||||||
|
_, cursor, p := s.stat()
|
||||||
|
for {
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '[':
|
||||||
|
bracketCount++
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
case ']':
|
||||||
|
bracketCount--
|
||||||
|
depth--
|
||||||
|
if bracketCount == 0 {
|
||||||
|
s.cursor = cursor + 1
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case '{':
|
||||||
|
depth++
|
||||||
|
if depth > maxDecodeNestingDepth {
|
||||||
|
return errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
case '}':
|
||||||
|
depth--
|
||||||
|
case '"':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if char(p, cursor) == nul {
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.statForRetry()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
goto SWITCH_OUT
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.statForRetry()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("string of object", cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("array of object", cursor)
|
||||||
|
}
|
||||||
|
SWITCH_OUT:
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) skipValue(depth int64) error {
|
||||||
|
_, cursor, p := s.stat()
|
||||||
|
for {
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("value of object", s.totalOffset())
|
||||||
|
case '{':
|
||||||
|
s.cursor = cursor + 1
|
||||||
|
return s.skipObject(depth + 1)
|
||||||
|
case '[':
|
||||||
|
s.cursor = cursor + 1
|
||||||
|
return s.skipArray(depth + 1)
|
||||||
|
case '"':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if char(p, cursor) == nul {
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.statForRetry()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
s.cursor = cursor + 1
|
||||||
|
return nil
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.statForRetry()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
c := char(p, cursor)
|
||||||
|
if floatTable[c] {
|
||||||
|
continue
|
||||||
|
} else if c == nul {
|
||||||
|
if s.read() {
|
||||||
|
s.cursor-- // for retry current character
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor = cursor
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case 't':
|
||||||
|
s.cursor = cursor
|
||||||
|
if err := trueBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case 'f':
|
||||||
|
s.cursor = cursor
|
||||||
|
if err := falseBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case 'n':
|
||||||
|
s.cursor = cursor
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nullBytes(s *Stream) error {
|
||||||
|
// current cursor's character is 'n'
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'u' {
|
||||||
|
if err := retryReadNull(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'l' {
|
||||||
|
if err := retryReadNull(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'l' {
|
||||||
|
if err := retryReadNull(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func retryReadNull(s *Stream) error {
|
||||||
|
if s.char() == nul && s.read() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func trueBytes(s *Stream) error {
|
||||||
|
// current cursor's character is 't'
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'r' {
|
||||||
|
if err := retryReadTrue(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'u' {
|
||||||
|
if err := retryReadTrue(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'e' {
|
||||||
|
if err := retryReadTrue(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func retryReadTrue(s *Stream) error {
|
||||||
|
if s.char() == nul && s.read() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func falseBytes(s *Stream) error {
|
||||||
|
// current cursor's character is 'f'
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'a' {
|
||||||
|
if err := retryReadFalse(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'l' {
|
||||||
|
if err := retryReadFalse(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 's' {
|
||||||
|
if err := retryReadFalse(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.char() != 'e' {
|
||||||
|
if err := retryReadFalse(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func retryReadFalse(s *Stream) error {
|
||||||
|
if s.char() == nul && s.read() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset())
|
||||||
|
}
|
371
vendor/github.com/goccy/go-json/internal/decoder/string.go
generated
vendored
Normal file
371
vendor/github.com/goccy/go-json/internal/decoder/string.go
generated
vendored
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unicode/utf8"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stringDecoder struct {
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStringDecoder(structName, fieldName string) *stringDecoder {
|
||||||
|
return &stringDecoder{
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *errors.UnmarshalTypeError {
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: typeName,
|
||||||
|
Type: reflect.TypeOf(""),
|
||||||
|
Offset: offset,
|
||||||
|
Struct: d.structName,
|
||||||
|
Field: d.fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *stringDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
bytes, err := d.decodeStreamByte(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
**(**string)(unsafe.Pointer(&p)) = *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
s.reset()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *stringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
bytes, c, err := d.decodeByte(ctx.Buf, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
**(**string)(unsafe.Pointer(&p)) = *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
hexToInt = [256]int{
|
||||||
|
'0': 0,
|
||||||
|
'1': 1,
|
||||||
|
'2': 2,
|
||||||
|
'3': 3,
|
||||||
|
'4': 4,
|
||||||
|
'5': 5,
|
||||||
|
'6': 6,
|
||||||
|
'7': 7,
|
||||||
|
'8': 8,
|
||||||
|
'9': 9,
|
||||||
|
'A': 10,
|
||||||
|
'B': 11,
|
||||||
|
'C': 12,
|
||||||
|
'D': 13,
|
||||||
|
'E': 14,
|
||||||
|
'F': 15,
|
||||||
|
'a': 10,
|
||||||
|
'b': 11,
|
||||||
|
'c': 12,
|
||||||
|
'd': 13,
|
||||||
|
'e': 14,
|
||||||
|
'f': 15,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func unicodeToRune(code []byte) rune {
|
||||||
|
var r rune
|
||||||
|
for i := 0; i < len(code); i++ {
|
||||||
|
r = r*16 + rune(hexToInt[code[i]])
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) {
|
||||||
|
const defaultOffset = 5
|
||||||
|
const surrogateOffset = 11
|
||||||
|
|
||||||
|
if s.cursor+defaultOffset >= s.length {
|
||||||
|
if !s.read() {
|
||||||
|
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])
|
||||||
|
if utf16.IsSurrogate(r) {
|
||||||
|
if s.cursor+surrogateOffset >= s.length {
|
||||||
|
s.read()
|
||||||
|
p = s.bufptr()
|
||||||
|
}
|
||||||
|
if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
|
||||||
|
return unicode.ReplacementChar, defaultOffset, p, nil
|
||||||
|
}
|
||||||
|
r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset])
|
||||||
|
if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar {
|
||||||
|
return r, surrogateOffset, p, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, defaultOffset, p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeUnicode(s *Stream, p unsafe.Pointer) (unsafe.Pointer, error) {
|
||||||
|
const backSlashAndULen = 2 // length of \u
|
||||||
|
|
||||||
|
r, offset, pp, err := decodeUnicodeRune(s, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
unicode := []byte(string(r))
|
||||||
|
unicodeLen := int64(len(unicode))
|
||||||
|
s.buf = append(append(s.buf[:s.cursor-1], unicode...), s.buf[s.cursor+offset:]...)
|
||||||
|
unicodeOrgLen := offset - 1
|
||||||
|
s.length = s.length - (backSlashAndULen + (unicodeOrgLen - unicodeLen))
|
||||||
|
s.cursor = s.cursor - backSlashAndULen + unicodeLen
|
||||||
|
return pp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeEscapeString(s *Stream, p unsafe.Pointer) (unsafe.Pointer, error) {
|
||||||
|
s.cursor++
|
||||||
|
RETRY:
|
||||||
|
switch s.buf[s.cursor] {
|
||||||
|
case '"':
|
||||||
|
s.buf[s.cursor] = '"'
|
||||||
|
case '\\':
|
||||||
|
s.buf[s.cursor] = '\\'
|
||||||
|
case '/':
|
||||||
|
s.buf[s.cursor] = '/'
|
||||||
|
case 'b':
|
||||||
|
s.buf[s.cursor] = '\b'
|
||||||
|
case 'f':
|
||||||
|
s.buf[s.cursor] = '\f'
|
||||||
|
case 'n':
|
||||||
|
s.buf[s.cursor] = '\n'
|
||||||
|
case 'r':
|
||||||
|
s.buf[s.cursor] = '\r'
|
||||||
|
case 't':
|
||||||
|
s.buf[s.cursor] = '\t'
|
||||||
|
case 'u':
|
||||||
|
return decodeUnicode(s, p)
|
||||||
|
case nul:
|
||||||
|
if !s.read() {
|
||||||
|
return nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
|
||||||
|
}
|
||||||
|
goto RETRY
|
||||||
|
default:
|
||||||
|
return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||||
|
}
|
||||||
|
s.buf = append(s.buf[:s.cursor-1], s.buf[s.cursor:]...)
|
||||||
|
s.length--
|
||||||
|
s.cursor--
|
||||||
|
p = s.bufptr()
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
runeErrBytes = []byte(string(utf8.RuneError))
|
||||||
|
runeErrBytesLen = int64(len(runeErrBytes))
|
||||||
|
)
|
||||||
|
|
||||||
|
func stringBytes(s *Stream) ([]byte, error) {
|
||||||
|
_, cursor, p := s.stat()
|
||||||
|
cursor++ // skip double quote char
|
||||||
|
start := cursor
|
||||||
|
for {
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '\\':
|
||||||
|
s.cursor = cursor
|
||||||
|
pp, err := decodeEscapeString(s, p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p = pp
|
||||||
|
cursor = s.cursor
|
||||||
|
case '"':
|
||||||
|
literal := s.buf[start:cursor]
|
||||||
|
cursor++
|
||||||
|
s.cursor = cursor
|
||||||
|
return literal, nil
|
||||||
|
case
|
||||||
|
// 0x00 is nul, 0x5c is '\\', 0x22 is '"' .
|
||||||
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0x00-0x0F
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 0x10-0x1F
|
||||||
|
0x20, 0x21 /*0x22,*/, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 0x20-0x2F
|
||||||
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 0x30-0x3F
|
||||||
|
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 0x40-0x4F
|
||||||
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B /*0x5C,*/, 0x5D, 0x5E, 0x5F, // 0x50-0x5F
|
||||||
|
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 0x60-0x6F
|
||||||
|
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F: // 0x70-0x7F
|
||||||
|
// character is ASCII. skip to next char
|
||||||
|
case
|
||||||
|
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 0x80-0x8F
|
||||||
|
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 0x90-0x9F
|
||||||
|
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // 0xA0-0xAF
|
||||||
|
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // 0xB0-0xBF
|
||||||
|
0xC0, 0xC1, // 0xC0-0xC1
|
||||||
|
0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF: // 0xF5-0xFE
|
||||||
|
// character is invalid
|
||||||
|
s.buf = append(append(append([]byte{}, s.buf[:cursor]...), runeErrBytes...), s.buf[cursor+1:]...)
|
||||||
|
_, _, p = s.stat()
|
||||||
|
cursor += runeErrBytesLen
|
||||||
|
s.length += runeErrBytesLen
|
||||||
|
continue
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
goto ERROR
|
||||||
|
case 0xEF:
|
||||||
|
// RuneError is {0xEF, 0xBF, 0xBD}
|
||||||
|
if s.buf[cursor+1] == 0xBF && s.buf[cursor+2] == 0xBD {
|
||||||
|
// found RuneError: skip
|
||||||
|
cursor += 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
// multi bytes character
|
||||||
|
if !utf8.FullRune(s.buf[cursor : len(s.buf)-1]) {
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, 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)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
ERROR:
|
||||||
|
return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *stringDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
case '[':
|
||||||
|
return nil, d.errUnmarshalType("array", s.totalOffset())
|
||||||
|
case '{':
|
||||||
|
return nil, d.errUnmarshalType("object", s.totalOffset())
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return nil, d.errUnmarshalType("number", s.totalOffset())
|
||||||
|
case '"':
|
||||||
|
return stringBytes(s)
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
case '[':
|
||||||
|
return nil, 0, d.errUnmarshalType("array", cursor)
|
||||||
|
case '{':
|
||||||
|
return nil, 0, d.errUnmarshalType("object", cursor)
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return nil, 0, d.errUnmarshalType("number", cursor)
|
||||||
|
case '"':
|
||||||
|
cursor++
|
||||||
|
start := cursor
|
||||||
|
b := (*sliceHeader)(unsafe.Pointer(&buf)).data
|
||||||
|
for {
|
||||||
|
switch char(b, cursor) {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
switch char(b, cursor) {
|
||||||
|
case '"':
|
||||||
|
buf[cursor] = '"'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case '\\':
|
||||||
|
buf[cursor] = '\\'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case '/':
|
||||||
|
buf[cursor] = '/'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case 'b':
|
||||||
|
buf[cursor] = '\b'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case 'f':
|
||||||
|
buf[cursor] = '\f'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case 'n':
|
||||||
|
buf[cursor] = '\n'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case 'r':
|
||||||
|
buf[cursor] = '\r'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case 't':
|
||||||
|
buf[cursor] = '\t'
|
||||||
|
buf = append(buf[:cursor-1], buf[cursor:]...)
|
||||||
|
case 'u':
|
||||||
|
buflen := int64(len(buf))
|
||||||
|
if cursor+5 >= buflen {
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
||||||
|
}
|
||||||
|
code := unicodeToRune(buf[cursor+1 : cursor+5])
|
||||||
|
unicode := []byte(string(code))
|
||||||
|
buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...)
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
case '"':
|
||||||
|
literal := buf[start:cursor]
|
||||||
|
cursor++
|
||||||
|
return literal, cursor, nil
|
||||||
|
case nul:
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("string", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return nil, cursor, nil
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
819
vendor/github.com/goccy/go-json/internal/decoder/struct.go
generated
vendored
Normal file
819
vendor/github.com/goccy/go-json/internal/decoder/struct.go
generated
vendored
Normal file
@ -0,0 +1,819 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"math/bits"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type structFieldSet struct {
|
||||||
|
dec Decoder
|
||||||
|
offset uintptr
|
||||||
|
isTaggedKey bool
|
||||||
|
fieldIdx int
|
||||||
|
key string
|
||||||
|
keyLen int64
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type structDecoder struct {
|
||||||
|
fieldMap map[string]*structFieldSet
|
||||||
|
fieldUniqueNameNum int
|
||||||
|
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() {
|
||||||
|
fieldUniqueNameMap := map[string]int{}
|
||||||
|
fieldIdx := -1
|
||||||
|
for k, v := range d.fieldMap {
|
||||||
|
lower := strings.ToLower(k)
|
||||||
|
idx, exists := fieldUniqueNameMap[lower]
|
||||||
|
if exists {
|
||||||
|
v.fieldIdx = idx
|
||||||
|
} else {
|
||||||
|
fieldIdx++
|
||||||
|
v.fieldIdx = fieldIdx
|
||||||
|
}
|
||||||
|
fieldUniqueNameMap[lower] = fieldIdx
|
||||||
|
}
|
||||||
|
d.fieldUniqueNameNum = len(fieldUniqueNameMap)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode from '\uXXXX'
|
||||||
|
func decodeKeyCharByUnicodeRune(buf []byte, cursor int64) ([]byte, int64) {
|
||||||
|
const defaultOffset = 4
|
||||||
|
const surrogateOffset = 6
|
||||||
|
|
||||||
|
r := unicodeToRune(buf[cursor : cursor+defaultOffset])
|
||||||
|
if utf16.IsSurrogate(r) {
|
||||||
|
cursor += defaultOffset
|
||||||
|
if cursor+surrogateOffset >= int64(len(buf)) || buf[cursor] != '\\' || buf[cursor+1] != 'u' {
|
||||||
|
return []byte(string(unicode.ReplacementChar)), cursor + defaultOffset - 1
|
||||||
|
}
|
||||||
|
cursor += 2
|
||||||
|
r2 := unicodeToRune(buf[cursor : cursor+defaultOffset])
|
||||||
|
if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar {
|
||||||
|
return []byte(string(r)), cursor + defaultOffset - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []byte(string(r)), cursor + defaultOffset - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeKeyCharByEscapedChar(buf []byte, cursor int64) ([]byte, int64) {
|
||||||
|
c := buf[cursor]
|
||||||
|
cursor++
|
||||||
|
switch c {
|
||||||
|
case '"':
|
||||||
|
return []byte{'"'}, cursor
|
||||||
|
case '\\':
|
||||||
|
return []byte{'\\'}, cursor
|
||||||
|
case '/':
|
||||||
|
return []byte{'/'}, cursor
|
||||||
|
case 'b':
|
||||||
|
return []byte{'\b'}, cursor
|
||||||
|
case 'f':
|
||||||
|
return []byte{'\f'}, cursor
|
||||||
|
case 'n':
|
||||||
|
return []byte{'\n'}, cursor
|
||||||
|
case 'r':
|
||||||
|
return []byte{'\r'}, cursor
|
||||||
|
case 't':
|
||||||
|
return []byte{'\t'}, cursor
|
||||||
|
case 'u':
|
||||||
|
return decodeKeyCharByUnicodeRune(buf, cursor)
|
||||||
|
}
|
||||||
|
return nil, cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) {
|
||||||
|
var (
|
||||||
|
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, nil, nil
|
||||||
|
case nul:
|
||||||
|
return 0, nil, errors.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, errors.ErrUnexpectedEndOfJSON("string", cursor)
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor)
|
||||||
|
for _, c := range chars {
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
return decodeKeyNotFound(b, cursor)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
cursor = nextCursor
|
||||||
|
default:
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
return decodeKeyNotFound(b, cursor)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return cursor, nil, errors.ErrInvalidBeginningOfValue(char(b, cursor), cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) {
|
||||||
|
var (
|
||||||
|
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, nil, nil
|
||||||
|
case nul:
|
||||||
|
return 0, nil, errors.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, errors.ErrUnexpectedEndOfJSON("string", cursor)
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor)
|
||||||
|
for _, c := range chars {
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
return decodeKeyNotFound(b, cursor)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
cursor = nextCursor
|
||||||
|
default:
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
return decodeKeyNotFound(b, cursor)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return cursor, nil, errors.ErrInvalidBeginningOfValue(char(b, cursor), cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeKeyNotFound(b unsafe.Pointer, cursor int64) (int64, *structFieldSet, error) {
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch char(b, cursor) {
|
||||||
|
case '"':
|
||||||
|
cursor++
|
||||||
|
return cursor, nil, nil
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if char(b, cursor) == nul {
|
||||||
|
return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor)
|
||||||
|
}
|
||||||
|
case nul:
|
||||||
|
return 0, nil, errors.ErrUnexpectedEndOfJSON("string", 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 (
|
||||||
|
curBit uint8 = math.MaxUint8
|
||||||
|
)
|
||||||
|
_, cursor, p := s.stat()
|
||||||
|
for {
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset())
|
||||||
|
case '"':
|
||||||
|
cursor++
|
||||||
|
FIRST_CHAR:
|
||||||
|
start := cursor
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '"':
|
||||||
|
cursor++
|
||||||
|
s.cursor = cursor
|
||||||
|
return nil, "", nil
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
goto FIRST_CHAR
|
||||||
|
}
|
||||||
|
return nil, "", errors.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() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||||
|
case '\\':
|
||||||
|
s.cursor = cursor + 1 // skip '\' char
|
||||||
|
chars, err := decodeKeyCharByEscapeCharStream(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
cursor = s.cursor
|
||||||
|
for _, c := range chars {
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
s.cursor = cursor
|
||||||
|
return decodeKeyNotFoundStream(s, start)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
s.cursor = cursor
|
||||||
|
return decodeKeyNotFoundStream(s, start)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeKeyByBitmapUint16Stream(d *structDecoder, s *Stream) (*structFieldSet, string, error) {
|
||||||
|
var (
|
||||||
|
curBit uint16 = math.MaxUint16
|
||||||
|
)
|
||||||
|
_, cursor, p := s.stat()
|
||||||
|
for {
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset())
|
||||||
|
case '"':
|
||||||
|
cursor++
|
||||||
|
FIRST_CHAR:
|
||||||
|
start := cursor
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '"':
|
||||||
|
cursor++
|
||||||
|
s.cursor = cursor
|
||||||
|
return nil, "", nil
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if s.read() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
goto FIRST_CHAR
|
||||||
|
}
|
||||||
|
return nil, "", errors.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() {
|
||||||
|
_, cursor, p = s.stat()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||||
|
case '\\':
|
||||||
|
s.cursor = cursor + 1 // skip '\' char
|
||||||
|
chars, err := decodeKeyCharByEscapeCharStream(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
cursor = s.cursor
|
||||||
|
for _, c := range chars {
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
s.cursor = cursor
|
||||||
|
return decodeKeyNotFoundStream(s, start)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
|
||||||
|
if curBit == 0 {
|
||||||
|
s.cursor = cursor
|
||||||
|
return decodeKeyNotFoundStream(s, start)
|
||||||
|
}
|
||||||
|
keyIdx++
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode from '\uXXXX'
|
||||||
|
func decodeKeyCharByUnicodeRuneStream(s *Stream) ([]byte, error) {
|
||||||
|
const defaultOffset = 4
|
||||||
|
const surrogateOffset = 6
|
||||||
|
|
||||||
|
if s.cursor+defaultOffset >= s.length {
|
||||||
|
if !s.read() {
|
||||||
|
return nil, errors.ErrInvalidCharacter(s.char(), "escaped unicode char", s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r := unicodeToRune(s.buf[s.cursor : s.cursor+defaultOffset])
|
||||||
|
if utf16.IsSurrogate(r) {
|
||||||
|
s.cursor += defaultOffset
|
||||||
|
if s.cursor+surrogateOffset >= s.length {
|
||||||
|
s.read()
|
||||||
|
}
|
||||||
|
if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor] != '\\' || s.buf[s.cursor+1] != 'u' {
|
||||||
|
s.cursor += defaultOffset - 1
|
||||||
|
return []byte(string(unicode.ReplacementChar)), nil
|
||||||
|
}
|
||||||
|
r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset])
|
||||||
|
if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar {
|
||||||
|
s.cursor += defaultOffset - 1
|
||||||
|
return []byte(string(r)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor += defaultOffset - 1
|
||||||
|
return []byte(string(r)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeKeyCharByEscapeCharStream(s *Stream) ([]byte, error) {
|
||||||
|
c := s.buf[s.cursor]
|
||||||
|
s.cursor++
|
||||||
|
RETRY:
|
||||||
|
switch c {
|
||||||
|
case '"':
|
||||||
|
return []byte{'"'}, nil
|
||||||
|
case '\\':
|
||||||
|
return []byte{'\\'}, nil
|
||||||
|
case '/':
|
||||||
|
return []byte{'/'}, nil
|
||||||
|
case 'b':
|
||||||
|
return []byte{'\b'}, nil
|
||||||
|
case 'f':
|
||||||
|
return []byte{'\f'}, nil
|
||||||
|
case 'n':
|
||||||
|
return []byte{'\n'}, nil
|
||||||
|
case 'r':
|
||||||
|
return []byte{'\r'}, nil
|
||||||
|
case 't':
|
||||||
|
return []byte{'\t'}, nil
|
||||||
|
case 'u':
|
||||||
|
return decodeKeyCharByUnicodeRuneStream(s)
|
||||||
|
case nul:
|
||||||
|
if !s.read() {
|
||||||
|
return nil, errors.ErrInvalidCharacter(s.char(), "escaped char", s.totalOffset())
|
||||||
|
}
|
||||||
|
goto RETRY
|
||||||
|
default:
|
||||||
|
return nil, errors.ErrUnexpectedEndOfJSON("struct field", s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeKeyNotFoundStream(s *Stream, start int64) (*structFieldSet, string, error) {
|
||||||
|
buf, cursor, p := s.stat()
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
switch char(p, cursor) {
|
||||||
|
case '"':
|
||||||
|
b := buf[start:cursor]
|
||||||
|
key := *(*string)(unsafe.Pointer(&b))
|
||||||
|
cursor++
|
||||||
|
s.cursor = cursor
|
||||||
|
return nil, key, nil
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if char(p, cursor) == nul {
|
||||||
|
s.cursor = cursor
|
||||||
|
if !s.read() {
|
||||||
|
return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||||
|
}
|
||||||
|
buf, cursor, p = s.statForRetry()
|
||||||
|
}
|
||||||
|
case nul:
|
||||||
|
s.cursor = cursor
|
||||||
|
if !s.read() {
|
||||||
|
return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset())
|
||||||
|
}
|
||||||
|
buf, cursor, p = s.statForRetry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 errors.ErrExceededMaxDepth(s.char(), s.cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := s.skipWhiteSpace()
|
||||||
|
switch c {
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
if s.char() != '{' {
|
||||||
|
return errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if s.skipWhiteSpace() == '}' {
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
seenFields map[int]struct{}
|
||||||
|
seenFieldNum int
|
||||||
|
)
|
||||||
|
firstWin := (s.Option.Flags & FirstWinOption) != 0
|
||||||
|
if firstWin {
|
||||||
|
seenFields = make(map[int]struct{}, d.fieldUniqueNameNum)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
s.reset()
|
||||||
|
field, key, err := d.keyStreamDecoder(d, s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if s.skipWhiteSpace() != ':' {
|
||||||
|
return errors.ErrExpected("colon after object key", s.totalOffset())
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
if field != nil {
|
||||||
|
if field.err != nil {
|
||||||
|
return field.err
|
||||||
|
}
|
||||||
|
if firstWin {
|
||||||
|
if _, exists := seenFields[field.fieldIdx]; exists {
|
||||||
|
if err := s.skipValue(depth); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
seenFieldNum++
|
||||||
|
if d.fieldUniqueNameNum <= seenFieldNum {
|
||||||
|
return s.skipObject(depth)
|
||||||
|
}
|
||||||
|
seenFields[field.fieldIdx] = struct{}{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c := s.skipWhiteSpace()
|
||||||
|
if c == '}' {
|
||||||
|
s.cursor++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if c != ',' {
|
||||||
|
return errors.ErrExpected("comma after object element", s.totalOffset())
|
||||||
|
}
|
||||||
|
s.cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *structDecoder) 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)
|
||||||
|
}
|
||||||
|
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, errors.ErrInvalidBeginningOfValue(char(b, cursor), cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
cursor = skipWhiteSpace(buf, cursor)
|
||||||
|
if buf[cursor] == '}' {
|
||||||
|
cursor++
|
||||||
|
return cursor, nil
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
seenFields map[int]struct{}
|
||||||
|
seenFieldNum int
|
||||||
|
)
|
||||||
|
firstWin := (ctx.Option.Flags & FirstWinOption) != 0
|
||||||
|
if firstWin {
|
||||||
|
seenFields = make(map[int]struct{}, d.fieldUniqueNameNum)
|
||||||
|
}
|
||||||
|
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, errors.ErrExpected("colon after object key", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
if cursor >= buflen {
|
||||||
|
return 0, errors.ErrExpected("object value after colon", cursor)
|
||||||
|
}
|
||||||
|
if field != nil {
|
||||||
|
if field.err != nil {
|
||||||
|
return 0, field.err
|
||||||
|
}
|
||||||
|
if firstWin {
|
||||||
|
if _, exists := seenFields[field.fieldIdx]; exists {
|
||||||
|
c, err := skipValue(buf, cursor, depth)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
} else {
|
||||||
|
c, err := field.dec.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+field.offset))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
seenFieldNum++
|
||||||
|
if d.fieldUniqueNameNum <= seenFieldNum {
|
||||||
|
return skipObject(buf, cursor, depth)
|
||||||
|
}
|
||||||
|
seenFields[field.fieldIdx] = struct{}{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c, err := field.dec.Decode(ctx, 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, errors.ErrExpected("comma after object element", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
29
vendor/github.com/goccy/go-json/internal/decoder/type.go
generated
vendored
Normal file
29
vendor/github.com/goccy/go-json/internal/decoder/type.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding"
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Decoder interface {
|
||||||
|
Decode(*RuntimeContext, int64, int64, unsafe.Pointer) (int64, error)
|
||||||
|
DecodeStream(*Stream, int64, unsafe.Pointer) error
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
nul = '\000'
|
||||||
|
maxDecodeNestingDepth = 10000
|
||||||
|
)
|
||||||
|
|
||||||
|
type unmarshalerContext interface {
|
||||||
|
UnmarshalJSON(context.Context, []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
unmarshalJSONType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
||||||
|
unmarshalJSONContextType = reflect.TypeOf((*unmarshalerContext)(nil)).Elem()
|
||||||
|
unmarshalTextType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||||
|
)
|
190
vendor/github.com/goccy/go-json/internal/decoder/uint.go
generated
vendored
Normal file
190
vendor/github.com/goccy/go-json/internal/decoder/uint.go
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type uintDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
kind reflect.Kind
|
||||||
|
op func(unsafe.Pointer, uint64)
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUintDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, uint64)) *uintDecoder {
|
||||||
|
return &uintDecoder{
|
||||||
|
typ: typ,
|
||||||
|
kind: typ.Kind(),
|
||||||
|
op: op,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *uintDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError {
|
||||||
|
return &errors.UnmarshalTypeError{
|
||||||
|
Value: fmt.Sprintf("number %s", string(buf)),
|
||||||
|
Type: runtime.RType2Type(d.typ),
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pow10u64 = [...]uint64{
|
||||||
|
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
|
||||||
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||||
|
}
|
||||||
|
pow10u64Len = len(pow10u64)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *uintDecoder) parseUint(b []byte) (uint64, error) {
|
||||||
|
maxDigit := len(b)
|
||||||
|
if maxDigit > pow10u64Len {
|
||||||
|
return 0, fmt.Errorf("invalid length of number")
|
||||||
|
}
|
||||||
|
sum := uint64(0)
|
||||||
|
for i := 0; i < maxDigit; i++ {
|
||||||
|
c := uint64(b[i]) - 48
|
||||||
|
digitValue := pow10u64[maxDigit-i-1]
|
||||||
|
sum += c * digitValue
|
||||||
|
}
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *uintDecoder) decodeStreamByte(s *Stream) ([]byte, error) {
|
||||||
|
for {
|
||||||
|
switch s.char() {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
s.cursor++
|
||||||
|
continue
|
||||||
|
case '0':
|
||||||
|
s.cursor++
|
||||||
|
return numZeroBuf, nil
|
||||||
|
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
start := s.cursor
|
||||||
|
for {
|
||||||
|
s.cursor++
|
||||||
|
if numTable[s.char()] {
|
||||||
|
continue
|
||||||
|
} else if s.char() == nul {
|
||||||
|
if s.read() {
|
||||||
|
s.cursor-- // for retry current character
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
num := s.buf[start:s.cursor]
|
||||||
|
return num, nil
|
||||||
|
case 'n':
|
||||||
|
if err := nullBytes(s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
case nul:
|
||||||
|
if s.read() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, d.typeError([]byte{s.char()}, s.totalOffset())
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, errors.ErrUnexpectedEndOfJSON("number(unsigned integer)", s.totalOffset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *uintDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
for {
|
||||||
|
switch buf[cursor] {
|
||||||
|
case ' ', '\n', '\t', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case '0':
|
||||||
|
cursor++
|
||||||
|
return numZeroBuf, cursor, nil
|
||||||
|
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
start := cursor
|
||||||
|
cursor++
|
||||||
|
for numTable[buf[cursor]] {
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
num := buf[start:cursor]
|
||||||
|
return num, cursor, nil
|
||||||
|
case 'n':
|
||||||
|
if err := validateNull(buf, cursor); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor += 4
|
||||||
|
return nil, cursor, nil
|
||||||
|
default:
|
||||||
|
return nil, 0, d.typeError([]byte{buf[cursor]}, cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *uintDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
bytes, err := d.decodeStreamByte(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
u64, err := d.parseUint(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
switch d.kind {
|
||||||
|
case reflect.Uint8:
|
||||||
|
if (1 << 8) <= u64 {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
if (1 << 16) <= u64 {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
if (1 << 32) <= u64 {
|
||||||
|
return d.typeError(bytes, s.totalOffset())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.op(p, u64)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *uintDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
bytes, c, err := d.decodeByte(ctx.Buf, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
u64, err := d.parseUint(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
switch d.kind {
|
||||||
|
case reflect.Uint8:
|
||||||
|
if (1 << 8) <= u64 {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
if (1 << 16) <= u64 {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
if (1 << 32) <= u64 {
|
||||||
|
return 0, d.typeError(bytes, cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.op(p, u64)
|
||||||
|
return cursor, nil
|
||||||
|
}
|
91
vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go
generated
vendored
Normal file
91
vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type unmarshalJSONDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUnmarshalJSONDecoder(typ *runtime.Type, 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 *errors.UnmarshalTypeError:
|
||||||
|
e.Struct = d.structName
|
||||||
|
e.Field = d.fieldName
|
||||||
|
case *errors.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 (s.Option.Flags & ContextOption) != 0 {
|
||||||
|
if err := v.(unmarshalerContext).UnmarshalJSON(s.Option.Context, dst); err != nil {
|
||||||
|
d.annotateError(s.cursor, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil {
|
||||||
|
d.annotateError(s.cursor, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *unmarshalJSONDecoder) 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]
|
||||||
|
dst := make([]byte, len(src))
|
||||||
|
copy(dst, src)
|
||||||
|
|
||||||
|
v := *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: d.typ,
|
||||||
|
ptr: p,
|
||||||
|
}))
|
||||||
|
if (ctx.Option.Flags & ContextOption) != 0 {
|
||||||
|
if err := v.(unmarshalerContext).UnmarshalJSON(ctx.Option.Context, dst); err != nil {
|
||||||
|
d.annotateError(cursor, err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil {
|
||||||
|
d.annotateError(cursor, err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return end, nil
|
||||||
|
}
|
280
vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go
generated
vendored
Normal file
280
vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go
generated
vendored
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unicode/utf8"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type unmarshalTextDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUnmarshalTextDecoder(typ *runtime.Type, structName, fieldName string) *unmarshalTextDecoder {
|
||||||
|
return &unmarshalTextDecoder{
|
||||||
|
typ: typ,
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *unmarshalTextDecoder) annotateError(cursor int64, err error) {
|
||||||
|
switch e := err.(type) {
|
||||||
|
case *errors.UnmarshalTypeError:
|
||||||
|
e.Struct = d.structName
|
||||||
|
e.Field = d.fieldName
|
||||||
|
case *errors.SyntaxError:
|
||||||
|
e.Offset = cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nullbytes = []byte(`null`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *unmarshalTextDecoder) 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: "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 bytes.Equal(src, nullbytes) {
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst := make([]byte, len(src))
|
||||||
|
copy(dst, src)
|
||||||
|
|
||||||
|
if b, ok := unquoteBytes(dst); ok {
|
||||||
|
dst = b
|
||||||
|
}
|
||||||
|
v := *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: d.typ,
|
||||||
|
ptr: p,
|
||||||
|
}))
|
||||||
|
if err := v.(encoding.TextUnmarshaler).UnmarshalText(dst); err != nil {
|
||||||
|
d.annotateError(s.cursor, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *unmarshalTextDecoder) 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: "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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s, ok := unquoteBytes(src); ok {
|
||||||
|
src = s
|
||||||
|
}
|
||||||
|
v := *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: d.typ,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
||||||
|
}))
|
||||||
|
if err := v.(encoding.TextUnmarshaler).UnmarshalText(src); err != nil {
|
||||||
|
d.annotateError(cursor, err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return end, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unquoteBytes(s []byte) (t []byte, ok bool) {
|
||||||
|
length := len(s)
|
||||||
|
if length < 2 || s[0] != '"' || s[length-1] != '"' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s = s[1 : length-1]
|
||||||
|
length -= 2
|
||||||
|
|
||||||
|
// Check for unusual characters. If there are none,
|
||||||
|
// then no unquoting is needed, so return a slice of the
|
||||||
|
// original bytes.
|
||||||
|
r := 0
|
||||||
|
for r < length {
|
||||||
|
c := s[r]
|
||||||
|
if c == '\\' || c == '"' || c < ' ' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if c < utf8.RuneSelf {
|
||||||
|
r++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rr, size := utf8.DecodeRune(s[r:])
|
||||||
|
if rr == utf8.RuneError && size == 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
r += size
|
||||||
|
}
|
||||||
|
if r == length {
|
||||||
|
return s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, length+2*utf8.UTFMax)
|
||||||
|
w := copy(b, s[0:r])
|
||||||
|
for r < length {
|
||||||
|
// Out of room? Can only happen if s is full of
|
||||||
|
// malformed UTF-8 and we're replacing each
|
||||||
|
// byte with RuneError.
|
||||||
|
if w >= len(b)-2*utf8.UTFMax {
|
||||||
|
nb := make([]byte, (len(b)+utf8.UTFMax)*2)
|
||||||
|
copy(nb, b[0:w])
|
||||||
|
b = nb
|
||||||
|
}
|
||||||
|
switch c := s[r]; {
|
||||||
|
case c == '\\':
|
||||||
|
r++
|
||||||
|
if r >= length {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch s[r] {
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
case '"', '\\', '/', '\'':
|
||||||
|
b[w] = s[r]
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'b':
|
||||||
|
b[w] = '\b'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'f':
|
||||||
|
b[w] = '\f'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'n':
|
||||||
|
b[w] = '\n'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'r':
|
||||||
|
b[w] = '\r'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 't':
|
||||||
|
b[w] = '\t'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'u':
|
||||||
|
r--
|
||||||
|
rr := getu4(s[r:])
|
||||||
|
if rr < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r += 6
|
||||||
|
if utf16.IsSurrogate(rr) {
|
||||||
|
rr1 := getu4(s[r:])
|
||||||
|
if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
|
||||||
|
// A valid pair; consume.
|
||||||
|
r += 6
|
||||||
|
w += utf8.EncodeRune(b[w:], dec)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Invalid surrogate; fall back to replacement rune.
|
||||||
|
rr = unicode.ReplacementChar
|
||||||
|
}
|
||||||
|
w += utf8.EncodeRune(b[w:], rr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quote, control characters are invalid.
|
||||||
|
case c == '"', c < ' ':
|
||||||
|
return
|
||||||
|
|
||||||
|
// ASCII
|
||||||
|
case c < utf8.RuneSelf:
|
||||||
|
b[w] = c
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
|
||||||
|
// Coerce to well-formed UTF-8.
|
||||||
|
default:
|
||||||
|
rr, size := utf8.DecodeRune(s[r:])
|
||||||
|
r += size
|
||||||
|
w += utf8.EncodeRune(b[w:], rr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b[0:w], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getu4(s []byte) rune {
|
||||||
|
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
var r rune
|
||||||
|
for _, c := range s[2:6] {
|
||||||
|
switch {
|
||||||
|
case '0' <= c && c <= '9':
|
||||||
|
c = c - '0'
|
||||||
|
case 'a' <= c && c <= 'f':
|
||||||
|
c = c - 'a' + 10
|
||||||
|
case 'A' <= c && c <= 'F':
|
||||||
|
c = c - 'A' + 10
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
r = r*16 + rune(c)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
68
vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go
generated
vendored
Normal file
68
vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package decoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wrappedStringDecoder struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
dec Decoder
|
||||||
|
stringDecoder *stringDecoder
|
||||||
|
structName string
|
||||||
|
fieldName string
|
||||||
|
isPtrType bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWrappedStringDecoder(typ *runtime.Type, dec Decoder, structName, fieldName string) *wrappedStringDecoder {
|
||||||
|
return &wrappedStringDecoder{
|
||||||
|
typ: typ,
|
||||||
|
dec: dec,
|
||||||
|
stringDecoder: newStringDecoder(structName, fieldName),
|
||||||
|
structName: structName,
|
||||||
|
fieldName: fieldName,
|
||||||
|
isPtrType: typ.Kind() == reflect.Ptr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *wrappedStringDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
|
||||||
|
bytes, err := d.stringDecoder.decodeStreamByte(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
if d.isPtrType {
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
b := make([]byte, len(bytes)+1)
|
||||||
|
copy(b, bytes)
|
||||||
|
if _, err := d.dec.Decode(&RuntimeContext{Buf: b}, 0, depth, p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *wrappedStringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
|
||||||
|
bytes, c, err := d.stringDecoder.decodeByte(ctx.Buf, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if bytes == nil {
|
||||||
|
if d.isPtrType {
|
||||||
|
*(*unsafe.Pointer)(p) = nil
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
bytes = append(bytes, nul)
|
||||||
|
oldBuf := ctx.Buf
|
||||||
|
ctx.Buf = bytes
|
||||||
|
if _, err := d.dec.Decode(ctx, 0, depth, p); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
ctx.Buf = oldBuf
|
||||||
|
return c, nil
|
||||||
|
}
|
286
vendor/github.com/goccy/go-json/internal/encoder/compact.go
generated
vendored
Normal file
286
vendor/github.com/goccy/go-json/internal/encoder/compact.go
generated
vendored
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
isWhiteSpace = [256]bool{
|
||||||
|
' ': true,
|
||||||
|
'\n': true,
|
||||||
|
'\t': true,
|
||||||
|
'\r': true,
|
||||||
|
}
|
||||||
|
isHTMLEscapeChar = [256]bool{
|
||||||
|
'<': true,
|
||||||
|
'>': true,
|
||||||
|
'&': true,
|
||||||
|
}
|
||||||
|
nul = byte('\000')
|
||||||
|
)
|
||||||
|
|
||||||
|
func Compact(buf *bytes.Buffer, src []byte, escape bool) error {
|
||||||
|
if len(src) == 0 {
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("", 0)
|
||||||
|
}
|
||||||
|
buf.Grow(len(src))
|
||||||
|
dst := buf.Bytes()
|
||||||
|
|
||||||
|
ctx := TakeRuntimeContext()
|
||||||
|
ctxBuf := ctx.Buf[:0]
|
||||||
|
ctxBuf = append(append(ctxBuf, src...), nul)
|
||||||
|
ctx.Buf = ctxBuf
|
||||||
|
|
||||||
|
if err := compactAndWrite(buf, dst, ctxBuf, escape); err != nil {
|
||||||
|
ReleaseRuntimeContext(ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ReleaseRuntimeContext(ctx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactAndWrite(buf *bytes.Buffer, dst []byte, src []byte, escape bool) error {
|
||||||
|
dst, err := compact(dst, src, escape)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := buf.Write(dst); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compact(dst, src []byte, escape bool) ([]byte, error) {
|
||||||
|
buf, cursor, err := compactValue(dst, src, 0, escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateEndBuf(src, cursor); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEndBuf(src []byte, cursor int64) error {
|
||||||
|
for {
|
||||||
|
switch src[cursor] {
|
||||||
|
case ' ', '\t', '\n', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case nul:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.ErrSyntax(
|
||||||
|
fmt.Sprintf("invalid character '%c' after top-level value", src[cursor]),
|
||||||
|
cursor+1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipWhiteSpace(buf []byte, cursor int64) int64 {
|
||||||
|
LOOP:
|
||||||
|
if isWhiteSpace[buf[cursor]] {
|
||||||
|
cursor++
|
||||||
|
goto LOOP
|
||||||
|
}
|
||||||
|
return cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactValue(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) {
|
||||||
|
for {
|
||||||
|
switch src[cursor] {
|
||||||
|
case ' ', '\t', '\n', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case '{':
|
||||||
|
return compactObject(dst, src, cursor, escape)
|
||||||
|
case '}':
|
||||||
|
return nil, 0, errors.ErrSyntax("unexpected character '}'", cursor)
|
||||||
|
case '[':
|
||||||
|
return compactArray(dst, src, cursor, escape)
|
||||||
|
case ']':
|
||||||
|
return nil, 0, errors.ErrSyntax("unexpected character ']'", cursor)
|
||||||
|
case '"':
|
||||||
|
return compactString(dst, src, cursor, escape)
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return compactNumber(dst, src, cursor)
|
||||||
|
case 't':
|
||||||
|
return compactTrue(dst, src, cursor)
|
||||||
|
case 'f':
|
||||||
|
return compactFalse(dst, src, cursor)
|
||||||
|
case 'n':
|
||||||
|
return compactNull(dst, src, cursor)
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrSyntax(fmt.Sprintf("unexpected character '%c'", src[cursor]), cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactObject(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) {
|
||||||
|
if src[cursor] == '{' {
|
||||||
|
dst = append(dst, '{')
|
||||||
|
} else {
|
||||||
|
return nil, 0, errors.ErrExpected("expected { character for object value", cursor)
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor+1)
|
||||||
|
if src[cursor] == '}' {
|
||||||
|
dst = append(dst, '}')
|
||||||
|
return dst, cursor + 1, nil
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
dst, cursor, err = compactString(dst, src, cursor, escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
if src[cursor] != ':' {
|
||||||
|
return nil, 0, errors.ErrExpected("colon after object key", cursor)
|
||||||
|
}
|
||||||
|
dst = append(dst, ':')
|
||||||
|
dst, cursor, err = compactValue(dst, src, cursor+1, escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
switch src[cursor] {
|
||||||
|
case '}':
|
||||||
|
dst = append(dst, '}')
|
||||||
|
cursor++
|
||||||
|
return dst, cursor, nil
|
||||||
|
case ',':
|
||||||
|
dst = append(dst, ',')
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrExpected("comma after object value", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactArray(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) {
|
||||||
|
if src[cursor] == '[' {
|
||||||
|
dst = append(dst, '[')
|
||||||
|
} else {
|
||||||
|
return nil, 0, errors.ErrExpected("expected [ character for array value", cursor)
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor+1)
|
||||||
|
if src[cursor] == ']' {
|
||||||
|
dst = append(dst, ']')
|
||||||
|
return dst, cursor + 1, nil
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
dst, cursor, err = compactValue(dst, src, cursor, escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
switch src[cursor] {
|
||||||
|
case ']':
|
||||||
|
dst = append(dst, ']')
|
||||||
|
cursor++
|
||||||
|
return dst, cursor, nil
|
||||||
|
case ',':
|
||||||
|
dst = append(dst, ',')
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrExpected("comma after array value", cursor)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactString(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) {
|
||||||
|
if src[cursor] != '"' {
|
||||||
|
return nil, 0, errors.ErrInvalidCharacter(src[cursor], "string", cursor)
|
||||||
|
}
|
||||||
|
start := cursor
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
c := src[cursor]
|
||||||
|
if escape {
|
||||||
|
if isHTMLEscapeChar[c] {
|
||||||
|
dst = append(dst, src[start:cursor]...)
|
||||||
|
dst = append(dst, `\u00`...)
|
||||||
|
dst = append(dst, hex[c>>4], hex[c&0xF])
|
||||||
|
start = cursor + 1
|
||||||
|
} else if c == 0xE2 && cursor+2 < int64(len(src)) && src[cursor+1] == 0x80 && src[cursor+2]&^1 == 0xA8 {
|
||||||
|
dst = append(dst, src[start:cursor]...)
|
||||||
|
dst = append(dst, `\u202`...)
|
||||||
|
dst = append(dst, hex[src[cursor+2]&0xF])
|
||||||
|
cursor += 2
|
||||||
|
start = cursor + 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case '\\':
|
||||||
|
cursor++
|
||||||
|
if src[cursor] == nul {
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("string", int64(len(src)))
|
||||||
|
}
|
||||||
|
case '"':
|
||||||
|
cursor++
|
||||||
|
return append(dst, src[start:cursor]...), cursor, nil
|
||||||
|
case nul:
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("string", int64(len(src)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactNumber(dst, src []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
start := cursor
|
||||||
|
for {
|
||||||
|
cursor++
|
||||||
|
if floatTable[src[cursor]] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
num := src[start:cursor]
|
||||||
|
if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&num)), 64); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
dst = append(dst, num...)
|
||||||
|
return dst, cursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactTrue(dst, src []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
if cursor+3 >= int64(len(src)) {
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("true", cursor)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(src[cursor:cursor+4], []byte(`true`)) {
|
||||||
|
return nil, 0, errors.ErrInvalidCharacter(src[cursor], "true", cursor)
|
||||||
|
}
|
||||||
|
dst = append(dst, "true"...)
|
||||||
|
cursor += 4
|
||||||
|
return dst, cursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactFalse(dst, src []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
if cursor+4 >= int64(len(src)) {
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("false", cursor)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(src[cursor:cursor+5], []byte(`false`)) {
|
||||||
|
return nil, 0, errors.ErrInvalidCharacter(src[cursor], "false", cursor)
|
||||||
|
}
|
||||||
|
dst = append(dst, "false"...)
|
||||||
|
cursor += 5
|
||||||
|
return dst, cursor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compactNull(dst, src []byte, cursor int64) ([]byte, int64, error) {
|
||||||
|
if cursor+3 >= int64(len(src)) {
|
||||||
|
return nil, 0, errors.ErrUnexpectedEndOfJSON("null", cursor)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(src[cursor:cursor+4], []byte(`null`)) {
|
||||||
|
return nil, 0, errors.ErrInvalidCharacter(src[cursor], "null", cursor)
|
||||||
|
}
|
||||||
|
dst = append(dst, "null"...)
|
||||||
|
cursor += 4
|
||||||
|
return dst, cursor, nil
|
||||||
|
}
|
1570
vendor/github.com/goccy/go-json/internal/encoder/compiler.go
generated
vendored
Normal file
1570
vendor/github.com/goccy/go-json/internal/encoder/compiler.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
56
vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go
generated
vendored
Normal file
56
vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// +build !race
|
||||||
|
|
||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
|
if typeptr > typeAddr.MaxTypeAddr {
|
||||||
|
return compileToGetCodeSetSlowPath(typeptr)
|
||||||
|
}
|
||||||
|
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||||
|
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||||
|
return codeSet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// noescape trick for header.typ ( reflect.*rtype )
|
||||||
|
copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
|
||||||
|
|
||||||
|
noescapeKeyCode, err := compileHead(&compileContext{
|
||||||
|
typ: copiedType,
|
||||||
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
escapeKeyCode, err := compileHead(&compileContext{
|
||||||
|
typ: copiedType,
|
||||||
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
escapeKey: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
noescapeKeyCode = copyOpcode(noescapeKeyCode)
|
||||||
|
escapeKeyCode = copyOpcode(escapeKeyCode)
|
||||||
|
setTotalLengthToInterfaceOp(noescapeKeyCode)
|
||||||
|
setTotalLengthToInterfaceOp(escapeKeyCode)
|
||||||
|
interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
|
||||||
|
interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
|
||||||
|
codeLength := noescapeKeyCode.TotalLength()
|
||||||
|
codeSet := &OpcodeSet{
|
||||||
|
Type: copiedType,
|
||||||
|
NoescapeKeyCode: noescapeKeyCode,
|
||||||
|
EscapeKeyCode: escapeKeyCode,
|
||||||
|
InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
|
||||||
|
InterfaceEscapeKeyCode: interfaceEscapeKeyCode,
|
||||||
|
CodeLength: codeLength,
|
||||||
|
EndCode: ToEndCode(interfaceNoescapeKeyCode),
|
||||||
|
}
|
||||||
|
cachedOpcodeSets[index] = codeSet
|
||||||
|
return codeSet, nil
|
||||||
|
}
|
65
vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go
generated
vendored
Normal file
65
vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// +build race
|
||||||
|
|
||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var setsMu sync.RWMutex
|
||||||
|
|
||||||
|
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
|
if typeptr > typeAddr.MaxTypeAddr {
|
||||||
|
return compileToGetCodeSetSlowPath(typeptr)
|
||||||
|
}
|
||||||
|
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||||
|
setsMu.RLock()
|
||||||
|
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||||
|
setsMu.RUnlock()
|
||||||
|
return codeSet, nil
|
||||||
|
}
|
||||||
|
setsMu.RUnlock()
|
||||||
|
|
||||||
|
// noescape trick for header.typ ( reflect.*rtype )
|
||||||
|
copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr))
|
||||||
|
|
||||||
|
noescapeKeyCode, err := compileHead(&compileContext{
|
||||||
|
typ: copiedType,
|
||||||
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
escapeKeyCode, err := compileHead(&compileContext{
|
||||||
|
typ: copiedType,
|
||||||
|
structTypeToCompiledCode: map[uintptr]*CompiledCode{},
|
||||||
|
escapeKey: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
noescapeKeyCode = copyOpcode(noescapeKeyCode)
|
||||||
|
escapeKeyCode = copyOpcode(escapeKeyCode)
|
||||||
|
setTotalLengthToInterfaceOp(noescapeKeyCode)
|
||||||
|
setTotalLengthToInterfaceOp(escapeKeyCode)
|
||||||
|
interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
|
||||||
|
interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
|
||||||
|
codeLength := noescapeKeyCode.TotalLength()
|
||||||
|
codeSet := &OpcodeSet{
|
||||||
|
Type: copiedType,
|
||||||
|
NoescapeKeyCode: noescapeKeyCode,
|
||||||
|
EscapeKeyCode: escapeKeyCode,
|
||||||
|
InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
|
||||||
|
InterfaceEscapeKeyCode: interfaceEscapeKeyCode,
|
||||||
|
CodeLength: codeLength,
|
||||||
|
EndCode: ToEndCode(interfaceNoescapeKeyCode),
|
||||||
|
}
|
||||||
|
setsMu.Lock()
|
||||||
|
cachedOpcodeSets[index] = codeSet
|
||||||
|
setsMu.Unlock()
|
||||||
|
return codeSet, nil
|
||||||
|
}
|
141
vendor/github.com/goccy/go-json/internal/encoder/context.go
generated
vendored
Normal file
141
vendor/github.com/goccy/go-json/internal/encoder/context.go
generated
vendored
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type compileContext struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
opcodeIndex uint32
|
||||||
|
ptrIndex int
|
||||||
|
indent uint32
|
||||||
|
escapeKey bool
|
||||||
|
structTypeToCompiledCode map[uintptr]*CompiledCode
|
||||||
|
|
||||||
|
parent *compileContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) context() *compileContext {
|
||||||
|
return &compileContext{
|
||||||
|
typ: c.typ,
|
||||||
|
opcodeIndex: c.opcodeIndex,
|
||||||
|
ptrIndex: c.ptrIndex,
|
||||||
|
indent: c.indent,
|
||||||
|
escapeKey: c.escapeKey,
|
||||||
|
structTypeToCompiledCode: c.structTypeToCompiledCode,
|
||||||
|
parent: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) withType(typ *runtime.Type) *compileContext {
|
||||||
|
ctx := c.context()
|
||||||
|
ctx.typ = typ
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) incIndent() *compileContext {
|
||||||
|
ctx := c.context()
|
||||||
|
ctx.indent++
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) decIndent() *compileContext {
|
||||||
|
ctx := c.context()
|
||||||
|
ctx.indent--
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) incIndex() {
|
||||||
|
c.incOpcodeIndex()
|
||||||
|
c.incPtrIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) decIndex() {
|
||||||
|
c.decOpcodeIndex()
|
||||||
|
c.decPtrIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) incOpcodeIndex() {
|
||||||
|
c.opcodeIndex++
|
||||||
|
if c.parent != nil {
|
||||||
|
c.parent.incOpcodeIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) decOpcodeIndex() {
|
||||||
|
c.opcodeIndex--
|
||||||
|
if c.parent != nil {
|
||||||
|
c.parent.decOpcodeIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) incPtrIndex() {
|
||||||
|
c.ptrIndex++
|
||||||
|
if c.parent != nil {
|
||||||
|
c.parent.incPtrIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compileContext) decPtrIndex() {
|
||||||
|
c.ptrIndex--
|
||||||
|
if c.parent != nil {
|
||||||
|
c.parent.decPtrIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
bufSize = 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
runtimeContextPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &RuntimeContext{
|
||||||
|
Buf: make([]byte, 0, bufSize),
|
||||||
|
Ptrs: make([]uintptr, 128),
|
||||||
|
KeepRefs: make([]unsafe.Pointer, 0, 8),
|
||||||
|
Option: &Option{},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type RuntimeContext struct {
|
||||||
|
Context context.Context
|
||||||
|
Buf []byte
|
||||||
|
MarshalBuf []byte
|
||||||
|
Ptrs []uintptr
|
||||||
|
KeepRefs []unsafe.Pointer
|
||||||
|
SeenPtr []uintptr
|
||||||
|
BaseIndent uint32
|
||||||
|
Prefix []byte
|
||||||
|
IndentStr []byte
|
||||||
|
Option *Option
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeContext) Init(p uintptr, codelen int) {
|
||||||
|
if len(c.Ptrs) < codelen {
|
||||||
|
c.Ptrs = make([]uintptr, codelen)
|
||||||
|
}
|
||||||
|
c.Ptrs[0] = p
|
||||||
|
c.KeepRefs = c.KeepRefs[:0]
|
||||||
|
c.SeenPtr = c.SeenPtr[:0]
|
||||||
|
c.BaseIndent = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RuntimeContext) Ptr() uintptr {
|
||||||
|
header := (*runtime.SliceHeader)(unsafe.Pointer(&c.Ptrs))
|
||||||
|
return uintptr(header.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TakeRuntimeContext() *RuntimeContext {
|
||||||
|
return runtimeContextPool.Get().(*RuntimeContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReleaseRuntimeContext(ctx *RuntimeContext) {
|
||||||
|
runtimeContextPool.Put(ctx)
|
||||||
|
}
|
551
vendor/github.com/goccy/go-json/internal/encoder/encoder.go
generated
vendored
Normal file
551
vendor/github.com/goccy/go-json/internal/encoder/encoder.go
generated
vendored
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t OpType) IsMultipleOpHead() bool {
|
||||||
|
switch t {
|
||||||
|
case OpStructHead:
|
||||||
|
return true
|
||||||
|
case OpStructHeadSlice:
|
||||||
|
return true
|
||||||
|
case OpStructHeadArray:
|
||||||
|
return true
|
||||||
|
case OpStructHeadMap:
|
||||||
|
return true
|
||||||
|
case OpStructHeadStruct:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmpty:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmptySlice:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmptyArray:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmptyMap:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmptyStruct:
|
||||||
|
return true
|
||||||
|
case OpStructHeadSlicePtr:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmptySlicePtr:
|
||||||
|
return true
|
||||||
|
case OpStructHeadArrayPtr:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmptyArrayPtr:
|
||||||
|
return true
|
||||||
|
case OpStructHeadMapPtr:
|
||||||
|
return true
|
||||||
|
case OpStructHeadOmitEmptyMapPtr:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t OpType) IsMultipleOpField() bool {
|
||||||
|
switch t {
|
||||||
|
case OpStructField:
|
||||||
|
return true
|
||||||
|
case OpStructFieldSlice:
|
||||||
|
return true
|
||||||
|
case OpStructFieldArray:
|
||||||
|
return true
|
||||||
|
case OpStructFieldMap:
|
||||||
|
return true
|
||||||
|
case OpStructFieldStruct:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmpty:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmptySlice:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmptyArray:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmptyMap:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmptyStruct:
|
||||||
|
return true
|
||||||
|
case OpStructFieldSlicePtr:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmptySlicePtr:
|
||||||
|
return true
|
||||||
|
case OpStructFieldArrayPtr:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmptyArrayPtr:
|
||||||
|
return true
|
||||||
|
case OpStructFieldMapPtr:
|
||||||
|
return true
|
||||||
|
case OpStructFieldOmitEmptyMapPtr:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpcodeSet struct {
|
||||||
|
Type *runtime.Type
|
||||||
|
NoescapeKeyCode *Opcode
|
||||||
|
EscapeKeyCode *Opcode
|
||||||
|
InterfaceNoescapeKeyCode *Opcode
|
||||||
|
InterfaceEscapeKeyCode *Opcode
|
||||||
|
CodeLength int
|
||||||
|
EndCode *Opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
type CompiledCode struct {
|
||||||
|
Code *Opcode
|
||||||
|
Linked bool // whether recursive code already have linked
|
||||||
|
CurLen uintptr
|
||||||
|
NextLen uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
const StartDetectingCyclesAfter = 1000
|
||||||
|
|
||||||
|
func Load(base uintptr, idx uintptr) uintptr {
|
||||||
|
addr := base + idx
|
||||||
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Store(base uintptr, idx uintptr, p uintptr) {
|
||||||
|
addr := base + idx
|
||||||
|
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr {
|
||||||
|
addr := base + idx
|
||||||
|
p := **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return PtrToPtr(p)
|
||||||
|
/*
|
||||||
|
for i := 0; i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
p = PtrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
|
||||||
|
func PtrToPtr(p uintptr) uintptr {
|
||||||
|
return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
|
||||||
|
}
|
||||||
|
func PtrToNPtr(p uintptr, ptrNum int) uintptr {
|
||||||
|
for i := 0; i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = PtrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func PtrToUnsafePtr(p uintptr) unsafe.Pointer {
|
||||||
|
return *(*unsafe.Pointer)(unsafe.Pointer(&p))
|
||||||
|
}
|
||||||
|
func PtrToInterface(code *Opcode, p uintptr) interface{} {
|
||||||
|
return *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: code.Type,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrUnsupportedValue(code *Opcode, ptr uintptr) *errors.UnsupportedValueError {
|
||||||
|
v := *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: code.Type,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)),
|
||||||
|
}))
|
||||||
|
return &errors.UnsupportedValueError{
|
||||||
|
Value: reflect.ValueOf(v),
|
||||||
|
Str: fmt.Sprintf("encountered a cycle via %s", code.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrUnsupportedFloat(v float64) *errors.UnsupportedValueError {
|
||||||
|
return &errors.UnsupportedValueError{
|
||||||
|
Value: reflect.ValueOf(v),
|
||||||
|
Str: strconv.FormatFloat(v, 'g', -1, 64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrMarshalerWithCode(code *Opcode, err error) *errors.MarshalerError {
|
||||||
|
return &errors.MarshalerError{
|
||||||
|
Type: runtime.RType2Type(code.Type),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type emptyInterface struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapItem struct {
|
||||||
|
Key []byte
|
||||||
|
Value []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mapslice struct {
|
||||||
|
Items []MapItem
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mapslice) Len() int {
|
||||||
|
return len(m.Items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mapslice) Less(i, j int) bool {
|
||||||
|
return bytes.Compare(m.Items[i].Key, m.Items[j].Key) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mapslice) Swap(i, j int) {
|
||||||
|
m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
type MapContext struct {
|
||||||
|
Pos []int
|
||||||
|
Slice *Mapslice
|
||||||
|
Buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapContextPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &MapContext{}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMapContext(mapLen int) *MapContext {
|
||||||
|
ctx := mapContextPool.Get().(*MapContext)
|
||||||
|
if ctx.Slice == nil {
|
||||||
|
ctx.Slice = &Mapslice{
|
||||||
|
Items: make([]MapItem, 0, mapLen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cap(ctx.Pos) < (mapLen*2 + 1) {
|
||||||
|
ctx.Pos = make([]int, 0, mapLen*2+1)
|
||||||
|
ctx.Slice.Items = make([]MapItem, 0, mapLen)
|
||||||
|
} else {
|
||||||
|
ctx.Pos = ctx.Pos[:0]
|
||||||
|
ctx.Slice.Items = ctx.Slice.Items[:0]
|
||||||
|
}
|
||||||
|
ctx.Buf = ctx.Buf[:0]
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReleaseMapContext(c *MapContext) {
|
||||||
|
mapContextPool.Put(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname MapIterInit reflect.mapiterinit
|
||||||
|
//go:noescape
|
||||||
|
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname MapIterKey reflect.mapiterkey
|
||||||
|
//go:noescape
|
||||||
|
func MapIterKey(it unsafe.Pointer) unsafe.Pointer
|
||||||
|
|
||||||
|
//go:linkname MapIterNext reflect.mapiternext
|
||||||
|
//go:noescape
|
||||||
|
func MapIterNext(it unsafe.Pointer)
|
||||||
|
|
||||||
|
//go:linkname MapLen reflect.maplen
|
||||||
|
//go:noescape
|
||||||
|
func MapLen(m unsafe.Pointer) int
|
||||||
|
|
||||||
|
func AppendByteSlice(_ *RuntimeContext, b []byte, src []byte) []byte {
|
||||||
|
if src == nil {
|
||||||
|
return append(b, `null`...)
|
||||||
|
}
|
||||||
|
encodedLen := base64.StdEncoding.EncodedLen(len(src))
|
||||||
|
b = append(b, '"')
|
||||||
|
pos := len(b)
|
||||||
|
remainLen := cap(b[pos:])
|
||||||
|
var buf []byte
|
||||||
|
if remainLen > encodedLen {
|
||||||
|
buf = b[pos : pos+encodedLen]
|
||||||
|
} else {
|
||||||
|
buf = make([]byte, encodedLen)
|
||||||
|
}
|
||||||
|
base64.StdEncoding.Encode(buf, src)
|
||||||
|
return append(append(b, buf...), '"')
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendFloat32(_ *RuntimeContext, b []byte, v float32) []byte {
|
||||||
|
f64 := float64(v)
|
||||||
|
abs := math.Abs(f64)
|
||||||
|
fmt := byte('f')
|
||||||
|
// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
|
||||||
|
if abs != 0 {
|
||||||
|
f32 := float32(abs)
|
||||||
|
if f32 < 1e-6 || f32 >= 1e21 {
|
||||||
|
fmt = 'e'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strconv.AppendFloat(b, f64, fmt, -1, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendFloat64(_ *RuntimeContext, b []byte, v float64) []byte {
|
||||||
|
abs := math.Abs(v)
|
||||||
|
fmt := byte('f')
|
||||||
|
// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
|
||||||
|
if abs != 0 {
|
||||||
|
if abs < 1e-6 || abs >= 1e21 {
|
||||||
|
fmt = 'e'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strconv.AppendFloat(b, v, fmt, -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendBool(_ *RuntimeContext, b []byte, v bool) []byte {
|
||||||
|
if v {
|
||||||
|
return append(b, "true"...)
|
||||||
|
}
|
||||||
|
return append(b, "false"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
floatTable = [256]bool{
|
||||||
|
'0': true,
|
||||||
|
'1': true,
|
||||||
|
'2': true,
|
||||||
|
'3': true,
|
||||||
|
'4': true,
|
||||||
|
'5': true,
|
||||||
|
'6': true,
|
||||||
|
'7': true,
|
||||||
|
'8': true,
|
||||||
|
'9': true,
|
||||||
|
'.': true,
|
||||||
|
'e': true,
|
||||||
|
'E': true,
|
||||||
|
'+': true,
|
||||||
|
'-': true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func AppendNumber(_ *RuntimeContext, b []byte, n json.Number) ([]byte, error) {
|
||||||
|
if len(n) == 0 {
|
||||||
|
return append(b, '0'), nil
|
||||||
|
}
|
||||||
|
for i := 0; i < len(n); i++ {
|
||||||
|
if !floatTable[n[i]] {
|
||||||
|
return nil, fmt.Errorf("json: invalid number literal %q", n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = append(b, n...)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
rv := reflect.ValueOf(v) // convert by dynamic interface type
|
||||||
|
if (code.Flags & AddrForMarshalerFlags) != 0 {
|
||||||
|
if rv.CanAddr() {
|
||||||
|
rv = rv.Addr()
|
||||||
|
} else {
|
||||||
|
newV := reflect.New(rv.Type())
|
||||||
|
newV.Elem().Set(rv)
|
||||||
|
rv = newV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = rv.Interface()
|
||||||
|
var bb []byte
|
||||||
|
if (code.Flags & MarshalerContextFlags) != 0 {
|
||||||
|
marshaler, ok := v.(marshalerContext)
|
||||||
|
if !ok {
|
||||||
|
return AppendNull(ctx, b), nil
|
||||||
|
}
|
||||||
|
b, err := marshaler.MarshalJSON(ctx.Option.Context)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
bb = b
|
||||||
|
} else {
|
||||||
|
marshaler, ok := v.(json.Marshaler)
|
||||||
|
if !ok {
|
||||||
|
return AppendNull(ctx, b), nil
|
||||||
|
}
|
||||||
|
b, err := marshaler.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
bb = b
|
||||||
|
}
|
||||||
|
marshalBuf := ctx.MarshalBuf[:0]
|
||||||
|
marshalBuf = append(append(marshalBuf, bb...), nul)
|
||||||
|
compactedBuf, err := compact(b, marshalBuf, (ctx.Option.Flag&HTMLEscapeOption) != 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
ctx.MarshalBuf = marshalBuf
|
||||||
|
return compactedBuf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
rv := reflect.ValueOf(v) // convert by dynamic interface type
|
||||||
|
if (code.Flags & AddrForMarshalerFlags) != 0 {
|
||||||
|
if rv.CanAddr() {
|
||||||
|
rv = rv.Addr()
|
||||||
|
} else {
|
||||||
|
newV := reflect.New(rv.Type())
|
||||||
|
newV.Elem().Set(rv)
|
||||||
|
rv = newV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = rv.Interface()
|
||||||
|
var bb []byte
|
||||||
|
if (code.Flags & MarshalerContextFlags) != 0 {
|
||||||
|
marshaler, ok := v.(marshalerContext)
|
||||||
|
if !ok {
|
||||||
|
return AppendNull(ctx, b), nil
|
||||||
|
}
|
||||||
|
b, err := marshaler.MarshalJSON(ctx.Option.Context)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
bb = b
|
||||||
|
} else {
|
||||||
|
marshaler, ok := v.(json.Marshaler)
|
||||||
|
if !ok {
|
||||||
|
return AppendNull(ctx, b), nil
|
||||||
|
}
|
||||||
|
b, err := marshaler.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
bb = b
|
||||||
|
}
|
||||||
|
marshalBuf := ctx.MarshalBuf[:0]
|
||||||
|
marshalBuf = append(append(marshalBuf, bb...), nul)
|
||||||
|
indentedBuf, err := doIndent(
|
||||||
|
b,
|
||||||
|
marshalBuf,
|
||||||
|
string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), int(ctx.BaseIndent+code.Indent)),
|
||||||
|
string(ctx.IndentStr),
|
||||||
|
(ctx.Option.Flag&HTMLEscapeOption) != 0,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
ctx.MarshalBuf = marshalBuf
|
||||||
|
return indentedBuf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendMarshalText(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
rv := reflect.ValueOf(v) // convert by dynamic interface type
|
||||||
|
if (code.Flags & AddrForMarshalerFlags) != 0 {
|
||||||
|
if rv.CanAddr() {
|
||||||
|
rv = rv.Addr()
|
||||||
|
} else {
|
||||||
|
newV := reflect.New(rv.Type())
|
||||||
|
newV.Elem().Set(rv)
|
||||||
|
rv = newV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = rv.Interface()
|
||||||
|
marshaler, ok := v.(encoding.TextMarshaler)
|
||||||
|
if !ok {
|
||||||
|
return AppendNull(ctx, b), nil
|
||||||
|
}
|
||||||
|
bytes, err := marshaler.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendMarshalTextIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
rv := reflect.ValueOf(v) // convert by dynamic interface type
|
||||||
|
if (code.Flags & AddrForMarshalerFlags) != 0 {
|
||||||
|
if rv.CanAddr() {
|
||||||
|
rv = rv.Addr()
|
||||||
|
} else {
|
||||||
|
newV := reflect.New(rv.Type())
|
||||||
|
newV.Elem().Set(rv)
|
||||||
|
rv = newV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = rv.Interface()
|
||||||
|
marshaler, ok := v.(encoding.TextMarshaler)
|
||||||
|
if !ok {
|
||||||
|
return AppendNull(ctx, b), nil
|
||||||
|
}
|
||||||
|
bytes, err := marshaler.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||||
|
}
|
||||||
|
return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendNull(_ *RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, "null"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendComma(_ *RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendCommaIndent(_ *RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendStructEnd(_ *RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendStructEndIndent(ctx *RuntimeContext, code *Opcode, b []byte) []byte {
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = append(b, ctx.Prefix...)
|
||||||
|
indentNum := ctx.BaseIndent + code.Indent - 1
|
||||||
|
for i := uint32(0); i < indentNum; i++ {
|
||||||
|
b = append(b, ctx.IndentStr...)
|
||||||
|
}
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendIndent(ctx *RuntimeContext, b []byte, indent uint32) []byte {
|
||||||
|
b = append(b, ctx.Prefix...)
|
||||||
|
indentNum := ctx.BaseIndent + indent
|
||||||
|
for i := uint32(0); i < indentNum; i++ {
|
||||||
|
b = append(b, ctx.IndentStr...)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsNilForMarshaler(v interface{}) bool {
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return !rv.Bool()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return rv.Int() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return rv.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return math.Float64bits(rv.Float()) == 0
|
||||||
|
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Func:
|
||||||
|
return rv.IsNil()
|
||||||
|
case reflect.Slice:
|
||||||
|
return rv.IsNil() || rv.Len() == 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
211
vendor/github.com/goccy/go-json/internal/encoder/indent.go
generated
vendored
Normal file
211
vendor/github.com/goccy/go-json/internal/encoder/indent.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func takeIndentSrcRuntimeContext(src []byte) (*RuntimeContext, []byte) {
|
||||||
|
ctx := TakeRuntimeContext()
|
||||||
|
buf := ctx.Buf[:0]
|
||||||
|
buf = append(append(buf, src...), nul)
|
||||||
|
ctx.Buf = buf
|
||||||
|
return ctx, buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func Indent(buf *bytes.Buffer, src []byte, prefix, indentStr string) error {
|
||||||
|
if len(src) == 0 {
|
||||||
|
return errors.ErrUnexpectedEndOfJSON("", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
srcCtx, srcBuf := takeIndentSrcRuntimeContext(src)
|
||||||
|
dstCtx := TakeRuntimeContext()
|
||||||
|
dst := dstCtx.Buf[:0]
|
||||||
|
|
||||||
|
dst, err := indentAndWrite(buf, dst, srcBuf, prefix, indentStr)
|
||||||
|
if err != nil {
|
||||||
|
ReleaseRuntimeContext(srcCtx)
|
||||||
|
ReleaseRuntimeContext(dstCtx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dstCtx.Buf = dst
|
||||||
|
ReleaseRuntimeContext(srcCtx)
|
||||||
|
ReleaseRuntimeContext(dstCtx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func indentAndWrite(buf *bytes.Buffer, dst []byte, src []byte, prefix, indentStr string) ([]byte, error) {
|
||||||
|
dst, err := doIndent(dst, src, prefix, indentStr, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := buf.Write(dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dst, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func doIndent(dst, src []byte, prefix, indentStr string, escape bool) ([]byte, error) {
|
||||||
|
buf, cursor, err := indentValue(dst, src, 0, 0, []byte(prefix), []byte(indentStr), escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateEndBuf(src, cursor); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func indentValue(
|
||||||
|
dst []byte,
|
||||||
|
src []byte,
|
||||||
|
indentNum int,
|
||||||
|
cursor int64,
|
||||||
|
prefix []byte,
|
||||||
|
indentBytes []byte,
|
||||||
|
escape bool) ([]byte, int64, error) {
|
||||||
|
for {
|
||||||
|
switch src[cursor] {
|
||||||
|
case ' ', '\t', '\n', '\r':
|
||||||
|
cursor++
|
||||||
|
continue
|
||||||
|
case '{':
|
||||||
|
return indentObject(dst, src, indentNum, cursor, prefix, indentBytes, escape)
|
||||||
|
case '}':
|
||||||
|
return nil, 0, errors.ErrSyntax("unexpected character '}'", cursor)
|
||||||
|
case '[':
|
||||||
|
return indentArray(dst, src, indentNum, cursor, prefix, indentBytes, escape)
|
||||||
|
case ']':
|
||||||
|
return nil, 0, errors.ErrSyntax("unexpected character ']'", cursor)
|
||||||
|
case '"':
|
||||||
|
return compactString(dst, src, cursor, escape)
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return compactNumber(dst, src, cursor)
|
||||||
|
case 't':
|
||||||
|
return compactTrue(dst, src, cursor)
|
||||||
|
case 'f':
|
||||||
|
return compactFalse(dst, src, cursor)
|
||||||
|
case 'n':
|
||||||
|
return compactNull(dst, src, cursor)
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrSyntax(fmt.Sprintf("unexpected character '%c'", src[cursor]), cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func indentObject(
|
||||||
|
dst []byte,
|
||||||
|
src []byte,
|
||||||
|
indentNum int,
|
||||||
|
cursor int64,
|
||||||
|
prefix []byte,
|
||||||
|
indentBytes []byte,
|
||||||
|
escape bool) ([]byte, int64, error) {
|
||||||
|
if src[cursor] == '{' {
|
||||||
|
dst = append(dst, '{')
|
||||||
|
} else {
|
||||||
|
return nil, 0, errors.ErrExpected("expected { character for object value", cursor)
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor+1)
|
||||||
|
if src[cursor] == '}' {
|
||||||
|
dst = append(dst, '}')
|
||||||
|
return dst, cursor + 1, nil
|
||||||
|
}
|
||||||
|
indentNum++
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
dst = append(append(dst, '\n'), prefix...)
|
||||||
|
for i := 0; i < indentNum; i++ {
|
||||||
|
dst = append(dst, indentBytes...)
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
dst, cursor, err = compactString(dst, src, cursor, escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
if src[cursor] != ':' {
|
||||||
|
return nil, 0, errors.ErrSyntax(
|
||||||
|
fmt.Sprintf("invalid character '%c' after object key", src[cursor]),
|
||||||
|
cursor+1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
dst = append(dst, ':', ' ')
|
||||||
|
dst, cursor, err = indentValue(dst, src, indentNum, cursor+1, prefix, indentBytes, escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
switch src[cursor] {
|
||||||
|
case '}':
|
||||||
|
dst = append(append(dst, '\n'), prefix...)
|
||||||
|
for i := 0; i < indentNum-1; i++ {
|
||||||
|
dst = append(dst, indentBytes...)
|
||||||
|
}
|
||||||
|
dst = append(dst, '}')
|
||||||
|
cursor++
|
||||||
|
return dst, cursor, nil
|
||||||
|
case ',':
|
||||||
|
dst = append(dst, ',')
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrSyntax(
|
||||||
|
fmt.Sprintf("invalid character '%c' after object key:value pair", src[cursor]),
|
||||||
|
cursor+1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func indentArray(
|
||||||
|
dst []byte,
|
||||||
|
src []byte,
|
||||||
|
indentNum int,
|
||||||
|
cursor int64,
|
||||||
|
prefix []byte,
|
||||||
|
indentBytes []byte,
|
||||||
|
escape bool) ([]byte, int64, error) {
|
||||||
|
if src[cursor] == '[' {
|
||||||
|
dst = append(dst, '[')
|
||||||
|
} else {
|
||||||
|
return nil, 0, errors.ErrExpected("expected [ character for array value", cursor)
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor+1)
|
||||||
|
if src[cursor] == ']' {
|
||||||
|
dst = append(dst, ']')
|
||||||
|
return dst, cursor + 1, nil
|
||||||
|
}
|
||||||
|
indentNum++
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
dst = append(append(dst, '\n'), prefix...)
|
||||||
|
for i := 0; i < indentNum; i++ {
|
||||||
|
dst = append(dst, indentBytes...)
|
||||||
|
}
|
||||||
|
dst, cursor, err = indentValue(dst, src, indentNum, cursor, prefix, indentBytes, escape)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
cursor = skipWhiteSpace(src, cursor)
|
||||||
|
switch src[cursor] {
|
||||||
|
case ']':
|
||||||
|
dst = append(append(dst, '\n'), prefix...)
|
||||||
|
for i := 0; i < indentNum-1; i++ {
|
||||||
|
dst = append(dst, indentBytes...)
|
||||||
|
}
|
||||||
|
dst = append(dst, ']')
|
||||||
|
cursor++
|
||||||
|
return dst, cursor, nil
|
||||||
|
case ',':
|
||||||
|
dst = append(dst, ',')
|
||||||
|
default:
|
||||||
|
return nil, 0, errors.ErrSyntax(
|
||||||
|
fmt.Sprintf("invalid character '%c' after array value", src[cursor]),
|
||||||
|
cursor+1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
cursor++
|
||||||
|
}
|
||||||
|
}
|
130
vendor/github.com/goccy/go-json/internal/encoder/int.go
generated
vendored
Normal file
130
vendor/github.com/goccy/go-json/internal/encoder/int.go
generated
vendored
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var endianness int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var b [2]byte
|
||||||
|
*(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD)
|
||||||
|
|
||||||
|
switch b[0] {
|
||||||
|
case 0xCD:
|
||||||
|
endianness = 0 // LE
|
||||||
|
case 0xAB:
|
||||||
|
endianness = 1 // BE
|
||||||
|
default:
|
||||||
|
panic("could not determine endianness")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "00010203...96979899" cast to []uint16
|
||||||
|
var intLELookup = [100]uint16{
|
||||||
|
0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
|
||||||
|
0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
|
||||||
|
0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
|
||||||
|
0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933,
|
||||||
|
0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934,
|
||||||
|
0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935,
|
||||||
|
0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936,
|
||||||
|
0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
|
||||||
|
0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
|
||||||
|
0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939,
|
||||||
|
}
|
||||||
|
|
||||||
|
var intBELookup = [100]uint16{
|
||||||
|
0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039,
|
||||||
|
0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139,
|
||||||
|
0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239,
|
||||||
|
0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339,
|
||||||
|
0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439,
|
||||||
|
0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539,
|
||||||
|
0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639,
|
||||||
|
0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739,
|
||||||
|
0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839,
|
||||||
|
0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939,
|
||||||
|
}
|
||||||
|
|
||||||
|
var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup}
|
||||||
|
|
||||||
|
func numMask(numBitSize uint8) uint64 {
|
||||||
|
return 1<<numBitSize - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendInt(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte {
|
||||||
|
mask := numMask(code.NumBitSize)
|
||||||
|
n := u64 & mask
|
||||||
|
negative := (u64>>(code.NumBitSize-1))&1 == 1
|
||||||
|
if !negative {
|
||||||
|
if n < 10 {
|
||||||
|
return append(out, byte(n+'0'))
|
||||||
|
} else if n < 100 {
|
||||||
|
u := intLELookup[n]
|
||||||
|
return append(out, byte(u), byte(u>>8))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n = -n & mask
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup := intLookup[endianness]
|
||||||
|
|
||||||
|
var b [22]byte
|
||||||
|
u := (*[11]uint16)(unsafe.Pointer(&b))
|
||||||
|
i := 11
|
||||||
|
|
||||||
|
for n >= 100 {
|
||||||
|
j := n % 100
|
||||||
|
n /= 100
|
||||||
|
i--
|
||||||
|
u[i] = lookup[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
i--
|
||||||
|
u[i] = lookup[n]
|
||||||
|
|
||||||
|
i *= 2 // convert to byte index
|
||||||
|
if n < 10 {
|
||||||
|
i++ // remove leading zero
|
||||||
|
}
|
||||||
|
if negative {
|
||||||
|
i--
|
||||||
|
b[i] = '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(out, b[i:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendUint(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte {
|
||||||
|
mask := numMask(code.NumBitSize)
|
||||||
|
n := u64 & mask
|
||||||
|
if n < 10 {
|
||||||
|
return append(out, byte(n+'0'))
|
||||||
|
} else if n < 100 {
|
||||||
|
u := intLELookup[n]
|
||||||
|
return append(out, byte(u), byte(u>>8))
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup := intLookup[endianness]
|
||||||
|
|
||||||
|
var b [22]byte
|
||||||
|
u := (*[11]uint16)(unsafe.Pointer(&b))
|
||||||
|
i := 11
|
||||||
|
|
||||||
|
for n >= 100 {
|
||||||
|
j := n % 100
|
||||||
|
n /= 100
|
||||||
|
i--
|
||||||
|
u[i] = lookup[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
i--
|
||||||
|
u[i] = lookup[n]
|
||||||
|
|
||||||
|
i *= 2 // convert to byte index
|
||||||
|
if n < 10 {
|
||||||
|
i++ // remove leading zero
|
||||||
|
}
|
||||||
|
return append(out, b[i:]...)
|
||||||
|
}
|
8
vendor/github.com/goccy/go-json/internal/encoder/map112.go
generated
vendored
Normal file
8
vendor/github.com/goccy/go-json/internal/encoder/map112.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// +build !go1.13
|
||||||
|
|
||||||
|
package encoder
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:linkname MapIterValue reflect.mapitervalue
|
||||||
|
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
|
8
vendor/github.com/goccy/go-json/internal/encoder/map113.go
generated
vendored
Normal file
8
vendor/github.com/goccy/go-json/internal/encoder/map113.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// +build go1.13
|
||||||
|
|
||||||
|
package encoder
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:linkname MapIterValue reflect.mapiterelem
|
||||||
|
func MapIterValue(it unsafe.Pointer) unsafe.Pointer
|
772
vendor/github.com/goccy/go-json/internal/encoder/opcode.go
generated
vendored
Normal file
772
vendor/github.com/goccy/go-json/internal/encoder/opcode.go
generated
vendored
Normal file
@ -0,0 +1,772 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
type OpFlags uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
AnonymousHeadFlags OpFlags = 1 << 0
|
||||||
|
AnonymousKeyFlags OpFlags = 1 << 1
|
||||||
|
IndirectFlags OpFlags = 1 << 2
|
||||||
|
IsTaggedKeyFlags OpFlags = 1 << 3
|
||||||
|
NilCheckFlags OpFlags = 1 << 4
|
||||||
|
AddrForMarshalerFlags OpFlags = 1 << 5
|
||||||
|
IsNextOpPtrTypeFlags OpFlags = 1 << 6
|
||||||
|
IsNilableTypeFlags OpFlags = 1 << 7
|
||||||
|
MarshalerContextFlags OpFlags = 1 << 8
|
||||||
|
NonEmptyInterfaceFlags OpFlags = 1 << 9
|
||||||
|
)
|
||||||
|
|
||||||
|
type Opcode struct {
|
||||||
|
Op OpType // operation type
|
||||||
|
Idx uint32 // offset to access ptr
|
||||||
|
Next *Opcode // next opcode
|
||||||
|
End *Opcode // array/slice/struct/map end
|
||||||
|
NextField *Opcode // next struct field
|
||||||
|
Key string // struct field key
|
||||||
|
Offset uint32 // offset size from struct header
|
||||||
|
PtrNum uint8 // pointer number: e.g. double pointer is 2.
|
||||||
|
NumBitSize uint8
|
||||||
|
Flags OpFlags
|
||||||
|
|
||||||
|
Type *runtime.Type // go type
|
||||||
|
PrevField *Opcode // prev struct field
|
||||||
|
Jmp *CompiledCode // for recursive call
|
||||||
|
ElemIdx uint32 // offset to access array/slice/map elem
|
||||||
|
Length uint32 // offset to access slice/map length or array length
|
||||||
|
MapIter uint32 // offset to access map iterator
|
||||||
|
MapPos uint32 // offset to access position list for sorted map
|
||||||
|
Indent uint32 // indent number
|
||||||
|
Size uint32 // array/slice elem size
|
||||||
|
DisplayIdx uint32 // opcode index
|
||||||
|
DisplayKey string // key text to display
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) MaxIdx() uint32 {
|
||||||
|
max := uint32(0)
|
||||||
|
for _, value := range []uint32{
|
||||||
|
c.Idx,
|
||||||
|
c.ElemIdx,
|
||||||
|
c.Length,
|
||||||
|
c.MapIter,
|
||||||
|
c.MapPos,
|
||||||
|
c.Size,
|
||||||
|
} {
|
||||||
|
if max < value {
|
||||||
|
max = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) ToHeaderType(isString bool) OpType {
|
||||||
|
switch c.Op {
|
||||||
|
case OpInt:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadIntString
|
||||||
|
}
|
||||||
|
return OpStructHeadInt
|
||||||
|
case OpIntPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadIntPtrString
|
||||||
|
}
|
||||||
|
return OpStructHeadIntPtr
|
||||||
|
case OpUint:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadUintString
|
||||||
|
}
|
||||||
|
return OpStructHeadUint
|
||||||
|
case OpUintPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadUintPtrString
|
||||||
|
}
|
||||||
|
return OpStructHeadUintPtr
|
||||||
|
case OpFloat32:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadFloat32String
|
||||||
|
}
|
||||||
|
return OpStructHeadFloat32
|
||||||
|
case OpFloat32Ptr:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadFloat32PtrString
|
||||||
|
}
|
||||||
|
return OpStructHeadFloat32Ptr
|
||||||
|
case OpFloat64:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadFloat64String
|
||||||
|
}
|
||||||
|
return OpStructHeadFloat64
|
||||||
|
case OpFloat64Ptr:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadFloat64PtrString
|
||||||
|
}
|
||||||
|
return OpStructHeadFloat64Ptr
|
||||||
|
case OpString:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadStringString
|
||||||
|
}
|
||||||
|
return OpStructHeadString
|
||||||
|
case OpStringPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadStringPtrString
|
||||||
|
}
|
||||||
|
return OpStructHeadStringPtr
|
||||||
|
case OpNumber:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadNumberString
|
||||||
|
}
|
||||||
|
return OpStructHeadNumber
|
||||||
|
case OpNumberPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadNumberPtrString
|
||||||
|
}
|
||||||
|
return OpStructHeadNumberPtr
|
||||||
|
case OpBool:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadBoolString
|
||||||
|
}
|
||||||
|
return OpStructHeadBool
|
||||||
|
case OpBoolPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructHeadBoolPtrString
|
||||||
|
}
|
||||||
|
return OpStructHeadBoolPtr
|
||||||
|
case OpBytes:
|
||||||
|
return OpStructHeadBytes
|
||||||
|
case OpBytesPtr:
|
||||||
|
return OpStructHeadBytesPtr
|
||||||
|
case OpMap:
|
||||||
|
return OpStructHeadMap
|
||||||
|
case OpMapPtr:
|
||||||
|
c.Op = OpMap
|
||||||
|
return OpStructHeadMapPtr
|
||||||
|
case OpArray:
|
||||||
|
return OpStructHeadArray
|
||||||
|
case OpArrayPtr:
|
||||||
|
c.Op = OpArray
|
||||||
|
return OpStructHeadArrayPtr
|
||||||
|
case OpSlice:
|
||||||
|
return OpStructHeadSlice
|
||||||
|
case OpSlicePtr:
|
||||||
|
c.Op = OpSlice
|
||||||
|
return OpStructHeadSlicePtr
|
||||||
|
case OpMarshalJSON:
|
||||||
|
return OpStructHeadMarshalJSON
|
||||||
|
case OpMarshalJSONPtr:
|
||||||
|
return OpStructHeadMarshalJSONPtr
|
||||||
|
case OpMarshalText:
|
||||||
|
return OpStructHeadMarshalText
|
||||||
|
case OpMarshalTextPtr:
|
||||||
|
return OpStructHeadMarshalTextPtr
|
||||||
|
}
|
||||||
|
return OpStructHead
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) ToFieldType(isString bool) OpType {
|
||||||
|
switch c.Op {
|
||||||
|
case OpInt:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldIntString
|
||||||
|
}
|
||||||
|
return OpStructFieldInt
|
||||||
|
case OpIntPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldIntPtrString
|
||||||
|
}
|
||||||
|
return OpStructFieldIntPtr
|
||||||
|
case OpUint:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldUintString
|
||||||
|
}
|
||||||
|
return OpStructFieldUint
|
||||||
|
case OpUintPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldUintPtrString
|
||||||
|
}
|
||||||
|
return OpStructFieldUintPtr
|
||||||
|
case OpFloat32:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldFloat32String
|
||||||
|
}
|
||||||
|
return OpStructFieldFloat32
|
||||||
|
case OpFloat32Ptr:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldFloat32PtrString
|
||||||
|
}
|
||||||
|
return OpStructFieldFloat32Ptr
|
||||||
|
case OpFloat64:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldFloat64String
|
||||||
|
}
|
||||||
|
return OpStructFieldFloat64
|
||||||
|
case OpFloat64Ptr:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldFloat64PtrString
|
||||||
|
}
|
||||||
|
return OpStructFieldFloat64Ptr
|
||||||
|
case OpString:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldStringString
|
||||||
|
}
|
||||||
|
return OpStructFieldString
|
||||||
|
case OpStringPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldStringPtrString
|
||||||
|
}
|
||||||
|
return OpStructFieldStringPtr
|
||||||
|
case OpNumber:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldNumberString
|
||||||
|
}
|
||||||
|
return OpStructFieldNumber
|
||||||
|
case OpNumberPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldNumberPtrString
|
||||||
|
}
|
||||||
|
return OpStructFieldNumberPtr
|
||||||
|
case OpBool:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldBoolString
|
||||||
|
}
|
||||||
|
return OpStructFieldBool
|
||||||
|
case OpBoolPtr:
|
||||||
|
if isString {
|
||||||
|
return OpStructFieldBoolPtrString
|
||||||
|
}
|
||||||
|
return OpStructFieldBoolPtr
|
||||||
|
case OpBytes:
|
||||||
|
return OpStructFieldBytes
|
||||||
|
case OpBytesPtr:
|
||||||
|
return OpStructFieldBytesPtr
|
||||||
|
case OpMap:
|
||||||
|
return OpStructFieldMap
|
||||||
|
case OpMapPtr:
|
||||||
|
c.Op = OpMap
|
||||||
|
return OpStructFieldMapPtr
|
||||||
|
case OpArray:
|
||||||
|
return OpStructFieldArray
|
||||||
|
case OpArrayPtr:
|
||||||
|
c.Op = OpArray
|
||||||
|
return OpStructFieldArrayPtr
|
||||||
|
case OpSlice:
|
||||||
|
return OpStructFieldSlice
|
||||||
|
case OpSlicePtr:
|
||||||
|
c.Op = OpSlice
|
||||||
|
return OpStructFieldSlicePtr
|
||||||
|
case OpMarshalJSON:
|
||||||
|
return OpStructFieldMarshalJSON
|
||||||
|
case OpMarshalJSONPtr:
|
||||||
|
return OpStructFieldMarshalJSONPtr
|
||||||
|
case OpMarshalText:
|
||||||
|
return OpStructFieldMarshalText
|
||||||
|
case OpMarshalTextPtr:
|
||||||
|
return OpStructFieldMarshalTextPtr
|
||||||
|
}
|
||||||
|
return OpStructField
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOpCode(ctx *compileContext, op OpType) *Opcode {
|
||||||
|
return newOpCodeWithNext(ctx, op, newEndOp(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func opcodeOffset(idx int) uint32 {
|
||||||
|
return uint32(idx) * uintptrSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyOpcode(code *Opcode) *Opcode {
|
||||||
|
codeMap := map[uintptr]*Opcode{}
|
||||||
|
return code.copy(codeMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTotalLengthToInterfaceOp(code *Opcode) {
|
||||||
|
c := code
|
||||||
|
for c.Op != OpEnd && c.Op != OpInterfaceEnd {
|
||||||
|
if c.Op == OpInterface {
|
||||||
|
c.Length = uint32(code.TotalLength())
|
||||||
|
}
|
||||||
|
switch c.Op.CodeType() {
|
||||||
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||||
|
c = c.End
|
||||||
|
default:
|
||||||
|
c = c.Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToEndCode(code *Opcode) *Opcode {
|
||||||
|
c := code
|
||||||
|
for c.Op != OpEnd && c.Op != OpInterfaceEnd {
|
||||||
|
switch c.Op.CodeType() {
|
||||||
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||||
|
c = c.End
|
||||||
|
default:
|
||||||
|
c = c.Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyToInterfaceOpcode(code *Opcode) *Opcode {
|
||||||
|
copied := copyOpcode(code)
|
||||||
|
c := copied
|
||||||
|
c = ToEndCode(c)
|
||||||
|
c.Idx += uintptrSize
|
||||||
|
c.ElemIdx = c.Idx + uintptrSize
|
||||||
|
c.Length = c.Idx + 2*uintptrSize
|
||||||
|
c.Op = OpInterfaceEnd
|
||||||
|
return copied
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOpCodeWithNext(ctx *compileContext, op OpType, next *Opcode) *Opcode {
|
||||||
|
return &Opcode{
|
||||||
|
Op: op,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
Next: next,
|
||||||
|
Type: ctx.typ,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEndOp(ctx *compileContext) *Opcode {
|
||||||
|
return newOpCodeWithNext(ctx, OpEnd, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) copy(codeMap map[uintptr]*Opcode) *Opcode {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
addr := uintptr(unsafe.Pointer(c))
|
||||||
|
if code, exists := codeMap[addr]; exists {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
copied := &Opcode{
|
||||||
|
Op: c.Op,
|
||||||
|
Key: c.Key,
|
||||||
|
PtrNum: c.PtrNum,
|
||||||
|
NumBitSize: c.NumBitSize,
|
||||||
|
Flags: c.Flags,
|
||||||
|
Idx: c.Idx,
|
||||||
|
Offset: c.Offset,
|
||||||
|
Type: c.Type,
|
||||||
|
DisplayIdx: c.DisplayIdx,
|
||||||
|
DisplayKey: c.DisplayKey,
|
||||||
|
ElemIdx: c.ElemIdx,
|
||||||
|
Length: c.Length,
|
||||||
|
MapIter: c.MapIter,
|
||||||
|
MapPos: c.MapPos,
|
||||||
|
Size: c.Size,
|
||||||
|
Indent: c.Indent,
|
||||||
|
}
|
||||||
|
codeMap[addr] = copied
|
||||||
|
copied.End = c.End.copy(codeMap)
|
||||||
|
copied.PrevField = c.PrevField.copy(codeMap)
|
||||||
|
copied.NextField = c.NextField.copy(codeMap)
|
||||||
|
copied.Next = c.Next.copy(codeMap)
|
||||||
|
copied.Jmp = c.Jmp
|
||||||
|
return copied
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) BeforeLastCode() *Opcode {
|
||||||
|
code := c
|
||||||
|
for {
|
||||||
|
var nextCode *Opcode
|
||||||
|
switch code.Op.CodeType() {
|
||||||
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||||
|
nextCode = code.End
|
||||||
|
default:
|
||||||
|
nextCode = code.Next
|
||||||
|
}
|
||||||
|
if nextCode.Op == OpEnd {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
code = nextCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) TotalLength() int {
|
||||||
|
var idx int
|
||||||
|
code := c
|
||||||
|
for code.Op != OpEnd && code.Op != OpInterfaceEnd {
|
||||||
|
maxIdx := int(code.MaxIdx() / uintptrSize)
|
||||||
|
if idx < maxIdx {
|
||||||
|
idx = maxIdx
|
||||||
|
}
|
||||||
|
if code.Op == OpRecursiveEnd {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch code.Op.CodeType() {
|
||||||
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||||
|
code = code.End
|
||||||
|
default:
|
||||||
|
code = code.Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxIdx := int(code.MaxIdx() / uintptrSize)
|
||||||
|
if idx < maxIdx {
|
||||||
|
idx = maxIdx
|
||||||
|
}
|
||||||
|
return idx + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) decOpcodeIndex() {
|
||||||
|
for code := c; code.Op != OpEnd; {
|
||||||
|
code.DisplayIdx--
|
||||||
|
if code.Idx > 0 {
|
||||||
|
code.Idx -= uintptrSize
|
||||||
|
}
|
||||||
|
if code.ElemIdx > 0 {
|
||||||
|
code.ElemIdx -= uintptrSize
|
||||||
|
}
|
||||||
|
if code.MapIter > 0 {
|
||||||
|
code.MapIter -= uintptrSize
|
||||||
|
}
|
||||||
|
if code.Length > 0 && code.Op.CodeType() != CodeArrayHead && code.Op.CodeType() != CodeArrayElem {
|
||||||
|
code.Length -= uintptrSize
|
||||||
|
}
|
||||||
|
switch code.Op.CodeType() {
|
||||||
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||||
|
code = code.End
|
||||||
|
default:
|
||||||
|
code = code.Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) decIndent() {
|
||||||
|
for code := c; code.Op != OpEnd; {
|
||||||
|
code.Indent--
|
||||||
|
switch code.Op.CodeType() {
|
||||||
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||||
|
code = code.End
|
||||||
|
default:
|
||||||
|
code = code.Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) dumpHead(code *Opcode) string {
|
||||||
|
var length uint32
|
||||||
|
if code.Op.CodeType() == CodeArrayHead {
|
||||||
|
length = code.Length
|
||||||
|
} else {
|
||||||
|
length = code.Length / uintptrSize
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d])`,
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
code.ElemIdx/uintptrSize,
|
||||||
|
length,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) dumpMapHead(code *Opcode) string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
code.ElemIdx/uintptrSize,
|
||||||
|
code.Length/uintptrSize,
|
||||||
|
code.MapIter/uintptrSize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) dumpMapEnd(code *Opcode) string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
`[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`,
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
code.MapPos/uintptrSize,
|
||||||
|
code.Length/uintptrSize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) dumpElem(code *Opcode) string {
|
||||||
|
var length uint32
|
||||||
|
if code.Op.CodeType() == CodeArrayElem {
|
||||||
|
length = code.Length
|
||||||
|
} else {
|
||||||
|
length = code.Length / uintptrSize
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`,
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
code.ElemIdx/uintptrSize,
|
||||||
|
length,
|
||||||
|
code.Size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) dumpField(code *Opcode) string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
`[%d]%s%s ([idx:%d][key:%s][offset:%d])`,
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
code.DisplayKey,
|
||||||
|
code.Offset,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) dumpKey(code *Opcode) string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
code.ElemIdx/uintptrSize,
|
||||||
|
code.Length/uintptrSize,
|
||||||
|
code.MapIter/uintptrSize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) dumpValue(code *Opcode) string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
`[%d]%s%s ([idx:%d][mapIter:%d])`,
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
code.MapIter/uintptrSize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Opcode) Dump() string {
|
||||||
|
codes := []string{}
|
||||||
|
for code := c; code.Op != OpEnd && code.Op != OpInterfaceEnd; {
|
||||||
|
switch code.Op.CodeType() {
|
||||||
|
case CodeSliceHead:
|
||||||
|
codes = append(codes, c.dumpHead(code))
|
||||||
|
code = code.Next
|
||||||
|
case CodeMapHead:
|
||||||
|
codes = append(codes, c.dumpMapHead(code))
|
||||||
|
code = code.Next
|
||||||
|
case CodeArrayElem, CodeSliceElem:
|
||||||
|
codes = append(codes, c.dumpElem(code))
|
||||||
|
code = code.End
|
||||||
|
case CodeMapKey:
|
||||||
|
codes = append(codes, c.dumpKey(code))
|
||||||
|
code = code.End
|
||||||
|
case CodeMapValue:
|
||||||
|
codes = append(codes, c.dumpValue(code))
|
||||||
|
code = code.Next
|
||||||
|
case CodeMapEnd:
|
||||||
|
codes = append(codes, c.dumpMapEnd(code))
|
||||||
|
code = code.Next
|
||||||
|
case CodeStructField:
|
||||||
|
codes = append(codes, c.dumpField(code))
|
||||||
|
code = code.Next
|
||||||
|
case CodeStructEnd:
|
||||||
|
codes = append(codes, c.dumpField(code))
|
||||||
|
code = code.Next
|
||||||
|
default:
|
||||||
|
codes = append(codes, fmt.Sprintf(
|
||||||
|
"[%d]%s%s ([idx:%d])",
|
||||||
|
code.DisplayIdx,
|
||||||
|
strings.Repeat("-", int(code.Indent)),
|
||||||
|
code.Op,
|
||||||
|
code.Idx/uintptrSize,
|
||||||
|
))
|
||||||
|
code = code.Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(codes, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func prevField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode {
|
||||||
|
if _, exists := removedFields[code]; exists {
|
||||||
|
return prevField(code.PrevField, removedFields)
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode {
|
||||||
|
if _, exists := removedFields[code]; exists {
|
||||||
|
return nextField(code.NextField, removedFields)
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkPrevToNextField(cur *Opcode, removedFields map[*Opcode]struct{}) {
|
||||||
|
prev := prevField(cur.PrevField, removedFields)
|
||||||
|
prev.NextField = nextField(cur.NextField, removedFields)
|
||||||
|
code := prev
|
||||||
|
fcode := cur
|
||||||
|
for {
|
||||||
|
var nextCode *Opcode
|
||||||
|
switch code.Op.CodeType() {
|
||||||
|
case CodeArrayElem, CodeSliceElem, CodeMapKey:
|
||||||
|
nextCode = code.End
|
||||||
|
default:
|
||||||
|
nextCode = code.Next
|
||||||
|
}
|
||||||
|
if nextCode == fcode {
|
||||||
|
code.Next = fcode.Next
|
||||||
|
break
|
||||||
|
} else if nextCode.Op == OpEnd {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
code = nextCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSliceHeaderCode(ctx *compileContext) *Opcode {
|
||||||
|
idx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
length := opcodeOffset(ctx.ptrIndex)
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpSlice,
|
||||||
|
Idx: idx,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
ElemIdx: elemIdx,
|
||||||
|
Length: length,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode {
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpSliceElem,
|
||||||
|
Idx: head.Idx,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
ElemIdx: head.ElemIdx,
|
||||||
|
Length: head.Length,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
Size: uint32(size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode {
|
||||||
|
idx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpArray,
|
||||||
|
Idx: idx,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
ElemIdx: elemIdx,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
Length: uint32(alen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintptr) *Opcode {
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpArrayElem,
|
||||||
|
Idx: head.Idx,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
ElemIdx: head.ElemIdx,
|
||||||
|
Length: uint32(length),
|
||||||
|
Indent: ctx.indent,
|
||||||
|
Size: uint32(size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapHeaderCode(ctx *compileContext) *Opcode {
|
||||||
|
idx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
length := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
mapIter := opcodeOffset(ctx.ptrIndex)
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpMap,
|
||||||
|
Idx: idx,
|
||||||
|
Type: ctx.typ,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
ElemIdx: elemIdx,
|
||||||
|
Length: length,
|
||||||
|
MapIter: mapIter,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapKeyCode(ctx *compileContext, head *Opcode) *Opcode {
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpMapKey,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
ElemIdx: head.ElemIdx,
|
||||||
|
Length: head.Length,
|
||||||
|
MapIter: head.MapIter,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapValueCode(ctx *compileContext, head *Opcode) *Opcode {
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpMapValue,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
ElemIdx: head.ElemIdx,
|
||||||
|
Length: head.Length,
|
||||||
|
MapIter: head.MapIter,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode {
|
||||||
|
mapPos := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
idx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpMapEnd,
|
||||||
|
Idx: idx,
|
||||||
|
Next: newEndOp(ctx),
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Length: head.Length,
|
||||||
|
MapPos: mapPos,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInterfaceCode(ctx *compileContext) *Opcode {
|
||||||
|
var flag OpFlags
|
||||||
|
if ctx.typ.NumMethod() > 0 {
|
||||||
|
flag |= NonEmptyInterfaceFlags
|
||||||
|
}
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpInterface,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
Next: newEndOp(ctx),
|
||||||
|
Type: ctx.typ,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
Flags: flag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRecursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode {
|
||||||
|
return &Opcode{
|
||||||
|
Op: OpRecursive,
|
||||||
|
Idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
Next: newEndOp(ctx),
|
||||||
|
Type: ctx.typ,
|
||||||
|
DisplayIdx: ctx.opcodeIndex,
|
||||||
|
Indent: ctx.indent,
|
||||||
|
Jmp: jmp,
|
||||||
|
}
|
||||||
|
}
|
41
vendor/github.com/goccy/go-json/internal/encoder/option.go
generated
vendored
Normal file
41
vendor/github.com/goccy/go-json/internal/encoder/option.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type OptionFlag uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
HTMLEscapeOption OptionFlag = 1 << iota
|
||||||
|
IndentOption
|
||||||
|
UnorderedMapOption
|
||||||
|
DebugOption
|
||||||
|
ColorizeOption
|
||||||
|
ContextOption
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option struct {
|
||||||
|
Flag OptionFlag
|
||||||
|
ColorScheme *ColorScheme
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type EncodeFormat struct {
|
||||||
|
Header string
|
||||||
|
Footer string
|
||||||
|
}
|
||||||
|
|
||||||
|
type EncodeFormatScheme struct {
|
||||||
|
Int EncodeFormat
|
||||||
|
Uint EncodeFormat
|
||||||
|
Float EncodeFormat
|
||||||
|
Bool EncodeFormat
|
||||||
|
String EncodeFormat
|
||||||
|
Binary EncodeFormat
|
||||||
|
ObjectKey EncodeFormat
|
||||||
|
Null EncodeFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
ColorScheme = EncodeFormatScheme
|
||||||
|
ColorFormat = EncodeFormat
|
||||||
|
)
|
934
vendor/github.com/goccy/go-json/internal/encoder/optype.go
generated
vendored
Normal file
934
vendor/github.com/goccy/go-json/internal/encoder/optype.go
generated
vendored
Normal file
@ -0,0 +1,934 @@
|
|||||||
|
// Code generated by internal/cmd/generator. DO NOT EDIT!
|
||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CodeType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
CodeOp CodeType = 0
|
||||||
|
CodeArrayHead CodeType = 1
|
||||||
|
CodeArrayElem CodeType = 2
|
||||||
|
CodeSliceHead CodeType = 3
|
||||||
|
CodeSliceElem CodeType = 4
|
||||||
|
CodeMapHead CodeType = 5
|
||||||
|
CodeMapKey CodeType = 6
|
||||||
|
CodeMapValue CodeType = 7
|
||||||
|
CodeMapEnd CodeType = 8
|
||||||
|
CodeRecursive CodeType = 9
|
||||||
|
CodeStructField CodeType = 10
|
||||||
|
CodeStructEnd CodeType = 11
|
||||||
|
)
|
||||||
|
|
||||||
|
var opTypeStrings = [401]string{
|
||||||
|
"End",
|
||||||
|
"Interface",
|
||||||
|
"Ptr",
|
||||||
|
"SliceElem",
|
||||||
|
"SliceEnd",
|
||||||
|
"ArrayElem",
|
||||||
|
"ArrayEnd",
|
||||||
|
"MapKey",
|
||||||
|
"MapValue",
|
||||||
|
"MapEnd",
|
||||||
|
"Recursive",
|
||||||
|
"RecursivePtr",
|
||||||
|
"RecursiveEnd",
|
||||||
|
"InterfaceEnd",
|
||||||
|
"StructAnonymousEnd",
|
||||||
|
"Int",
|
||||||
|
"Uint",
|
||||||
|
"Float32",
|
||||||
|
"Float64",
|
||||||
|
"Bool",
|
||||||
|
"String",
|
||||||
|
"Bytes",
|
||||||
|
"Number",
|
||||||
|
"Array",
|
||||||
|
"Map",
|
||||||
|
"Slice",
|
||||||
|
"Struct",
|
||||||
|
"MarshalJSON",
|
||||||
|
"MarshalText",
|
||||||
|
"IntString",
|
||||||
|
"UintString",
|
||||||
|
"Float32String",
|
||||||
|
"Float64String",
|
||||||
|
"BoolString",
|
||||||
|
"StringString",
|
||||||
|
"NumberString",
|
||||||
|
"IntPtr",
|
||||||
|
"UintPtr",
|
||||||
|
"Float32Ptr",
|
||||||
|
"Float64Ptr",
|
||||||
|
"BoolPtr",
|
||||||
|
"StringPtr",
|
||||||
|
"BytesPtr",
|
||||||
|
"NumberPtr",
|
||||||
|
"ArrayPtr",
|
||||||
|
"MapPtr",
|
||||||
|
"SlicePtr",
|
||||||
|
"MarshalJSONPtr",
|
||||||
|
"MarshalTextPtr",
|
||||||
|
"InterfacePtr",
|
||||||
|
"IntPtrString",
|
||||||
|
"UintPtrString",
|
||||||
|
"Float32PtrString",
|
||||||
|
"Float64PtrString",
|
||||||
|
"BoolPtrString",
|
||||||
|
"StringPtrString",
|
||||||
|
"NumberPtrString",
|
||||||
|
"StructHeadInt",
|
||||||
|
"StructHeadOmitEmptyInt",
|
||||||
|
"StructPtrHeadInt",
|
||||||
|
"StructPtrHeadOmitEmptyInt",
|
||||||
|
"StructHeadUint",
|
||||||
|
"StructHeadOmitEmptyUint",
|
||||||
|
"StructPtrHeadUint",
|
||||||
|
"StructPtrHeadOmitEmptyUint",
|
||||||
|
"StructHeadFloat32",
|
||||||
|
"StructHeadOmitEmptyFloat32",
|
||||||
|
"StructPtrHeadFloat32",
|
||||||
|
"StructPtrHeadOmitEmptyFloat32",
|
||||||
|
"StructHeadFloat64",
|
||||||
|
"StructHeadOmitEmptyFloat64",
|
||||||
|
"StructPtrHeadFloat64",
|
||||||
|
"StructPtrHeadOmitEmptyFloat64",
|
||||||
|
"StructHeadBool",
|
||||||
|
"StructHeadOmitEmptyBool",
|
||||||
|
"StructPtrHeadBool",
|
||||||
|
"StructPtrHeadOmitEmptyBool",
|
||||||
|
"StructHeadString",
|
||||||
|
"StructHeadOmitEmptyString",
|
||||||
|
"StructPtrHeadString",
|
||||||
|
"StructPtrHeadOmitEmptyString",
|
||||||
|
"StructHeadBytes",
|
||||||
|
"StructHeadOmitEmptyBytes",
|
||||||
|
"StructPtrHeadBytes",
|
||||||
|
"StructPtrHeadOmitEmptyBytes",
|
||||||
|
"StructHeadNumber",
|
||||||
|
"StructHeadOmitEmptyNumber",
|
||||||
|
"StructPtrHeadNumber",
|
||||||
|
"StructPtrHeadOmitEmptyNumber",
|
||||||
|
"StructHeadArray",
|
||||||
|
"StructHeadOmitEmptyArray",
|
||||||
|
"StructPtrHeadArray",
|
||||||
|
"StructPtrHeadOmitEmptyArray",
|
||||||
|
"StructHeadMap",
|
||||||
|
"StructHeadOmitEmptyMap",
|
||||||
|
"StructPtrHeadMap",
|
||||||
|
"StructPtrHeadOmitEmptyMap",
|
||||||
|
"StructHeadSlice",
|
||||||
|
"StructHeadOmitEmptySlice",
|
||||||
|
"StructPtrHeadSlice",
|
||||||
|
"StructPtrHeadOmitEmptySlice",
|
||||||
|
"StructHeadStruct",
|
||||||
|
"StructHeadOmitEmptyStruct",
|
||||||
|
"StructPtrHeadStruct",
|
||||||
|
"StructPtrHeadOmitEmptyStruct",
|
||||||
|
"StructHeadMarshalJSON",
|
||||||
|
"StructHeadOmitEmptyMarshalJSON",
|
||||||
|
"StructPtrHeadMarshalJSON",
|
||||||
|
"StructPtrHeadOmitEmptyMarshalJSON",
|
||||||
|
"StructHeadMarshalText",
|
||||||
|
"StructHeadOmitEmptyMarshalText",
|
||||||
|
"StructPtrHeadMarshalText",
|
||||||
|
"StructPtrHeadOmitEmptyMarshalText",
|
||||||
|
"StructHeadIntString",
|
||||||
|
"StructHeadOmitEmptyIntString",
|
||||||
|
"StructPtrHeadIntString",
|
||||||
|
"StructPtrHeadOmitEmptyIntString",
|
||||||
|
"StructHeadUintString",
|
||||||
|
"StructHeadOmitEmptyUintString",
|
||||||
|
"StructPtrHeadUintString",
|
||||||
|
"StructPtrHeadOmitEmptyUintString",
|
||||||
|
"StructHeadFloat32String",
|
||||||
|
"StructHeadOmitEmptyFloat32String",
|
||||||
|
"StructPtrHeadFloat32String",
|
||||||
|
"StructPtrHeadOmitEmptyFloat32String",
|
||||||
|
"StructHeadFloat64String",
|
||||||
|
"StructHeadOmitEmptyFloat64String",
|
||||||
|
"StructPtrHeadFloat64String",
|
||||||
|
"StructPtrHeadOmitEmptyFloat64String",
|
||||||
|
"StructHeadBoolString",
|
||||||
|
"StructHeadOmitEmptyBoolString",
|
||||||
|
"StructPtrHeadBoolString",
|
||||||
|
"StructPtrHeadOmitEmptyBoolString",
|
||||||
|
"StructHeadStringString",
|
||||||
|
"StructHeadOmitEmptyStringString",
|
||||||
|
"StructPtrHeadStringString",
|
||||||
|
"StructPtrHeadOmitEmptyStringString",
|
||||||
|
"StructHeadNumberString",
|
||||||
|
"StructHeadOmitEmptyNumberString",
|
||||||
|
"StructPtrHeadNumberString",
|
||||||
|
"StructPtrHeadOmitEmptyNumberString",
|
||||||
|
"StructHeadIntPtr",
|
||||||
|
"StructHeadOmitEmptyIntPtr",
|
||||||
|
"StructPtrHeadIntPtr",
|
||||||
|
"StructPtrHeadOmitEmptyIntPtr",
|
||||||
|
"StructHeadUintPtr",
|
||||||
|
"StructHeadOmitEmptyUintPtr",
|
||||||
|
"StructPtrHeadUintPtr",
|
||||||
|
"StructPtrHeadOmitEmptyUintPtr",
|
||||||
|
"StructHeadFloat32Ptr",
|
||||||
|
"StructHeadOmitEmptyFloat32Ptr",
|
||||||
|
"StructPtrHeadFloat32Ptr",
|
||||||
|
"StructPtrHeadOmitEmptyFloat32Ptr",
|
||||||
|
"StructHeadFloat64Ptr",
|
||||||
|
"StructHeadOmitEmptyFloat64Ptr",
|
||||||
|
"StructPtrHeadFloat64Ptr",
|
||||||
|
"StructPtrHeadOmitEmptyFloat64Ptr",
|
||||||
|
"StructHeadBoolPtr",
|
||||||
|
"StructHeadOmitEmptyBoolPtr",
|
||||||
|
"StructPtrHeadBoolPtr",
|
||||||
|
"StructPtrHeadOmitEmptyBoolPtr",
|
||||||
|
"StructHeadStringPtr",
|
||||||
|
"StructHeadOmitEmptyStringPtr",
|
||||||
|
"StructPtrHeadStringPtr",
|
||||||
|
"StructPtrHeadOmitEmptyStringPtr",
|
||||||
|
"StructHeadBytesPtr",
|
||||||
|
"StructHeadOmitEmptyBytesPtr",
|
||||||
|
"StructPtrHeadBytesPtr",
|
||||||
|
"StructPtrHeadOmitEmptyBytesPtr",
|
||||||
|
"StructHeadNumberPtr",
|
||||||
|
"StructHeadOmitEmptyNumberPtr",
|
||||||
|
"StructPtrHeadNumberPtr",
|
||||||
|
"StructPtrHeadOmitEmptyNumberPtr",
|
||||||
|
"StructHeadArrayPtr",
|
||||||
|
"StructHeadOmitEmptyArrayPtr",
|
||||||
|
"StructPtrHeadArrayPtr",
|
||||||
|
"StructPtrHeadOmitEmptyArrayPtr",
|
||||||
|
"StructHeadMapPtr",
|
||||||
|
"StructHeadOmitEmptyMapPtr",
|
||||||
|
"StructPtrHeadMapPtr",
|
||||||
|
"StructPtrHeadOmitEmptyMapPtr",
|
||||||
|
"StructHeadSlicePtr",
|
||||||
|
"StructHeadOmitEmptySlicePtr",
|
||||||
|
"StructPtrHeadSlicePtr",
|
||||||
|
"StructPtrHeadOmitEmptySlicePtr",
|
||||||
|
"StructHeadMarshalJSONPtr",
|
||||||
|
"StructHeadOmitEmptyMarshalJSONPtr",
|
||||||
|
"StructPtrHeadMarshalJSONPtr",
|
||||||
|
"StructPtrHeadOmitEmptyMarshalJSONPtr",
|
||||||
|
"StructHeadMarshalTextPtr",
|
||||||
|
"StructHeadOmitEmptyMarshalTextPtr",
|
||||||
|
"StructPtrHeadMarshalTextPtr",
|
||||||
|
"StructPtrHeadOmitEmptyMarshalTextPtr",
|
||||||
|
"StructHeadInterfacePtr",
|
||||||
|
"StructHeadOmitEmptyInterfacePtr",
|
||||||
|
"StructPtrHeadInterfacePtr",
|
||||||
|
"StructPtrHeadOmitEmptyInterfacePtr",
|
||||||
|
"StructHeadIntPtrString",
|
||||||
|
"StructHeadOmitEmptyIntPtrString",
|
||||||
|
"StructPtrHeadIntPtrString",
|
||||||
|
"StructPtrHeadOmitEmptyIntPtrString",
|
||||||
|
"StructHeadUintPtrString",
|
||||||
|
"StructHeadOmitEmptyUintPtrString",
|
||||||
|
"StructPtrHeadUintPtrString",
|
||||||
|
"StructPtrHeadOmitEmptyUintPtrString",
|
||||||
|
"StructHeadFloat32PtrString",
|
||||||
|
"StructHeadOmitEmptyFloat32PtrString",
|
||||||
|
"StructPtrHeadFloat32PtrString",
|
||||||
|
"StructPtrHeadOmitEmptyFloat32PtrString",
|
||||||
|
"StructHeadFloat64PtrString",
|
||||||
|
"StructHeadOmitEmptyFloat64PtrString",
|
||||||
|
"StructPtrHeadFloat64PtrString",
|
||||||
|
"StructPtrHeadOmitEmptyFloat64PtrString",
|
||||||
|
"StructHeadBoolPtrString",
|
||||||
|
"StructHeadOmitEmptyBoolPtrString",
|
||||||
|
"StructPtrHeadBoolPtrString",
|
||||||
|
"StructPtrHeadOmitEmptyBoolPtrString",
|
||||||
|
"StructHeadStringPtrString",
|
||||||
|
"StructHeadOmitEmptyStringPtrString",
|
||||||
|
"StructPtrHeadStringPtrString",
|
||||||
|
"StructPtrHeadOmitEmptyStringPtrString",
|
||||||
|
"StructHeadNumberPtrString",
|
||||||
|
"StructHeadOmitEmptyNumberPtrString",
|
||||||
|
"StructPtrHeadNumberPtrString",
|
||||||
|
"StructPtrHeadOmitEmptyNumberPtrString",
|
||||||
|
"StructHead",
|
||||||
|
"StructHeadOmitEmpty",
|
||||||
|
"StructPtrHead",
|
||||||
|
"StructPtrHeadOmitEmpty",
|
||||||
|
"StructFieldInt",
|
||||||
|
"StructFieldOmitEmptyInt",
|
||||||
|
"StructEndInt",
|
||||||
|
"StructEndOmitEmptyInt",
|
||||||
|
"StructFieldUint",
|
||||||
|
"StructFieldOmitEmptyUint",
|
||||||
|
"StructEndUint",
|
||||||
|
"StructEndOmitEmptyUint",
|
||||||
|
"StructFieldFloat32",
|
||||||
|
"StructFieldOmitEmptyFloat32",
|
||||||
|
"StructEndFloat32",
|
||||||
|
"StructEndOmitEmptyFloat32",
|
||||||
|
"StructFieldFloat64",
|
||||||
|
"StructFieldOmitEmptyFloat64",
|
||||||
|
"StructEndFloat64",
|
||||||
|
"StructEndOmitEmptyFloat64",
|
||||||
|
"StructFieldBool",
|
||||||
|
"StructFieldOmitEmptyBool",
|
||||||
|
"StructEndBool",
|
||||||
|
"StructEndOmitEmptyBool",
|
||||||
|
"StructFieldString",
|
||||||
|
"StructFieldOmitEmptyString",
|
||||||
|
"StructEndString",
|
||||||
|
"StructEndOmitEmptyString",
|
||||||
|
"StructFieldBytes",
|
||||||
|
"StructFieldOmitEmptyBytes",
|
||||||
|
"StructEndBytes",
|
||||||
|
"StructEndOmitEmptyBytes",
|
||||||
|
"StructFieldNumber",
|
||||||
|
"StructFieldOmitEmptyNumber",
|
||||||
|
"StructEndNumber",
|
||||||
|
"StructEndOmitEmptyNumber",
|
||||||
|
"StructFieldArray",
|
||||||
|
"StructFieldOmitEmptyArray",
|
||||||
|
"StructEndArray",
|
||||||
|
"StructEndOmitEmptyArray",
|
||||||
|
"StructFieldMap",
|
||||||
|
"StructFieldOmitEmptyMap",
|
||||||
|
"StructEndMap",
|
||||||
|
"StructEndOmitEmptyMap",
|
||||||
|
"StructFieldSlice",
|
||||||
|
"StructFieldOmitEmptySlice",
|
||||||
|
"StructEndSlice",
|
||||||
|
"StructEndOmitEmptySlice",
|
||||||
|
"StructFieldStruct",
|
||||||
|
"StructFieldOmitEmptyStruct",
|
||||||
|
"StructEndStruct",
|
||||||
|
"StructEndOmitEmptyStruct",
|
||||||
|
"StructFieldMarshalJSON",
|
||||||
|
"StructFieldOmitEmptyMarshalJSON",
|
||||||
|
"StructEndMarshalJSON",
|
||||||
|
"StructEndOmitEmptyMarshalJSON",
|
||||||
|
"StructFieldMarshalText",
|
||||||
|
"StructFieldOmitEmptyMarshalText",
|
||||||
|
"StructEndMarshalText",
|
||||||
|
"StructEndOmitEmptyMarshalText",
|
||||||
|
"StructFieldIntString",
|
||||||
|
"StructFieldOmitEmptyIntString",
|
||||||
|
"StructEndIntString",
|
||||||
|
"StructEndOmitEmptyIntString",
|
||||||
|
"StructFieldUintString",
|
||||||
|
"StructFieldOmitEmptyUintString",
|
||||||
|
"StructEndUintString",
|
||||||
|
"StructEndOmitEmptyUintString",
|
||||||
|
"StructFieldFloat32String",
|
||||||
|
"StructFieldOmitEmptyFloat32String",
|
||||||
|
"StructEndFloat32String",
|
||||||
|
"StructEndOmitEmptyFloat32String",
|
||||||
|
"StructFieldFloat64String",
|
||||||
|
"StructFieldOmitEmptyFloat64String",
|
||||||
|
"StructEndFloat64String",
|
||||||
|
"StructEndOmitEmptyFloat64String",
|
||||||
|
"StructFieldBoolString",
|
||||||
|
"StructFieldOmitEmptyBoolString",
|
||||||
|
"StructEndBoolString",
|
||||||
|
"StructEndOmitEmptyBoolString",
|
||||||
|
"StructFieldStringString",
|
||||||
|
"StructFieldOmitEmptyStringString",
|
||||||
|
"StructEndStringString",
|
||||||
|
"StructEndOmitEmptyStringString",
|
||||||
|
"StructFieldNumberString",
|
||||||
|
"StructFieldOmitEmptyNumberString",
|
||||||
|
"StructEndNumberString",
|
||||||
|
"StructEndOmitEmptyNumberString",
|
||||||
|
"StructFieldIntPtr",
|
||||||
|
"StructFieldOmitEmptyIntPtr",
|
||||||
|
"StructEndIntPtr",
|
||||||
|
"StructEndOmitEmptyIntPtr",
|
||||||
|
"StructFieldUintPtr",
|
||||||
|
"StructFieldOmitEmptyUintPtr",
|
||||||
|
"StructEndUintPtr",
|
||||||
|
"StructEndOmitEmptyUintPtr",
|
||||||
|
"StructFieldFloat32Ptr",
|
||||||
|
"StructFieldOmitEmptyFloat32Ptr",
|
||||||
|
"StructEndFloat32Ptr",
|
||||||
|
"StructEndOmitEmptyFloat32Ptr",
|
||||||
|
"StructFieldFloat64Ptr",
|
||||||
|
"StructFieldOmitEmptyFloat64Ptr",
|
||||||
|
"StructEndFloat64Ptr",
|
||||||
|
"StructEndOmitEmptyFloat64Ptr",
|
||||||
|
"StructFieldBoolPtr",
|
||||||
|
"StructFieldOmitEmptyBoolPtr",
|
||||||
|
"StructEndBoolPtr",
|
||||||
|
"StructEndOmitEmptyBoolPtr",
|
||||||
|
"StructFieldStringPtr",
|
||||||
|
"StructFieldOmitEmptyStringPtr",
|
||||||
|
"StructEndStringPtr",
|
||||||
|
"StructEndOmitEmptyStringPtr",
|
||||||
|
"StructFieldBytesPtr",
|
||||||
|
"StructFieldOmitEmptyBytesPtr",
|
||||||
|
"StructEndBytesPtr",
|
||||||
|
"StructEndOmitEmptyBytesPtr",
|
||||||
|
"StructFieldNumberPtr",
|
||||||
|
"StructFieldOmitEmptyNumberPtr",
|
||||||
|
"StructEndNumberPtr",
|
||||||
|
"StructEndOmitEmptyNumberPtr",
|
||||||
|
"StructFieldArrayPtr",
|
||||||
|
"StructFieldOmitEmptyArrayPtr",
|
||||||
|
"StructEndArrayPtr",
|
||||||
|
"StructEndOmitEmptyArrayPtr",
|
||||||
|
"StructFieldMapPtr",
|
||||||
|
"StructFieldOmitEmptyMapPtr",
|
||||||
|
"StructEndMapPtr",
|
||||||
|
"StructEndOmitEmptyMapPtr",
|
||||||
|
"StructFieldSlicePtr",
|
||||||
|
"StructFieldOmitEmptySlicePtr",
|
||||||
|
"StructEndSlicePtr",
|
||||||
|
"StructEndOmitEmptySlicePtr",
|
||||||
|
"StructFieldMarshalJSONPtr",
|
||||||
|
"StructFieldOmitEmptyMarshalJSONPtr",
|
||||||
|
"StructEndMarshalJSONPtr",
|
||||||
|
"StructEndOmitEmptyMarshalJSONPtr",
|
||||||
|
"StructFieldMarshalTextPtr",
|
||||||
|
"StructFieldOmitEmptyMarshalTextPtr",
|
||||||
|
"StructEndMarshalTextPtr",
|
||||||
|
"StructEndOmitEmptyMarshalTextPtr",
|
||||||
|
"StructFieldInterfacePtr",
|
||||||
|
"StructFieldOmitEmptyInterfacePtr",
|
||||||
|
"StructEndInterfacePtr",
|
||||||
|
"StructEndOmitEmptyInterfacePtr",
|
||||||
|
"StructFieldIntPtrString",
|
||||||
|
"StructFieldOmitEmptyIntPtrString",
|
||||||
|
"StructEndIntPtrString",
|
||||||
|
"StructEndOmitEmptyIntPtrString",
|
||||||
|
"StructFieldUintPtrString",
|
||||||
|
"StructFieldOmitEmptyUintPtrString",
|
||||||
|
"StructEndUintPtrString",
|
||||||
|
"StructEndOmitEmptyUintPtrString",
|
||||||
|
"StructFieldFloat32PtrString",
|
||||||
|
"StructFieldOmitEmptyFloat32PtrString",
|
||||||
|
"StructEndFloat32PtrString",
|
||||||
|
"StructEndOmitEmptyFloat32PtrString",
|
||||||
|
"StructFieldFloat64PtrString",
|
||||||
|
"StructFieldOmitEmptyFloat64PtrString",
|
||||||
|
"StructEndFloat64PtrString",
|
||||||
|
"StructEndOmitEmptyFloat64PtrString",
|
||||||
|
"StructFieldBoolPtrString",
|
||||||
|
"StructFieldOmitEmptyBoolPtrString",
|
||||||
|
"StructEndBoolPtrString",
|
||||||
|
"StructEndOmitEmptyBoolPtrString",
|
||||||
|
"StructFieldStringPtrString",
|
||||||
|
"StructFieldOmitEmptyStringPtrString",
|
||||||
|
"StructEndStringPtrString",
|
||||||
|
"StructEndOmitEmptyStringPtrString",
|
||||||
|
"StructFieldNumberPtrString",
|
||||||
|
"StructFieldOmitEmptyNumberPtrString",
|
||||||
|
"StructEndNumberPtrString",
|
||||||
|
"StructEndOmitEmptyNumberPtrString",
|
||||||
|
"StructField",
|
||||||
|
"StructFieldOmitEmpty",
|
||||||
|
"StructEnd",
|
||||||
|
"StructEndOmitEmpty",
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpType uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
OpEnd OpType = 0
|
||||||
|
OpInterface OpType = 1
|
||||||
|
OpPtr OpType = 2
|
||||||
|
OpSliceElem OpType = 3
|
||||||
|
OpSliceEnd OpType = 4
|
||||||
|
OpArrayElem OpType = 5
|
||||||
|
OpArrayEnd OpType = 6
|
||||||
|
OpMapKey OpType = 7
|
||||||
|
OpMapValue OpType = 8
|
||||||
|
OpMapEnd OpType = 9
|
||||||
|
OpRecursive OpType = 10
|
||||||
|
OpRecursivePtr OpType = 11
|
||||||
|
OpRecursiveEnd OpType = 12
|
||||||
|
OpInterfaceEnd OpType = 13
|
||||||
|
OpStructAnonymousEnd OpType = 14
|
||||||
|
OpInt OpType = 15
|
||||||
|
OpUint OpType = 16
|
||||||
|
OpFloat32 OpType = 17
|
||||||
|
OpFloat64 OpType = 18
|
||||||
|
OpBool OpType = 19
|
||||||
|
OpString OpType = 20
|
||||||
|
OpBytes OpType = 21
|
||||||
|
OpNumber OpType = 22
|
||||||
|
OpArray OpType = 23
|
||||||
|
OpMap OpType = 24
|
||||||
|
OpSlice OpType = 25
|
||||||
|
OpStruct OpType = 26
|
||||||
|
OpMarshalJSON OpType = 27
|
||||||
|
OpMarshalText OpType = 28
|
||||||
|
OpIntString OpType = 29
|
||||||
|
OpUintString OpType = 30
|
||||||
|
OpFloat32String OpType = 31
|
||||||
|
OpFloat64String OpType = 32
|
||||||
|
OpBoolString OpType = 33
|
||||||
|
OpStringString OpType = 34
|
||||||
|
OpNumberString OpType = 35
|
||||||
|
OpIntPtr OpType = 36
|
||||||
|
OpUintPtr OpType = 37
|
||||||
|
OpFloat32Ptr OpType = 38
|
||||||
|
OpFloat64Ptr OpType = 39
|
||||||
|
OpBoolPtr OpType = 40
|
||||||
|
OpStringPtr OpType = 41
|
||||||
|
OpBytesPtr OpType = 42
|
||||||
|
OpNumberPtr OpType = 43
|
||||||
|
OpArrayPtr OpType = 44
|
||||||
|
OpMapPtr OpType = 45
|
||||||
|
OpSlicePtr OpType = 46
|
||||||
|
OpMarshalJSONPtr OpType = 47
|
||||||
|
OpMarshalTextPtr OpType = 48
|
||||||
|
OpInterfacePtr OpType = 49
|
||||||
|
OpIntPtrString OpType = 50
|
||||||
|
OpUintPtrString OpType = 51
|
||||||
|
OpFloat32PtrString OpType = 52
|
||||||
|
OpFloat64PtrString OpType = 53
|
||||||
|
OpBoolPtrString OpType = 54
|
||||||
|
OpStringPtrString OpType = 55
|
||||||
|
OpNumberPtrString OpType = 56
|
||||||
|
OpStructHeadInt OpType = 57
|
||||||
|
OpStructHeadOmitEmptyInt OpType = 58
|
||||||
|
OpStructPtrHeadInt OpType = 59
|
||||||
|
OpStructPtrHeadOmitEmptyInt OpType = 60
|
||||||
|
OpStructHeadUint OpType = 61
|
||||||
|
OpStructHeadOmitEmptyUint OpType = 62
|
||||||
|
OpStructPtrHeadUint OpType = 63
|
||||||
|
OpStructPtrHeadOmitEmptyUint OpType = 64
|
||||||
|
OpStructHeadFloat32 OpType = 65
|
||||||
|
OpStructHeadOmitEmptyFloat32 OpType = 66
|
||||||
|
OpStructPtrHeadFloat32 OpType = 67
|
||||||
|
OpStructPtrHeadOmitEmptyFloat32 OpType = 68
|
||||||
|
OpStructHeadFloat64 OpType = 69
|
||||||
|
OpStructHeadOmitEmptyFloat64 OpType = 70
|
||||||
|
OpStructPtrHeadFloat64 OpType = 71
|
||||||
|
OpStructPtrHeadOmitEmptyFloat64 OpType = 72
|
||||||
|
OpStructHeadBool OpType = 73
|
||||||
|
OpStructHeadOmitEmptyBool OpType = 74
|
||||||
|
OpStructPtrHeadBool OpType = 75
|
||||||
|
OpStructPtrHeadOmitEmptyBool OpType = 76
|
||||||
|
OpStructHeadString OpType = 77
|
||||||
|
OpStructHeadOmitEmptyString OpType = 78
|
||||||
|
OpStructPtrHeadString OpType = 79
|
||||||
|
OpStructPtrHeadOmitEmptyString OpType = 80
|
||||||
|
OpStructHeadBytes OpType = 81
|
||||||
|
OpStructHeadOmitEmptyBytes OpType = 82
|
||||||
|
OpStructPtrHeadBytes OpType = 83
|
||||||
|
OpStructPtrHeadOmitEmptyBytes OpType = 84
|
||||||
|
OpStructHeadNumber OpType = 85
|
||||||
|
OpStructHeadOmitEmptyNumber OpType = 86
|
||||||
|
OpStructPtrHeadNumber OpType = 87
|
||||||
|
OpStructPtrHeadOmitEmptyNumber OpType = 88
|
||||||
|
OpStructHeadArray OpType = 89
|
||||||
|
OpStructHeadOmitEmptyArray OpType = 90
|
||||||
|
OpStructPtrHeadArray OpType = 91
|
||||||
|
OpStructPtrHeadOmitEmptyArray OpType = 92
|
||||||
|
OpStructHeadMap OpType = 93
|
||||||
|
OpStructHeadOmitEmptyMap OpType = 94
|
||||||
|
OpStructPtrHeadMap OpType = 95
|
||||||
|
OpStructPtrHeadOmitEmptyMap OpType = 96
|
||||||
|
OpStructHeadSlice OpType = 97
|
||||||
|
OpStructHeadOmitEmptySlice OpType = 98
|
||||||
|
OpStructPtrHeadSlice OpType = 99
|
||||||
|
OpStructPtrHeadOmitEmptySlice OpType = 100
|
||||||
|
OpStructHeadStruct OpType = 101
|
||||||
|
OpStructHeadOmitEmptyStruct OpType = 102
|
||||||
|
OpStructPtrHeadStruct OpType = 103
|
||||||
|
OpStructPtrHeadOmitEmptyStruct OpType = 104
|
||||||
|
OpStructHeadMarshalJSON OpType = 105
|
||||||
|
OpStructHeadOmitEmptyMarshalJSON OpType = 106
|
||||||
|
OpStructPtrHeadMarshalJSON OpType = 107
|
||||||
|
OpStructPtrHeadOmitEmptyMarshalJSON OpType = 108
|
||||||
|
OpStructHeadMarshalText OpType = 109
|
||||||
|
OpStructHeadOmitEmptyMarshalText OpType = 110
|
||||||
|
OpStructPtrHeadMarshalText OpType = 111
|
||||||
|
OpStructPtrHeadOmitEmptyMarshalText OpType = 112
|
||||||
|
OpStructHeadIntString OpType = 113
|
||||||
|
OpStructHeadOmitEmptyIntString OpType = 114
|
||||||
|
OpStructPtrHeadIntString OpType = 115
|
||||||
|
OpStructPtrHeadOmitEmptyIntString OpType = 116
|
||||||
|
OpStructHeadUintString OpType = 117
|
||||||
|
OpStructHeadOmitEmptyUintString OpType = 118
|
||||||
|
OpStructPtrHeadUintString OpType = 119
|
||||||
|
OpStructPtrHeadOmitEmptyUintString OpType = 120
|
||||||
|
OpStructHeadFloat32String OpType = 121
|
||||||
|
OpStructHeadOmitEmptyFloat32String OpType = 122
|
||||||
|
OpStructPtrHeadFloat32String OpType = 123
|
||||||
|
OpStructPtrHeadOmitEmptyFloat32String OpType = 124
|
||||||
|
OpStructHeadFloat64String OpType = 125
|
||||||
|
OpStructHeadOmitEmptyFloat64String OpType = 126
|
||||||
|
OpStructPtrHeadFloat64String OpType = 127
|
||||||
|
OpStructPtrHeadOmitEmptyFloat64String OpType = 128
|
||||||
|
OpStructHeadBoolString OpType = 129
|
||||||
|
OpStructHeadOmitEmptyBoolString OpType = 130
|
||||||
|
OpStructPtrHeadBoolString OpType = 131
|
||||||
|
OpStructPtrHeadOmitEmptyBoolString OpType = 132
|
||||||
|
OpStructHeadStringString OpType = 133
|
||||||
|
OpStructHeadOmitEmptyStringString OpType = 134
|
||||||
|
OpStructPtrHeadStringString OpType = 135
|
||||||
|
OpStructPtrHeadOmitEmptyStringString OpType = 136
|
||||||
|
OpStructHeadNumberString OpType = 137
|
||||||
|
OpStructHeadOmitEmptyNumberString OpType = 138
|
||||||
|
OpStructPtrHeadNumberString OpType = 139
|
||||||
|
OpStructPtrHeadOmitEmptyNumberString OpType = 140
|
||||||
|
OpStructHeadIntPtr OpType = 141
|
||||||
|
OpStructHeadOmitEmptyIntPtr OpType = 142
|
||||||
|
OpStructPtrHeadIntPtr OpType = 143
|
||||||
|
OpStructPtrHeadOmitEmptyIntPtr OpType = 144
|
||||||
|
OpStructHeadUintPtr OpType = 145
|
||||||
|
OpStructHeadOmitEmptyUintPtr OpType = 146
|
||||||
|
OpStructPtrHeadUintPtr OpType = 147
|
||||||
|
OpStructPtrHeadOmitEmptyUintPtr OpType = 148
|
||||||
|
OpStructHeadFloat32Ptr OpType = 149
|
||||||
|
OpStructHeadOmitEmptyFloat32Ptr OpType = 150
|
||||||
|
OpStructPtrHeadFloat32Ptr OpType = 151
|
||||||
|
OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 152
|
||||||
|
OpStructHeadFloat64Ptr OpType = 153
|
||||||
|
OpStructHeadOmitEmptyFloat64Ptr OpType = 154
|
||||||
|
OpStructPtrHeadFloat64Ptr OpType = 155
|
||||||
|
OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 156
|
||||||
|
OpStructHeadBoolPtr OpType = 157
|
||||||
|
OpStructHeadOmitEmptyBoolPtr OpType = 158
|
||||||
|
OpStructPtrHeadBoolPtr OpType = 159
|
||||||
|
OpStructPtrHeadOmitEmptyBoolPtr OpType = 160
|
||||||
|
OpStructHeadStringPtr OpType = 161
|
||||||
|
OpStructHeadOmitEmptyStringPtr OpType = 162
|
||||||
|
OpStructPtrHeadStringPtr OpType = 163
|
||||||
|
OpStructPtrHeadOmitEmptyStringPtr OpType = 164
|
||||||
|
OpStructHeadBytesPtr OpType = 165
|
||||||
|
OpStructHeadOmitEmptyBytesPtr OpType = 166
|
||||||
|
OpStructPtrHeadBytesPtr OpType = 167
|
||||||
|
OpStructPtrHeadOmitEmptyBytesPtr OpType = 168
|
||||||
|
OpStructHeadNumberPtr OpType = 169
|
||||||
|
OpStructHeadOmitEmptyNumberPtr OpType = 170
|
||||||
|
OpStructPtrHeadNumberPtr OpType = 171
|
||||||
|
OpStructPtrHeadOmitEmptyNumberPtr OpType = 172
|
||||||
|
OpStructHeadArrayPtr OpType = 173
|
||||||
|
OpStructHeadOmitEmptyArrayPtr OpType = 174
|
||||||
|
OpStructPtrHeadArrayPtr OpType = 175
|
||||||
|
OpStructPtrHeadOmitEmptyArrayPtr OpType = 176
|
||||||
|
OpStructHeadMapPtr OpType = 177
|
||||||
|
OpStructHeadOmitEmptyMapPtr OpType = 178
|
||||||
|
OpStructPtrHeadMapPtr OpType = 179
|
||||||
|
OpStructPtrHeadOmitEmptyMapPtr OpType = 180
|
||||||
|
OpStructHeadSlicePtr OpType = 181
|
||||||
|
OpStructHeadOmitEmptySlicePtr OpType = 182
|
||||||
|
OpStructPtrHeadSlicePtr OpType = 183
|
||||||
|
OpStructPtrHeadOmitEmptySlicePtr OpType = 184
|
||||||
|
OpStructHeadMarshalJSONPtr OpType = 185
|
||||||
|
OpStructHeadOmitEmptyMarshalJSONPtr OpType = 186
|
||||||
|
OpStructPtrHeadMarshalJSONPtr OpType = 187
|
||||||
|
OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 188
|
||||||
|
OpStructHeadMarshalTextPtr OpType = 189
|
||||||
|
OpStructHeadOmitEmptyMarshalTextPtr OpType = 190
|
||||||
|
OpStructPtrHeadMarshalTextPtr OpType = 191
|
||||||
|
OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 192
|
||||||
|
OpStructHeadInterfacePtr OpType = 193
|
||||||
|
OpStructHeadOmitEmptyInterfacePtr OpType = 194
|
||||||
|
OpStructPtrHeadInterfacePtr OpType = 195
|
||||||
|
OpStructPtrHeadOmitEmptyInterfacePtr OpType = 196
|
||||||
|
OpStructHeadIntPtrString OpType = 197
|
||||||
|
OpStructHeadOmitEmptyIntPtrString OpType = 198
|
||||||
|
OpStructPtrHeadIntPtrString OpType = 199
|
||||||
|
OpStructPtrHeadOmitEmptyIntPtrString OpType = 200
|
||||||
|
OpStructHeadUintPtrString OpType = 201
|
||||||
|
OpStructHeadOmitEmptyUintPtrString OpType = 202
|
||||||
|
OpStructPtrHeadUintPtrString OpType = 203
|
||||||
|
OpStructPtrHeadOmitEmptyUintPtrString OpType = 204
|
||||||
|
OpStructHeadFloat32PtrString OpType = 205
|
||||||
|
OpStructHeadOmitEmptyFloat32PtrString OpType = 206
|
||||||
|
OpStructPtrHeadFloat32PtrString OpType = 207
|
||||||
|
OpStructPtrHeadOmitEmptyFloat32PtrString OpType = 208
|
||||||
|
OpStructHeadFloat64PtrString OpType = 209
|
||||||
|
OpStructHeadOmitEmptyFloat64PtrString OpType = 210
|
||||||
|
OpStructPtrHeadFloat64PtrString OpType = 211
|
||||||
|
OpStructPtrHeadOmitEmptyFloat64PtrString OpType = 212
|
||||||
|
OpStructHeadBoolPtrString OpType = 213
|
||||||
|
OpStructHeadOmitEmptyBoolPtrString OpType = 214
|
||||||
|
OpStructPtrHeadBoolPtrString OpType = 215
|
||||||
|
OpStructPtrHeadOmitEmptyBoolPtrString OpType = 216
|
||||||
|
OpStructHeadStringPtrString OpType = 217
|
||||||
|
OpStructHeadOmitEmptyStringPtrString OpType = 218
|
||||||
|
OpStructPtrHeadStringPtrString OpType = 219
|
||||||
|
OpStructPtrHeadOmitEmptyStringPtrString OpType = 220
|
||||||
|
OpStructHeadNumberPtrString OpType = 221
|
||||||
|
OpStructHeadOmitEmptyNumberPtrString OpType = 222
|
||||||
|
OpStructPtrHeadNumberPtrString OpType = 223
|
||||||
|
OpStructPtrHeadOmitEmptyNumberPtrString OpType = 224
|
||||||
|
OpStructHead OpType = 225
|
||||||
|
OpStructHeadOmitEmpty OpType = 226
|
||||||
|
OpStructPtrHead OpType = 227
|
||||||
|
OpStructPtrHeadOmitEmpty OpType = 228
|
||||||
|
OpStructFieldInt OpType = 229
|
||||||
|
OpStructFieldOmitEmptyInt OpType = 230
|
||||||
|
OpStructEndInt OpType = 231
|
||||||
|
OpStructEndOmitEmptyInt OpType = 232
|
||||||
|
OpStructFieldUint OpType = 233
|
||||||
|
OpStructFieldOmitEmptyUint OpType = 234
|
||||||
|
OpStructEndUint OpType = 235
|
||||||
|
OpStructEndOmitEmptyUint OpType = 236
|
||||||
|
OpStructFieldFloat32 OpType = 237
|
||||||
|
OpStructFieldOmitEmptyFloat32 OpType = 238
|
||||||
|
OpStructEndFloat32 OpType = 239
|
||||||
|
OpStructEndOmitEmptyFloat32 OpType = 240
|
||||||
|
OpStructFieldFloat64 OpType = 241
|
||||||
|
OpStructFieldOmitEmptyFloat64 OpType = 242
|
||||||
|
OpStructEndFloat64 OpType = 243
|
||||||
|
OpStructEndOmitEmptyFloat64 OpType = 244
|
||||||
|
OpStructFieldBool OpType = 245
|
||||||
|
OpStructFieldOmitEmptyBool OpType = 246
|
||||||
|
OpStructEndBool OpType = 247
|
||||||
|
OpStructEndOmitEmptyBool OpType = 248
|
||||||
|
OpStructFieldString OpType = 249
|
||||||
|
OpStructFieldOmitEmptyString OpType = 250
|
||||||
|
OpStructEndString OpType = 251
|
||||||
|
OpStructEndOmitEmptyString OpType = 252
|
||||||
|
OpStructFieldBytes OpType = 253
|
||||||
|
OpStructFieldOmitEmptyBytes OpType = 254
|
||||||
|
OpStructEndBytes OpType = 255
|
||||||
|
OpStructEndOmitEmptyBytes OpType = 256
|
||||||
|
OpStructFieldNumber OpType = 257
|
||||||
|
OpStructFieldOmitEmptyNumber OpType = 258
|
||||||
|
OpStructEndNumber OpType = 259
|
||||||
|
OpStructEndOmitEmptyNumber OpType = 260
|
||||||
|
OpStructFieldArray OpType = 261
|
||||||
|
OpStructFieldOmitEmptyArray OpType = 262
|
||||||
|
OpStructEndArray OpType = 263
|
||||||
|
OpStructEndOmitEmptyArray OpType = 264
|
||||||
|
OpStructFieldMap OpType = 265
|
||||||
|
OpStructFieldOmitEmptyMap OpType = 266
|
||||||
|
OpStructEndMap OpType = 267
|
||||||
|
OpStructEndOmitEmptyMap OpType = 268
|
||||||
|
OpStructFieldSlice OpType = 269
|
||||||
|
OpStructFieldOmitEmptySlice OpType = 270
|
||||||
|
OpStructEndSlice OpType = 271
|
||||||
|
OpStructEndOmitEmptySlice OpType = 272
|
||||||
|
OpStructFieldStruct OpType = 273
|
||||||
|
OpStructFieldOmitEmptyStruct OpType = 274
|
||||||
|
OpStructEndStruct OpType = 275
|
||||||
|
OpStructEndOmitEmptyStruct OpType = 276
|
||||||
|
OpStructFieldMarshalJSON OpType = 277
|
||||||
|
OpStructFieldOmitEmptyMarshalJSON OpType = 278
|
||||||
|
OpStructEndMarshalJSON OpType = 279
|
||||||
|
OpStructEndOmitEmptyMarshalJSON OpType = 280
|
||||||
|
OpStructFieldMarshalText OpType = 281
|
||||||
|
OpStructFieldOmitEmptyMarshalText OpType = 282
|
||||||
|
OpStructEndMarshalText OpType = 283
|
||||||
|
OpStructEndOmitEmptyMarshalText OpType = 284
|
||||||
|
OpStructFieldIntString OpType = 285
|
||||||
|
OpStructFieldOmitEmptyIntString OpType = 286
|
||||||
|
OpStructEndIntString OpType = 287
|
||||||
|
OpStructEndOmitEmptyIntString OpType = 288
|
||||||
|
OpStructFieldUintString OpType = 289
|
||||||
|
OpStructFieldOmitEmptyUintString OpType = 290
|
||||||
|
OpStructEndUintString OpType = 291
|
||||||
|
OpStructEndOmitEmptyUintString OpType = 292
|
||||||
|
OpStructFieldFloat32String OpType = 293
|
||||||
|
OpStructFieldOmitEmptyFloat32String OpType = 294
|
||||||
|
OpStructEndFloat32String OpType = 295
|
||||||
|
OpStructEndOmitEmptyFloat32String OpType = 296
|
||||||
|
OpStructFieldFloat64String OpType = 297
|
||||||
|
OpStructFieldOmitEmptyFloat64String OpType = 298
|
||||||
|
OpStructEndFloat64String OpType = 299
|
||||||
|
OpStructEndOmitEmptyFloat64String OpType = 300
|
||||||
|
OpStructFieldBoolString OpType = 301
|
||||||
|
OpStructFieldOmitEmptyBoolString OpType = 302
|
||||||
|
OpStructEndBoolString OpType = 303
|
||||||
|
OpStructEndOmitEmptyBoolString OpType = 304
|
||||||
|
OpStructFieldStringString OpType = 305
|
||||||
|
OpStructFieldOmitEmptyStringString OpType = 306
|
||||||
|
OpStructEndStringString OpType = 307
|
||||||
|
OpStructEndOmitEmptyStringString OpType = 308
|
||||||
|
OpStructFieldNumberString OpType = 309
|
||||||
|
OpStructFieldOmitEmptyNumberString OpType = 310
|
||||||
|
OpStructEndNumberString OpType = 311
|
||||||
|
OpStructEndOmitEmptyNumberString OpType = 312
|
||||||
|
OpStructFieldIntPtr OpType = 313
|
||||||
|
OpStructFieldOmitEmptyIntPtr OpType = 314
|
||||||
|
OpStructEndIntPtr OpType = 315
|
||||||
|
OpStructEndOmitEmptyIntPtr OpType = 316
|
||||||
|
OpStructFieldUintPtr OpType = 317
|
||||||
|
OpStructFieldOmitEmptyUintPtr OpType = 318
|
||||||
|
OpStructEndUintPtr OpType = 319
|
||||||
|
OpStructEndOmitEmptyUintPtr OpType = 320
|
||||||
|
OpStructFieldFloat32Ptr OpType = 321
|
||||||
|
OpStructFieldOmitEmptyFloat32Ptr OpType = 322
|
||||||
|
OpStructEndFloat32Ptr OpType = 323
|
||||||
|
OpStructEndOmitEmptyFloat32Ptr OpType = 324
|
||||||
|
OpStructFieldFloat64Ptr OpType = 325
|
||||||
|
OpStructFieldOmitEmptyFloat64Ptr OpType = 326
|
||||||
|
OpStructEndFloat64Ptr OpType = 327
|
||||||
|
OpStructEndOmitEmptyFloat64Ptr OpType = 328
|
||||||
|
OpStructFieldBoolPtr OpType = 329
|
||||||
|
OpStructFieldOmitEmptyBoolPtr OpType = 330
|
||||||
|
OpStructEndBoolPtr OpType = 331
|
||||||
|
OpStructEndOmitEmptyBoolPtr OpType = 332
|
||||||
|
OpStructFieldStringPtr OpType = 333
|
||||||
|
OpStructFieldOmitEmptyStringPtr OpType = 334
|
||||||
|
OpStructEndStringPtr OpType = 335
|
||||||
|
OpStructEndOmitEmptyStringPtr OpType = 336
|
||||||
|
OpStructFieldBytesPtr OpType = 337
|
||||||
|
OpStructFieldOmitEmptyBytesPtr OpType = 338
|
||||||
|
OpStructEndBytesPtr OpType = 339
|
||||||
|
OpStructEndOmitEmptyBytesPtr OpType = 340
|
||||||
|
OpStructFieldNumberPtr OpType = 341
|
||||||
|
OpStructFieldOmitEmptyNumberPtr OpType = 342
|
||||||
|
OpStructEndNumberPtr OpType = 343
|
||||||
|
OpStructEndOmitEmptyNumberPtr OpType = 344
|
||||||
|
OpStructFieldArrayPtr OpType = 345
|
||||||
|
OpStructFieldOmitEmptyArrayPtr OpType = 346
|
||||||
|
OpStructEndArrayPtr OpType = 347
|
||||||
|
OpStructEndOmitEmptyArrayPtr OpType = 348
|
||||||
|
OpStructFieldMapPtr OpType = 349
|
||||||
|
OpStructFieldOmitEmptyMapPtr OpType = 350
|
||||||
|
OpStructEndMapPtr OpType = 351
|
||||||
|
OpStructEndOmitEmptyMapPtr OpType = 352
|
||||||
|
OpStructFieldSlicePtr OpType = 353
|
||||||
|
OpStructFieldOmitEmptySlicePtr OpType = 354
|
||||||
|
OpStructEndSlicePtr OpType = 355
|
||||||
|
OpStructEndOmitEmptySlicePtr OpType = 356
|
||||||
|
OpStructFieldMarshalJSONPtr OpType = 357
|
||||||
|
OpStructFieldOmitEmptyMarshalJSONPtr OpType = 358
|
||||||
|
OpStructEndMarshalJSONPtr OpType = 359
|
||||||
|
OpStructEndOmitEmptyMarshalJSONPtr OpType = 360
|
||||||
|
OpStructFieldMarshalTextPtr OpType = 361
|
||||||
|
OpStructFieldOmitEmptyMarshalTextPtr OpType = 362
|
||||||
|
OpStructEndMarshalTextPtr OpType = 363
|
||||||
|
OpStructEndOmitEmptyMarshalTextPtr OpType = 364
|
||||||
|
OpStructFieldInterfacePtr OpType = 365
|
||||||
|
OpStructFieldOmitEmptyInterfacePtr OpType = 366
|
||||||
|
OpStructEndInterfacePtr OpType = 367
|
||||||
|
OpStructEndOmitEmptyInterfacePtr OpType = 368
|
||||||
|
OpStructFieldIntPtrString OpType = 369
|
||||||
|
OpStructFieldOmitEmptyIntPtrString OpType = 370
|
||||||
|
OpStructEndIntPtrString OpType = 371
|
||||||
|
OpStructEndOmitEmptyIntPtrString OpType = 372
|
||||||
|
OpStructFieldUintPtrString OpType = 373
|
||||||
|
OpStructFieldOmitEmptyUintPtrString OpType = 374
|
||||||
|
OpStructEndUintPtrString OpType = 375
|
||||||
|
OpStructEndOmitEmptyUintPtrString OpType = 376
|
||||||
|
OpStructFieldFloat32PtrString OpType = 377
|
||||||
|
OpStructFieldOmitEmptyFloat32PtrString OpType = 378
|
||||||
|
OpStructEndFloat32PtrString OpType = 379
|
||||||
|
OpStructEndOmitEmptyFloat32PtrString OpType = 380
|
||||||
|
OpStructFieldFloat64PtrString OpType = 381
|
||||||
|
OpStructFieldOmitEmptyFloat64PtrString OpType = 382
|
||||||
|
OpStructEndFloat64PtrString OpType = 383
|
||||||
|
OpStructEndOmitEmptyFloat64PtrString OpType = 384
|
||||||
|
OpStructFieldBoolPtrString OpType = 385
|
||||||
|
OpStructFieldOmitEmptyBoolPtrString OpType = 386
|
||||||
|
OpStructEndBoolPtrString OpType = 387
|
||||||
|
OpStructEndOmitEmptyBoolPtrString OpType = 388
|
||||||
|
OpStructFieldStringPtrString OpType = 389
|
||||||
|
OpStructFieldOmitEmptyStringPtrString OpType = 390
|
||||||
|
OpStructEndStringPtrString OpType = 391
|
||||||
|
OpStructEndOmitEmptyStringPtrString OpType = 392
|
||||||
|
OpStructFieldNumberPtrString OpType = 393
|
||||||
|
OpStructFieldOmitEmptyNumberPtrString OpType = 394
|
||||||
|
OpStructEndNumberPtrString OpType = 395
|
||||||
|
OpStructEndOmitEmptyNumberPtrString OpType = 396
|
||||||
|
OpStructField OpType = 397
|
||||||
|
OpStructFieldOmitEmpty OpType = 398
|
||||||
|
OpStructEnd OpType = 399
|
||||||
|
OpStructEndOmitEmpty OpType = 400
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t OpType) String() string {
|
||||||
|
if int(t) >= 401 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return opTypeStrings[int(t)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t OpType) CodeType() CodeType {
|
||||||
|
if strings.Contains(t.String(), "Struct") {
|
||||||
|
if strings.Contains(t.String(), "End") {
|
||||||
|
return CodeStructEnd
|
||||||
|
}
|
||||||
|
return CodeStructField
|
||||||
|
}
|
||||||
|
switch t {
|
||||||
|
case OpArray, OpArrayPtr:
|
||||||
|
return CodeArrayHead
|
||||||
|
case OpArrayElem:
|
||||||
|
return CodeArrayElem
|
||||||
|
case OpSlice, OpSlicePtr:
|
||||||
|
return CodeSliceHead
|
||||||
|
case OpSliceElem:
|
||||||
|
return CodeSliceElem
|
||||||
|
case OpMap, OpMapPtr:
|
||||||
|
return CodeMapHead
|
||||||
|
case OpMapKey:
|
||||||
|
return CodeMapKey
|
||||||
|
case OpMapValue:
|
||||||
|
return CodeMapValue
|
||||||
|
case OpMapEnd:
|
||||||
|
return CodeMapEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
return CodeOp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t OpType) HeadToPtrHead() OpType {
|
||||||
|
if strings.Index(t.String(), "PtrHead") > 0 {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := strings.Index(t.String(), "Head")
|
||||||
|
if idx == -1 {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
suffix := "PtrHead" + t.String()[idx+len("Head"):]
|
||||||
|
|
||||||
|
const toPtrOffset = 2
|
||||||
|
if strings.Contains(OpType(int(t)+toPtrOffset).String(), suffix) {
|
||||||
|
return OpType(int(t) + toPtrOffset)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t OpType) HeadToOmitEmptyHead() OpType {
|
||||||
|
const toOmitEmptyOffset = 1
|
||||||
|
if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") {
|
||||||
|
return OpType(int(t) + toOmitEmptyOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t OpType) PtrHeadToHead() OpType {
|
||||||
|
idx := strings.Index(t.String(), "Ptr")
|
||||||
|
if idx == -1 {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
suffix := t.String()[idx+len("Ptr"):]
|
||||||
|
|
||||||
|
const toPtrOffset = 2
|
||||||
|
if strings.Contains(OpType(int(t)-toPtrOffset).String(), suffix) {
|
||||||
|
return OpType(int(t) - toPtrOffset)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t OpType) FieldToEnd() OpType {
|
||||||
|
idx := strings.Index(t.String(), "Field")
|
||||||
|
if idx == -1 {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
suffix := t.String()[idx+len("Field"):]
|
||||||
|
if suffix == "" || suffix == "OmitEmpty" {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
const toEndOffset = 2
|
||||||
|
if strings.Contains(OpType(int(t)+toEndOffset).String(), "End"+suffix) {
|
||||||
|
return OpType(int(t) + toEndOffset)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t OpType) FieldToOmitEmptyField() OpType {
|
||||||
|
const toOmitEmptyOffset = 1
|
||||||
|
if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") {
|
||||||
|
return OpType(int(t) + toOmitEmptyOffset)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
640
vendor/github.com/goccy/go-json/internal/encoder/string.go
generated
vendored
Normal file
640
vendor/github.com/goccy/go-json/internal/encoder/string.go
generated
vendored
Normal file
@ -0,0 +1,640 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/bits"
|
||||||
|
"reflect"
|
||||||
|
"unicode/utf8"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
lsb = 0x0101010101010101
|
||||||
|
msb = 0x8080808080808080
|
||||||
|
)
|
||||||
|
|
||||||
|
var needEscapeWithHTML = [256]bool{
|
||||||
|
'"': true,
|
||||||
|
'&': true,
|
||||||
|
'<': true,
|
||||||
|
'>': true,
|
||||||
|
'\\': true,
|
||||||
|
0x00: true,
|
||||||
|
0x01: true,
|
||||||
|
0x02: true,
|
||||||
|
0x03: true,
|
||||||
|
0x04: true,
|
||||||
|
0x05: true,
|
||||||
|
0x06: true,
|
||||||
|
0x07: true,
|
||||||
|
0x08: true,
|
||||||
|
0x09: true,
|
||||||
|
0x0a: true,
|
||||||
|
0x0b: true,
|
||||||
|
0x0c: true,
|
||||||
|
0x0d: true,
|
||||||
|
0x0e: true,
|
||||||
|
0x0f: true,
|
||||||
|
0x10: true,
|
||||||
|
0x11: true,
|
||||||
|
0x12: true,
|
||||||
|
0x13: true,
|
||||||
|
0x14: true,
|
||||||
|
0x15: true,
|
||||||
|
0x16: true,
|
||||||
|
0x17: true,
|
||||||
|
0x18: true,
|
||||||
|
0x19: true,
|
||||||
|
0x1a: true,
|
||||||
|
0x1b: true,
|
||||||
|
0x1c: true,
|
||||||
|
0x1d: true,
|
||||||
|
0x1e: true,
|
||||||
|
0x1f: true,
|
||||||
|
/* 0x20 - 0x7f */
|
||||||
|
0x80: true,
|
||||||
|
0x81: true,
|
||||||
|
0x82: true,
|
||||||
|
0x83: true,
|
||||||
|
0x84: true,
|
||||||
|
0x85: true,
|
||||||
|
0x86: true,
|
||||||
|
0x87: true,
|
||||||
|
0x88: true,
|
||||||
|
0x89: true,
|
||||||
|
0x8a: true,
|
||||||
|
0x8b: true,
|
||||||
|
0x8c: true,
|
||||||
|
0x8d: true,
|
||||||
|
0x8e: true,
|
||||||
|
0x8f: true,
|
||||||
|
0x90: true,
|
||||||
|
0x91: true,
|
||||||
|
0x92: true,
|
||||||
|
0x93: true,
|
||||||
|
0x94: true,
|
||||||
|
0x95: true,
|
||||||
|
0x96: true,
|
||||||
|
0x97: true,
|
||||||
|
0x98: true,
|
||||||
|
0x99: true,
|
||||||
|
0x9a: true,
|
||||||
|
0x9b: true,
|
||||||
|
0x9c: true,
|
||||||
|
0x9d: true,
|
||||||
|
0x9e: true,
|
||||||
|
0x9f: true,
|
||||||
|
0xa0: true,
|
||||||
|
0xa1: true,
|
||||||
|
0xa2: true,
|
||||||
|
0xa3: true,
|
||||||
|
0xa4: true,
|
||||||
|
0xa5: true,
|
||||||
|
0xa6: true,
|
||||||
|
0xa7: true,
|
||||||
|
0xa8: true,
|
||||||
|
0xa9: true,
|
||||||
|
0xaa: true,
|
||||||
|
0xab: true,
|
||||||
|
0xac: true,
|
||||||
|
0xad: true,
|
||||||
|
0xae: true,
|
||||||
|
0xaf: true,
|
||||||
|
0xb0: true,
|
||||||
|
0xb1: true,
|
||||||
|
0xb2: true,
|
||||||
|
0xb3: true,
|
||||||
|
0xb4: true,
|
||||||
|
0xb5: true,
|
||||||
|
0xb6: true,
|
||||||
|
0xb7: true,
|
||||||
|
0xb8: true,
|
||||||
|
0xb9: true,
|
||||||
|
0xba: true,
|
||||||
|
0xbb: true,
|
||||||
|
0xbc: true,
|
||||||
|
0xbd: true,
|
||||||
|
0xbe: true,
|
||||||
|
0xbf: true,
|
||||||
|
0xc0: true,
|
||||||
|
0xc1: true,
|
||||||
|
0xc2: true,
|
||||||
|
0xc3: true,
|
||||||
|
0xc4: true,
|
||||||
|
0xc5: true,
|
||||||
|
0xc6: true,
|
||||||
|
0xc7: true,
|
||||||
|
0xc8: true,
|
||||||
|
0xc9: true,
|
||||||
|
0xca: true,
|
||||||
|
0xcb: true,
|
||||||
|
0xcc: true,
|
||||||
|
0xcd: true,
|
||||||
|
0xce: true,
|
||||||
|
0xcf: true,
|
||||||
|
0xd0: true,
|
||||||
|
0xd1: true,
|
||||||
|
0xd2: true,
|
||||||
|
0xd3: true,
|
||||||
|
0xd4: true,
|
||||||
|
0xd5: true,
|
||||||
|
0xd6: true,
|
||||||
|
0xd7: true,
|
||||||
|
0xd8: true,
|
||||||
|
0xd9: true,
|
||||||
|
0xda: true,
|
||||||
|
0xdb: true,
|
||||||
|
0xdc: true,
|
||||||
|
0xdd: true,
|
||||||
|
0xde: true,
|
||||||
|
0xdf: true,
|
||||||
|
0xe0: true,
|
||||||
|
0xe1: true,
|
||||||
|
0xe2: true,
|
||||||
|
0xe3: true,
|
||||||
|
0xe4: true,
|
||||||
|
0xe5: true,
|
||||||
|
0xe6: true,
|
||||||
|
0xe7: true,
|
||||||
|
0xe8: true,
|
||||||
|
0xe9: true,
|
||||||
|
0xea: true,
|
||||||
|
0xeb: true,
|
||||||
|
0xec: true,
|
||||||
|
0xed: true,
|
||||||
|
0xee: true,
|
||||||
|
0xef: true,
|
||||||
|
0xf0: true,
|
||||||
|
0xf1: true,
|
||||||
|
0xf2: true,
|
||||||
|
0xf3: true,
|
||||||
|
0xf4: true,
|
||||||
|
0xf5: true,
|
||||||
|
0xf6: true,
|
||||||
|
0xf7: true,
|
||||||
|
0xf8: true,
|
||||||
|
0xf9: true,
|
||||||
|
0xfa: true,
|
||||||
|
0xfb: true,
|
||||||
|
0xfc: true,
|
||||||
|
0xfd: true,
|
||||||
|
0xfe: true,
|
||||||
|
0xff: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var needEscape = [256]bool{
|
||||||
|
'"': true,
|
||||||
|
'\\': true,
|
||||||
|
0x00: true,
|
||||||
|
0x01: true,
|
||||||
|
0x02: true,
|
||||||
|
0x03: true,
|
||||||
|
0x04: true,
|
||||||
|
0x05: true,
|
||||||
|
0x06: true,
|
||||||
|
0x07: true,
|
||||||
|
0x08: true,
|
||||||
|
0x09: true,
|
||||||
|
0x0a: true,
|
||||||
|
0x0b: true,
|
||||||
|
0x0c: true,
|
||||||
|
0x0d: true,
|
||||||
|
0x0e: true,
|
||||||
|
0x0f: true,
|
||||||
|
0x10: true,
|
||||||
|
0x11: true,
|
||||||
|
0x12: true,
|
||||||
|
0x13: true,
|
||||||
|
0x14: true,
|
||||||
|
0x15: true,
|
||||||
|
0x16: true,
|
||||||
|
0x17: true,
|
||||||
|
0x18: true,
|
||||||
|
0x19: true,
|
||||||
|
0x1a: true,
|
||||||
|
0x1b: true,
|
||||||
|
0x1c: true,
|
||||||
|
0x1d: true,
|
||||||
|
0x1e: true,
|
||||||
|
0x1f: true,
|
||||||
|
/* 0x20 - 0x7f */
|
||||||
|
0x80: true,
|
||||||
|
0x81: true,
|
||||||
|
0x82: true,
|
||||||
|
0x83: true,
|
||||||
|
0x84: true,
|
||||||
|
0x85: true,
|
||||||
|
0x86: true,
|
||||||
|
0x87: true,
|
||||||
|
0x88: true,
|
||||||
|
0x89: true,
|
||||||
|
0x8a: true,
|
||||||
|
0x8b: true,
|
||||||
|
0x8c: true,
|
||||||
|
0x8d: true,
|
||||||
|
0x8e: true,
|
||||||
|
0x8f: true,
|
||||||
|
0x90: true,
|
||||||
|
0x91: true,
|
||||||
|
0x92: true,
|
||||||
|
0x93: true,
|
||||||
|
0x94: true,
|
||||||
|
0x95: true,
|
||||||
|
0x96: true,
|
||||||
|
0x97: true,
|
||||||
|
0x98: true,
|
||||||
|
0x99: true,
|
||||||
|
0x9a: true,
|
||||||
|
0x9b: true,
|
||||||
|
0x9c: true,
|
||||||
|
0x9d: true,
|
||||||
|
0x9e: true,
|
||||||
|
0x9f: true,
|
||||||
|
0xa0: true,
|
||||||
|
0xa1: true,
|
||||||
|
0xa2: true,
|
||||||
|
0xa3: true,
|
||||||
|
0xa4: true,
|
||||||
|
0xa5: true,
|
||||||
|
0xa6: true,
|
||||||
|
0xa7: true,
|
||||||
|
0xa8: true,
|
||||||
|
0xa9: true,
|
||||||
|
0xaa: true,
|
||||||
|
0xab: true,
|
||||||
|
0xac: true,
|
||||||
|
0xad: true,
|
||||||
|
0xae: true,
|
||||||
|
0xaf: true,
|
||||||
|
0xb0: true,
|
||||||
|
0xb1: true,
|
||||||
|
0xb2: true,
|
||||||
|
0xb3: true,
|
||||||
|
0xb4: true,
|
||||||
|
0xb5: true,
|
||||||
|
0xb6: true,
|
||||||
|
0xb7: true,
|
||||||
|
0xb8: true,
|
||||||
|
0xb9: true,
|
||||||
|
0xba: true,
|
||||||
|
0xbb: true,
|
||||||
|
0xbc: true,
|
||||||
|
0xbd: true,
|
||||||
|
0xbe: true,
|
||||||
|
0xbf: true,
|
||||||
|
0xc0: true,
|
||||||
|
0xc1: true,
|
||||||
|
0xc2: true,
|
||||||
|
0xc3: true,
|
||||||
|
0xc4: true,
|
||||||
|
0xc5: true,
|
||||||
|
0xc6: true,
|
||||||
|
0xc7: true,
|
||||||
|
0xc8: true,
|
||||||
|
0xc9: true,
|
||||||
|
0xca: true,
|
||||||
|
0xcb: true,
|
||||||
|
0xcc: true,
|
||||||
|
0xcd: true,
|
||||||
|
0xce: true,
|
||||||
|
0xcf: true,
|
||||||
|
0xd0: true,
|
||||||
|
0xd1: true,
|
||||||
|
0xd2: true,
|
||||||
|
0xd3: true,
|
||||||
|
0xd4: true,
|
||||||
|
0xd5: true,
|
||||||
|
0xd6: true,
|
||||||
|
0xd7: true,
|
||||||
|
0xd8: true,
|
||||||
|
0xd9: true,
|
||||||
|
0xda: true,
|
||||||
|
0xdb: true,
|
||||||
|
0xdc: true,
|
||||||
|
0xdd: true,
|
||||||
|
0xde: true,
|
||||||
|
0xdf: true,
|
||||||
|
0xe0: true,
|
||||||
|
0xe1: true,
|
||||||
|
0xe2: true,
|
||||||
|
0xe3: true,
|
||||||
|
0xe4: true,
|
||||||
|
0xe5: true,
|
||||||
|
0xe6: true,
|
||||||
|
0xe7: true,
|
||||||
|
0xe8: true,
|
||||||
|
0xe9: true,
|
||||||
|
0xea: true,
|
||||||
|
0xeb: true,
|
||||||
|
0xec: true,
|
||||||
|
0xed: true,
|
||||||
|
0xee: true,
|
||||||
|
0xef: true,
|
||||||
|
0xf0: true,
|
||||||
|
0xf1: true,
|
||||||
|
0xf2: true,
|
||||||
|
0xf3: true,
|
||||||
|
0xf4: true,
|
||||||
|
0xf5: true,
|
||||||
|
0xf6: true,
|
||||||
|
0xf7: true,
|
||||||
|
0xf8: true,
|
||||||
|
0xf9: true,
|
||||||
|
0xfa: true,
|
||||||
|
0xfb: true,
|
||||||
|
0xfc: true,
|
||||||
|
0xfd: true,
|
||||||
|
0xfe: true,
|
||||||
|
0xff: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var hex = "0123456789abcdef"
|
||||||
|
|
||||||
|
// escapeIndex finds the index of the first char in `s` that requires escaping.
|
||||||
|
// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if
|
||||||
|
// it includes a double quote or backslash.
|
||||||
|
// If no chars in `s` require escaping, the return value is -1.
|
||||||
|
func escapeIndex(s string) int {
|
||||||
|
chunks := stringToUint64Slice(s)
|
||||||
|
for _, n := range chunks {
|
||||||
|
// combine masks before checking for the MSB of each byte. We include
|
||||||
|
// `n` in the mask to check whether any of the *input* byte MSBs were
|
||||||
|
// set (i.e. the byte was outside the ASCII range).
|
||||||
|
mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\')
|
||||||
|
if (mask & msb) != 0 {
|
||||||
|
return bits.TrailingZeros64(mask&msb) / 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valLen := len(s)
|
||||||
|
for i := len(chunks) * 8; i < valLen; i++ {
|
||||||
|
if needEscape[s[i]] {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// below return a mask that can be used to determine if any of the bytes
|
||||||
|
// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was
|
||||||
|
// below `b`. The result is only valid if `b`, and each byte in `n`, is below
|
||||||
|
// 0x80.
|
||||||
|
func below(n uint64, b byte) uint64 {
|
||||||
|
return n - expand(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// contains returns a mask that can be used to determine if any of the
|
||||||
|
// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then
|
||||||
|
// that byte is equal to `b`. The result is only valid if `b`, and each
|
||||||
|
// byte in `n`, is below 0x80.
|
||||||
|
func contains(n uint64, b byte) uint64 {
|
||||||
|
return (n ^ expand(b)) - lsb
|
||||||
|
}
|
||||||
|
|
||||||
|
// expand puts the specified byte into each of the 8 bytes of a uint64.
|
||||||
|
func expand(b byte) uint64 {
|
||||||
|
return lsb * uint64(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:govet
|
||||||
|
func stringToUint64Slice(s string) []uint64 {
|
||||||
|
return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{
|
||||||
|
Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data,
|
||||||
|
Len: len(s) / 8,
|
||||||
|
Cap: len(s) / 8,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte {
|
||||||
|
if ctx.Option.Flag&HTMLEscapeOption == 0 {
|
||||||
|
return appendString(buf, s)
|
||||||
|
}
|
||||||
|
valLen := len(s)
|
||||||
|
if valLen == 0 {
|
||||||
|
return append(buf, `""`...)
|
||||||
|
}
|
||||||
|
buf = append(buf, '"')
|
||||||
|
var (
|
||||||
|
i, j int
|
||||||
|
)
|
||||||
|
if valLen >= 8 {
|
||||||
|
chunks := stringToUint64Slice(s)
|
||||||
|
for _, n := range chunks {
|
||||||
|
// combine masks before checking for the MSB of each byte. We include
|
||||||
|
// `n` in the mask to check whether any of the *input* byte MSBs were
|
||||||
|
// set (i.e. the byte was outside the ASCII range).
|
||||||
|
mask := n | (n - (lsb * 0x20)) |
|
||||||
|
((n ^ (lsb * '"')) - lsb) |
|
||||||
|
((n ^ (lsb * '\\')) - lsb) |
|
||||||
|
((n ^ (lsb * '<')) - lsb) |
|
||||||
|
((n ^ (lsb * '>')) - lsb) |
|
||||||
|
((n ^ (lsb * '&')) - lsb)
|
||||||
|
if (mask & msb) != 0 {
|
||||||
|
j = bits.TrailingZeros64(mask&msb) / 8
|
||||||
|
goto ESCAPE_END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := len(chunks) * 8; i < valLen; i++ {
|
||||||
|
if needEscapeWithHTML[s[i]] {
|
||||||
|
j = i
|
||||||
|
goto ESCAPE_END
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no found any escape characters.
|
||||||
|
return append(append(buf, s...), '"')
|
||||||
|
}
|
||||||
|
ESCAPE_END:
|
||||||
|
for j < valLen {
|
||||||
|
c := s[j]
|
||||||
|
|
||||||
|
if !needEscapeWithHTML[c] {
|
||||||
|
// fast path: most of the time, printable ascii characters are used
|
||||||
|
j++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case '\\', '"':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', c)
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', 'n')
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', 'r')
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', 't')
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '<', '>', '&':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\u00`...)
|
||||||
|
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||||
|
if c < 0x20 {
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\u00`...)
|
||||||
|
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r, size := utf8.DecodeRuneInString(s[j:])
|
||||||
|
|
||||||
|
if r == utf8.RuneError && size == 1 {
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\ufffd`...)
|
||||||
|
i = j + size
|
||||||
|
j = j + size
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r {
|
||||||
|
case '\u2028', '\u2029':
|
||||||
|
// U+2028 is LINE SEPARATOR.
|
||||||
|
// U+2029 is PARAGRAPH SEPARATOR.
|
||||||
|
// They are both technically valid characters in JSON strings,
|
||||||
|
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||||
|
// and can lead to security holes there. It is valid JSON to
|
||||||
|
// escape them, so we do so unconditionally.
|
||||||
|
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\u202`...)
|
||||||
|
buf = append(buf, hex[r&0xF])
|
||||||
|
i = j + size
|
||||||
|
j = j + size
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
j += size
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(append(buf, s[i:]...), '"')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendString(buf []byte, s string) []byte {
|
||||||
|
valLen := len(s)
|
||||||
|
if valLen == 0 {
|
||||||
|
return append(buf, `""`...)
|
||||||
|
}
|
||||||
|
buf = append(buf, '"')
|
||||||
|
var escapeIdx int
|
||||||
|
if valLen >= 8 {
|
||||||
|
if escapeIdx = escapeIndex(s); escapeIdx < 0 {
|
||||||
|
return append(append(buf, s...), '"')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
j := escapeIdx
|
||||||
|
for j < valLen {
|
||||||
|
c := s[j]
|
||||||
|
|
||||||
|
if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' {
|
||||||
|
// fast path: most of the time, printable ascii characters are used
|
||||||
|
j++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case '\\', '"':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', c)
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', 'n')
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', 'r')
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, '\\', 't')
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
case '<', '>', '&':
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\u00`...)
|
||||||
|
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||||
|
if c < 0x20 {
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\u00`...)
|
||||||
|
buf = append(buf, hex[c>>4], hex[c&0xF])
|
||||||
|
i = j + 1
|
||||||
|
j = j + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r, size := utf8.DecodeRuneInString(s[j:])
|
||||||
|
|
||||||
|
if r == utf8.RuneError && size == 1 {
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\ufffd`...)
|
||||||
|
i = j + size
|
||||||
|
j = j + size
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r {
|
||||||
|
case '\u2028', '\u2029':
|
||||||
|
// U+2028 is LINE SEPARATOR.
|
||||||
|
// U+2029 is PARAGRAPH SEPARATOR.
|
||||||
|
// They are both technically valid characters in JSON strings,
|
||||||
|
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||||
|
// and can lead to security holes there. It is valid JSON to
|
||||||
|
// escape them, so we do so unconditionally.
|
||||||
|
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||||
|
buf = append(buf, s[i:j]...)
|
||||||
|
buf = append(buf, `\u202`...)
|
||||||
|
buf = append(buf, hex[r&0xF])
|
||||||
|
i = j + size
|
||||||
|
j = j + size
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
j += size
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(append(buf, s[i:]...), '"')
|
||||||
|
}
|
34
vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go
generated
vendored
Normal file
34
vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||||
|
defer func() {
|
||||||
|
var code *encoder.Opcode
|
||||||
|
if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 {
|
||||||
|
code = codeSet.EscapeKeyCode
|
||||||
|
} else {
|
||||||
|
code = codeSet.NoescapeKeyCode
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Println("=============[DEBUG]===============")
|
||||||
|
fmt.Println("* [TYPE]")
|
||||||
|
fmt.Println(codeSet.Type)
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [ALL OPCODE]")
|
||||||
|
fmt.Println(code.Dump())
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [CONTEXT]")
|
||||||
|
fmt.Printf("%+v\n", ctx)
|
||||||
|
fmt.Println("===================================")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return Run(ctx, b, codeSet)
|
||||||
|
}
|
9
vendor/github.com/goccy/go-json/internal/encoder/vm/hack.go
generated
vendored
Normal file
9
vendor/github.com/goccy/go-json/internal/encoder/vm/hack.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_indent`, `vm_color`, `vm_color_indent` packages uses a lot of memory to compile,
|
||||||
|
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||||
|
// dependency order: vm => vm_indent => vm_color => vm_color_indent
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_indent"
|
||||||
|
)
|
191
vendor/github.com/goccy/go-json/internal/encoder/vm/util.go
generated
vendored
Normal file
191
vendor/github.com/goccy/go-json/internal/encoder/vm/util.go
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendInt = encoder.AppendInt
|
||||||
|
appendUint = encoder.AppendUint
|
||||||
|
appendFloat32 = encoder.AppendFloat32
|
||||||
|
appendFloat64 = encoder.AppendFloat64
|
||||||
|
appendString = encoder.AppendString
|
||||||
|
appendByteSlice = encoder.AppendByteSlice
|
||||||
|
appendNumber = encoder.AppendNumber
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
mapiterinit = encoder.MapIterInit
|
||||||
|
mapiterkey = encoder.MapIterKey
|
||||||
|
mapitervalue = encoder.MapIterValue
|
||||||
|
mapiternext = encoder.MapIterNext
|
||||||
|
maplen = encoder.MapLen
|
||||||
|
)
|
||||||
|
|
||||||
|
type emptyInterface struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonEmptyInterface struct {
|
||||||
|
itab *struct {
|
||||||
|
ityp *runtime.Type // static interface type
|
||||||
|
typ *runtime.Type // dynamic concrete type
|
||||||
|
// unused fields...
|
||||||
|
}
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder: opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
|
func load(base uintptr, idx uint32) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func store(base uintptr, idx uint32, p uintptr) {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
p := **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToPtr(p uintptr) uintptr {
|
||||||
|
return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
|
||||||
|
}
|
||||||
|
func ptrToNPtr(p uintptr, ptrNum uint8) uintptr {
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
|
||||||
|
return *(*unsafe.Pointer)(unsafe.Pointer(&p))
|
||||||
|
}
|
||||||
|
func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
|
||||||
|
return *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: code.Type,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendBool(_ *encoder.RuntimeContext, b []byte, v bool) []byte {
|
||||||
|
if v {
|
||||||
|
return append(b, "true"...)
|
||||||
|
}
|
||||||
|
return append(b, "false"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendNull(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, "null"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ':'
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-1] = ':'
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
b[len(b)-1] = '}'
|
||||||
|
b = append(b, ',')
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSON(ctx, code, b, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalText(ctx, code, b, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, '[')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ']'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '}'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, code.Key...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
if b[last] == ',' {
|
||||||
|
b[last] = '}'
|
||||||
|
return appendComma(ctx, b)
|
||||||
|
}
|
||||||
|
return appendStructEnd(ctx, code, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
5056
vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go
generated
vendored
Normal file
5056
vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
34
vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go
generated
vendored
Normal file
34
vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package vm_color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||||
|
var code *encoder.Opcode
|
||||||
|
if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 {
|
||||||
|
code = codeSet.EscapeKeyCode
|
||||||
|
} else {
|
||||||
|
code = codeSet.NoescapeKeyCode
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Println("=============[DEBUG]===============")
|
||||||
|
fmt.Println("* [TYPE]")
|
||||||
|
fmt.Println(codeSet.Type)
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [ALL OPCODE]")
|
||||||
|
fmt.Println(code.Dump())
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [CONTEXT]")
|
||||||
|
fmt.Printf("%+v\n", ctx)
|
||||||
|
fmt.Println("===================================")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return Run(ctx, b, codeSet)
|
||||||
|
}
|
9
vendor/github.com/goccy/go-json/internal/encoder/vm_color/hack.go
generated
vendored
Normal file
9
vendor/github.com/goccy/go-json/internal/encoder/vm_color/hack.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package vm_color
|
||||||
|
|
||||||
|
import (
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_indent`, `vm_color`, `vm_color_indent` packages uses a lot of memory to compile,
|
||||||
|
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||||
|
// dependency order: vm => vm_indent => vm_color => vm_color_indent
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_color_indent"
|
||||||
|
)
|
255
vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go
generated
vendored
Normal file
255
vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
package vm_color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
mapiterinit = encoder.MapIterInit
|
||||||
|
mapiterkey = encoder.MapIterKey
|
||||||
|
mapitervalue = encoder.MapIterValue
|
||||||
|
mapiternext = encoder.MapIterNext
|
||||||
|
maplen = encoder.MapLen
|
||||||
|
)
|
||||||
|
|
||||||
|
type emptyInterface struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonEmptyInterface struct {
|
||||||
|
itab *struct {
|
||||||
|
ityp *runtime.Type // static interface type
|
||||||
|
typ *runtime.Type // dynamic concrete type
|
||||||
|
// unused fields...
|
||||||
|
}
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder: opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
|
func load(base uintptr, idx uint32) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func store(base uintptr, idx uint32, p uintptr) {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
p := **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToPtr(p uintptr) uintptr {
|
||||||
|
return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
|
||||||
|
}
|
||||||
|
func ptrToNPtr(p uintptr, ptrNum uint8) uintptr {
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
|
||||||
|
return *(*unsafe.Pointer)(unsafe.Pointer(&p))
|
||||||
|
}
|
||||||
|
func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
|
||||||
|
return *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: code.Type,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Int
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendInt(ctx, b, v, code)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Uint
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendUint(ctx, b, v, code)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendFloat32(ctx *encoder.RuntimeContext, b []byte, v float32) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Float
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendFloat32(ctx, b, v)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendFloat64(ctx *encoder.RuntimeContext, b []byte, v float64) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Float
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendFloat64(ctx, b, v)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendString(ctx *encoder.RuntimeContext, b []byte, v string) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.String
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendString(ctx, b, v)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendByteSlice(ctx *encoder.RuntimeContext, b []byte, src []byte) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Binary
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendByteSlice(ctx, b, src)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendNumber(ctx *encoder.RuntimeContext, b []byte, n json.Number) ([]byte, error) {
|
||||||
|
format := ctx.Option.ColorScheme.Int
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
bb, err := encoder.AppendNumber(ctx, b, n)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append(bb, format.Footer...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendBool(ctx *encoder.RuntimeContext, b []byte, v bool) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Bool
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
if v {
|
||||||
|
b = append(b, "true"...)
|
||||||
|
} else {
|
||||||
|
b = append(b, "false"...)
|
||||||
|
}
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendNull(ctx *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Null
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = append(b, "null"...)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ':'
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = append(b, key[:len(key)-1]...)
|
||||||
|
b = append(b, ':')
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '}'
|
||||||
|
b = append(b, ',')
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSON(ctx, code, b, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
format := ctx.Option.ColorScheme.String
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
bb, err := encoder.AppendMarshalText(ctx, code, b, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append(bb, format.Footer...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, '[')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = ']'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '}'
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.ObjectKey
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = append(b, code.Key[:len(code.Key)-1]...)
|
||||||
|
b = append(b, format.Footer...)
|
||||||
|
|
||||||
|
return append(b, ':')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||||
|
return append(b, '}', ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
if b[last] == ',' {
|
||||||
|
b[last] = '}'
|
||||||
|
return appendComma(ctx, b)
|
||||||
|
}
|
||||||
|
return appendStructEnd(ctx, code, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {}
|
||||||
|
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||||
|
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
5056
vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go
generated
vendored
Normal file
5056
vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
34
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go
generated
vendored
Normal file
34
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package vm_color_indent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||||
|
var code *encoder.Opcode
|
||||||
|
if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 {
|
||||||
|
code = codeSet.EscapeKeyCode
|
||||||
|
} else {
|
||||||
|
code = codeSet.NoescapeKeyCode
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Println("=============[DEBUG]===============")
|
||||||
|
fmt.Println("* [TYPE]")
|
||||||
|
fmt.Println(codeSet.Type)
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [ALL OPCODE]")
|
||||||
|
fmt.Println(code.Dump())
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [CONTEXT]")
|
||||||
|
fmt.Printf("%+v\n", ctx)
|
||||||
|
fmt.Println("===================================")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return Run(ctx, b, codeSet)
|
||||||
|
}
|
276
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go
generated
vendored
Normal file
276
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go
generated
vendored
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
package vm_color_indent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendIndent = encoder.AppendIndent
|
||||||
|
appendStructEnd = encoder.AppendStructEndIndent
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
mapiterinit = encoder.MapIterInit
|
||||||
|
mapiterkey = encoder.MapIterKey
|
||||||
|
mapitervalue = encoder.MapIterValue
|
||||||
|
mapiternext = encoder.MapIterNext
|
||||||
|
maplen = encoder.MapLen
|
||||||
|
)
|
||||||
|
|
||||||
|
type emptyInterface struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonEmptyInterface struct {
|
||||||
|
itab *struct {
|
||||||
|
ityp *runtime.Type // static interface type
|
||||||
|
typ *runtime.Type // dynamic concrete type
|
||||||
|
// unused fields...
|
||||||
|
}
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
|
func load(base uintptr, idx uint32) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func store(base uintptr, idx uint32, p uintptr) {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
p := **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToPtr(p uintptr) uintptr {
|
||||||
|
return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
|
||||||
|
}
|
||||||
|
func ptrToNPtr(p uintptr, ptrNum uint8) uintptr {
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
|
||||||
|
return *(*unsafe.Pointer)(unsafe.Pointer(&p))
|
||||||
|
}
|
||||||
|
func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
|
||||||
|
return *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: code.Type,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Int
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendInt(ctx, b, v, code)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Uint
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendUint(ctx, b, v, code)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendFloat32(ctx *encoder.RuntimeContext, b []byte, v float32) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Float
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendFloat32(ctx, b, v)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendFloat64(ctx *encoder.RuntimeContext, b []byte, v float64) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Float
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendFloat64(ctx, b, v)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendString(ctx *encoder.RuntimeContext, b []byte, v string) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.String
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendString(ctx, b, v)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendByteSlice(ctx *encoder.RuntimeContext, b []byte, src []byte) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Binary
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = encoder.AppendByteSlice(ctx, b, src)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendNumber(ctx *encoder.RuntimeContext, b []byte, n json.Number) ([]byte, error) {
|
||||||
|
format := ctx.Option.ColorScheme.Int
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
bb, err := encoder.AppendNumber(ctx, b, n)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append(bb, format.Footer...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendBool(ctx *encoder.RuntimeContext, b []byte, v bool) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Bool
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
if v {
|
||||||
|
b = append(b, "true"...)
|
||||||
|
} else {
|
||||||
|
b = append(b, "false"...)
|
||||||
|
}
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendNull(ctx *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
format := ctx.Option.ColorScheme.Null
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = append(b, "null"...)
|
||||||
|
return append(b, format.Footer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ':', ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = appendIndent(ctx, b, code.Indent+1)
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-2] = ':'
|
||||||
|
b[len(b)-1] = ' '
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = append(b, '[', '\n')
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '\n'
|
||||||
|
b = appendIndent(ctx, b, code.Indent-1)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSONIndent(ctx, code, b, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
format := ctx.Option.ColorScheme.String
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
bb, err := encoder.AppendMarshalTextIndent(ctx, code, b, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append(bb, format.Footer...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
|
||||||
|
format := ctx.Option.ColorScheme.ObjectKey
|
||||||
|
b = append(b, format.Header...)
|
||||||
|
b = append(b, code.Key[:len(code.Key)-1]...)
|
||||||
|
b = append(b, format.Footer...)
|
||||||
|
|
||||||
|
return append(b, ':', ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
if b[last-1] == '{' {
|
||||||
|
b[last] = '}'
|
||||||
|
} else {
|
||||||
|
if b[last] == '\n' {
|
||||||
|
// to remove ',' and '\n' characters
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
}
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent-1)
|
||||||
|
b = append(b, '}')
|
||||||
|
}
|
||||||
|
return appendComma(ctx, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
|
||||||
|
ctx.BaseIndent = uint32(load(ctxptr, code.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
|
||||||
|
store(ctxptr, code.Length, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent)
|
||||||
|
}
|
5056
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go
generated
vendored
Normal file
5056
vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
34
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go
generated
vendored
Normal file
34
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package vm_indent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||||
|
var code *encoder.Opcode
|
||||||
|
if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 {
|
||||||
|
code = codeSet.EscapeKeyCode
|
||||||
|
} else {
|
||||||
|
code = codeSet.NoescapeKeyCode
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Println("=============[DEBUG]===============")
|
||||||
|
fmt.Println("* [TYPE]")
|
||||||
|
fmt.Println(codeSet.Type)
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [ALL OPCODE]")
|
||||||
|
fmt.Println(code.Dump())
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Println("* [CONTEXT]")
|
||||||
|
fmt.Printf("%+v\n", ctx)
|
||||||
|
fmt.Println("===================================")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return Run(ctx, b, codeSet)
|
||||||
|
}
|
9
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/hack.go
generated
vendored
Normal file
9
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/hack.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package vm_indent
|
||||||
|
|
||||||
|
import (
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_indent`, `vm_color`, `vm_color_indent` packages uses a lot of memory to compile,
|
||||||
|
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||||
|
// dependency order: vm => vm_indent => vm_color => vm_color_indent
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_color"
|
||||||
|
)
|
213
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go
generated
vendored
Normal file
213
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
package vm_indent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
||||||
|
var (
|
||||||
|
appendInt = encoder.AppendInt
|
||||||
|
appendUint = encoder.AppendUint
|
||||||
|
appendFloat32 = encoder.AppendFloat32
|
||||||
|
appendFloat64 = encoder.AppendFloat64
|
||||||
|
appendString = encoder.AppendString
|
||||||
|
appendByteSlice = encoder.AppendByteSlice
|
||||||
|
appendNumber = encoder.AppendNumber
|
||||||
|
appendStructEnd = encoder.AppendStructEndIndent
|
||||||
|
appendIndent = encoder.AppendIndent
|
||||||
|
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||||
|
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||||
|
mapiterinit = encoder.MapIterInit
|
||||||
|
mapiterkey = encoder.MapIterKey
|
||||||
|
mapitervalue = encoder.MapIterValue
|
||||||
|
mapiternext = encoder.MapIterNext
|
||||||
|
maplen = encoder.MapLen
|
||||||
|
)
|
||||||
|
|
||||||
|
type emptyInterface struct {
|
||||||
|
typ *runtime.Type
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonEmptyInterface struct {
|
||||||
|
itab *struct {
|
||||||
|
ityp *runtime.Type // static interface type
|
||||||
|
typ *runtime.Type // dynamic concrete type
|
||||||
|
// unused fields...
|
||||||
|
}
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func errUnimplementedOp(op encoder.OpType) error {
|
||||||
|
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
|
||||||
|
}
|
||||||
|
|
||||||
|
func load(base uintptr, idx uint32) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func store(base uintptr, idx uint32, p uintptr) {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr {
|
||||||
|
addr := base + uintptr(idx)
|
||||||
|
p := **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToPtr(p uintptr) uintptr {
|
||||||
|
return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
|
||||||
|
}
|
||||||
|
func ptrToNPtr(p uintptr, ptrNum uint8) uintptr {
|
||||||
|
for i := uint8(0); i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
|
||||||
|
return *(*unsafe.Pointer)(unsafe.Pointer(&p))
|
||||||
|
}
|
||||||
|
func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
|
||||||
|
return *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: code.Type,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendBool(_ *encoder.RuntimeContext, b []byte, v bool) []byte {
|
||||||
|
if v {
|
||||||
|
return append(b, "true"...)
|
||||||
|
}
|
||||||
|
return append(b, "false"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendNull(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, "null"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendComma(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendColon(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, ':', ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||||
|
b = appendIndent(ctx, b, code.Indent+1)
|
||||||
|
b = append(b, key...)
|
||||||
|
b[len(b)-2] = ':'
|
||||||
|
b[len(b)-1] = ' '
|
||||||
|
return append(b, value...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = append(b, '[', '\n')
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
return append(b, ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '[', ']', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{', '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
b[last] = '\n'
|
||||||
|
b = appendIndent(ctx, b, code.Indent-1)
|
||||||
|
return append(b, '}', ',', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalJSONIndent(ctx, code, b, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||||
|
return encoder.AppendMarshalTextIndent(ctx, code, b, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte {
|
||||||
|
return append(b, '{', '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
b = appendIndent(ctx, b, code.Indent)
|
||||||
|
b = append(b, code.Key...)
|
||||||
|
return append(b, ' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
last := len(b) - 1
|
||||||
|
if b[last-1] == '{' {
|
||||||
|
b[last] = '}'
|
||||||
|
} else {
|
||||||
|
if b[last] == '\n' {
|
||||||
|
// to remove ',' and '\n' characters
|
||||||
|
b = b[:len(b)-2]
|
||||||
|
}
|
||||||
|
b = append(b, '\n')
|
||||||
|
b = appendIndent(ctx, b, code.Indent-1)
|
||||||
|
b = append(b, '}')
|
||||||
|
}
|
||||||
|
return appendComma(ctx, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
|
||||||
|
ctx.BaseIndent = uint32(load(ctxptr, code.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
|
||||||
|
store(ctxptr, code.Length, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||||
|
return appendIndent(ctx, b, code.Indent)
|
||||||
|
}
|
5056
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go
generated
vendored
Normal file
5056
vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
164
vendor/github.com/goccy/go-json/internal/errors/error.go
generated
vendored
Normal file
164
vendor/github.com/goccy/go-json/internal/errors/error.go
generated
vendored
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InvalidUTF8Error struct {
|
||||||
|
S string // the whole string value that caused the error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidUTF8Error) Error() string {
|
||||||
|
return fmt.Sprintf("json: invalid UTF-8 in string: %s", strconv.Quote(e.S))
|
||||||
|
}
|
||||||
|
|
||||||
|
type InvalidUnmarshalError struct {
|
||||||
|
Type reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidUnmarshalError) Error() string {
|
||||||
|
if e.Type == nil {
|
||||||
|
return "json: Unmarshal(nil)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Type.Kind() != reflect.Ptr {
|
||||||
|
return fmt.Sprintf("json: Unmarshal(non-pointer %s)", e.Type)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("json: Unmarshal(nil %s)", e.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method.
|
||||||
|
type MarshalerError struct {
|
||||||
|
Type reflect.Type
|
||||||
|
Err error
|
||||||
|
sourceFunc string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MarshalerError) Error() string {
|
||||||
|
srcFunc := e.sourceFunc
|
||||||
|
if srcFunc == "" {
|
||||||
|
srcFunc = "MarshalJSON"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("json: error calling %s for type %s: %s", srcFunc, e.Type, e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap returns the underlying error.
|
||||||
|
func (e *MarshalerError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
|
// A SyntaxError is a description of a JSON syntax error.
|
||||||
|
type SyntaxError struct {
|
||||||
|
msg string // description of error
|
||||||
|
Offset int64 // error occurred after reading Offset bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SyntaxError) Error() string { return e.msg }
|
||||||
|
|
||||||
|
// An UnmarshalFieldError describes a JSON object key that
|
||||||
|
// led to an unexported (and therefore unwritable) struct field.
|
||||||
|
//
|
||||||
|
// Deprecated: No longer used; kept for compatibility.
|
||||||
|
type UnmarshalFieldError struct {
|
||||||
|
Key string
|
||||||
|
Type reflect.Type
|
||||||
|
Field reflect.StructField
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnmarshalFieldError) Error() string {
|
||||||
|
return fmt.Sprintf("json: cannot unmarshal object key %s into unexported field %s of type %s",
|
||||||
|
strconv.Quote(e.Key), e.Field.Name, e.Type.String(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An UnmarshalTypeError describes a JSON value that was
|
||||||
|
// not appropriate for a value of a specific Go type.
|
||||||
|
type UnmarshalTypeError struct {
|
||||||
|
Value string // description of JSON value - "bool", "array", "number -5"
|
||||||
|
Type reflect.Type // type of Go value it could not be assigned to
|
||||||
|
Offset int64 // error occurred after reading Offset bytes
|
||||||
|
Struct string // name of the struct type containing the field
|
||||||
|
Field string // the full path from root node to the field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnmarshalTypeError) Error() string {
|
||||||
|
if e.Struct != "" || e.Field != "" {
|
||||||
|
return fmt.Sprintf("json: cannot unmarshal %s into Go struct field %s.%s of type %s",
|
||||||
|
e.Value, e.Struct, e.Field, e.Type,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("json: cannot unmarshal %s into Go value of type %s", e.Value, e.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An UnsupportedTypeError is returned by Marshal when attempting
|
||||||
|
// to encode an unsupported value type.
|
||||||
|
type UnsupportedTypeError struct {
|
||||||
|
Type reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnsupportedTypeError) Error() string {
|
||||||
|
return fmt.Sprintf("json: unsupported type: %s", e.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnsupportedValueError struct {
|
||||||
|
Value reflect.Value
|
||||||
|
Str string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnsupportedValueError) Error() string {
|
||||||
|
return fmt.Sprintf("json: unsupported value: %s", e.Str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrSyntax(msg string, offset int64) *SyntaxError {
|
||||||
|
return &SyntaxError{msg: msg, Offset: offset}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrMarshaler(typ reflect.Type, err error, msg string) *MarshalerError {
|
||||||
|
return &MarshalerError{
|
||||||
|
Type: typ,
|
||||||
|
Err: err,
|
||||||
|
sourceFunc: msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrExceededMaxDepth(c byte, cursor int64) *SyntaxError {
|
||||||
|
return &SyntaxError{
|
||||||
|
msg: fmt.Sprintf(`invalid character "%c" exceeded max depth`, c),
|
||||||
|
Offset: cursor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrNotAtBeginningOfValue(cursor int64) *SyntaxError {
|
||||||
|
return &SyntaxError{msg: "not at beginning of value", Offset: cursor}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrUnexpectedEndOfJSON(msg string, cursor int64) *SyntaxError {
|
||||||
|
return &SyntaxError{
|
||||||
|
msg: fmt.Sprintf("json: %s unexpected end of JSON input", msg),
|
||||||
|
Offset: cursor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrExpected(msg string, cursor int64) *SyntaxError {
|
||||||
|
return &SyntaxError{msg: fmt.Sprintf("expected %s", msg), Offset: cursor}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrInvalidCharacter(c byte, context string, cursor int64) *SyntaxError {
|
||||||
|
if c == 0 {
|
||||||
|
return &SyntaxError{
|
||||||
|
msg: fmt.Sprintf("json: invalid character as %s", context),
|
||||||
|
Offset: cursor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &SyntaxError{
|
||||||
|
msg: fmt.Sprintf("json: invalid character %c as %s", c, context),
|
||||||
|
Offset: cursor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrInvalidBeginningOfValue(c byte, cursor int64) *SyntaxError {
|
||||||
|
return &SyntaxError{
|
||||||
|
msg: fmt.Sprintf("invalid character '%c' looking for beginning of value", c),
|
||||||
|
Offset: cursor,
|
||||||
|
}
|
||||||
|
}
|
263
vendor/github.com/goccy/go-json/internal/runtime/rtype.go
generated
vendored
Normal file
263
vendor/github.com/goccy/go-json/internal/runtime/rtype.go
generated
vendored
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type representing reflect.rtype for noescape trick
|
||||||
|
type Type struct{}
|
||||||
|
|
||||||
|
//go:linkname rtype_Align reflect.(*rtype).Align
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Align(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) Align() int {
|
||||||
|
return rtype_Align(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_FieldAlign reflect.(*rtype).FieldAlign
|
||||||
|
//go:noescape
|
||||||
|
func rtype_FieldAlign(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) FieldAlign() int {
|
||||||
|
return rtype_FieldAlign(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Method reflect.(*rtype).Method
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Method(*Type, int) reflect.Method
|
||||||
|
|
||||||
|
func (t *Type) Method(a0 int) reflect.Method {
|
||||||
|
return rtype_Method(t, a0)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_MethodByName reflect.(*rtype).MethodByName
|
||||||
|
//go:noescape
|
||||||
|
func rtype_MethodByName(*Type, string) (reflect.Method, bool)
|
||||||
|
|
||||||
|
func (t *Type) MethodByName(a0 string) (reflect.Method, bool) {
|
||||||
|
return rtype_MethodByName(t, a0)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_NumMethod reflect.(*rtype).NumMethod
|
||||||
|
//go:noescape
|
||||||
|
func rtype_NumMethod(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) NumMethod() int {
|
||||||
|
return rtype_NumMethod(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Name reflect.(*rtype).Name
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Name(*Type) string
|
||||||
|
|
||||||
|
func (t *Type) Name() string {
|
||||||
|
return rtype_Name(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_PkgPath reflect.(*rtype).PkgPath
|
||||||
|
//go:noescape
|
||||||
|
func rtype_PkgPath(*Type) string
|
||||||
|
|
||||||
|
func (t *Type) PkgPath() string {
|
||||||
|
return rtype_PkgPath(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Size reflect.(*rtype).Size
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Size(*Type) uintptr
|
||||||
|
|
||||||
|
func (t *Type) Size() uintptr {
|
||||||
|
return rtype_Size(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_String reflect.(*rtype).String
|
||||||
|
//go:noescape
|
||||||
|
func rtype_String(*Type) string
|
||||||
|
|
||||||
|
func (t *Type) String() string {
|
||||||
|
return rtype_String(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Kind reflect.(*rtype).Kind
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Kind(*Type) reflect.Kind
|
||||||
|
|
||||||
|
func (t *Type) Kind() reflect.Kind {
|
||||||
|
return rtype_Kind(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Implements reflect.(*rtype).Implements
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Implements(*Type, reflect.Type) bool
|
||||||
|
|
||||||
|
func (t *Type) Implements(u reflect.Type) bool {
|
||||||
|
return rtype_Implements(t, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_AssignableTo reflect.(*rtype).AssignableTo
|
||||||
|
//go:noescape
|
||||||
|
func rtype_AssignableTo(*Type, reflect.Type) bool
|
||||||
|
|
||||||
|
func (t *Type) AssignableTo(u reflect.Type) bool {
|
||||||
|
return rtype_AssignableTo(t, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_ConvertibleTo reflect.(*rtype).ConvertibleTo
|
||||||
|
//go:noescape
|
||||||
|
func rtype_ConvertibleTo(*Type, reflect.Type) bool
|
||||||
|
|
||||||
|
func (t *Type) ConvertibleTo(u reflect.Type) bool {
|
||||||
|
return rtype_ConvertibleTo(t, u)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Comparable reflect.(*rtype).Comparable
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Comparable(*Type) bool
|
||||||
|
|
||||||
|
func (t *Type) Comparable() bool {
|
||||||
|
return rtype_Comparable(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Bits reflect.(*rtype).Bits
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Bits(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) Bits() int {
|
||||||
|
return rtype_Bits(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_ChanDir reflect.(*rtype).ChanDir
|
||||||
|
//go:noescape
|
||||||
|
func rtype_ChanDir(*Type) reflect.ChanDir
|
||||||
|
|
||||||
|
func (t *Type) ChanDir() reflect.ChanDir {
|
||||||
|
return rtype_ChanDir(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_IsVariadic reflect.(*rtype).IsVariadic
|
||||||
|
//go:noescape
|
||||||
|
func rtype_IsVariadic(*Type) bool
|
||||||
|
|
||||||
|
func (t *Type) IsVariadic() bool {
|
||||||
|
return rtype_IsVariadic(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Elem reflect.(*rtype).Elem
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Elem(*Type) reflect.Type
|
||||||
|
|
||||||
|
func (t *Type) Elem() *Type {
|
||||||
|
return Type2RType(rtype_Elem(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Field reflect.(*rtype).Field
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Field(*Type, int) reflect.StructField
|
||||||
|
|
||||||
|
func (t *Type) Field(i int) reflect.StructField {
|
||||||
|
return rtype_Field(t, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_FieldByIndex reflect.(*rtype).FieldByIndex
|
||||||
|
//go:noescape
|
||||||
|
func rtype_FieldByIndex(*Type, []int) reflect.StructField
|
||||||
|
|
||||||
|
func (t *Type) FieldByIndex(index []int) reflect.StructField {
|
||||||
|
return rtype_FieldByIndex(t, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_FieldByName reflect.(*rtype).FieldByName
|
||||||
|
//go:noescape
|
||||||
|
func rtype_FieldByName(*Type, string) (reflect.StructField, bool)
|
||||||
|
|
||||||
|
func (t *Type) FieldByName(name string) (reflect.StructField, bool) {
|
||||||
|
return rtype_FieldByName(t, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_FieldByNameFunc reflect.(*rtype).FieldByNameFunc
|
||||||
|
//go:noescape
|
||||||
|
func rtype_FieldByNameFunc(*Type, func(string) bool) (reflect.StructField, bool)
|
||||||
|
|
||||||
|
func (t *Type) FieldByNameFunc(match func(string) bool) (reflect.StructField, bool) {
|
||||||
|
return rtype_FieldByNameFunc(t, match)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_In reflect.(*rtype).In
|
||||||
|
//go:noescape
|
||||||
|
func rtype_In(*Type, int) reflect.Type
|
||||||
|
|
||||||
|
func (t *Type) In(i int) reflect.Type {
|
||||||
|
return rtype_In(t, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Key reflect.(*rtype).Key
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Key(*Type) reflect.Type
|
||||||
|
|
||||||
|
func (t *Type) Key() *Type {
|
||||||
|
return Type2RType(rtype_Key(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Len reflect.(*rtype).Len
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Len(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) Len() int {
|
||||||
|
return rtype_Len(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_NumField reflect.(*rtype).NumField
|
||||||
|
//go:noescape
|
||||||
|
func rtype_NumField(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) NumField() int {
|
||||||
|
return rtype_NumField(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_NumIn reflect.(*rtype).NumIn
|
||||||
|
//go:noescape
|
||||||
|
func rtype_NumIn(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) NumIn() int {
|
||||||
|
return rtype_NumIn(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_NumOut reflect.(*rtype).NumOut
|
||||||
|
//go:noescape
|
||||||
|
func rtype_NumOut(*Type) int
|
||||||
|
|
||||||
|
func (t *Type) NumOut() int {
|
||||||
|
return rtype_NumOut(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname rtype_Out reflect.(*rtype).Out
|
||||||
|
//go:noescape
|
||||||
|
func rtype_Out(*Type, int) reflect.Type
|
||||||
|
|
||||||
|
//go:linkname PtrTo reflect.(*rtype).ptrTo
|
||||||
|
//go:noescape
|
||||||
|
func PtrTo(*Type) *Type
|
||||||
|
|
||||||
|
func (t *Type) Out(i int) reflect.Type {
|
||||||
|
return rtype_Out(t, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname IfaceIndir reflect.ifaceIndir
|
||||||
|
//go:noescape
|
||||||
|
func IfaceIndir(*Type) bool
|
||||||
|
|
||||||
|
//go:linkname RType2Type reflect.toType
|
||||||
|
//go:noescape
|
||||||
|
func RType2Type(t *Type) reflect.Type
|
||||||
|
|
||||||
|
//go:nolint structcheck
|
||||||
|
type emptyInterface struct {
|
||||||
|
_ *Type
|
||||||
|
ptr unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func Type2RType(t reflect.Type) *Type {
|
||||||
|
return (*Type)(((*emptyInterface)(unsafe.Pointer(&t))).ptr)
|
||||||
|
}
|
87
vendor/github.com/goccy/go-json/internal/runtime/struct_field.go
generated
vendored
Normal file
87
vendor/github.com/goccy/go-json/internal/runtime/struct_field.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getTag(field reflect.StructField) string {
|
||||||
|
return field.Tag.Get("json")
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsIgnoredStructField(field reflect.StructField) bool {
|
||||||
|
if field.PkgPath != "" {
|
||||||
|
if field.Anonymous {
|
||||||
|
if !(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) && field.Type.Kind() != reflect.Struct {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// private field
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tag := getTag(field)
|
||||||
|
return tag == "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructTag struct {
|
||||||
|
Key string
|
||||||
|
IsTaggedKey bool
|
||||||
|
IsOmitEmpty bool
|
||||||
|
IsString bool
|
||||||
|
Field reflect.StructField
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructTags []*StructTag
|
||||||
|
|
||||||
|
func (t StructTags) ExistsKey(key string) bool {
|
||||||
|
for _, tt := range t {
|
||||||
|
if tt.Key == key {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidTag(s string) bool {
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, c := range s {
|
||||||
|
switch {
|
||||||
|
case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
|
||||||
|
// Backslash and quote chars are reserved, but
|
||||||
|
// otherwise any punctuation chars are allowed
|
||||||
|
// in a tag name.
|
||||||
|
case !unicode.IsLetter(c) && !unicode.IsDigit(c):
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func StructTagFromField(field reflect.StructField) *StructTag {
|
||||||
|
keyName := field.Name
|
||||||
|
tag := getTag(field)
|
||||||
|
st := &StructTag{Field: field}
|
||||||
|
opts := strings.Split(tag, ",")
|
||||||
|
if len(opts) > 0 {
|
||||||
|
if opts[0] != "" && isValidTag(opts[0]) {
|
||||||
|
keyName = opts[0]
|
||||||
|
st.IsTaggedKey = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st.Key = keyName
|
||||||
|
if len(opts) > 1 {
|
||||||
|
for _, opt := range opts[1:] {
|
||||||
|
switch opt {
|
||||||
|
case "omitempty":
|
||||||
|
st.IsOmitEmpty = true
|
||||||
|
case "string":
|
||||||
|
st.IsString = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return st
|
||||||
|
}
|
100
vendor/github.com/goccy/go-json/internal/runtime/type.go
generated
vendored
Normal file
100
vendor/github.com/goccy/go-json/internal/runtime/type.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SliceHeader struct {
|
||||||
|
Data unsafe.Pointer
|
||||||
|
Len int
|
||||||
|
Cap int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxAcceptableTypeAddrRange = 1024 * 1024 * 2 // 2 Mib
|
||||||
|
)
|
||||||
|
|
||||||
|
type TypeAddr struct {
|
||||||
|
BaseTypeAddr uintptr
|
||||||
|
MaxTypeAddr uintptr
|
||||||
|
AddrRange uintptr
|
||||||
|
AddrShift uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
typeAddr *TypeAddr
|
||||||
|
alreadyAnalyzed bool
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname typelinks reflect.typelinks
|
||||||
|
func typelinks() ([]unsafe.Pointer, [][]int32)
|
||||||
|
|
||||||
|
//go:linkname rtypeOff reflect.rtypeOff
|
||||||
|
func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer
|
||||||
|
|
||||||
|
func AnalyzeTypeAddr() *TypeAddr {
|
||||||
|
defer func() {
|
||||||
|
alreadyAnalyzed = true
|
||||||
|
}()
|
||||||
|
if alreadyAnalyzed {
|
||||||
|
return typeAddr
|
||||||
|
}
|
||||||
|
sections, offsets := typelinks()
|
||||||
|
if len(sections) != 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(offsets) != 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
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 := (*Type)(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isAligned64 = isAligned64 && (addr-min)&63 == 0
|
||||||
|
isAligned32 = isAligned32 && (addr-min)&31 == 0
|
||||||
|
}
|
||||||
|
addrRange := max - min
|
||||||
|
if addrRange == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var addrShift uintptr
|
||||||
|
if isAligned64 {
|
||||||
|
addrShift = 6
|
||||||
|
} else if isAligned32 {
|
||||||
|
addrShift = 5
|
||||||
|
}
|
||||||
|
cacheSize := addrRange >> addrShift
|
||||||
|
if cacheSize > maxAcceptableTypeAddrRange {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
typeAddr = &TypeAddr{
|
||||||
|
BaseTypeAddr: min,
|
||||||
|
MaxTypeAddr: max,
|
||||||
|
AddrRange: addrRange,
|
||||||
|
AddrShift: addrShift,
|
||||||
|
}
|
||||||
|
return typeAddr
|
||||||
|
}
|
366
vendor/github.com/goccy/go-json/json.go
generated
vendored
Normal file
366
vendor/github.com/goccy/go-json/json.go
generated
vendored
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Marshaler is the interface implemented by types that
|
||||||
|
// can marshal themselves into valid JSON.
|
||||||
|
type Marshaler interface {
|
||||||
|
MarshalJSON() ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalerContext is the interface implemented by types that
|
||||||
|
// can marshal themselves into valid JSON with context.Context.
|
||||||
|
type MarshalerContext interface {
|
||||||
|
MarshalJSON(context.Context) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshaler is the interface implemented by types
|
||||||
|
// that can unmarshal a JSON description of themselves.
|
||||||
|
// The input can be assumed to be a valid encoding of
|
||||||
|
// a JSON value. UnmarshalJSON must copy the JSON data
|
||||||
|
// if it wishes to retain the data after returning.
|
||||||
|
//
|
||||||
|
// By convention, to approximate the behavior of Unmarshal itself,
|
||||||
|
// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
|
||||||
|
type Unmarshaler interface {
|
||||||
|
UnmarshalJSON([]byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalerContext is the interface implemented by types
|
||||||
|
// that can unmarshal with context.Context a JSON description of themselves.
|
||||||
|
type UnmarshalerContext interface {
|
||||||
|
UnmarshalJSON(context.Context, []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal returns the JSON encoding of v.
|
||||||
|
//
|
||||||
|
// Marshal traverses the value v recursively.
|
||||||
|
// If an encountered value implements the Marshaler interface
|
||||||
|
// and is not a nil pointer, Marshal calls its MarshalJSON method
|
||||||
|
// to produce JSON. If no MarshalJSON method is present but the
|
||||||
|
// value implements encoding.TextMarshaler instead, Marshal calls
|
||||||
|
// its MarshalText method and encodes the result as a JSON string.
|
||||||
|
// The nil pointer exception is not strictly necessary
|
||||||
|
// but mimics a similar, necessary exception in the behavior of
|
||||||
|
// UnmarshalJSON.
|
||||||
|
//
|
||||||
|
// Otherwise, Marshal uses the following type-dependent default encodings:
|
||||||
|
//
|
||||||
|
// Boolean values encode as JSON booleans.
|
||||||
|
//
|
||||||
|
// Floating point, integer, and Number values encode as JSON numbers.
|
||||||
|
//
|
||||||
|
// String values encode as JSON strings coerced to valid UTF-8,
|
||||||
|
// replacing invalid bytes with the Unicode replacement rune.
|
||||||
|
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
|
||||||
|
// to keep some browsers from misinterpreting JSON output as HTML.
|
||||||
|
// Ampersand "&" is also escaped to "\u0026" for the same reason.
|
||||||
|
// This escaping can be disabled using an Encoder that had SetEscapeHTML(false)
|
||||||
|
// called on it.
|
||||||
|
//
|
||||||
|
// Array and slice values encode as JSON arrays, except that
|
||||||
|
// []byte encodes as a base64-encoded string, and a nil slice
|
||||||
|
// encodes as the null JSON value.
|
||||||
|
//
|
||||||
|
// Struct values encode as JSON objects.
|
||||||
|
// Each exported struct field becomes a member of the object, using the
|
||||||
|
// field name as the object key, unless the field is omitted for one of the
|
||||||
|
// reasons given below.
|
||||||
|
//
|
||||||
|
// The encoding of each struct field can be customized by the format string
|
||||||
|
// stored under the "json" key in the struct field's tag.
|
||||||
|
// The format string gives the name of the field, possibly followed by a
|
||||||
|
// comma-separated list of options. The name may be empty in order to
|
||||||
|
// specify options without overriding the default field name.
|
||||||
|
//
|
||||||
|
// The "omitempty" option specifies that the field should be omitted
|
||||||
|
// from the encoding if the field has an empty value, defined as
|
||||||
|
// false, 0, a nil pointer, a nil interface value, and any empty array,
|
||||||
|
// slice, map, or string.
|
||||||
|
//
|
||||||
|
// As a special case, if the field tag is "-", the field is always omitted.
|
||||||
|
// Note that a field with name "-" can still be generated using the tag "-,".
|
||||||
|
//
|
||||||
|
// Examples of struct field tags and their meanings:
|
||||||
|
//
|
||||||
|
// // Field appears in JSON as key "myName".
|
||||||
|
// Field int `json:"myName"`
|
||||||
|
//
|
||||||
|
// // Field appears in JSON as key "myName" and
|
||||||
|
// // the field is omitted from the object if its value is empty,
|
||||||
|
// // as defined above.
|
||||||
|
// Field int `json:"myName,omitempty"`
|
||||||
|
//
|
||||||
|
// // Field appears in JSON as key "Field" (the default), but
|
||||||
|
// // the field is skipped if empty.
|
||||||
|
// // Note the leading comma.
|
||||||
|
// Field int `json:",omitempty"`
|
||||||
|
//
|
||||||
|
// // Field is ignored by this package.
|
||||||
|
// Field int `json:"-"`
|
||||||
|
//
|
||||||
|
// // Field appears in JSON as key "-".
|
||||||
|
// Field int `json:"-,"`
|
||||||
|
//
|
||||||
|
// The "string" option signals that a field is stored as JSON inside a
|
||||||
|
// JSON-encoded string. It applies only to fields of string, floating point,
|
||||||
|
// integer, or boolean types. This extra level of encoding is sometimes used
|
||||||
|
// when communicating with JavaScript programs:
|
||||||
|
//
|
||||||
|
// Int64String int64 `json:",string"`
|
||||||
|
//
|
||||||
|
// The key name will be used if it's a non-empty string consisting of
|
||||||
|
// only Unicode letters, digits, and ASCII punctuation except quotation
|
||||||
|
// marks, backslash, and comma.
|
||||||
|
//
|
||||||
|
// Anonymous struct fields are usually marshaled as if their inner exported fields
|
||||||
|
// were fields in the outer struct, subject to the usual Go visibility rules amended
|
||||||
|
// as described in the next paragraph.
|
||||||
|
// An anonymous struct field with a name given in its JSON tag is treated as
|
||||||
|
// having that name, rather than being anonymous.
|
||||||
|
// An anonymous struct field of interface type is treated the same as having
|
||||||
|
// that type as its name, rather than being anonymous.
|
||||||
|
//
|
||||||
|
// The Go visibility rules for struct fields are amended for JSON when
|
||||||
|
// deciding which field to marshal or unmarshal. If there are
|
||||||
|
// multiple fields at the same level, and that level is the least
|
||||||
|
// nested (and would therefore be the nesting level selected by the
|
||||||
|
// usual Go rules), the following extra rules apply:
|
||||||
|
//
|
||||||
|
// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
|
||||||
|
// even if there are multiple untagged fields that would otherwise conflict.
|
||||||
|
//
|
||||||
|
// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
|
||||||
|
//
|
||||||
|
// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
|
||||||
|
//
|
||||||
|
// Handling of anonymous struct fields is new in Go 1.1.
|
||||||
|
// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
|
||||||
|
// an anonymous struct field in both current and earlier versions, give the field
|
||||||
|
// a JSON tag of "-".
|
||||||
|
//
|
||||||
|
// Map values encode as JSON objects. The map's key type must either be a
|
||||||
|
// string, an integer type, or implement encoding.TextMarshaler. The map keys
|
||||||
|
// are sorted and used as JSON object keys by applying the following rules,
|
||||||
|
// subject to the UTF-8 coercion described for string values above:
|
||||||
|
// - string keys are used directly
|
||||||
|
// - encoding.TextMarshalers are marshaled
|
||||||
|
// - integer keys are converted to strings
|
||||||
|
//
|
||||||
|
// Pointer values encode as the value pointed to.
|
||||||
|
// A nil pointer encodes as the null JSON value.
|
||||||
|
//
|
||||||
|
// Interface values encode as the value contained in the interface.
|
||||||
|
// A nil interface value encodes as the null JSON value.
|
||||||
|
//
|
||||||
|
// Channel, complex, and function values cannot be encoded in JSON.
|
||||||
|
// Attempting to encode such a value causes Marshal to return
|
||||||
|
// an UnsupportedTypeError.
|
||||||
|
//
|
||||||
|
// JSON cannot represent cyclic data structures and Marshal does not
|
||||||
|
// handle them. Passing cyclic structures to Marshal will result in
|
||||||
|
// an infinite recursion.
|
||||||
|
//
|
||||||
|
func Marshal(v interface{}) ([]byte, error) {
|
||||||
|
return MarshalWithOption(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalNoEscape returns the JSON encoding of v and doesn't escape v.
|
||||||
|
func MarshalNoEscape(v interface{}) ([]byte, error) {
|
||||||
|
return marshalNoEscape(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalContext returns the JSON encoding of v with context.Context and EncodeOption.
|
||||||
|
func MarshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||||
|
return marshalContext(ctx, v, optFuncs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalWithOption returns the JSON encoding of v with EncodeOption.
|
||||||
|
func MarshalWithOption(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||||
|
return marshal(v, optFuncs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalIndent is like Marshal but applies Indent to format the output.
|
||||||
|
// Each JSON element in the output will begin on a new line beginning with prefix
|
||||||
|
// followed by one or more copies of indent according to the indentation nesting.
|
||||||
|
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
|
||||||
|
return MarshalIndentWithOption(v, prefix, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalIndentWithOption is like Marshal but applies Indent to format the output with EncodeOption.
|
||||||
|
func MarshalIndentWithOption(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) {
|
||||||
|
return marshalIndent(v, prefix, indent, optFuncs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal parses the JSON-encoded data and stores the result
|
||||||
|
// in the value pointed to by v. If v is nil or not a pointer,
|
||||||
|
// Unmarshal returns an InvalidUnmarshalError.
|
||||||
|
//
|
||||||
|
// Unmarshal uses the inverse of the encodings that
|
||||||
|
// Marshal uses, allocating maps, slices, and pointers as necessary,
|
||||||
|
// with the following additional rules:
|
||||||
|
//
|
||||||
|
// To unmarshal JSON into a pointer, Unmarshal first handles the case of
|
||||||
|
// the JSON being the JSON literal null. In that case, Unmarshal sets
|
||||||
|
// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
|
||||||
|
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
|
||||||
|
// allocates a new value for it to point to.
|
||||||
|
//
|
||||||
|
// To unmarshal JSON into a value implementing the Unmarshaler interface,
|
||||||
|
// Unmarshal calls that value's UnmarshalJSON method, including
|
||||||
|
// when the input is a JSON null.
|
||||||
|
// Otherwise, if the value implements encoding.TextUnmarshaler
|
||||||
|
// and the input is a JSON quoted string, Unmarshal calls that value's
|
||||||
|
// UnmarshalText method with the unquoted form of the string.
|
||||||
|
//
|
||||||
|
// To unmarshal JSON into a struct, Unmarshal matches incoming object
|
||||||
|
// keys to the keys used by Marshal (either the struct field name or its tag),
|
||||||
|
// preferring an exact match but also accepting a case-insensitive match. By
|
||||||
|
// default, object keys which don't have a corresponding struct field are
|
||||||
|
// ignored (see Decoder.DisallowUnknownFields for an alternative).
|
||||||
|
//
|
||||||
|
// To unmarshal JSON into an interface value,
|
||||||
|
// Unmarshal stores one of these in the interface value:
|
||||||
|
//
|
||||||
|
// bool, for JSON booleans
|
||||||
|
// float64, for JSON numbers
|
||||||
|
// string, for JSON strings
|
||||||
|
// []interface{}, for JSON arrays
|
||||||
|
// map[string]interface{}, for JSON objects
|
||||||
|
// nil for JSON null
|
||||||
|
//
|
||||||
|
// To unmarshal a JSON array into a slice, Unmarshal resets the slice length
|
||||||
|
// to zero and then appends each element to the slice.
|
||||||
|
// As a special case, to unmarshal an empty JSON array into a slice,
|
||||||
|
// Unmarshal replaces the slice with a new empty slice.
|
||||||
|
//
|
||||||
|
// To unmarshal a JSON array into a Go array, Unmarshal decodes
|
||||||
|
// JSON array elements into corresponding Go array elements.
|
||||||
|
// If the Go array is smaller than the JSON array,
|
||||||
|
// the additional JSON array elements are discarded.
|
||||||
|
// If the JSON array is smaller than the Go array,
|
||||||
|
// the additional Go array elements are set to zero values.
|
||||||
|
//
|
||||||
|
// To unmarshal a JSON object into a map, Unmarshal first establishes a map to
|
||||||
|
// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
|
||||||
|
// reuses the existing map, keeping existing entries. Unmarshal then stores
|
||||||
|
// key-value pairs from the JSON object into the map. The map's key type must
|
||||||
|
// either be any string type, an integer, implement json.Unmarshaler, or
|
||||||
|
// implement encoding.TextUnmarshaler.
|
||||||
|
//
|
||||||
|
// If a JSON value is not appropriate for a given target type,
|
||||||
|
// or if a JSON number overflows the target type, Unmarshal
|
||||||
|
// skips that field and completes the unmarshaling as best it can.
|
||||||
|
// If no more serious errors are encountered, Unmarshal returns
|
||||||
|
// an UnmarshalTypeError describing the earliest such error. In any
|
||||||
|
// case, it's not guaranteed that all the remaining fields following
|
||||||
|
// the problematic one will be unmarshaled into the target object.
|
||||||
|
//
|
||||||
|
// The JSON null value unmarshals into an interface, map, pointer, or slice
|
||||||
|
// by setting that Go value to nil. Because null is often used in JSON to mean
|
||||||
|
// ``not present,'' unmarshaling a JSON null into any other Go type has no effect
|
||||||
|
// on the value and produces no error.
|
||||||
|
//
|
||||||
|
// When unmarshaling quoted strings, invalid UTF-8 or
|
||||||
|
// invalid UTF-16 surrogate pairs are not treated as an error.
|
||||||
|
// Instead, they are replaced by the Unicode replacement
|
||||||
|
// character U+FFFD.
|
||||||
|
//
|
||||||
|
func Unmarshal(data []byte, v interface{}) error {
|
||||||
|
return unmarshal(data, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalContext parses the JSON-encoded data and stores the result
|
||||||
|
// in the value pointed to by v. If you implement the UnmarshalerContext interface,
|
||||||
|
// call it with ctx as an argument.
|
||||||
|
func UnmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
|
||||||
|
return unmarshalContext(ctx, data, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalWithOption(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
|
||||||
|
return unmarshal(data, v, optFuncs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error {
|
||||||
|
return unmarshalNoEscape(data, v, optFuncs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Token holds a value of one of these types:
|
||||||
|
//
|
||||||
|
// Delim, for the four JSON delimiters [ ] { }
|
||||||
|
// bool, for JSON booleans
|
||||||
|
// float64, for JSON numbers
|
||||||
|
// Number, for JSON numbers
|
||||||
|
// string, for JSON string literals
|
||||||
|
// nil, for JSON null
|
||||||
|
//
|
||||||
|
type Token = json.Token
|
||||||
|
|
||||||
|
// A Number represents a JSON number literal.
|
||||||
|
type Number = json.Number
|
||||||
|
|
||||||
|
// RawMessage is a raw encoded JSON value.
|
||||||
|
// It implements Marshaler and Unmarshaler and can
|
||||||
|
// be used to delay JSON decoding or precompute a JSON encoding.
|
||||||
|
type RawMessage = json.RawMessage
|
||||||
|
|
||||||
|
// A Delim is a JSON array or object delimiter, one of [ ] { or }.
|
||||||
|
type Delim = json.Delim
|
||||||
|
|
||||||
|
// Compact appends to dst the JSON-encoded src with
|
||||||
|
// insignificant space characters elided.
|
||||||
|
func Compact(dst *bytes.Buffer, src []byte) error {
|
||||||
|
return encoder.Compact(dst, src, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indent appends to dst an indented form of the JSON-encoded src.
|
||||||
|
// Each element in a JSON object or array begins on a new,
|
||||||
|
// indented line beginning with prefix followed by one or more
|
||||||
|
// copies of indent according to the indentation nesting.
|
||||||
|
// The data appended to dst does not begin with the prefix nor
|
||||||
|
// any indentation, to make it easier to embed inside other formatted JSON data.
|
||||||
|
// Although leading space characters (space, tab, carriage return, newline)
|
||||||
|
// at the beginning of src are dropped, trailing space characters
|
||||||
|
// at the end of src are preserved and copied to dst.
|
||||||
|
// For example, if src has no trailing spaces, neither will dst;
|
||||||
|
// if src ends in a trailing newline, so will dst.
|
||||||
|
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
|
||||||
|
return encoder.Indent(dst, src, prefix, indent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
|
||||||
|
// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
|
||||||
|
// so that the JSON will be safe to embed inside HTML <script> tags.
|
||||||
|
// For historical reasons, web browsers don't honor standard HTML
|
||||||
|
// escaping within <script> tags, so an alternative JSON encoding must
|
||||||
|
// be used.
|
||||||
|
func HTMLEscape(dst *bytes.Buffer, src []byte) {
|
||||||
|
var v interface{}
|
||||||
|
dec := NewDecoder(bytes.NewBuffer(src))
|
||||||
|
dec.UseNumber()
|
||||||
|
if err := dec.Decode(&v); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf, _ := marshal(v)
|
||||||
|
dst.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid reports whether data is a valid JSON encoding.
|
||||||
|
func Valid(data []byte) bool {
|
||||||
|
var v interface{}
|
||||||
|
decoder := NewDecoder(bytes.NewReader(data))
|
||||||
|
err := decoder.Decode(&v)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !decoder.More() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return decoder.InputOffset() >= int64(len(data))
|
||||||
|
}
|
46
vendor/github.com/goccy/go-json/option.go
generated
vendored
Normal file
46
vendor/github.com/goccy/go-json/option.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goccy/go-json/internal/decoder"
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EncodeOption = encoder.Option
|
||||||
|
type EncodeOptionFunc func(*EncodeOption)
|
||||||
|
|
||||||
|
// UnorderedMap doesn't sort when encoding map type.
|
||||||
|
func UnorderedMap() EncodeOptionFunc {
|
||||||
|
return func(opt *EncodeOption) {
|
||||||
|
opt.Flag |= encoder.UnorderedMapOption
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug outputs debug information when panic occurs during encoding.
|
||||||
|
func Debug() EncodeOptionFunc {
|
||||||
|
return func(opt *EncodeOption) {
|
||||||
|
opt.Flag |= encoder.DebugOption
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colorize add an identifier for coloring to the string of the encoded result.
|
||||||
|
func Colorize(scheme *ColorScheme) EncodeOptionFunc {
|
||||||
|
return func(opt *EncodeOption) {
|
||||||
|
opt.Flag |= encoder.ColorizeOption
|
||||||
|
opt.ColorScheme = scheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DecodeOption = decoder.Option
|
||||||
|
type DecodeOptionFunc func(*DecodeOption)
|
||||||
|
|
||||||
|
// DecodeFieldPriorityFirstWin
|
||||||
|
// 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.
|
||||||
|
// This option allow you to change this behavior.
|
||||||
|
// this 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.
|
||||||
|
func DecodeFieldPriorityFirstWin() DecodeOptionFunc {
|
||||||
|
return func(opt *DecodeOption) {
|
||||||
|
opt.Flags |= decoder.FirstWinOption
|
||||||
|
}
|
||||||
|
}
|
16
vendor/github.com/golang/snappy/.gitignore
generated
vendored
Normal file
16
vendor/github.com/golang/snappy/.gitignore
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
cmd/snappytool/snappytool
|
||||||
|
testdata/bench
|
||||||
|
|
||||||
|
# These explicitly listed benchmark data files are for an obsolete version of
|
||||||
|
# snappy_test.go.
|
||||||
|
testdata/alice29.txt
|
||||||
|
testdata/asyoulik.txt
|
||||||
|
testdata/fireworks.jpeg
|
||||||
|
testdata/geo.protodata
|
||||||
|
testdata/html
|
||||||
|
testdata/html_x_4
|
||||||
|
testdata/kppkn.gtb
|
||||||
|
testdata/lcet10.txt
|
||||||
|
testdata/paper-100k.pdf
|
||||||
|
testdata/plrabn12.txt
|
||||||
|
testdata/urls.10K
|
18
vendor/github.com/golang/snappy/AUTHORS
generated
vendored
Normal file
18
vendor/github.com/golang/snappy/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# This is the official list of Snappy-Go authors for copyright purposes.
|
||||||
|
# This file is distinct from the CONTRIBUTORS files.
|
||||||
|
# See the latter for an explanation.
|
||||||
|
|
||||||
|
# Names should be added to this file as
|
||||||
|
# Name or Organization <email address>
|
||||||
|
# The email address is not required for organizations.
|
||||||
|
|
||||||
|
# Please keep the list sorted.
|
||||||
|
|
||||||
|
Amazon.com, Inc
|
||||||
|
Damian Gryski <dgryski@gmail.com>
|
||||||
|
Eric Buth <eric@topos.com>
|
||||||
|
Google Inc.
|
||||||
|
Jan Mercl <0xjnml@gmail.com>
|
||||||
|
Klaus Post <klauspost@gmail.com>
|
||||||
|
Rodolfo Carvalho <rhcarvalho@gmail.com>
|
||||||
|
Sebastien Binet <seb.binet@gmail.com>
|
41
vendor/github.com/golang/snappy/CONTRIBUTORS
generated
vendored
Normal file
41
vendor/github.com/golang/snappy/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# This is the official list of people who can contribute
|
||||||
|
# (and typically have contributed) code to the Snappy-Go repository.
|
||||||
|
# The AUTHORS file lists the copyright holders; this file
|
||||||
|
# lists people. For example, Google employees are listed here
|
||||||
|
# but not in AUTHORS, because Google holds the copyright.
|
||||||
|
#
|
||||||
|
# The submission process automatically checks to make sure
|
||||||
|
# that people submitting code are listed in this file (by email address).
|
||||||
|
#
|
||||||
|
# Names should be added to this file only after verifying that
|
||||||
|
# the individual or the individual's organization has agreed to
|
||||||
|
# the appropriate Contributor License Agreement, found here:
|
||||||
|
#
|
||||||
|
# http://code.google.com/legal/individual-cla-v1.0.html
|
||||||
|
# http://code.google.com/legal/corporate-cla-v1.0.html
|
||||||
|
#
|
||||||
|
# The agreement for individuals can be filled out on the web.
|
||||||
|
#
|
||||||
|
# When adding J Random Contributor's name to this file,
|
||||||
|
# either J's name or J's organization's name should be
|
||||||
|
# added to the AUTHORS file, depending on whether the
|
||||||
|
# individual or corporate CLA was used.
|
||||||
|
|
||||||
|
# Names should be added to this file like so:
|
||||||
|
# Name <email address>
|
||||||
|
|
||||||
|
# Please keep the list sorted.
|
||||||
|
|
||||||
|
Alex Legg <alexlegg@google.com>
|
||||||
|
Damian Gryski <dgryski@gmail.com>
|
||||||
|
Eric Buth <eric@topos.com>
|
||||||
|
Jan Mercl <0xjnml@gmail.com>
|
||||||
|
Jonathan Swinney <jswinney@amazon.com>
|
||||||
|
Kai Backman <kaib@golang.org>
|
||||||
|
Klaus Post <klauspost@gmail.com>
|
||||||
|
Marc-Antoine Ruel <maruel@chromium.org>
|
||||||
|
Nigel Tao <nigeltao@golang.org>
|
||||||
|
Rob Pike <r@golang.org>
|
||||||
|
Rodolfo Carvalho <rhcarvalho@gmail.com>
|
||||||
|
Russ Cox <rsc@golang.org>
|
||||||
|
Sebastien Binet <seb.binet@gmail.com>
|
27
vendor/github.com/golang/snappy/LICENSE
generated
vendored
Normal file
27
vendor/github.com/golang/snappy/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
107
vendor/github.com/golang/snappy/README
generated
vendored
Normal file
107
vendor/github.com/golang/snappy/README
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
The Snappy compression format in the Go programming language.
|
||||||
|
|
||||||
|
To download and install from source:
|
||||||
|
$ go get github.com/golang/snappy
|
||||||
|
|
||||||
|
Unless otherwise noted, the Snappy-Go source files are distributed
|
||||||
|
under the BSD-style license found in the LICENSE file.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Benchmarks.
|
||||||
|
|
||||||
|
The golang/snappy benchmarks include compressing (Z) and decompressing (U) ten
|
||||||
|
or so files, the same set used by the C++ Snappy code (github.com/google/snappy
|
||||||
|
and note the "google", not "golang"). On an "Intel(R) Core(TM) i7-3770 CPU @
|
||||||
|
3.40GHz", Go's GOARCH=amd64 numbers as of 2016-05-29:
|
||||||
|
|
||||||
|
"go test -test.bench=."
|
||||||
|
|
||||||
|
_UFlat0-8 2.19GB/s ± 0% html
|
||||||
|
_UFlat1-8 1.41GB/s ± 0% urls
|
||||||
|
_UFlat2-8 23.5GB/s ± 2% jpg
|
||||||
|
_UFlat3-8 1.91GB/s ± 0% jpg_200
|
||||||
|
_UFlat4-8 14.0GB/s ± 1% pdf
|
||||||
|
_UFlat5-8 1.97GB/s ± 0% html4
|
||||||
|
_UFlat6-8 814MB/s ± 0% txt1
|
||||||
|
_UFlat7-8 785MB/s ± 0% txt2
|
||||||
|
_UFlat8-8 857MB/s ± 0% txt3
|
||||||
|
_UFlat9-8 719MB/s ± 1% txt4
|
||||||
|
_UFlat10-8 2.84GB/s ± 0% pb
|
||||||
|
_UFlat11-8 1.05GB/s ± 0% gaviota
|
||||||
|
|
||||||
|
_ZFlat0-8 1.04GB/s ± 0% html
|
||||||
|
_ZFlat1-8 534MB/s ± 0% urls
|
||||||
|
_ZFlat2-8 15.7GB/s ± 1% jpg
|
||||||
|
_ZFlat3-8 740MB/s ± 3% jpg_200
|
||||||
|
_ZFlat4-8 9.20GB/s ± 1% pdf
|
||||||
|
_ZFlat5-8 991MB/s ± 0% html4
|
||||||
|
_ZFlat6-8 379MB/s ± 0% txt1
|
||||||
|
_ZFlat7-8 352MB/s ± 0% txt2
|
||||||
|
_ZFlat8-8 396MB/s ± 1% txt3
|
||||||
|
_ZFlat9-8 327MB/s ± 1% txt4
|
||||||
|
_ZFlat10-8 1.33GB/s ± 1% pb
|
||||||
|
_ZFlat11-8 605MB/s ± 1% gaviota
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"go test -test.bench=. -tags=noasm"
|
||||||
|
|
||||||
|
_UFlat0-8 621MB/s ± 2% html
|
||||||
|
_UFlat1-8 494MB/s ± 1% urls
|
||||||
|
_UFlat2-8 23.2GB/s ± 1% jpg
|
||||||
|
_UFlat3-8 1.12GB/s ± 1% jpg_200
|
||||||
|
_UFlat4-8 4.35GB/s ± 1% pdf
|
||||||
|
_UFlat5-8 609MB/s ± 0% html4
|
||||||
|
_UFlat6-8 296MB/s ± 0% txt1
|
||||||
|
_UFlat7-8 288MB/s ± 0% txt2
|
||||||
|
_UFlat8-8 309MB/s ± 1% txt3
|
||||||
|
_UFlat9-8 280MB/s ± 1% txt4
|
||||||
|
_UFlat10-8 753MB/s ± 0% pb
|
||||||
|
_UFlat11-8 400MB/s ± 0% gaviota
|
||||||
|
|
||||||
|
_ZFlat0-8 409MB/s ± 1% html
|
||||||
|
_ZFlat1-8 250MB/s ± 1% urls
|
||||||
|
_ZFlat2-8 12.3GB/s ± 1% jpg
|
||||||
|
_ZFlat3-8 132MB/s ± 0% jpg_200
|
||||||
|
_ZFlat4-8 2.92GB/s ± 0% pdf
|
||||||
|
_ZFlat5-8 405MB/s ± 1% html4
|
||||||
|
_ZFlat6-8 179MB/s ± 1% txt1
|
||||||
|
_ZFlat7-8 170MB/s ± 1% txt2
|
||||||
|
_ZFlat8-8 189MB/s ± 1% txt3
|
||||||
|
_ZFlat9-8 164MB/s ± 1% txt4
|
||||||
|
_ZFlat10-8 479MB/s ± 1% pb
|
||||||
|
_ZFlat11-8 270MB/s ± 1% gaviota
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
For comparison (Go's encoded output is byte-for-byte identical to C++'s), here
|
||||||
|
are the numbers from C++ Snappy's
|
||||||
|
|
||||||
|
make CXXFLAGS="-O2 -DNDEBUG -g" clean snappy_unittest.log && cat snappy_unittest.log
|
||||||
|
|
||||||
|
BM_UFlat/0 2.4GB/s html
|
||||||
|
BM_UFlat/1 1.4GB/s urls
|
||||||
|
BM_UFlat/2 21.8GB/s jpg
|
||||||
|
BM_UFlat/3 1.5GB/s jpg_200
|
||||||
|
BM_UFlat/4 13.3GB/s pdf
|
||||||
|
BM_UFlat/5 2.1GB/s html4
|
||||||
|
BM_UFlat/6 1.0GB/s txt1
|
||||||
|
BM_UFlat/7 959.4MB/s txt2
|
||||||
|
BM_UFlat/8 1.0GB/s txt3
|
||||||
|
BM_UFlat/9 864.5MB/s txt4
|
||||||
|
BM_UFlat/10 2.9GB/s pb
|
||||||
|
BM_UFlat/11 1.2GB/s gaviota
|
||||||
|
|
||||||
|
BM_ZFlat/0 944.3MB/s html (22.31 %)
|
||||||
|
BM_ZFlat/1 501.6MB/s urls (47.78 %)
|
||||||
|
BM_ZFlat/2 14.3GB/s jpg (99.95 %)
|
||||||
|
BM_ZFlat/3 538.3MB/s jpg_200 (73.00 %)
|
||||||
|
BM_ZFlat/4 8.3GB/s pdf (83.30 %)
|
||||||
|
BM_ZFlat/5 903.5MB/s html4 (22.52 %)
|
||||||
|
BM_ZFlat/6 336.0MB/s txt1 (57.88 %)
|
||||||
|
BM_ZFlat/7 312.3MB/s txt2 (61.91 %)
|
||||||
|
BM_ZFlat/8 353.1MB/s txt3 (54.99 %)
|
||||||
|
BM_ZFlat/9 289.9MB/s txt4 (66.26 %)
|
||||||
|
BM_ZFlat/10 1.2GB/s pb (19.68 %)
|
||||||
|
BM_ZFlat/11 527.4MB/s gaviota (37.72 %)
|
264
vendor/github.com/golang/snappy/decode.go
generated
vendored
Normal file
264
vendor/github.com/golang/snappy/decode.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package snappy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrCorrupt reports that the input is invalid.
|
||||||
|
ErrCorrupt = errors.New("snappy: corrupt input")
|
||||||
|
// ErrTooLarge reports that the uncompressed length is too large.
|
||||||
|
ErrTooLarge = errors.New("snappy: decoded block is too large")
|
||||||
|
// ErrUnsupported reports that the input isn't supported.
|
||||||
|
ErrUnsupported = errors.New("snappy: unsupported input")
|
||||||
|
|
||||||
|
errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
|
||||||
|
)
|
||||||
|
|
||||||
|
// DecodedLen returns the length of the decoded block.
|
||||||
|
func DecodedLen(src []byte) (int, error) {
|
||||||
|
v, _, err := decodedLen(src)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodedLen returns the length of the decoded block and the number of bytes
|
||||||
|
// that the length header occupied.
|
||||||
|
func decodedLen(src []byte) (blockLen, headerLen int, err error) {
|
||||||
|
v, n := binary.Uvarint(src)
|
||||||
|
if n <= 0 || v > 0xffffffff {
|
||||||
|
return 0, 0, ErrCorrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
const wordSize = 32 << (^uint(0) >> 32 & 1)
|
||||||
|
if wordSize == 32 && v > 0x7fffffff {
|
||||||
|
return 0, 0, ErrTooLarge
|
||||||
|
}
|
||||||
|
return int(v), n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
decodeErrCodeCorrupt = 1
|
||||||
|
decodeErrCodeUnsupportedLiteralLength = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decode returns the decoded form of src. The returned slice may be a sub-
|
||||||
|
// slice of dst if dst was large enough to hold the entire decoded block.
|
||||||
|
// Otherwise, a newly allocated slice will be returned.
|
||||||
|
//
|
||||||
|
// The dst and src must not overlap. It is valid to pass a nil dst.
|
||||||
|
//
|
||||||
|
// Decode handles the Snappy block format, not the Snappy stream format.
|
||||||
|
func Decode(dst, src []byte) ([]byte, error) {
|
||||||
|
dLen, s, err := decodedLen(src)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if dLen <= len(dst) {
|
||||||
|
dst = dst[:dLen]
|
||||||
|
} else {
|
||||||
|
dst = make([]byte, dLen)
|
||||||
|
}
|
||||||
|
switch decode(dst, src[s:]) {
|
||||||
|
case 0:
|
||||||
|
return dst, nil
|
||||||
|
case decodeErrCodeUnsupportedLiteralLength:
|
||||||
|
return nil, errUnsupportedLiteralLength
|
||||||
|
}
|
||||||
|
return nil, ErrCorrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReader returns a new Reader that decompresses from r, using the framing
|
||||||
|
// format described at
|
||||||
|
// https://github.com/google/snappy/blob/master/framing_format.txt
|
||||||
|
func NewReader(r io.Reader) *Reader {
|
||||||
|
return &Reader{
|
||||||
|
r: r,
|
||||||
|
decoded: make([]byte, maxBlockSize),
|
||||||
|
buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reader is an io.Reader that can read Snappy-compressed bytes.
|
||||||
|
//
|
||||||
|
// Reader handles the Snappy stream format, not the Snappy block format.
|
||||||
|
type Reader struct {
|
||||||
|
r io.Reader
|
||||||
|
err error
|
||||||
|
decoded []byte
|
||||||
|
buf []byte
|
||||||
|
// decoded[i:j] contains decoded bytes that have not yet been passed on.
|
||||||
|
i, j int
|
||||||
|
readHeader bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset discards any buffered data, resets all state, and switches the Snappy
|
||||||
|
// reader to read from r. This permits reusing a Reader rather than allocating
|
||||||
|
// a new one.
|
||||||
|
func (r *Reader) Reset(reader io.Reader) {
|
||||||
|
r.r = reader
|
||||||
|
r.err = nil
|
||||||
|
r.i = 0
|
||||||
|
r.j = 0
|
||||||
|
r.readHeader = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
|
||||||
|
if _, r.err = io.ReadFull(r.r, p); r.err != nil {
|
||||||
|
if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) fill() error {
|
||||||
|
for r.i >= r.j {
|
||||||
|
if !r.readFull(r.buf[:4], true) {
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
chunkType := r.buf[0]
|
||||||
|
if !r.readHeader {
|
||||||
|
if chunkType != chunkTypeStreamIdentifier {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
r.readHeader = true
|
||||||
|
}
|
||||||
|
chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
|
||||||
|
if chunkLen > len(r.buf) {
|
||||||
|
r.err = ErrUnsupported
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The chunk types are specified at
|
||||||
|
// https://github.com/google/snappy/blob/master/framing_format.txt
|
||||||
|
switch chunkType {
|
||||||
|
case chunkTypeCompressedData:
|
||||||
|
// Section 4.2. Compressed data (chunk type 0x00).
|
||||||
|
if chunkLen < checksumSize {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
buf := r.buf[:chunkLen]
|
||||||
|
if !r.readFull(buf, false) {
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
|
||||||
|
buf = buf[checksumSize:]
|
||||||
|
|
||||||
|
n, err := DecodedLen(buf)
|
||||||
|
if err != nil {
|
||||||
|
r.err = err
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
if n > len(r.decoded) {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
if _, err := Decode(r.decoded, buf); err != nil {
|
||||||
|
r.err = err
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
if crc(r.decoded[:n]) != checksum {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
r.i, r.j = 0, n
|
||||||
|
continue
|
||||||
|
|
||||||
|
case chunkTypeUncompressedData:
|
||||||
|
// Section 4.3. Uncompressed data (chunk type 0x01).
|
||||||
|
if chunkLen < checksumSize {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
buf := r.buf[:checksumSize]
|
||||||
|
if !r.readFull(buf, false) {
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
|
||||||
|
// Read directly into r.decoded instead of via r.buf.
|
||||||
|
n := chunkLen - checksumSize
|
||||||
|
if n > len(r.decoded) {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
if !r.readFull(r.decoded[:n], false) {
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
if crc(r.decoded[:n]) != checksum {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
r.i, r.j = 0, n
|
||||||
|
continue
|
||||||
|
|
||||||
|
case chunkTypeStreamIdentifier:
|
||||||
|
// Section 4.1. Stream identifier (chunk type 0xff).
|
||||||
|
if chunkLen != len(magicBody) {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
if !r.readFull(r.buf[:len(magicBody)], false) {
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
for i := 0; i < len(magicBody); i++ {
|
||||||
|
if r.buf[i] != magicBody[i] {
|
||||||
|
r.err = ErrCorrupt
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if chunkType <= 0x7f {
|
||||||
|
// Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
|
||||||
|
r.err = ErrUnsupported
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
// Section 4.4 Padding (chunk type 0xfe).
|
||||||
|
// Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
|
||||||
|
if !r.readFull(r.buf[:chunkLen], false) {
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read satisfies the io.Reader interface.
|
||||||
|
func (r *Reader) Read(p []byte) (int, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return 0, r.err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.fill(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n := copy(p, r.decoded[r.i:r.j])
|
||||||
|
r.i += n
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadByte satisfies the io.ByteReader interface.
|
||||||
|
func (r *Reader) ReadByte() (byte, error) {
|
||||||
|
if r.err != nil {
|
||||||
|
return 0, r.err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.fill(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := r.decoded[r.i]
|
||||||
|
r.i++
|
||||||
|
return c, nil
|
||||||
|
}
|
490
vendor/github.com/golang/snappy/decode_amd64.s
generated
vendored
Normal file
490
vendor/github.com/golang/snappy/decode_amd64.s
generated
vendored
Normal file
@ -0,0 +1,490 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !noasm
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// The asm code generally follows the pure Go code in decode_other.go, except
|
||||||
|
// where marked with a "!!!".
|
||||||
|
|
||||||
|
// func decode(dst, src []byte) int
|
||||||
|
//
|
||||||
|
// All local variables fit into registers. The non-zero stack size is only to
|
||||||
|
// spill registers and push args when issuing a CALL. The register allocation:
|
||||||
|
// - AX scratch
|
||||||
|
// - BX scratch
|
||||||
|
// - CX length or x
|
||||||
|
// - DX offset
|
||||||
|
// - SI &src[s]
|
||||||
|
// - DI &dst[d]
|
||||||
|
// + R8 dst_base
|
||||||
|
// + R9 dst_len
|
||||||
|
// + R10 dst_base + dst_len
|
||||||
|
// + R11 src_base
|
||||||
|
// + R12 src_len
|
||||||
|
// + R13 src_base + src_len
|
||||||
|
// - R14 used by doCopy
|
||||||
|
// - R15 used by doCopy
|
||||||
|
//
|
||||||
|
// The registers R8-R13 (marked with a "+") are set at the start of the
|
||||||
|
// function, and after a CALL returns, and are not otherwise modified.
|
||||||
|
//
|
||||||
|
// The d variable is implicitly DI - R8, and len(dst)-d is R10 - DI.
|
||||||
|
// The s variable is implicitly SI - R11, and len(src)-s is R13 - SI.
|
||||||
|
TEXT ·decode(SB), NOSPLIT, $48-56
|
||||||
|
// Initialize SI, DI and R8-R13.
|
||||||
|
MOVQ dst_base+0(FP), R8
|
||||||
|
MOVQ dst_len+8(FP), R9
|
||||||
|
MOVQ R8, DI
|
||||||
|
MOVQ R8, R10
|
||||||
|
ADDQ R9, R10
|
||||||
|
MOVQ src_base+24(FP), R11
|
||||||
|
MOVQ src_len+32(FP), R12
|
||||||
|
MOVQ R11, SI
|
||||||
|
MOVQ R11, R13
|
||||||
|
ADDQ R12, R13
|
||||||
|
|
||||||
|
loop:
|
||||||
|
// for s < len(src)
|
||||||
|
CMPQ SI, R13
|
||||||
|
JEQ end
|
||||||
|
|
||||||
|
// CX = uint32(src[s])
|
||||||
|
//
|
||||||
|
// switch src[s] & 0x03
|
||||||
|
MOVBLZX (SI), CX
|
||||||
|
MOVL CX, BX
|
||||||
|
ANDL $3, BX
|
||||||
|
CMPL BX, $1
|
||||||
|
JAE tagCopy
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// The code below handles literal tags.
|
||||||
|
|
||||||
|
// case tagLiteral:
|
||||||
|
// x := uint32(src[s] >> 2)
|
||||||
|
// switch
|
||||||
|
SHRL $2, CX
|
||||||
|
CMPL CX, $60
|
||||||
|
JAE tagLit60Plus
|
||||||
|
|
||||||
|
// case x < 60:
|
||||||
|
// s++
|
||||||
|
INCQ SI
|
||||||
|
|
||||||
|
doLit:
|
||||||
|
// This is the end of the inner "switch", when we have a literal tag.
|
||||||
|
//
|
||||||
|
// We assume that CX == x and x fits in a uint32, where x is the variable
|
||||||
|
// used in the pure Go decode_other.go code.
|
||||||
|
|
||||||
|
// length = int(x) + 1
|
||||||
|
//
|
||||||
|
// Unlike the pure Go code, we don't need to check if length <= 0 because
|
||||||
|
// CX can hold 64 bits, so the increment cannot overflow.
|
||||||
|
INCQ CX
|
||||||
|
|
||||||
|
// Prepare to check if copying length bytes will run past the end of dst or
|
||||||
|
// src.
|
||||||
|
//
|
||||||
|
// AX = len(dst) - d
|
||||||
|
// BX = len(src) - s
|
||||||
|
MOVQ R10, AX
|
||||||
|
SUBQ DI, AX
|
||||||
|
MOVQ R13, BX
|
||||||
|
SUBQ SI, BX
|
||||||
|
|
||||||
|
// !!! Try a faster technique for short (16 or fewer bytes) copies.
|
||||||
|
//
|
||||||
|
// if length > 16 || len(dst)-d < 16 || len(src)-s < 16 {
|
||||||
|
// goto callMemmove // Fall back on calling runtime·memmove.
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The C++ snappy code calls this TryFastAppend. It also checks len(src)-s
|
||||||
|
// against 21 instead of 16, because it cannot assume that all of its input
|
||||||
|
// is contiguous in memory and so it needs to leave enough source bytes to
|
||||||
|
// read the next tag without refilling buffers, but Go's Decode assumes
|
||||||
|
// contiguousness (the src argument is a []byte).
|
||||||
|
CMPQ CX, $16
|
||||||
|
JGT callMemmove
|
||||||
|
CMPQ AX, $16
|
||||||
|
JLT callMemmove
|
||||||
|
CMPQ BX, $16
|
||||||
|
JLT callMemmove
|
||||||
|
|
||||||
|
// !!! Implement the copy from src to dst as a 16-byte load and store.
|
||||||
|
// (Decode's documentation says that dst and src must not overlap.)
|
||||||
|
//
|
||||||
|
// This always copies 16 bytes, instead of only length bytes, but that's
|
||||||
|
// OK. If the input is a valid Snappy encoding then subsequent iterations
|
||||||
|
// will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
|
||||||
|
// non-nil error), so the overrun will be ignored.
|
||||||
|
//
|
||||||
|
// Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
|
||||||
|
// 16-byte loads and stores. This technique probably wouldn't be as
|
||||||
|
// effective on architectures that are fussier about alignment.
|
||||||
|
MOVOU 0(SI), X0
|
||||||
|
MOVOU X0, 0(DI)
|
||||||
|
|
||||||
|
// d += length
|
||||||
|
// s += length
|
||||||
|
ADDQ CX, DI
|
||||||
|
ADDQ CX, SI
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
callMemmove:
|
||||||
|
// if length > len(dst)-d || length > len(src)-s { etc }
|
||||||
|
CMPQ CX, AX
|
||||||
|
JGT errCorrupt
|
||||||
|
CMPQ CX, BX
|
||||||
|
JGT errCorrupt
|
||||||
|
|
||||||
|
// copy(dst[d:], src[s:s+length])
|
||||||
|
//
|
||||||
|
// This means calling runtime·memmove(&dst[d], &src[s], length), so we push
|
||||||
|
// DI, SI and CX as arguments. Coincidentally, we also need to spill those
|
||||||
|
// three registers to the stack, to save local variables across the CALL.
|
||||||
|
MOVQ DI, 0(SP)
|
||||||
|
MOVQ SI, 8(SP)
|
||||||
|
MOVQ CX, 16(SP)
|
||||||
|
MOVQ DI, 24(SP)
|
||||||
|
MOVQ SI, 32(SP)
|
||||||
|
MOVQ CX, 40(SP)
|
||||||
|
CALL runtime·memmove(SB)
|
||||||
|
|
||||||
|
// Restore local variables: unspill registers from the stack and
|
||||||
|
// re-calculate R8-R13.
|
||||||
|
MOVQ 24(SP), DI
|
||||||
|
MOVQ 32(SP), SI
|
||||||
|
MOVQ 40(SP), CX
|
||||||
|
MOVQ dst_base+0(FP), R8
|
||||||
|
MOVQ dst_len+8(FP), R9
|
||||||
|
MOVQ R8, R10
|
||||||
|
ADDQ R9, R10
|
||||||
|
MOVQ src_base+24(FP), R11
|
||||||
|
MOVQ src_len+32(FP), R12
|
||||||
|
MOVQ R11, R13
|
||||||
|
ADDQ R12, R13
|
||||||
|
|
||||||
|
// d += length
|
||||||
|
// s += length
|
||||||
|
ADDQ CX, DI
|
||||||
|
ADDQ CX, SI
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
tagLit60Plus:
|
||||||
|
// !!! This fragment does the
|
||||||
|
//
|
||||||
|
// s += x - 58; if uint(s) > uint(len(src)) { etc }
|
||||||
|
//
|
||||||
|
// checks. In the asm version, we code it once instead of once per switch case.
|
||||||
|
ADDQ CX, SI
|
||||||
|
SUBQ $58, SI
|
||||||
|
MOVQ SI, BX
|
||||||
|
SUBQ R11, BX
|
||||||
|
CMPQ BX, R12
|
||||||
|
JA errCorrupt
|
||||||
|
|
||||||
|
// case x == 60:
|
||||||
|
CMPL CX, $61
|
||||||
|
JEQ tagLit61
|
||||||
|
JA tagLit62Plus
|
||||||
|
|
||||||
|
// x = uint32(src[s-1])
|
||||||
|
MOVBLZX -1(SI), CX
|
||||||
|
JMP doLit
|
||||||
|
|
||||||
|
tagLit61:
|
||||||
|
// case x == 61:
|
||||||
|
// x = uint32(src[s-2]) | uint32(src[s-1])<<8
|
||||||
|
MOVWLZX -2(SI), CX
|
||||||
|
JMP doLit
|
||||||
|
|
||||||
|
tagLit62Plus:
|
||||||
|
CMPL CX, $62
|
||||||
|
JA tagLit63
|
||||||
|
|
||||||
|
// case x == 62:
|
||||||
|
// x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
|
||||||
|
MOVWLZX -3(SI), CX
|
||||||
|
MOVBLZX -1(SI), BX
|
||||||
|
SHLL $16, BX
|
||||||
|
ORL BX, CX
|
||||||
|
JMP doLit
|
||||||
|
|
||||||
|
tagLit63:
|
||||||
|
// case x == 63:
|
||||||
|
// x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
|
||||||
|
MOVL -4(SI), CX
|
||||||
|
JMP doLit
|
||||||
|
|
||||||
|
// The code above handles literal tags.
|
||||||
|
// ----------------------------------------
|
||||||
|
// The code below handles copy tags.
|
||||||
|
|
||||||
|
tagCopy4:
|
||||||
|
// case tagCopy4:
|
||||||
|
// s += 5
|
||||||
|
ADDQ $5, SI
|
||||||
|
|
||||||
|
// if uint(s) > uint(len(src)) { etc }
|
||||||
|
MOVQ SI, BX
|
||||||
|
SUBQ R11, BX
|
||||||
|
CMPQ BX, R12
|
||||||
|
JA errCorrupt
|
||||||
|
|
||||||
|
// length = 1 + int(src[s-5])>>2
|
||||||
|
SHRQ $2, CX
|
||||||
|
INCQ CX
|
||||||
|
|
||||||
|
// offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
|
||||||
|
MOVLQZX -4(SI), DX
|
||||||
|
JMP doCopy
|
||||||
|
|
||||||
|
tagCopy2:
|
||||||
|
// case tagCopy2:
|
||||||
|
// s += 3
|
||||||
|
ADDQ $3, SI
|
||||||
|
|
||||||
|
// if uint(s) > uint(len(src)) { etc }
|
||||||
|
MOVQ SI, BX
|
||||||
|
SUBQ R11, BX
|
||||||
|
CMPQ BX, R12
|
||||||
|
JA errCorrupt
|
||||||
|
|
||||||
|
// length = 1 + int(src[s-3])>>2
|
||||||
|
SHRQ $2, CX
|
||||||
|
INCQ CX
|
||||||
|
|
||||||
|
// offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
|
||||||
|
MOVWQZX -2(SI), DX
|
||||||
|
JMP doCopy
|
||||||
|
|
||||||
|
tagCopy:
|
||||||
|
// We have a copy tag. We assume that:
|
||||||
|
// - BX == src[s] & 0x03
|
||||||
|
// - CX == src[s]
|
||||||
|
CMPQ BX, $2
|
||||||
|
JEQ tagCopy2
|
||||||
|
JA tagCopy4
|
||||||
|
|
||||||
|
// case tagCopy1:
|
||||||
|
// s += 2
|
||||||
|
ADDQ $2, SI
|
||||||
|
|
||||||
|
// if uint(s) > uint(len(src)) { etc }
|
||||||
|
MOVQ SI, BX
|
||||||
|
SUBQ R11, BX
|
||||||
|
CMPQ BX, R12
|
||||||
|
JA errCorrupt
|
||||||
|
|
||||||
|
// offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
|
||||||
|
MOVQ CX, DX
|
||||||
|
ANDQ $0xe0, DX
|
||||||
|
SHLQ $3, DX
|
||||||
|
MOVBQZX -1(SI), BX
|
||||||
|
ORQ BX, DX
|
||||||
|
|
||||||
|
// length = 4 + int(src[s-2])>>2&0x7
|
||||||
|
SHRQ $2, CX
|
||||||
|
ANDQ $7, CX
|
||||||
|
ADDQ $4, CX
|
||||||
|
|
||||||
|
doCopy:
|
||||||
|
// This is the end of the outer "switch", when we have a copy tag.
|
||||||
|
//
|
||||||
|
// We assume that:
|
||||||
|
// - CX == length && CX > 0
|
||||||
|
// - DX == offset
|
||||||
|
|
||||||
|
// if offset <= 0 { etc }
|
||||||
|
CMPQ DX, $0
|
||||||
|
JLE errCorrupt
|
||||||
|
|
||||||
|
// if d < offset { etc }
|
||||||
|
MOVQ DI, BX
|
||||||
|
SUBQ R8, BX
|
||||||
|
CMPQ BX, DX
|
||||||
|
JLT errCorrupt
|
||||||
|
|
||||||
|
// if length > len(dst)-d { etc }
|
||||||
|
MOVQ R10, BX
|
||||||
|
SUBQ DI, BX
|
||||||
|
CMPQ CX, BX
|
||||||
|
JGT errCorrupt
|
||||||
|
|
||||||
|
// forwardCopy(dst[d:d+length], dst[d-offset:]); d += length
|
||||||
|
//
|
||||||
|
// Set:
|
||||||
|
// - R14 = len(dst)-d
|
||||||
|
// - R15 = &dst[d-offset]
|
||||||
|
MOVQ R10, R14
|
||||||
|
SUBQ DI, R14
|
||||||
|
MOVQ DI, R15
|
||||||
|
SUBQ DX, R15
|
||||||
|
|
||||||
|
// !!! Try a faster technique for short (16 or fewer bytes) forward copies.
|
||||||
|
//
|
||||||
|
// First, try using two 8-byte load/stores, similar to the doLit technique
|
||||||
|
// above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is
|
||||||
|
// still OK if offset >= 8. Note that this has to be two 8-byte load/stores
|
||||||
|
// and not one 16-byte load/store, and the first store has to be before the
|
||||||
|
// second load, due to the overlap if offset is in the range [8, 16).
|
||||||
|
//
|
||||||
|
// if length > 16 || offset < 8 || len(dst)-d < 16 {
|
||||||
|
// goto slowForwardCopy
|
||||||
|
// }
|
||||||
|
// copy 16 bytes
|
||||||
|
// d += length
|
||||||
|
CMPQ CX, $16
|
||||||
|
JGT slowForwardCopy
|
||||||
|
CMPQ DX, $8
|
||||||
|
JLT slowForwardCopy
|
||||||
|
CMPQ R14, $16
|
||||||
|
JLT slowForwardCopy
|
||||||
|
MOVQ 0(R15), AX
|
||||||
|
MOVQ AX, 0(DI)
|
||||||
|
MOVQ 8(R15), BX
|
||||||
|
MOVQ BX, 8(DI)
|
||||||
|
ADDQ CX, DI
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
slowForwardCopy:
|
||||||
|
// !!! If the forward copy is longer than 16 bytes, or if offset < 8, we
|
||||||
|
// can still try 8-byte load stores, provided we can overrun up to 10 extra
|
||||||
|
// bytes. As above, the overrun will be fixed up by subsequent iterations
|
||||||
|
// of the outermost loop.
|
||||||
|
//
|
||||||
|
// The C++ snappy code calls this technique IncrementalCopyFastPath. Its
|
||||||
|
// commentary says:
|
||||||
|
//
|
||||||
|
// ----
|
||||||
|
//
|
||||||
|
// The main part of this loop is a simple copy of eight bytes at a time
|
||||||
|
// until we've copied (at least) the requested amount of bytes. However,
|
||||||
|
// if d and d-offset are less than eight bytes apart (indicating a
|
||||||
|
// repeating pattern of length < 8), we first need to expand the pattern in
|
||||||
|
// order to get the correct results. For instance, if the buffer looks like
|
||||||
|
// this, with the eight-byte <d-offset> and <d> patterns marked as
|
||||||
|
// intervals:
|
||||||
|
//
|
||||||
|
// abxxxxxxxxxxxx
|
||||||
|
// [------] d-offset
|
||||||
|
// [------] d
|
||||||
|
//
|
||||||
|
// a single eight-byte copy from <d-offset> to <d> will repeat the pattern
|
||||||
|
// once, after which we can move <d> two bytes without moving <d-offset>:
|
||||||
|
//
|
||||||
|
// ababxxxxxxxxxx
|
||||||
|
// [------] d-offset
|
||||||
|
// [------] d
|
||||||
|
//
|
||||||
|
// and repeat the exercise until the two no longer overlap.
|
||||||
|
//
|
||||||
|
// This allows us to do very well in the special case of one single byte
|
||||||
|
// repeated many times, without taking a big hit for more general cases.
|
||||||
|
//
|
||||||
|
// The worst case of extra writing past the end of the match occurs when
|
||||||
|
// offset == 1 and length == 1; the last copy will read from byte positions
|
||||||
|
// [0..7] and write to [4..11], whereas it was only supposed to write to
|
||||||
|
// position 1. Thus, ten excess bytes.
|
||||||
|
//
|
||||||
|
// ----
|
||||||
|
//
|
||||||
|
// That "10 byte overrun" worst case is confirmed by Go's
|
||||||
|
// TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy
|
||||||
|
// and finishSlowForwardCopy algorithm.
|
||||||
|
//
|
||||||
|
// if length > len(dst)-d-10 {
|
||||||
|
// goto verySlowForwardCopy
|
||||||
|
// }
|
||||||
|
SUBQ $10, R14
|
||||||
|
CMPQ CX, R14
|
||||||
|
JGT verySlowForwardCopy
|
||||||
|
|
||||||
|
makeOffsetAtLeast8:
|
||||||
|
// !!! As above, expand the pattern so that offset >= 8 and we can use
|
||||||
|
// 8-byte load/stores.
|
||||||
|
//
|
||||||
|
// for offset < 8 {
|
||||||
|
// copy 8 bytes from dst[d-offset:] to dst[d:]
|
||||||
|
// length -= offset
|
||||||
|
// d += offset
|
||||||
|
// offset += offset
|
||||||
|
// // The two previous lines together means that d-offset, and therefore
|
||||||
|
// // R15, is unchanged.
|
||||||
|
// }
|
||||||
|
CMPQ DX, $8
|
||||||
|
JGE fixUpSlowForwardCopy
|
||||||
|
MOVQ (R15), BX
|
||||||
|
MOVQ BX, (DI)
|
||||||
|
SUBQ DX, CX
|
||||||
|
ADDQ DX, DI
|
||||||
|
ADDQ DX, DX
|
||||||
|
JMP makeOffsetAtLeast8
|
||||||
|
|
||||||
|
fixUpSlowForwardCopy:
|
||||||
|
// !!! Add length (which might be negative now) to d (implied by DI being
|
||||||
|
// &dst[d]) so that d ends up at the right place when we jump back to the
|
||||||
|
// top of the loop. Before we do that, though, we save DI to AX so that, if
|
||||||
|
// length is positive, copying the remaining length bytes will write to the
|
||||||
|
// right place.
|
||||||
|
MOVQ DI, AX
|
||||||
|
ADDQ CX, DI
|
||||||
|
|
||||||
|
finishSlowForwardCopy:
|
||||||
|
// !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative
|
||||||
|
// length means that we overrun, but as above, that will be fixed up by
|
||||||
|
// subsequent iterations of the outermost loop.
|
||||||
|
CMPQ CX, $0
|
||||||
|
JLE loop
|
||||||
|
MOVQ (R15), BX
|
||||||
|
MOVQ BX, (AX)
|
||||||
|
ADDQ $8, R15
|
||||||
|
ADDQ $8, AX
|
||||||
|
SUBQ $8, CX
|
||||||
|
JMP finishSlowForwardCopy
|
||||||
|
|
||||||
|
verySlowForwardCopy:
|
||||||
|
// verySlowForwardCopy is a simple implementation of forward copy. In C
|
||||||
|
// parlance, this is a do/while loop instead of a while loop, since we know
|
||||||
|
// that length > 0. In Go syntax:
|
||||||
|
//
|
||||||
|
// for {
|
||||||
|
// dst[d] = dst[d - offset]
|
||||||
|
// d++
|
||||||
|
// length--
|
||||||
|
// if length == 0 {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
MOVB (R15), BX
|
||||||
|
MOVB BX, (DI)
|
||||||
|
INCQ R15
|
||||||
|
INCQ DI
|
||||||
|
DECQ CX
|
||||||
|
JNZ verySlowForwardCopy
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
// The code above handles copy tags.
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
end:
|
||||||
|
// This is the end of the "for s < len(src)".
|
||||||
|
//
|
||||||
|
// if d != len(dst) { etc }
|
||||||
|
CMPQ DI, R10
|
||||||
|
JNE errCorrupt
|
||||||
|
|
||||||
|
// return 0
|
||||||
|
MOVQ $0, ret+48(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
errCorrupt:
|
||||||
|
// return decodeErrCodeCorrupt
|
||||||
|
MOVQ $1, ret+48(FP)
|
||||||
|
RET
|
494
vendor/github.com/golang/snappy/decode_arm64.s
generated
vendored
Normal file
494
vendor/github.com/golang/snappy/decode_arm64.s
generated
vendored
Normal file
@ -0,0 +1,494 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !noasm
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// The asm code generally follows the pure Go code in decode_other.go, except
|
||||||
|
// where marked with a "!!!".
|
||||||
|
|
||||||
|
// func decode(dst, src []byte) int
|
||||||
|
//
|
||||||
|
// All local variables fit into registers. The non-zero stack size is only to
|
||||||
|
// spill registers and push args when issuing a CALL. The register allocation:
|
||||||
|
// - R2 scratch
|
||||||
|
// - R3 scratch
|
||||||
|
// - R4 length or x
|
||||||
|
// - R5 offset
|
||||||
|
// - R6 &src[s]
|
||||||
|
// - R7 &dst[d]
|
||||||
|
// + R8 dst_base
|
||||||
|
// + R9 dst_len
|
||||||
|
// + R10 dst_base + dst_len
|
||||||
|
// + R11 src_base
|
||||||
|
// + R12 src_len
|
||||||
|
// + R13 src_base + src_len
|
||||||
|
// - R14 used by doCopy
|
||||||
|
// - R15 used by doCopy
|
||||||
|
//
|
||||||
|
// The registers R8-R13 (marked with a "+") are set at the start of the
|
||||||
|
// function, and after a CALL returns, and are not otherwise modified.
|
||||||
|
//
|
||||||
|
// The d variable is implicitly R7 - R8, and len(dst)-d is R10 - R7.
|
||||||
|
// The s variable is implicitly R6 - R11, and len(src)-s is R13 - R6.
|
||||||
|
TEXT ·decode(SB), NOSPLIT, $56-56
|
||||||
|
// Initialize R6, R7 and R8-R13.
|
||||||
|
MOVD dst_base+0(FP), R8
|
||||||
|
MOVD dst_len+8(FP), R9
|
||||||
|
MOVD R8, R7
|
||||||
|
MOVD R8, R10
|
||||||
|
ADD R9, R10, R10
|
||||||
|
MOVD src_base+24(FP), R11
|
||||||
|
MOVD src_len+32(FP), R12
|
||||||
|
MOVD R11, R6
|
||||||
|
MOVD R11, R13
|
||||||
|
ADD R12, R13, R13
|
||||||
|
|
||||||
|
loop:
|
||||||
|
// for s < len(src)
|
||||||
|
CMP R13, R6
|
||||||
|
BEQ end
|
||||||
|
|
||||||
|
// R4 = uint32(src[s])
|
||||||
|
//
|
||||||
|
// switch src[s] & 0x03
|
||||||
|
MOVBU (R6), R4
|
||||||
|
MOVW R4, R3
|
||||||
|
ANDW $3, R3
|
||||||
|
MOVW $1, R1
|
||||||
|
CMPW R1, R3
|
||||||
|
BGE tagCopy
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// The code below handles literal tags.
|
||||||
|
|
||||||
|
// case tagLiteral:
|
||||||
|
// x := uint32(src[s] >> 2)
|
||||||
|
// switch
|
||||||
|
MOVW $60, R1
|
||||||
|
LSRW $2, R4, R4
|
||||||
|
CMPW R4, R1
|
||||||
|
BLS tagLit60Plus
|
||||||
|
|
||||||
|
// case x < 60:
|
||||||
|
// s++
|
||||||
|
ADD $1, R6, R6
|
||||||
|
|
||||||
|
doLit:
|
||||||
|
// This is the end of the inner "switch", when we have a literal tag.
|
||||||
|
//
|
||||||
|
// We assume that R4 == x and x fits in a uint32, where x is the variable
|
||||||
|
// used in the pure Go decode_other.go code.
|
||||||
|
|
||||||
|
// length = int(x) + 1
|
||||||
|
//
|
||||||
|
// Unlike the pure Go code, we don't need to check if length <= 0 because
|
||||||
|
// R4 can hold 64 bits, so the increment cannot overflow.
|
||||||
|
ADD $1, R4, R4
|
||||||
|
|
||||||
|
// Prepare to check if copying length bytes will run past the end of dst or
|
||||||
|
// src.
|
||||||
|
//
|
||||||
|
// R2 = len(dst) - d
|
||||||
|
// R3 = len(src) - s
|
||||||
|
MOVD R10, R2
|
||||||
|
SUB R7, R2, R2
|
||||||
|
MOVD R13, R3
|
||||||
|
SUB R6, R3, R3
|
||||||
|
|
||||||
|
// !!! Try a faster technique for short (16 or fewer bytes) copies.
|
||||||
|
//
|
||||||
|
// if length > 16 || len(dst)-d < 16 || len(src)-s < 16 {
|
||||||
|
// goto callMemmove // Fall back on calling runtime·memmove.
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The C++ snappy code calls this TryFastAppend. It also checks len(src)-s
|
||||||
|
// against 21 instead of 16, because it cannot assume that all of its input
|
||||||
|
// is contiguous in memory and so it needs to leave enough source bytes to
|
||||||
|
// read the next tag without refilling buffers, but Go's Decode assumes
|
||||||
|
// contiguousness (the src argument is a []byte).
|
||||||
|
CMP $16, R4
|
||||||
|
BGT callMemmove
|
||||||
|
CMP $16, R2
|
||||||
|
BLT callMemmove
|
||||||
|
CMP $16, R3
|
||||||
|
BLT callMemmove
|
||||||
|
|
||||||
|
// !!! Implement the copy from src to dst as a 16-byte load and store.
|
||||||
|
// (Decode's documentation says that dst and src must not overlap.)
|
||||||
|
//
|
||||||
|
// This always copies 16 bytes, instead of only length bytes, but that's
|
||||||
|
// OK. If the input is a valid Snappy encoding then subsequent iterations
|
||||||
|
// will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
|
||||||
|
// non-nil error), so the overrun will be ignored.
|
||||||
|
//
|
||||||
|
// Note that on arm64, it is legal and cheap to issue unaligned 8-byte or
|
||||||
|
// 16-byte loads and stores. This technique probably wouldn't be as
|
||||||
|
// effective on architectures that are fussier about alignment.
|
||||||
|
LDP 0(R6), (R14, R15)
|
||||||
|
STP (R14, R15), 0(R7)
|
||||||
|
|
||||||
|
// d += length
|
||||||
|
// s += length
|
||||||
|
ADD R4, R7, R7
|
||||||
|
ADD R4, R6, R6
|
||||||
|
B loop
|
||||||
|
|
||||||
|
callMemmove:
|
||||||
|
// if length > len(dst)-d || length > len(src)-s { etc }
|
||||||
|
CMP R2, R4
|
||||||
|
BGT errCorrupt
|
||||||
|
CMP R3, R4
|
||||||
|
BGT errCorrupt
|
||||||
|
|
||||||
|
// copy(dst[d:], src[s:s+length])
|
||||||
|
//
|
||||||
|
// This means calling runtime·memmove(&dst[d], &src[s], length), so we push
|
||||||
|
// R7, R6 and R4 as arguments. Coincidentally, we also need to spill those
|
||||||
|
// three registers to the stack, to save local variables across the CALL.
|
||||||
|
MOVD R7, 8(RSP)
|
||||||
|
MOVD R6, 16(RSP)
|
||||||
|
MOVD R4, 24(RSP)
|
||||||
|
MOVD R7, 32(RSP)
|
||||||
|
MOVD R6, 40(RSP)
|
||||||
|
MOVD R4, 48(RSP)
|
||||||
|
CALL runtime·memmove(SB)
|
||||||
|
|
||||||
|
// Restore local variables: unspill registers from the stack and
|
||||||
|
// re-calculate R8-R13.
|
||||||
|
MOVD 32(RSP), R7
|
||||||
|
MOVD 40(RSP), R6
|
||||||
|
MOVD 48(RSP), R4
|
||||||
|
MOVD dst_base+0(FP), R8
|
||||||
|
MOVD dst_len+8(FP), R9
|
||||||
|
MOVD R8, R10
|
||||||
|
ADD R9, R10, R10
|
||||||
|
MOVD src_base+24(FP), R11
|
||||||
|
MOVD src_len+32(FP), R12
|
||||||
|
MOVD R11, R13
|
||||||
|
ADD R12, R13, R13
|
||||||
|
|
||||||
|
// d += length
|
||||||
|
// s += length
|
||||||
|
ADD R4, R7, R7
|
||||||
|
ADD R4, R6, R6
|
||||||
|
B loop
|
||||||
|
|
||||||
|
tagLit60Plus:
|
||||||
|
// !!! This fragment does the
|
||||||
|
//
|
||||||
|
// s += x - 58; if uint(s) > uint(len(src)) { etc }
|
||||||
|
//
|
||||||
|
// checks. In the asm version, we code it once instead of once per switch case.
|
||||||
|
ADD R4, R6, R6
|
||||||
|
SUB $58, R6, R6
|
||||||
|
MOVD R6, R3
|
||||||
|
SUB R11, R3, R3
|
||||||
|
CMP R12, R3
|
||||||
|
BGT errCorrupt
|
||||||
|
|
||||||
|
// case x == 60:
|
||||||
|
MOVW $61, R1
|
||||||
|
CMPW R1, R4
|
||||||
|
BEQ tagLit61
|
||||||
|
BGT tagLit62Plus
|
||||||
|
|
||||||
|
// x = uint32(src[s-1])
|
||||||
|
MOVBU -1(R6), R4
|
||||||
|
B doLit
|
||||||
|
|
||||||
|
tagLit61:
|
||||||
|
// case x == 61:
|
||||||
|
// x = uint32(src[s-2]) | uint32(src[s-1])<<8
|
||||||
|
MOVHU -2(R6), R4
|
||||||
|
B doLit
|
||||||
|
|
||||||
|
tagLit62Plus:
|
||||||
|
CMPW $62, R4
|
||||||
|
BHI tagLit63
|
||||||
|
|
||||||
|
// case x == 62:
|
||||||
|
// x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
|
||||||
|
MOVHU -3(R6), R4
|
||||||
|
MOVBU -1(R6), R3
|
||||||
|
ORR R3<<16, R4
|
||||||
|
B doLit
|
||||||
|
|
||||||
|
tagLit63:
|
||||||
|
// case x == 63:
|
||||||
|
// x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
|
||||||
|
MOVWU -4(R6), R4
|
||||||
|
B doLit
|
||||||
|
|
||||||
|
// The code above handles literal tags.
|
||||||
|
// ----------------------------------------
|
||||||
|
// The code below handles copy tags.
|
||||||
|
|
||||||
|
tagCopy4:
|
||||||
|
// case tagCopy4:
|
||||||
|
// s += 5
|
||||||
|
ADD $5, R6, R6
|
||||||
|
|
||||||
|
// if uint(s) > uint(len(src)) { etc }
|
||||||
|
MOVD R6, R3
|
||||||
|
SUB R11, R3, R3
|
||||||
|
CMP R12, R3
|
||||||
|
BGT errCorrupt
|
||||||
|
|
||||||
|
// length = 1 + int(src[s-5])>>2
|
||||||
|
MOVD $1, R1
|
||||||
|
ADD R4>>2, R1, R4
|
||||||
|
|
||||||
|
// offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
|
||||||
|
MOVWU -4(R6), R5
|
||||||
|
B doCopy
|
||||||
|
|
||||||
|
tagCopy2:
|
||||||
|
// case tagCopy2:
|
||||||
|
// s += 3
|
||||||
|
ADD $3, R6, R6
|
||||||
|
|
||||||
|
// if uint(s) > uint(len(src)) { etc }
|
||||||
|
MOVD R6, R3
|
||||||
|
SUB R11, R3, R3
|
||||||
|
CMP R12, R3
|
||||||
|
BGT errCorrupt
|
||||||
|
|
||||||
|
// length = 1 + int(src[s-3])>>2
|
||||||
|
MOVD $1, R1
|
||||||
|
ADD R4>>2, R1, R4
|
||||||
|
|
||||||
|
// offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
|
||||||
|
MOVHU -2(R6), R5
|
||||||
|
B doCopy
|
||||||
|
|
||||||
|
tagCopy:
|
||||||
|
// We have a copy tag. We assume that:
|
||||||
|
// - R3 == src[s] & 0x03
|
||||||
|
// - R4 == src[s]
|
||||||
|
CMP $2, R3
|
||||||
|
BEQ tagCopy2
|
||||||
|
BGT tagCopy4
|
||||||
|
|
||||||
|
// case tagCopy1:
|
||||||
|
// s += 2
|
||||||
|
ADD $2, R6, R6
|
||||||
|
|
||||||
|
// if uint(s) > uint(len(src)) { etc }
|
||||||
|
MOVD R6, R3
|
||||||
|
SUB R11, R3, R3
|
||||||
|
CMP R12, R3
|
||||||
|
BGT errCorrupt
|
||||||
|
|
||||||
|
// offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
|
||||||
|
MOVD R4, R5
|
||||||
|
AND $0xe0, R5
|
||||||
|
MOVBU -1(R6), R3
|
||||||
|
ORR R5<<3, R3, R5
|
||||||
|
|
||||||
|
// length = 4 + int(src[s-2])>>2&0x7
|
||||||
|
MOVD $7, R1
|
||||||
|
AND R4>>2, R1, R4
|
||||||
|
ADD $4, R4, R4
|
||||||
|
|
||||||
|
doCopy:
|
||||||
|
// This is the end of the outer "switch", when we have a copy tag.
|
||||||
|
//
|
||||||
|
// We assume that:
|
||||||
|
// - R4 == length && R4 > 0
|
||||||
|
// - R5 == offset
|
||||||
|
|
||||||
|
// if offset <= 0 { etc }
|
||||||
|
MOVD $0, R1
|
||||||
|
CMP R1, R5
|
||||||
|
BLE errCorrupt
|
||||||
|
|
||||||
|
// if d < offset { etc }
|
||||||
|
MOVD R7, R3
|
||||||
|
SUB R8, R3, R3
|
||||||
|
CMP R5, R3
|
||||||
|
BLT errCorrupt
|
||||||
|
|
||||||
|
// if length > len(dst)-d { etc }
|
||||||
|
MOVD R10, R3
|
||||||
|
SUB R7, R3, R3
|
||||||
|
CMP R3, R4
|
||||||
|
BGT errCorrupt
|
||||||
|
|
||||||
|
// forwardCopy(dst[d:d+length], dst[d-offset:]); d += length
|
||||||
|
//
|
||||||
|
// Set:
|
||||||
|
// - R14 = len(dst)-d
|
||||||
|
// - R15 = &dst[d-offset]
|
||||||
|
MOVD R10, R14
|
||||||
|
SUB R7, R14, R14
|
||||||
|
MOVD R7, R15
|
||||||
|
SUB R5, R15, R15
|
||||||
|
|
||||||
|
// !!! Try a faster technique for short (16 or fewer bytes) forward copies.
|
||||||
|
//
|
||||||
|
// First, try using two 8-byte load/stores, similar to the doLit technique
|
||||||
|
// above. Even if dst[d:d+length] and dst[d-offset:] can overlap, this is
|
||||||
|
// still OK if offset >= 8. Note that this has to be two 8-byte load/stores
|
||||||
|
// and not one 16-byte load/store, and the first store has to be before the
|
||||||
|
// second load, due to the overlap if offset is in the range [8, 16).
|
||||||
|
//
|
||||||
|
// if length > 16 || offset < 8 || len(dst)-d < 16 {
|
||||||
|
// goto slowForwardCopy
|
||||||
|
// }
|
||||||
|
// copy 16 bytes
|
||||||
|
// d += length
|
||||||
|
CMP $16, R4
|
||||||
|
BGT slowForwardCopy
|
||||||
|
CMP $8, R5
|
||||||
|
BLT slowForwardCopy
|
||||||
|
CMP $16, R14
|
||||||
|
BLT slowForwardCopy
|
||||||
|
MOVD 0(R15), R2
|
||||||
|
MOVD R2, 0(R7)
|
||||||
|
MOVD 8(R15), R3
|
||||||
|
MOVD R3, 8(R7)
|
||||||
|
ADD R4, R7, R7
|
||||||
|
B loop
|
||||||
|
|
||||||
|
slowForwardCopy:
|
||||||
|
// !!! If the forward copy is longer than 16 bytes, or if offset < 8, we
|
||||||
|
// can still try 8-byte load stores, provided we can overrun up to 10 extra
|
||||||
|
// bytes. As above, the overrun will be fixed up by subsequent iterations
|
||||||
|
// of the outermost loop.
|
||||||
|
//
|
||||||
|
// The C++ snappy code calls this technique IncrementalCopyFastPath. Its
|
||||||
|
// commentary says:
|
||||||
|
//
|
||||||
|
// ----
|
||||||
|
//
|
||||||
|
// The main part of this loop is a simple copy of eight bytes at a time
|
||||||
|
// until we've copied (at least) the requested amount of bytes. However,
|
||||||
|
// if d and d-offset are less than eight bytes apart (indicating a
|
||||||
|
// repeating pattern of length < 8), we first need to expand the pattern in
|
||||||
|
// order to get the correct results. For instance, if the buffer looks like
|
||||||
|
// this, with the eight-byte <d-offset> and <d> patterns marked as
|
||||||
|
// intervals:
|
||||||
|
//
|
||||||
|
// abxxxxxxxxxxxx
|
||||||
|
// [------] d-offset
|
||||||
|
// [------] d
|
||||||
|
//
|
||||||
|
// a single eight-byte copy from <d-offset> to <d> will repeat the pattern
|
||||||
|
// once, after which we can move <d> two bytes without moving <d-offset>:
|
||||||
|
//
|
||||||
|
// ababxxxxxxxxxx
|
||||||
|
// [------] d-offset
|
||||||
|
// [------] d
|
||||||
|
//
|
||||||
|
// and repeat the exercise until the two no longer overlap.
|
||||||
|
//
|
||||||
|
// This allows us to do very well in the special case of one single byte
|
||||||
|
// repeated many times, without taking a big hit for more general cases.
|
||||||
|
//
|
||||||
|
// The worst case of extra writing past the end of the match occurs when
|
||||||
|
// offset == 1 and length == 1; the last copy will read from byte positions
|
||||||
|
// [0..7] and write to [4..11], whereas it was only supposed to write to
|
||||||
|
// position 1. Thus, ten excess bytes.
|
||||||
|
//
|
||||||
|
// ----
|
||||||
|
//
|
||||||
|
// That "10 byte overrun" worst case is confirmed by Go's
|
||||||
|
// TestSlowForwardCopyOverrun, which also tests the fixUpSlowForwardCopy
|
||||||
|
// and finishSlowForwardCopy algorithm.
|
||||||
|
//
|
||||||
|
// if length > len(dst)-d-10 {
|
||||||
|
// goto verySlowForwardCopy
|
||||||
|
// }
|
||||||
|
SUB $10, R14, R14
|
||||||
|
CMP R14, R4
|
||||||
|
BGT verySlowForwardCopy
|
||||||
|
|
||||||
|
makeOffsetAtLeast8:
|
||||||
|
// !!! As above, expand the pattern so that offset >= 8 and we can use
|
||||||
|
// 8-byte load/stores.
|
||||||
|
//
|
||||||
|
// for offset < 8 {
|
||||||
|
// copy 8 bytes from dst[d-offset:] to dst[d:]
|
||||||
|
// length -= offset
|
||||||
|
// d += offset
|
||||||
|
// offset += offset
|
||||||
|
// // The two previous lines together means that d-offset, and therefore
|
||||||
|
// // R15, is unchanged.
|
||||||
|
// }
|
||||||
|
CMP $8, R5
|
||||||
|
BGE fixUpSlowForwardCopy
|
||||||
|
MOVD (R15), R3
|
||||||
|
MOVD R3, (R7)
|
||||||
|
SUB R5, R4, R4
|
||||||
|
ADD R5, R7, R7
|
||||||
|
ADD R5, R5, R5
|
||||||
|
B makeOffsetAtLeast8
|
||||||
|
|
||||||
|
fixUpSlowForwardCopy:
|
||||||
|
// !!! Add length (which might be negative now) to d (implied by R7 being
|
||||||
|
// &dst[d]) so that d ends up at the right place when we jump back to the
|
||||||
|
// top of the loop. Before we do that, though, we save R7 to R2 so that, if
|
||||||
|
// length is positive, copying the remaining length bytes will write to the
|
||||||
|
// right place.
|
||||||
|
MOVD R7, R2
|
||||||
|
ADD R4, R7, R7
|
||||||
|
|
||||||
|
finishSlowForwardCopy:
|
||||||
|
// !!! Repeat 8-byte load/stores until length <= 0. Ending with a negative
|
||||||
|
// length means that we overrun, but as above, that will be fixed up by
|
||||||
|
// subsequent iterations of the outermost loop.
|
||||||
|
MOVD $0, R1
|
||||||
|
CMP R1, R4
|
||||||
|
BLE loop
|
||||||
|
MOVD (R15), R3
|
||||||
|
MOVD R3, (R2)
|
||||||
|
ADD $8, R15, R15
|
||||||
|
ADD $8, R2, R2
|
||||||
|
SUB $8, R4, R4
|
||||||
|
B finishSlowForwardCopy
|
||||||
|
|
||||||
|
verySlowForwardCopy:
|
||||||
|
// verySlowForwardCopy is a simple implementation of forward copy. In C
|
||||||
|
// parlance, this is a do/while loop instead of a while loop, since we know
|
||||||
|
// that length > 0. In Go syntax:
|
||||||
|
//
|
||||||
|
// for {
|
||||||
|
// dst[d] = dst[d - offset]
|
||||||
|
// d++
|
||||||
|
// length--
|
||||||
|
// if length == 0 {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
MOVB (R15), R3
|
||||||
|
MOVB R3, (R7)
|
||||||
|
ADD $1, R15, R15
|
||||||
|
ADD $1, R7, R7
|
||||||
|
SUB $1, R4, R4
|
||||||
|
CBNZ R4, verySlowForwardCopy
|
||||||
|
B loop
|
||||||
|
|
||||||
|
// The code above handles copy tags.
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
end:
|
||||||
|
// This is the end of the "for s < len(src)".
|
||||||
|
//
|
||||||
|
// if d != len(dst) { etc }
|
||||||
|
CMP R10, R7
|
||||||
|
BNE errCorrupt
|
||||||
|
|
||||||
|
// return 0
|
||||||
|
MOVD $0, ret+48(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
errCorrupt:
|
||||||
|
// return decodeErrCodeCorrupt
|
||||||
|
MOVD $1, R2
|
||||||
|
MOVD R2, ret+48(FP)
|
||||||
|
RET
|
15
vendor/github.com/golang/snappy/decode_asm.go
generated
vendored
Normal file
15
vendor/github.com/golang/snappy/decode_asm.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2016 The Snappy-Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !noasm
|
||||||
|
// +build amd64 arm64
|
||||||
|
|
||||||
|
package snappy
|
||||||
|
|
||||||
|
// decode has the same semantics as in decode_other.go.
|
||||||
|
//
|
||||||
|
//go:noescape
|
||||||
|
func decode(dst, src []byte) int
|
115
vendor/github.com/golang/snappy/decode_other.go
generated
vendored
Normal file
115
vendor/github.com/golang/snappy/decode_other.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright 2016 The Snappy-Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !amd64,!arm64 appengine !gc noasm
|
||||||
|
|
||||||
|
package snappy
|
||||||
|
|
||||||
|
// decode writes the decoding of src to dst. It assumes that the varint-encoded
|
||||||
|
// length of the decompressed bytes has already been read, and that len(dst)
|
||||||
|
// equals that length.
|
||||||
|
//
|
||||||
|
// It returns 0 on success or a decodeErrCodeXxx error code on failure.
|
||||||
|
func decode(dst, src []byte) int {
|
||||||
|
var d, s, offset, length int
|
||||||
|
for s < len(src) {
|
||||||
|
switch src[s] & 0x03 {
|
||||||
|
case tagLiteral:
|
||||||
|
x := uint32(src[s] >> 2)
|
||||||
|
switch {
|
||||||
|
case x < 60:
|
||||||
|
s++
|
||||||
|
case x == 60:
|
||||||
|
s += 2
|
||||||
|
if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
x = uint32(src[s-1])
|
||||||
|
case x == 61:
|
||||||
|
s += 3
|
||||||
|
if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
x = uint32(src[s-2]) | uint32(src[s-1])<<8
|
||||||
|
case x == 62:
|
||||||
|
s += 4
|
||||||
|
if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
|
||||||
|
case x == 63:
|
||||||
|
s += 5
|
||||||
|
if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
|
||||||
|
}
|
||||||
|
length = int(x) + 1
|
||||||
|
if length <= 0 {
|
||||||
|
return decodeErrCodeUnsupportedLiteralLength
|
||||||
|
}
|
||||||
|
if length > len(dst)-d || length > len(src)-s {
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
copy(dst[d:], src[s:s+length])
|
||||||
|
d += length
|
||||||
|
s += length
|
||||||
|
continue
|
||||||
|
|
||||||
|
case tagCopy1:
|
||||||
|
s += 2
|
||||||
|
if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
length = 4 + int(src[s-2])>>2&0x7
|
||||||
|
offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
|
||||||
|
|
||||||
|
case tagCopy2:
|
||||||
|
s += 3
|
||||||
|
if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
length = 1 + int(src[s-3])>>2
|
||||||
|
offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
|
||||||
|
|
||||||
|
case tagCopy4:
|
||||||
|
s += 5
|
||||||
|
if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
length = 1 + int(src[s-5])>>2
|
||||||
|
offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
|
||||||
|
}
|
||||||
|
|
||||||
|
if offset <= 0 || d < offset || length > len(dst)-d {
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
// Copy from an earlier sub-slice of dst to a later sub-slice.
|
||||||
|
// If no overlap, use the built-in copy:
|
||||||
|
if offset >= length {
|
||||||
|
copy(dst[d:d+length], dst[d-offset:])
|
||||||
|
d += length
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlike the built-in copy function, this byte-by-byte copy always runs
|
||||||
|
// forwards, even if the slices overlap. Conceptually, this is:
|
||||||
|
//
|
||||||
|
// d += forwardCopy(dst[d:d+length], dst[d-offset:])
|
||||||
|
//
|
||||||
|
// We align the slices into a and b and show the compiler they are the same size.
|
||||||
|
// This allows the loop to run without bounds checks.
|
||||||
|
a := dst[d : d+length]
|
||||||
|
b := dst[d-offset:]
|
||||||
|
b = b[:len(a)]
|
||||||
|
for i := range a {
|
||||||
|
a[i] = b[i]
|
||||||
|
}
|
||||||
|
d += length
|
||||||
|
}
|
||||||
|
if d != len(dst) {
|
||||||
|
return decodeErrCodeCorrupt
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
289
vendor/github.com/golang/snappy/encode.go
generated
vendored
Normal file
289
vendor/github.com/golang/snappy/encode.go
generated
vendored
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package snappy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encode returns the encoded form of src. The returned slice may be a sub-
|
||||||
|
// slice of dst if dst was large enough to hold the entire encoded block.
|
||||||
|
// Otherwise, a newly allocated slice will be returned.
|
||||||
|
//
|
||||||
|
// The dst and src must not overlap. It is valid to pass a nil dst.
|
||||||
|
//
|
||||||
|
// Encode handles the Snappy block format, not the Snappy stream format.
|
||||||
|
func Encode(dst, src []byte) []byte {
|
||||||
|
if n := MaxEncodedLen(len(src)); n < 0 {
|
||||||
|
panic(ErrTooLarge)
|
||||||
|
} else if len(dst) < n {
|
||||||
|
dst = make([]byte, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The block starts with the varint-encoded length of the decompressed bytes.
|
||||||
|
d := binary.PutUvarint(dst, uint64(len(src)))
|
||||||
|
|
||||||
|
for len(src) > 0 {
|
||||||
|
p := src
|
||||||
|
src = nil
|
||||||
|
if len(p) > maxBlockSize {
|
||||||
|
p, src = p[:maxBlockSize], p[maxBlockSize:]
|
||||||
|
}
|
||||||
|
if len(p) < minNonLiteralBlockSize {
|
||||||
|
d += emitLiteral(dst[d:], p)
|
||||||
|
} else {
|
||||||
|
d += encodeBlock(dst[d:], p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dst[:d]
|
||||||
|
}
|
||||||
|
|
||||||
|
// inputMargin is the minimum number of extra input bytes to keep, inside
|
||||||
|
// encodeBlock's inner loop. On some architectures, this margin lets us
|
||||||
|
// implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
|
||||||
|
// literals can be implemented as a single load to and store from a 16-byte
|
||||||
|
// register. That literal's actual length can be as short as 1 byte, so this
|
||||||
|
// can copy up to 15 bytes too much, but that's OK as subsequent iterations of
|
||||||
|
// the encoding loop will fix up the copy overrun, and this inputMargin ensures
|
||||||
|
// that we don't overrun the dst and src buffers.
|
||||||
|
const inputMargin = 16 - 1
|
||||||
|
|
||||||
|
// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
|
||||||
|
// could be encoded with a copy tag. This is the minimum with respect to the
|
||||||
|
// algorithm used by encodeBlock, not a minimum enforced by the file format.
|
||||||
|
//
|
||||||
|
// The encoded output must start with at least a 1 byte literal, as there are
|
||||||
|
// no previous bytes to copy. A minimal (1 byte) copy after that, generated
|
||||||
|
// from an emitCopy call in encodeBlock's main loop, would require at least
|
||||||
|
// another inputMargin bytes, for the reason above: we want any emitLiteral
|
||||||
|
// calls inside encodeBlock's main loop to use the fast path if possible, which
|
||||||
|
// requires being able to overrun by inputMargin bytes. Thus,
|
||||||
|
// minNonLiteralBlockSize equals 1 + 1 + inputMargin.
|
||||||
|
//
|
||||||
|
// The C++ code doesn't use this exact threshold, but it could, as discussed at
|
||||||
|
// https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion
|
||||||
|
// The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an
|
||||||
|
// optimization. It should not affect the encoded form. This is tested by
|
||||||
|
// TestSameEncodingAsCppShortCopies.
|
||||||
|
const minNonLiteralBlockSize = 1 + 1 + inputMargin
|
||||||
|
|
||||||
|
// MaxEncodedLen returns the maximum length of a snappy block, given its
|
||||||
|
// uncompressed length.
|
||||||
|
//
|
||||||
|
// It will return a negative value if srcLen is too large to encode.
|
||||||
|
func MaxEncodedLen(srcLen int) int {
|
||||||
|
n := uint64(srcLen)
|
||||||
|
if n > 0xffffffff {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
// Compressed data can be defined as:
|
||||||
|
// compressed := item* literal*
|
||||||
|
// item := literal* copy
|
||||||
|
//
|
||||||
|
// The trailing literal sequence has a space blowup of at most 62/60
|
||||||
|
// since a literal of length 60 needs one tag byte + one extra byte
|
||||||
|
// for length information.
|
||||||
|
//
|
||||||
|
// Item blowup is trickier to measure. Suppose the "copy" op copies
|
||||||
|
// 4 bytes of data. Because of a special check in the encoding code,
|
||||||
|
// we produce a 4-byte copy only if the offset is < 65536. Therefore
|
||||||
|
// the copy op takes 3 bytes to encode, and this type of item leads
|
||||||
|
// to at most the 62/60 blowup for representing literals.
|
||||||
|
//
|
||||||
|
// Suppose the "copy" op copies 5 bytes of data. If the offset is big
|
||||||
|
// enough, it will take 5 bytes to encode the copy op. Therefore the
|
||||||
|
// worst case here is a one-byte literal followed by a five-byte copy.
|
||||||
|
// That is, 6 bytes of input turn into 7 bytes of "compressed" data.
|
||||||
|
//
|
||||||
|
// This last factor dominates the blowup, so the final estimate is:
|
||||||
|
n = 32 + n + n/6
|
||||||
|
if n > 0xffffffff {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errClosed = errors.New("snappy: Writer is closed")
|
||||||
|
|
||||||
|
// NewWriter returns a new Writer that compresses to w.
|
||||||
|
//
|
||||||
|
// The Writer returned does not buffer writes. There is no need to Flush or
|
||||||
|
// Close such a Writer.
|
||||||
|
//
|
||||||
|
// Deprecated: the Writer returned is not suitable for many small writes, only
|
||||||
|
// for few large writes. Use NewBufferedWriter instead, which is efficient
|
||||||
|
// regardless of the frequency and shape of the writes, and remember to Close
|
||||||
|
// that Writer when done.
|
||||||
|
func NewWriter(w io.Writer) *Writer {
|
||||||
|
return &Writer{
|
||||||
|
w: w,
|
||||||
|
obuf: make([]byte, obufLen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBufferedWriter returns a new Writer that compresses to w, using the
|
||||||
|
// framing format described at
|
||||||
|
// https://github.com/google/snappy/blob/master/framing_format.txt
|
||||||
|
//
|
||||||
|
// The Writer returned buffers writes. Users must call Close to guarantee all
|
||||||
|
// data has been forwarded to the underlying io.Writer. They may also call
|
||||||
|
// Flush zero or more times before calling Close.
|
||||||
|
func NewBufferedWriter(w io.Writer) *Writer {
|
||||||
|
return &Writer{
|
||||||
|
w: w,
|
||||||
|
ibuf: make([]byte, 0, maxBlockSize),
|
||||||
|
obuf: make([]byte, obufLen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writer is an io.Writer that can write Snappy-compressed bytes.
|
||||||
|
//
|
||||||
|
// Writer handles the Snappy stream format, not the Snappy block format.
|
||||||
|
type Writer struct {
|
||||||
|
w io.Writer
|
||||||
|
err error
|
||||||
|
|
||||||
|
// ibuf is a buffer for the incoming (uncompressed) bytes.
|
||||||
|
//
|
||||||
|
// Its use is optional. For backwards compatibility, Writers created by the
|
||||||
|
// NewWriter function have ibuf == nil, do not buffer incoming bytes, and
|
||||||
|
// therefore do not need to be Flush'ed or Close'd.
|
||||||
|
ibuf []byte
|
||||||
|
|
||||||
|
// obuf is a buffer for the outgoing (compressed) bytes.
|
||||||
|
obuf []byte
|
||||||
|
|
||||||
|
// wroteStreamHeader is whether we have written the stream header.
|
||||||
|
wroteStreamHeader bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset discards the writer's state and switches the Snappy writer to write to
|
||||||
|
// w. This permits reusing a Writer rather than allocating a new one.
|
||||||
|
func (w *Writer) Reset(writer io.Writer) {
|
||||||
|
w.w = writer
|
||||||
|
w.err = nil
|
||||||
|
if w.ibuf != nil {
|
||||||
|
w.ibuf = w.ibuf[:0]
|
||||||
|
}
|
||||||
|
w.wroteStreamHeader = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write satisfies the io.Writer interface.
|
||||||
|
func (w *Writer) Write(p []byte) (nRet int, errRet error) {
|
||||||
|
if w.ibuf == nil {
|
||||||
|
// Do not buffer incoming bytes. This does not perform or compress well
|
||||||
|
// if the caller of Writer.Write writes many small slices. This
|
||||||
|
// behavior is therefore deprecated, but still supported for backwards
|
||||||
|
// compatibility with code that doesn't explicitly Flush or Close.
|
||||||
|
return w.write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The remainder of this method is based on bufio.Writer.Write from the
|
||||||
|
// standard library.
|
||||||
|
|
||||||
|
for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil {
|
||||||
|
var n int
|
||||||
|
if len(w.ibuf) == 0 {
|
||||||
|
// Large write, empty buffer.
|
||||||
|
// Write directly from p to avoid copy.
|
||||||
|
n, _ = w.write(p)
|
||||||
|
} else {
|
||||||
|
n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
|
||||||
|
w.ibuf = w.ibuf[:len(w.ibuf)+n]
|
||||||
|
w.Flush()
|
||||||
|
}
|
||||||
|
nRet += n
|
||||||
|
p = p[n:]
|
||||||
|
}
|
||||||
|
if w.err != nil {
|
||||||
|
return nRet, w.err
|
||||||
|
}
|
||||||
|
n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
|
||||||
|
w.ibuf = w.ibuf[:len(w.ibuf)+n]
|
||||||
|
nRet += n
|
||||||
|
return nRet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) write(p []byte) (nRet int, errRet error) {
|
||||||
|
if w.err != nil {
|
||||||
|
return 0, w.err
|
||||||
|
}
|
||||||
|
for len(p) > 0 {
|
||||||
|
obufStart := len(magicChunk)
|
||||||
|
if !w.wroteStreamHeader {
|
||||||
|
w.wroteStreamHeader = true
|
||||||
|
copy(w.obuf, magicChunk)
|
||||||
|
obufStart = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var uncompressed []byte
|
||||||
|
if len(p) > maxBlockSize {
|
||||||
|
uncompressed, p = p[:maxBlockSize], p[maxBlockSize:]
|
||||||
|
} else {
|
||||||
|
uncompressed, p = p, nil
|
||||||
|
}
|
||||||
|
checksum := crc(uncompressed)
|
||||||
|
|
||||||
|
// Compress the buffer, discarding the result if the improvement
|
||||||
|
// isn't at least 12.5%.
|
||||||
|
compressed := Encode(w.obuf[obufHeaderLen:], uncompressed)
|
||||||
|
chunkType := uint8(chunkTypeCompressedData)
|
||||||
|
chunkLen := 4 + len(compressed)
|
||||||
|
obufEnd := obufHeaderLen + len(compressed)
|
||||||
|
if len(compressed) >= len(uncompressed)-len(uncompressed)/8 {
|
||||||
|
chunkType = chunkTypeUncompressedData
|
||||||
|
chunkLen = 4 + len(uncompressed)
|
||||||
|
obufEnd = obufHeaderLen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in the per-chunk header that comes before the body.
|
||||||
|
w.obuf[len(magicChunk)+0] = chunkType
|
||||||
|
w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0)
|
||||||
|
w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8)
|
||||||
|
w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16)
|
||||||
|
w.obuf[len(magicChunk)+4] = uint8(checksum >> 0)
|
||||||
|
w.obuf[len(magicChunk)+5] = uint8(checksum >> 8)
|
||||||
|
w.obuf[len(magicChunk)+6] = uint8(checksum >> 16)
|
||||||
|
w.obuf[len(magicChunk)+7] = uint8(checksum >> 24)
|
||||||
|
|
||||||
|
if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil {
|
||||||
|
w.err = err
|
||||||
|
return nRet, err
|
||||||
|
}
|
||||||
|
if chunkType == chunkTypeUncompressedData {
|
||||||
|
if _, err := w.w.Write(uncompressed); err != nil {
|
||||||
|
w.err = err
|
||||||
|
return nRet, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nRet += len(uncompressed)
|
||||||
|
}
|
||||||
|
return nRet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush flushes the Writer to its underlying io.Writer.
|
||||||
|
func (w *Writer) Flush() error {
|
||||||
|
if w.err != nil {
|
||||||
|
return w.err
|
||||||
|
}
|
||||||
|
if len(w.ibuf) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.write(w.ibuf)
|
||||||
|
w.ibuf = w.ibuf[:0]
|
||||||
|
return w.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close calls Flush and then closes the Writer.
|
||||||
|
func (w *Writer) Close() error {
|
||||||
|
w.Flush()
|
||||||
|
ret := w.err
|
||||||
|
if w.err == nil {
|
||||||
|
w.err = errClosed
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
730
vendor/github.com/golang/snappy/encode_amd64.s
generated
vendored
Normal file
730
vendor/github.com/golang/snappy/encode_amd64.s
generated
vendored
Normal file
@ -0,0 +1,730 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !noasm
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// The XXX lines assemble on Go 1.4, 1.5 and 1.7, but not 1.6, due to a
|
||||||
|
// Go toolchain regression. See https://github.com/golang/go/issues/15426 and
|
||||||
|
// https://github.com/golang/snappy/issues/29
|
||||||
|
//
|
||||||
|
// As a workaround, the package was built with a known good assembler, and
|
||||||
|
// those instructions were disassembled by "objdump -d" to yield the
|
||||||
|
// 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15
|
||||||
|
// style comments, in AT&T asm syntax. Note that rsp here is a physical
|
||||||
|
// register, not Go/asm's SP pseudo-register (see https://golang.org/doc/asm).
|
||||||
|
// The instructions were then encoded as "BYTE $0x.." sequences, which assemble
|
||||||
|
// fine on Go 1.6.
|
||||||
|
|
||||||
|
// The asm code generally follows the pure Go code in encode_other.go, except
|
||||||
|
// where marked with a "!!!".
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// func emitLiteral(dst, lit []byte) int
|
||||||
|
//
|
||||||
|
// All local variables fit into registers. The register allocation:
|
||||||
|
// - AX len(lit)
|
||||||
|
// - BX n
|
||||||
|
// - DX return value
|
||||||
|
// - DI &dst[i]
|
||||||
|
// - R10 &lit[0]
|
||||||
|
//
|
||||||
|
// The 24 bytes of stack space is to call runtime·memmove.
|
||||||
|
//
|
||||||
|
// The unusual register allocation of local variables, such as R10 for the
|
||||||
|
// source pointer, matches the allocation used at the call site in encodeBlock,
|
||||||
|
// which makes it easier to manually inline this function.
|
||||||
|
TEXT ·emitLiteral(SB), NOSPLIT, $24-56
|
||||||
|
MOVQ dst_base+0(FP), DI
|
||||||
|
MOVQ lit_base+24(FP), R10
|
||||||
|
MOVQ lit_len+32(FP), AX
|
||||||
|
MOVQ AX, DX
|
||||||
|
MOVL AX, BX
|
||||||
|
SUBL $1, BX
|
||||||
|
|
||||||
|
CMPL BX, $60
|
||||||
|
JLT oneByte
|
||||||
|
CMPL BX, $256
|
||||||
|
JLT twoBytes
|
||||||
|
|
||||||
|
threeBytes:
|
||||||
|
MOVB $0xf4, 0(DI)
|
||||||
|
MOVW BX, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
ADDQ $3, DX
|
||||||
|
JMP memmove
|
||||||
|
|
||||||
|
twoBytes:
|
||||||
|
MOVB $0xf0, 0(DI)
|
||||||
|
MOVB BX, 1(DI)
|
||||||
|
ADDQ $2, DI
|
||||||
|
ADDQ $2, DX
|
||||||
|
JMP memmove
|
||||||
|
|
||||||
|
oneByte:
|
||||||
|
SHLB $2, BX
|
||||||
|
MOVB BX, 0(DI)
|
||||||
|
ADDQ $1, DI
|
||||||
|
ADDQ $1, DX
|
||||||
|
|
||||||
|
memmove:
|
||||||
|
MOVQ DX, ret+48(FP)
|
||||||
|
|
||||||
|
// copy(dst[i:], lit)
|
||||||
|
//
|
||||||
|
// This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push
|
||||||
|
// DI, R10 and AX as arguments.
|
||||||
|
MOVQ DI, 0(SP)
|
||||||
|
MOVQ R10, 8(SP)
|
||||||
|
MOVQ AX, 16(SP)
|
||||||
|
CALL runtime·memmove(SB)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// func emitCopy(dst []byte, offset, length int) int
|
||||||
|
//
|
||||||
|
// All local variables fit into registers. The register allocation:
|
||||||
|
// - AX length
|
||||||
|
// - SI &dst[0]
|
||||||
|
// - DI &dst[i]
|
||||||
|
// - R11 offset
|
||||||
|
//
|
||||||
|
// The unusual register allocation of local variables, such as R11 for the
|
||||||
|
// offset, matches the allocation used at the call site in encodeBlock, which
|
||||||
|
// makes it easier to manually inline this function.
|
||||||
|
TEXT ·emitCopy(SB), NOSPLIT, $0-48
|
||||||
|
MOVQ dst_base+0(FP), DI
|
||||||
|
MOVQ DI, SI
|
||||||
|
MOVQ offset+24(FP), R11
|
||||||
|
MOVQ length+32(FP), AX
|
||||||
|
|
||||||
|
loop0:
|
||||||
|
// for length >= 68 { etc }
|
||||||
|
CMPL AX, $68
|
||||||
|
JLT step1
|
||||||
|
|
||||||
|
// Emit a length 64 copy, encoded as 3 bytes.
|
||||||
|
MOVB $0xfe, 0(DI)
|
||||||
|
MOVW R11, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
SUBL $64, AX
|
||||||
|
JMP loop0
|
||||||
|
|
||||||
|
step1:
|
||||||
|
// if length > 64 { etc }
|
||||||
|
CMPL AX, $64
|
||||||
|
JLE step2
|
||||||
|
|
||||||
|
// Emit a length 60 copy, encoded as 3 bytes.
|
||||||
|
MOVB $0xee, 0(DI)
|
||||||
|
MOVW R11, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
SUBL $60, AX
|
||||||
|
|
||||||
|
step2:
|
||||||
|
// if length >= 12 || offset >= 2048 { goto step3 }
|
||||||
|
CMPL AX, $12
|
||||||
|
JGE step3
|
||||||
|
CMPL R11, $2048
|
||||||
|
JGE step3
|
||||||
|
|
||||||
|
// Emit the remaining copy, encoded as 2 bytes.
|
||||||
|
MOVB R11, 1(DI)
|
||||||
|
SHRL $8, R11
|
||||||
|
SHLB $5, R11
|
||||||
|
SUBB $4, AX
|
||||||
|
SHLB $2, AX
|
||||||
|
ORB AX, R11
|
||||||
|
ORB $1, R11
|
||||||
|
MOVB R11, 0(DI)
|
||||||
|
ADDQ $2, DI
|
||||||
|
|
||||||
|
// Return the number of bytes written.
|
||||||
|
SUBQ SI, DI
|
||||||
|
MOVQ DI, ret+40(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
step3:
|
||||||
|
// Emit the remaining copy, encoded as 3 bytes.
|
||||||
|
SUBL $1, AX
|
||||||
|
SHLB $2, AX
|
||||||
|
ORB $2, AX
|
||||||
|
MOVB AX, 0(DI)
|
||||||
|
MOVW R11, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
|
||||||
|
// Return the number of bytes written.
|
||||||
|
SUBQ SI, DI
|
||||||
|
MOVQ DI, ret+40(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// func extendMatch(src []byte, i, j int) int
|
||||||
|
//
|
||||||
|
// All local variables fit into registers. The register allocation:
|
||||||
|
// - DX &src[0]
|
||||||
|
// - SI &src[j]
|
||||||
|
// - R13 &src[len(src) - 8]
|
||||||
|
// - R14 &src[len(src)]
|
||||||
|
// - R15 &src[i]
|
||||||
|
//
|
||||||
|
// The unusual register allocation of local variables, such as R15 for a source
|
||||||
|
// pointer, matches the allocation used at the call site in encodeBlock, which
|
||||||
|
// makes it easier to manually inline this function.
|
||||||
|
TEXT ·extendMatch(SB), NOSPLIT, $0-48
|
||||||
|
MOVQ src_base+0(FP), DX
|
||||||
|
MOVQ src_len+8(FP), R14
|
||||||
|
MOVQ i+24(FP), R15
|
||||||
|
MOVQ j+32(FP), SI
|
||||||
|
ADDQ DX, R14
|
||||||
|
ADDQ DX, R15
|
||||||
|
ADDQ DX, SI
|
||||||
|
MOVQ R14, R13
|
||||||
|
SUBQ $8, R13
|
||||||
|
|
||||||
|
cmp8:
|
||||||
|
// As long as we are 8 or more bytes before the end of src, we can load and
|
||||||
|
// compare 8 bytes at a time. If those 8 bytes are equal, repeat.
|
||||||
|
CMPQ SI, R13
|
||||||
|
JA cmp1
|
||||||
|
MOVQ (R15), AX
|
||||||
|
MOVQ (SI), BX
|
||||||
|
CMPQ AX, BX
|
||||||
|
JNE bsf
|
||||||
|
ADDQ $8, R15
|
||||||
|
ADDQ $8, SI
|
||||||
|
JMP cmp8
|
||||||
|
|
||||||
|
bsf:
|
||||||
|
// If those 8 bytes were not equal, XOR the two 8 byte values, and return
|
||||||
|
// the index of the first byte that differs. The BSF instruction finds the
|
||||||
|
// least significant 1 bit, the amd64 architecture is little-endian, and
|
||||||
|
// the shift by 3 converts a bit index to a byte index.
|
||||||
|
XORQ AX, BX
|
||||||
|
BSFQ BX, BX
|
||||||
|
SHRQ $3, BX
|
||||||
|
ADDQ BX, SI
|
||||||
|
|
||||||
|
// Convert from &src[ret] to ret.
|
||||||
|
SUBQ DX, SI
|
||||||
|
MOVQ SI, ret+40(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
cmp1:
|
||||||
|
// In src's tail, compare 1 byte at a time.
|
||||||
|
CMPQ SI, R14
|
||||||
|
JAE extendMatchEnd
|
||||||
|
MOVB (R15), AX
|
||||||
|
MOVB (SI), BX
|
||||||
|
CMPB AX, BX
|
||||||
|
JNE extendMatchEnd
|
||||||
|
ADDQ $1, R15
|
||||||
|
ADDQ $1, SI
|
||||||
|
JMP cmp1
|
||||||
|
|
||||||
|
extendMatchEnd:
|
||||||
|
// Convert from &src[ret] to ret.
|
||||||
|
SUBQ DX, SI
|
||||||
|
MOVQ SI, ret+40(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// func encodeBlock(dst, src []byte) (d int)
|
||||||
|
//
|
||||||
|
// All local variables fit into registers, other than "var table". The register
|
||||||
|
// allocation:
|
||||||
|
// - AX . .
|
||||||
|
// - BX . .
|
||||||
|
// - CX 56 shift (note that amd64 shifts by non-immediates must use CX).
|
||||||
|
// - DX 64 &src[0], tableSize
|
||||||
|
// - SI 72 &src[s]
|
||||||
|
// - DI 80 &dst[d]
|
||||||
|
// - R9 88 sLimit
|
||||||
|
// - R10 . &src[nextEmit]
|
||||||
|
// - R11 96 prevHash, currHash, nextHash, offset
|
||||||
|
// - R12 104 &src[base], skip
|
||||||
|
// - R13 . &src[nextS], &src[len(src) - 8]
|
||||||
|
// - R14 . len(src), bytesBetweenHashLookups, &src[len(src)], x
|
||||||
|
// - R15 112 candidate
|
||||||
|
//
|
||||||
|
// The second column (56, 64, etc) is the stack offset to spill the registers
|
||||||
|
// when calling other functions. We could pack this slightly tighter, but it's
|
||||||
|
// simpler to have a dedicated spill map independent of the function called.
|
||||||
|
//
|
||||||
|
// "var table [maxTableSize]uint16" takes up 32768 bytes of stack space. An
|
||||||
|
// extra 56 bytes, to call other functions, and an extra 64 bytes, to spill
|
||||||
|
// local variables (registers) during calls gives 32768 + 56 + 64 = 32888.
|
||||||
|
TEXT ·encodeBlock(SB), 0, $32888-56
|
||||||
|
MOVQ dst_base+0(FP), DI
|
||||||
|
MOVQ src_base+24(FP), SI
|
||||||
|
MOVQ src_len+32(FP), R14
|
||||||
|
|
||||||
|
// shift, tableSize := uint32(32-8), 1<<8
|
||||||
|
MOVQ $24, CX
|
||||||
|
MOVQ $256, DX
|
||||||
|
|
||||||
|
calcShift:
|
||||||
|
// for ; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 {
|
||||||
|
// shift--
|
||||||
|
// }
|
||||||
|
CMPQ DX, $16384
|
||||||
|
JGE varTable
|
||||||
|
CMPQ DX, R14
|
||||||
|
JGE varTable
|
||||||
|
SUBQ $1, CX
|
||||||
|
SHLQ $1, DX
|
||||||
|
JMP calcShift
|
||||||
|
|
||||||
|
varTable:
|
||||||
|
// var table [maxTableSize]uint16
|
||||||
|
//
|
||||||
|
// In the asm code, unlike the Go code, we can zero-initialize only the
|
||||||
|
// first tableSize elements. Each uint16 element is 2 bytes and each MOVOU
|
||||||
|
// writes 16 bytes, so we can do only tableSize/8 writes instead of the
|
||||||
|
// 2048 writes that would zero-initialize all of table's 32768 bytes.
|
||||||
|
SHRQ $3, DX
|
||||||
|
LEAQ table-32768(SP), BX
|
||||||
|
PXOR X0, X0
|
||||||
|
|
||||||
|
memclr:
|
||||||
|
MOVOU X0, 0(BX)
|
||||||
|
ADDQ $16, BX
|
||||||
|
SUBQ $1, DX
|
||||||
|
JNZ memclr
|
||||||
|
|
||||||
|
// !!! DX = &src[0]
|
||||||
|
MOVQ SI, DX
|
||||||
|
|
||||||
|
// sLimit := len(src) - inputMargin
|
||||||
|
MOVQ R14, R9
|
||||||
|
SUBQ $15, R9
|
||||||
|
|
||||||
|
// !!! Pre-emptively spill CX, DX and R9 to the stack. Their values don't
|
||||||
|
// change for the rest of the function.
|
||||||
|
MOVQ CX, 56(SP)
|
||||||
|
MOVQ DX, 64(SP)
|
||||||
|
MOVQ R9, 88(SP)
|
||||||
|
|
||||||
|
// nextEmit := 0
|
||||||
|
MOVQ DX, R10
|
||||||
|
|
||||||
|
// s := 1
|
||||||
|
ADDQ $1, SI
|
||||||
|
|
||||||
|
// nextHash := hash(load32(src, s), shift)
|
||||||
|
MOVL 0(SI), R11
|
||||||
|
IMULL $0x1e35a7bd, R11
|
||||||
|
SHRL CX, R11
|
||||||
|
|
||||||
|
outer:
|
||||||
|
// for { etc }
|
||||||
|
|
||||||
|
// skip := 32
|
||||||
|
MOVQ $32, R12
|
||||||
|
|
||||||
|
// nextS := s
|
||||||
|
MOVQ SI, R13
|
||||||
|
|
||||||
|
// candidate := 0
|
||||||
|
MOVQ $0, R15
|
||||||
|
|
||||||
|
inner0:
|
||||||
|
// for { etc }
|
||||||
|
|
||||||
|
// s := nextS
|
||||||
|
MOVQ R13, SI
|
||||||
|
|
||||||
|
// bytesBetweenHashLookups := skip >> 5
|
||||||
|
MOVQ R12, R14
|
||||||
|
SHRQ $5, R14
|
||||||
|
|
||||||
|
// nextS = s + bytesBetweenHashLookups
|
||||||
|
ADDQ R14, R13
|
||||||
|
|
||||||
|
// skip += bytesBetweenHashLookups
|
||||||
|
ADDQ R14, R12
|
||||||
|
|
||||||
|
// if nextS > sLimit { goto emitRemainder }
|
||||||
|
MOVQ R13, AX
|
||||||
|
SUBQ DX, AX
|
||||||
|
CMPQ AX, R9
|
||||||
|
JA emitRemainder
|
||||||
|
|
||||||
|
// candidate = int(table[nextHash])
|
||||||
|
// XXX: MOVWQZX table-32768(SP)(R11*2), R15
|
||||||
|
// XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15
|
||||||
|
BYTE $0x4e
|
||||||
|
BYTE $0x0f
|
||||||
|
BYTE $0xb7
|
||||||
|
BYTE $0x7c
|
||||||
|
BYTE $0x5c
|
||||||
|
BYTE $0x78
|
||||||
|
|
||||||
|
// table[nextHash] = uint16(s)
|
||||||
|
MOVQ SI, AX
|
||||||
|
SUBQ DX, AX
|
||||||
|
|
||||||
|
// XXX: MOVW AX, table-32768(SP)(R11*2)
|
||||||
|
// XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2)
|
||||||
|
BYTE $0x66
|
||||||
|
BYTE $0x42
|
||||||
|
BYTE $0x89
|
||||||
|
BYTE $0x44
|
||||||
|
BYTE $0x5c
|
||||||
|
BYTE $0x78
|
||||||
|
|
||||||
|
// nextHash = hash(load32(src, nextS), shift)
|
||||||
|
MOVL 0(R13), R11
|
||||||
|
IMULL $0x1e35a7bd, R11
|
||||||
|
SHRL CX, R11
|
||||||
|
|
||||||
|
// if load32(src, s) != load32(src, candidate) { continue } break
|
||||||
|
MOVL 0(SI), AX
|
||||||
|
MOVL (DX)(R15*1), BX
|
||||||
|
CMPL AX, BX
|
||||||
|
JNE inner0
|
||||||
|
|
||||||
|
fourByteMatch:
|
||||||
|
// As per the encode_other.go code:
|
||||||
|
//
|
||||||
|
// A 4-byte match has been found. We'll later see etc.
|
||||||
|
|
||||||
|
// !!! Jump to a fast path for short (<= 16 byte) literals. See the comment
|
||||||
|
// on inputMargin in encode.go.
|
||||||
|
MOVQ SI, AX
|
||||||
|
SUBQ R10, AX
|
||||||
|
CMPQ AX, $16
|
||||||
|
JLE emitLiteralFastPath
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Begin inline of the emitLiteral call.
|
||||||
|
//
|
||||||
|
// d += emitLiteral(dst[d:], src[nextEmit:s])
|
||||||
|
|
||||||
|
MOVL AX, BX
|
||||||
|
SUBL $1, BX
|
||||||
|
|
||||||
|
CMPL BX, $60
|
||||||
|
JLT inlineEmitLiteralOneByte
|
||||||
|
CMPL BX, $256
|
||||||
|
JLT inlineEmitLiteralTwoBytes
|
||||||
|
|
||||||
|
inlineEmitLiteralThreeBytes:
|
||||||
|
MOVB $0xf4, 0(DI)
|
||||||
|
MOVW BX, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
JMP inlineEmitLiteralMemmove
|
||||||
|
|
||||||
|
inlineEmitLiteralTwoBytes:
|
||||||
|
MOVB $0xf0, 0(DI)
|
||||||
|
MOVB BX, 1(DI)
|
||||||
|
ADDQ $2, DI
|
||||||
|
JMP inlineEmitLiteralMemmove
|
||||||
|
|
||||||
|
inlineEmitLiteralOneByte:
|
||||||
|
SHLB $2, BX
|
||||||
|
MOVB BX, 0(DI)
|
||||||
|
ADDQ $1, DI
|
||||||
|
|
||||||
|
inlineEmitLiteralMemmove:
|
||||||
|
// Spill local variables (registers) onto the stack; call; unspill.
|
||||||
|
//
|
||||||
|
// copy(dst[i:], lit)
|
||||||
|
//
|
||||||
|
// This means calling runtime·memmove(&dst[i], &lit[0], len(lit)), so we push
|
||||||
|
// DI, R10 and AX as arguments.
|
||||||
|
MOVQ DI, 0(SP)
|
||||||
|
MOVQ R10, 8(SP)
|
||||||
|
MOVQ AX, 16(SP)
|
||||||
|
ADDQ AX, DI // Finish the "d +=" part of "d += emitLiteral(etc)".
|
||||||
|
MOVQ SI, 72(SP)
|
||||||
|
MOVQ DI, 80(SP)
|
||||||
|
MOVQ R15, 112(SP)
|
||||||
|
CALL runtime·memmove(SB)
|
||||||
|
MOVQ 56(SP), CX
|
||||||
|
MOVQ 64(SP), DX
|
||||||
|
MOVQ 72(SP), SI
|
||||||
|
MOVQ 80(SP), DI
|
||||||
|
MOVQ 88(SP), R9
|
||||||
|
MOVQ 112(SP), R15
|
||||||
|
JMP inner1
|
||||||
|
|
||||||
|
inlineEmitLiteralEnd:
|
||||||
|
// End inline of the emitLiteral call.
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
emitLiteralFastPath:
|
||||||
|
// !!! Emit the 1-byte encoding "uint8(len(lit)-1)<<2".
|
||||||
|
MOVB AX, BX
|
||||||
|
SUBB $1, BX
|
||||||
|
SHLB $2, BX
|
||||||
|
MOVB BX, (DI)
|
||||||
|
ADDQ $1, DI
|
||||||
|
|
||||||
|
// !!! Implement the copy from lit to dst as a 16-byte load and store.
|
||||||
|
// (Encode's documentation says that dst and src must not overlap.)
|
||||||
|
//
|
||||||
|
// This always copies 16 bytes, instead of only len(lit) bytes, but that's
|
||||||
|
// OK. Subsequent iterations will fix up the overrun.
|
||||||
|
//
|
||||||
|
// Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
|
||||||
|
// 16-byte loads and stores. This technique probably wouldn't be as
|
||||||
|
// effective on architectures that are fussier about alignment.
|
||||||
|
MOVOU 0(R10), X0
|
||||||
|
MOVOU X0, 0(DI)
|
||||||
|
ADDQ AX, DI
|
||||||
|
|
||||||
|
inner1:
|
||||||
|
// for { etc }
|
||||||
|
|
||||||
|
// base := s
|
||||||
|
MOVQ SI, R12
|
||||||
|
|
||||||
|
// !!! offset := base - candidate
|
||||||
|
MOVQ R12, R11
|
||||||
|
SUBQ R15, R11
|
||||||
|
SUBQ DX, R11
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Begin inline of the extendMatch call.
|
||||||
|
//
|
||||||
|
// s = extendMatch(src, candidate+4, s+4)
|
||||||
|
|
||||||
|
// !!! R14 = &src[len(src)]
|
||||||
|
MOVQ src_len+32(FP), R14
|
||||||
|
ADDQ DX, R14
|
||||||
|
|
||||||
|
// !!! R13 = &src[len(src) - 8]
|
||||||
|
MOVQ R14, R13
|
||||||
|
SUBQ $8, R13
|
||||||
|
|
||||||
|
// !!! R15 = &src[candidate + 4]
|
||||||
|
ADDQ $4, R15
|
||||||
|
ADDQ DX, R15
|
||||||
|
|
||||||
|
// !!! s += 4
|
||||||
|
ADDQ $4, SI
|
||||||
|
|
||||||
|
inlineExtendMatchCmp8:
|
||||||
|
// As long as we are 8 or more bytes before the end of src, we can load and
|
||||||
|
// compare 8 bytes at a time. If those 8 bytes are equal, repeat.
|
||||||
|
CMPQ SI, R13
|
||||||
|
JA inlineExtendMatchCmp1
|
||||||
|
MOVQ (R15), AX
|
||||||
|
MOVQ (SI), BX
|
||||||
|
CMPQ AX, BX
|
||||||
|
JNE inlineExtendMatchBSF
|
||||||
|
ADDQ $8, R15
|
||||||
|
ADDQ $8, SI
|
||||||
|
JMP inlineExtendMatchCmp8
|
||||||
|
|
||||||
|
inlineExtendMatchBSF:
|
||||||
|
// If those 8 bytes were not equal, XOR the two 8 byte values, and return
|
||||||
|
// the index of the first byte that differs. The BSF instruction finds the
|
||||||
|
// least significant 1 bit, the amd64 architecture is little-endian, and
|
||||||
|
// the shift by 3 converts a bit index to a byte index.
|
||||||
|
XORQ AX, BX
|
||||||
|
BSFQ BX, BX
|
||||||
|
SHRQ $3, BX
|
||||||
|
ADDQ BX, SI
|
||||||
|
JMP inlineExtendMatchEnd
|
||||||
|
|
||||||
|
inlineExtendMatchCmp1:
|
||||||
|
// In src's tail, compare 1 byte at a time.
|
||||||
|
CMPQ SI, R14
|
||||||
|
JAE inlineExtendMatchEnd
|
||||||
|
MOVB (R15), AX
|
||||||
|
MOVB (SI), BX
|
||||||
|
CMPB AX, BX
|
||||||
|
JNE inlineExtendMatchEnd
|
||||||
|
ADDQ $1, R15
|
||||||
|
ADDQ $1, SI
|
||||||
|
JMP inlineExtendMatchCmp1
|
||||||
|
|
||||||
|
inlineExtendMatchEnd:
|
||||||
|
// End inline of the extendMatch call.
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Begin inline of the emitCopy call.
|
||||||
|
//
|
||||||
|
// d += emitCopy(dst[d:], base-candidate, s-base)
|
||||||
|
|
||||||
|
// !!! length := s - base
|
||||||
|
MOVQ SI, AX
|
||||||
|
SUBQ R12, AX
|
||||||
|
|
||||||
|
inlineEmitCopyLoop0:
|
||||||
|
// for length >= 68 { etc }
|
||||||
|
CMPL AX, $68
|
||||||
|
JLT inlineEmitCopyStep1
|
||||||
|
|
||||||
|
// Emit a length 64 copy, encoded as 3 bytes.
|
||||||
|
MOVB $0xfe, 0(DI)
|
||||||
|
MOVW R11, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
SUBL $64, AX
|
||||||
|
JMP inlineEmitCopyLoop0
|
||||||
|
|
||||||
|
inlineEmitCopyStep1:
|
||||||
|
// if length > 64 { etc }
|
||||||
|
CMPL AX, $64
|
||||||
|
JLE inlineEmitCopyStep2
|
||||||
|
|
||||||
|
// Emit a length 60 copy, encoded as 3 bytes.
|
||||||
|
MOVB $0xee, 0(DI)
|
||||||
|
MOVW R11, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
SUBL $60, AX
|
||||||
|
|
||||||
|
inlineEmitCopyStep2:
|
||||||
|
// if length >= 12 || offset >= 2048 { goto inlineEmitCopyStep3 }
|
||||||
|
CMPL AX, $12
|
||||||
|
JGE inlineEmitCopyStep3
|
||||||
|
CMPL R11, $2048
|
||||||
|
JGE inlineEmitCopyStep3
|
||||||
|
|
||||||
|
// Emit the remaining copy, encoded as 2 bytes.
|
||||||
|
MOVB R11, 1(DI)
|
||||||
|
SHRL $8, R11
|
||||||
|
SHLB $5, R11
|
||||||
|
SUBB $4, AX
|
||||||
|
SHLB $2, AX
|
||||||
|
ORB AX, R11
|
||||||
|
ORB $1, R11
|
||||||
|
MOVB R11, 0(DI)
|
||||||
|
ADDQ $2, DI
|
||||||
|
JMP inlineEmitCopyEnd
|
||||||
|
|
||||||
|
inlineEmitCopyStep3:
|
||||||
|
// Emit the remaining copy, encoded as 3 bytes.
|
||||||
|
SUBL $1, AX
|
||||||
|
SHLB $2, AX
|
||||||
|
ORB $2, AX
|
||||||
|
MOVB AX, 0(DI)
|
||||||
|
MOVW R11, 1(DI)
|
||||||
|
ADDQ $3, DI
|
||||||
|
|
||||||
|
inlineEmitCopyEnd:
|
||||||
|
// End inline of the emitCopy call.
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
// nextEmit = s
|
||||||
|
MOVQ SI, R10
|
||||||
|
|
||||||
|
// if s >= sLimit { goto emitRemainder }
|
||||||
|
MOVQ SI, AX
|
||||||
|
SUBQ DX, AX
|
||||||
|
CMPQ AX, R9
|
||||||
|
JAE emitRemainder
|
||||||
|
|
||||||
|
// As per the encode_other.go code:
|
||||||
|
//
|
||||||
|
// We could immediately etc.
|
||||||
|
|
||||||
|
// x := load64(src, s-1)
|
||||||
|
MOVQ -1(SI), R14
|
||||||
|
|
||||||
|
// prevHash := hash(uint32(x>>0), shift)
|
||||||
|
MOVL R14, R11
|
||||||
|
IMULL $0x1e35a7bd, R11
|
||||||
|
SHRL CX, R11
|
||||||
|
|
||||||
|
// table[prevHash] = uint16(s-1)
|
||||||
|
MOVQ SI, AX
|
||||||
|
SUBQ DX, AX
|
||||||
|
SUBQ $1, AX
|
||||||
|
|
||||||
|
// XXX: MOVW AX, table-32768(SP)(R11*2)
|
||||||
|
// XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2)
|
||||||
|
BYTE $0x66
|
||||||
|
BYTE $0x42
|
||||||
|
BYTE $0x89
|
||||||
|
BYTE $0x44
|
||||||
|
BYTE $0x5c
|
||||||
|
BYTE $0x78
|
||||||
|
|
||||||
|
// currHash := hash(uint32(x>>8), shift)
|
||||||
|
SHRQ $8, R14
|
||||||
|
MOVL R14, R11
|
||||||
|
IMULL $0x1e35a7bd, R11
|
||||||
|
SHRL CX, R11
|
||||||
|
|
||||||
|
// candidate = int(table[currHash])
|
||||||
|
// XXX: MOVWQZX table-32768(SP)(R11*2), R15
|
||||||
|
// XXX: 4e 0f b7 7c 5c 78 movzwq 0x78(%rsp,%r11,2),%r15
|
||||||
|
BYTE $0x4e
|
||||||
|
BYTE $0x0f
|
||||||
|
BYTE $0xb7
|
||||||
|
BYTE $0x7c
|
||||||
|
BYTE $0x5c
|
||||||
|
BYTE $0x78
|
||||||
|
|
||||||
|
// table[currHash] = uint16(s)
|
||||||
|
ADDQ $1, AX
|
||||||
|
|
||||||
|
// XXX: MOVW AX, table-32768(SP)(R11*2)
|
||||||
|
// XXX: 66 42 89 44 5c 78 mov %ax,0x78(%rsp,%r11,2)
|
||||||
|
BYTE $0x66
|
||||||
|
BYTE $0x42
|
||||||
|
BYTE $0x89
|
||||||
|
BYTE $0x44
|
||||||
|
BYTE $0x5c
|
||||||
|
BYTE $0x78
|
||||||
|
|
||||||
|
// if uint32(x>>8) == load32(src, candidate) { continue }
|
||||||
|
MOVL (DX)(R15*1), BX
|
||||||
|
CMPL R14, BX
|
||||||
|
JEQ inner1
|
||||||
|
|
||||||
|
// nextHash = hash(uint32(x>>16), shift)
|
||||||
|
SHRQ $8, R14
|
||||||
|
MOVL R14, R11
|
||||||
|
IMULL $0x1e35a7bd, R11
|
||||||
|
SHRL CX, R11
|
||||||
|
|
||||||
|
// s++
|
||||||
|
ADDQ $1, SI
|
||||||
|
|
||||||
|
// break out of the inner1 for loop, i.e. continue the outer loop.
|
||||||
|
JMP outer
|
||||||
|
|
||||||
|
emitRemainder:
|
||||||
|
// if nextEmit < len(src) { etc }
|
||||||
|
MOVQ src_len+32(FP), AX
|
||||||
|
ADDQ DX, AX
|
||||||
|
CMPQ R10, AX
|
||||||
|
JEQ encodeBlockEnd
|
||||||
|
|
||||||
|
// d += emitLiteral(dst[d:], src[nextEmit:])
|
||||||
|
//
|
||||||
|
// Push args.
|
||||||
|
MOVQ DI, 0(SP)
|
||||||
|
MOVQ $0, 8(SP) // Unnecessary, as the callee ignores it, but conservative.
|
||||||
|
MOVQ $0, 16(SP) // Unnecessary, as the callee ignores it, but conservative.
|
||||||
|
MOVQ R10, 24(SP)
|
||||||
|
SUBQ R10, AX
|
||||||
|
MOVQ AX, 32(SP)
|
||||||
|
MOVQ AX, 40(SP) // Unnecessary, as the callee ignores it, but conservative.
|
||||||
|
|
||||||
|
// Spill local variables (registers) onto the stack; call; unspill.
|
||||||
|
MOVQ DI, 80(SP)
|
||||||
|
CALL ·emitLiteral(SB)
|
||||||
|
MOVQ 80(SP), DI
|
||||||
|
|
||||||
|
// Finish the "d +=" part of "d += emitLiteral(etc)".
|
||||||
|
ADDQ 48(SP), DI
|
||||||
|
|
||||||
|
encodeBlockEnd:
|
||||||
|
MOVQ dst_base+0(FP), AX
|
||||||
|
SUBQ AX, DI
|
||||||
|
MOVQ DI, d+48(FP)
|
||||||
|
RET
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user