Merge pull request #57142 from nikhita/bump-jsoniter

Automatic merge from submit-queue (batch tested with PRs 57122, 57142, 57016, 56927, 56678). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

bump(13f864): github.com/json-iterator/go: use ConfigCompatibleWithStandardLibrary

Jsoniter in `ConfigFastest` mode does not support escape characters in object keys, whereas `ConfigCompatibleWithStandardLibrary` does.

Fixes kubernetes/kubernetes#56018
Related kubernetes/kubernetes#56055

Benchmark results:

```
BenchmarkDecodeIntoJSON-4                                              	   30000	     48522 ns/op	    3792 B/op	      63 allocs/op
BenchmarkDecodeIntoJSONCodecGenConfigFast-4                            	  100000	     17409 ns/op	    4524 B/op	      96 allocs/op
BenchmarkDecodeIntoJSONCodecGenConfigCompatibleWithStandardLibrary-4   	  100000	     18617 ns/op	    4924 B/op	     121 allocs/op
```

/assign sttts thockin mfojtik

Kubernetes-commit: 135d58b3941fac99ae0426e18cbda266b83ca49e
This commit is contained in:
Kubernetes Publisher 2017-12-16 23:32:38 -08:00
commit 17dfc25798
27 changed files with 680 additions and 209 deletions

108
Godeps/Godeps.json generated
View File

@ -228,7 +228,7 @@
}, },
{ {
"ImportPath": "github.com/json-iterator/go", "ImportPath": "github.com/json-iterator/go",
"Rev": "36b14963da70d11297d313183d7e6388c8510e1e" "Rev": "13f86432b882000a51c6e610c620974462691a97"
}, },
{ {
"ImportPath": "github.com/juju/ratelimit", "ImportPath": "github.com/juju/ratelimit",
@ -488,215 +488,215 @@
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/api/equality", "ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/api/errors", "ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/api/meta", "ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/api/resource", "ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/api/testing", "ImportPath": "k8s.io/apimachinery/pkg/api/testing",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer", "ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip", "ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery", "ImportPath": "k8s.io/apimachinery/pkg/apimachinery",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced", "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered", "ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer", "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion", "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1", "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1", "ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/conversion", "ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams", "ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/fields", "ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/labels", "ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime", "ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema", "ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer", "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json", "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf", "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer", "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming", "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning", "ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/selection", "ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/types", "ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/cache", "ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/clock", "ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/diff", "ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/errors", "ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/framer", "ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream", "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy", "ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr", "ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/json", "ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch", "ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/net", "ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand", "ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime", "ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/sets", "ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch", "ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/validation", "ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field", "ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/wait", "ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml", "ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/version", "ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/pkg/watch", "ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json", "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil", "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect", "ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "a88dfdd72a1d320a70de7ab2bb3375cfdf237864" "Rev": "5250765d28a6a1e07c6f09fe814a4b58ad74cc11"
}, },
{ {
"ImportPath": "k8s.io/kube-openapi/pkg/common", "ImportPath": "k8s.io/kube-openapi/pkg/common",

View File

@ -1,3 +1,4 @@
.idea /vendor
/bug_test.go
/coverage.txt /coverage.txt
/profile.out /.idea

View File

@ -2,6 +2,7 @@ language: go
go: go:
- 1.8.x - 1.8.x
- 1.x
before_install: before_install:
- go get -t -v ./... - go get -t -v ./...

33
vendor/github.com/json-iterator/go/Gopkg.lock generated vendored Normal file
View File

@ -0,0 +1,33 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/google/gofuzz"
packages = ["."]
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert","require"]
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
version = "v1.1.4"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "f8b7cf3941d3792cbbd570bb53c093adaf774334d1162c651565c97a58dc9d09"
solver-name = "gps-cdcl"
solver-version = 1

33
vendor/github.com/json-iterator/go/Gopkg.toml generated vendored Normal file
View File

@ -0,0 +1,33 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/davecgh/go-spew"
version = "1.1.0"
[[constraint]]
branch = "master"
name = "github.com/google/gofuzz"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.1.4"

View File

@ -44,7 +44,9 @@ with
```go ```go
import "github.com/json-iterator/go" import "github.com/json-iterator/go"
jsoniter.Marshal(&data)
var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Marshal(&data)
``` ```
Replace Replace
@ -58,7 +60,9 @@ with
```go ```go
import "github.com/json-iterator/go" import "github.com/json-iterator/go"
jsoniter.Unmarshal(input, &data)
var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Unmarshal(input, &data)
``` ```
[More documentation](http://jsoniter.com/migrate-from-go-std.html) [More documentation](http://jsoniter.com/migrate-from-go-std.html)
@ -76,5 +80,7 @@ Contributors
* [thockin](https://github.com/thockin) * [thockin](https://github.com/thockin)
* [mattn](https://github.com/mattn) * [mattn](https://github.com/mattn)
* [cch123](https://github.com/cch123) * [cch123](https://github.com/cch123)
* [Oleg Shaldybin](https://github.com/olegshaldybin)
* [Jason Toffaletti](https://github.com/toffaletti)
Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby) Report issue or pull request, or email taowen@gmail.com, or [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby)

12
vendor/github.com/json-iterator/go/build.sh generated vendored Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
set -e
set -x
if [ ! -d /tmp/build-golang/src/github.com/json-iterator ]; then
mkdir -p /tmp/build-golang/src/github.com/json-iterator
ln -s $PWD /tmp/build-golang/src/github.com/json-iterator/go
fi
export GOPATH=/tmp/build-golang
go get -u github.com/golang/dep/cmd/dep
cd /tmp/build-golang/src/github.com/json-iterator/go
exec $GOPATH/bin/dep ensure -update

View File

@ -110,6 +110,7 @@ type Encoder struct {
// Encode encode interface{} as JSON to io.Writer // Encode encode interface{} as JSON to io.Writer
func (adapter *Encoder) Encode(val interface{}) error { func (adapter *Encoder) Encode(val interface{}) error {
adapter.stream.WriteVal(val) adapter.stream.WriteVal(val)
adapter.stream.WriteRaw("\n")
adapter.stream.Flush() adapter.stream.Flush()
return adapter.stream.Error return adapter.stream.Error
} }
@ -125,3 +126,8 @@ func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) {
config.EscapeHTML = escapeHTML config.EscapeHTML = escapeHTML
adapter.stream.cfg = config.Froze().(*frozenConfig) adapter.stream.cfg = config.Froze().(*frozenConfig)
} }
// Valid reports whether data is a valid JSON encoding.
func Valid(data []byte) bool {
return ConfigDefault.Valid(data)
}

View File

@ -1,6 +1,7 @@
package jsoniter package jsoniter
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
@ -157,6 +158,8 @@ func (iter *Iterator) readAny() Any {
return iter.readArrayAny() return iter.readArrayAny()
case '-': case '-':
return iter.readNumberAny(false) return iter.readNumberAny(false)
case 0:
return &invalidAny{baseAny{}, errors.New("input is empty")}
default: default:
return iter.readNumberAny(true) return iter.readNumberAny(true)
} }

View File

@ -18,12 +18,15 @@ type Config struct {
SortMapKeys bool SortMapKeys bool
UseNumber bool UseNumber bool
TagKey string TagKey string
ValidateJsonRawMessage bool
ObjectFieldMustBeSimpleString bool
} }
type frozenConfig struct { type frozenConfig struct {
configBeforeFrozen Config configBeforeFrozen Config
sortMapKeys bool sortMapKeys bool
indentionStep int indentionStep int
objectFieldMustBeSimpleString bool
decoderCache unsafe.Pointer decoderCache unsafe.Pointer
encoderCache unsafe.Pointer encoderCache unsafe.Pointer
extensions []Extension extensions []Extension
@ -44,6 +47,8 @@ type API interface {
Get(data []byte, path ...interface{}) Any Get(data []byte, path ...interface{}) Any
NewEncoder(writer io.Writer) *Encoder NewEncoder(writer io.Writer) *Encoder
NewDecoder(reader io.Reader) *Decoder NewDecoder(reader io.Reader) *Decoder
Valid(data []byte) bool
RegisterExtension(extension Extension)
} }
// ConfigDefault the default API // ConfigDefault the default API
@ -55,12 +60,14 @@ var ConfigDefault = Config{
var ConfigCompatibleWithStandardLibrary = Config{ var ConfigCompatibleWithStandardLibrary = Config{
EscapeHTML: true, EscapeHTML: true,
SortMapKeys: true, SortMapKeys: true,
ValidateJsonRawMessage: true,
}.Froze() }.Froze()
// ConfigFastest marshals float with only 6 digits precision // ConfigFastest marshals float with only 6 digits precision
var ConfigFastest = Config{ var ConfigFastest = Config{
EscapeHTML: false, EscapeHTML: false,
MarshalFloatWith6Digits: true, MarshalFloatWith6Digits: true, // will lose precession
ObjectFieldMustBeSimpleString: true, // do not unescape object field
}.Froze() }.Froze()
// Froze forge API from config // Froze forge API from config
@ -69,6 +76,7 @@ func (cfg Config) Froze() API {
frozenConfig := &frozenConfig{ frozenConfig := &frozenConfig{
sortMapKeys: cfg.SortMapKeys, sortMapKeys: cfg.SortMapKeys,
indentionStep: cfg.IndentionStep, indentionStep: cfg.IndentionStep,
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
streamPool: make(chan *Stream, 16), streamPool: make(chan *Stream, 16),
iteratorPool: make(chan *Iterator, 16), iteratorPool: make(chan *Iterator, 16),
} }
@ -83,10 +91,31 @@ func (cfg Config) Froze() API {
if cfg.UseNumber { if cfg.UseNumber {
frozenConfig.useNumber() frozenConfig.useNumber()
} }
if cfg.ValidateJsonRawMessage {
frozenConfig.validateJsonRawMessage()
}
frozenConfig.configBeforeFrozen = cfg frozenConfig.configBeforeFrozen = cfg
return frozenConfig return frozenConfig
} }
func (cfg *frozenConfig) validateJsonRawMessage() {
encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
rawMessage := *(*json.RawMessage)(ptr)
iter := cfg.BorrowIterator([]byte(rawMessage))
iter.Read()
if iter.Error != nil {
stream.WriteRaw("null")
} else {
cfg.ReturnIterator(iter)
stream.WriteRaw(string(rawMessage))
}
}, func(ptr unsafe.Pointer) bool {
return false
}}
cfg.addEncoderToCache(reflect.TypeOf((*json.RawMessage)(nil)).Elem(), encoder)
cfg.addEncoderToCache(reflect.TypeOf((*RawMessage)(nil)).Elem(), encoder)
}
func (cfg *frozenConfig) useNumber() { func (cfg *frozenConfig) useNumber() {
cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
if iter.WhatIsNext() == NumberValue { if iter.WhatIsNext() == NumberValue {
@ -104,7 +133,7 @@ func (cfg *frozenConfig) getTagKey() string {
return tagKey return tagKey
} }
func (cfg *frozenConfig) registerExtension(extension Extension) { func (cfg *frozenConfig) RegisterExtension(extension Extension) {
cfg.extensions = append(cfg.extensions, extension) cfg.extensions = append(cfg.extensions, extension)
} }
@ -310,3 +339,10 @@ func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
iter := Parse(cfg, reader, 512) iter := Parse(cfg, reader, 512)
return &Decoder{iter} return &Decoder{iter}
} }
func (cfg *frozenConfig) Valid(data []byte) bool {
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
iter.Skip()
return iter.Error == nil
}

View File

@ -77,6 +77,7 @@ type Iterator struct {
captureStartedAt int captureStartedAt int
captured []byte captured []byte
Error error Error error
Attachment interface{} // open for customized decoder
} }
// NewIterator creates an empty Iterator instance // NewIterator creates an empty Iterator instance
@ -167,7 +168,7 @@ func (iter *Iterator) isObjectEnd() bool {
if c == '}' { if c == '}' {
return true return true
} }
iter.ReportError("isObjectEnd", "object ended prematurely") iter.ReportError("isObjectEnd", "object ended prematurely, unexpected char "+string([]byte{c}))
return true return true
} }
@ -200,8 +201,22 @@ func (iter *Iterator) ReportError(operation string, msg string) {
if peekStart < 0 { if peekStart < 0 {
peekStart = 0 peekStart = 0
} }
iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head, peekEnd := iter.head + 10
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) if peekEnd > iter.tail {
peekEnd = iter.tail
}
parsing := string(iter.buf[peekStart:peekEnd])
contextStart := iter.head - 50
if contextStart < 0 {
contextStart = 0
}
contextEnd := iter.head + 50
if contextEnd > iter.tail {
contextEnd = iter.tail
}
context := string(iter.buf[contextStart:contextEnd])
iter.Error = fmt.Errorf("%s: %s, error found in #%v byte of ...|%s|..., bigger context ...|%s|...",
operation, msg, iter.head-peekStart, parsing, context)
} }
// CurrentBuffer gets current buffer as string for debugging purpose // CurrentBuffer gets current buffer as string for debugging purpose
@ -210,7 +225,7 @@ func (iter *Iterator) CurrentBuffer() string {
if peekStart < 0 { if peekStart < 0 {
peekStart = 0 peekStart = 0
} }
return fmt.Sprintf("parsing %v ...|%s|... at %s", iter.head, return fmt.Sprintf("parsing #%v byte, around ...|%s|..., whole buffer ...|%s|...", iter.head,
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
} }

View File

@ -19,7 +19,7 @@ func (iter *Iterator) ReadArray() (ret bool) {
case ',': case ',':
return true return true
default: default:
iter.ReportError("ReadArray", "expect [ or , or ] or n, but found: "+string([]byte{c})) iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c}))
return return
} }
} }
@ -42,7 +42,7 @@ func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
c = iter.nextToken() c = iter.nextToken()
} }
if c != ']' { if c != ']' {
iter.ReportError("ReadArrayCB", "expect ] in the end") iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c}))
return false return false
} }
return true return true
@ -53,6 +53,6 @@ func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
iter.skipThreeBytes('u', 'l', 'l') iter.skipThreeBytes('u', 'l', 'l')
return true // null return true // null
} }
iter.ReportError("ReadArrayCB", "expect [ or n, but found: "+string([]byte{c})) iter.ReportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c}))
return false return false
} }

View File

@ -115,6 +115,7 @@ func (iter *Iterator) ReadUint32() (ret uint32) {
func (iter *Iterator) readUint32(c byte) (ret uint32) { func (iter *Iterator) readUint32(c byte) (ret uint32) {
ind := intDigits[c] ind := intDigits[c]
if ind == 0 { if ind == 0 {
iter.assertInteger()
return 0 // single zero return 0 // single zero
} }
if ind == invalidCharForNumber { if ind == invalidCharForNumber {
@ -127,12 +128,14 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
ind2 := intDigits[iter.buf[i]] ind2 := intDigits[iter.buf[i]]
if ind2 == invalidCharForNumber { if ind2 == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value return value
} }
i++ i++
ind3 := intDigits[iter.buf[i]] ind3 := intDigits[iter.buf[i]]
if ind3 == invalidCharForNumber { if ind3 == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value*10 + uint32(ind2) return value*10 + uint32(ind2)
} }
//iter.head = i + 1 //iter.head = i + 1
@ -141,30 +144,35 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
ind4 := intDigits[iter.buf[i]] ind4 := intDigits[iter.buf[i]]
if ind4 == invalidCharForNumber { if ind4 == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value*100 + uint32(ind2)*10 + uint32(ind3) return value*100 + uint32(ind2)*10 + uint32(ind3)
} }
i++ i++
ind5 := intDigits[iter.buf[i]] ind5 := intDigits[iter.buf[i]]
if ind5 == invalidCharForNumber { if ind5 == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4) return value*1000 + uint32(ind2)*100 + uint32(ind3)*10 + uint32(ind4)
} }
i++ i++
ind6 := intDigits[iter.buf[i]] ind6 := intDigits[iter.buf[i]]
if ind6 == invalidCharForNumber { if ind6 == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5) return value*10000 + uint32(ind2)*1000 + uint32(ind3)*100 + uint32(ind4)*10 + uint32(ind5)
} }
i++ i++
ind7 := intDigits[iter.buf[i]] ind7 := intDigits[iter.buf[i]]
if ind7 == invalidCharForNumber { if ind7 == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6) return value*100000 + uint32(ind2)*10000 + uint32(ind3)*1000 + uint32(ind4)*100 + uint32(ind5)*10 + uint32(ind6)
} }
i++ i++
ind8 := intDigits[iter.buf[i]] ind8 := intDigits[iter.buf[i]]
if ind8 == invalidCharForNumber { if ind8 == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7) return value*1000000 + uint32(ind2)*100000 + uint32(ind3)*10000 + uint32(ind4)*1000 + uint32(ind5)*100 + uint32(ind6)*10 + uint32(ind7)
} }
i++ i++
@ -172,6 +180,7 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
value = value*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8) value = value*10000000 + uint32(ind2)*1000000 + uint32(ind3)*100000 + uint32(ind4)*10000 + uint32(ind5)*1000 + uint32(ind6)*100 + uint32(ind7)*10 + uint32(ind8)
iter.head = i iter.head = i
if ind9 == invalidCharForNumber { if ind9 == invalidCharForNumber {
iter.assertInteger()
return value return value
} }
} }
@ -180,6 +189,7 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
ind = intDigits[iter.buf[i]] ind = intDigits[iter.buf[i]]
if ind == invalidCharForNumber { if ind == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value return value
} }
if value > uint32SafeToMultiply10 { if value > uint32SafeToMultiply10 {
@ -194,6 +204,7 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
value = (value << 3) + (value << 1) + uint32(ind) value = (value << 3) + (value << 1) + uint32(ind)
} }
if !iter.loadMore() { if !iter.loadMore() {
iter.assertInteger()
return value return value
} }
} }
@ -226,6 +237,7 @@ func (iter *Iterator) ReadUint64() uint64 {
func (iter *Iterator) readUint64(c byte) (ret uint64) { func (iter *Iterator) readUint64(c byte) (ret uint64) {
ind := intDigits[c] ind := intDigits[c]
if ind == 0 { if ind == 0 {
iter.assertInteger()
return 0 // single zero return 0 // single zero
} }
if ind == invalidCharForNumber { if ind == invalidCharForNumber {
@ -233,11 +245,73 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) {
return return
} }
value := uint64(ind) value := uint64(ind)
if iter.tail-iter.head > 10 {
i := iter.head
ind2 := intDigits[iter.buf[i]]
if ind2 == invalidCharForNumber {
iter.head = i
iter.assertInteger()
return value
}
i++
ind3 := intDigits[iter.buf[i]]
if ind3 == invalidCharForNumber {
iter.head = i
iter.assertInteger()
return value*10 + uint64(ind2)
}
//iter.head = i + 1
//value = value * 100 + uint32(ind2) * 10 + uint32(ind3)
i++
ind4 := intDigits[iter.buf[i]]
if ind4 == invalidCharForNumber {
iter.head = i
iter.assertInteger()
return value*100 + uint64(ind2)*10 + uint64(ind3)
}
i++
ind5 := intDigits[iter.buf[i]]
if ind5 == invalidCharForNumber {
iter.head = i
iter.assertInteger()
return value*1000 + uint64(ind2)*100 + uint64(ind3)*10 + uint64(ind4)
}
i++
ind6 := intDigits[iter.buf[i]]
if ind6 == invalidCharForNumber {
iter.head = i
iter.assertInteger()
return value*10000 + uint64(ind2)*1000 + uint64(ind3)*100 + uint64(ind4)*10 + uint64(ind5)
}
i++
ind7 := intDigits[iter.buf[i]]
if ind7 == invalidCharForNumber {
iter.head = i
iter.assertInteger()
return value*100000 + uint64(ind2)*10000 + uint64(ind3)*1000 + uint64(ind4)*100 + uint64(ind5)*10 + uint64(ind6)
}
i++
ind8 := intDigits[iter.buf[i]]
if ind8 == invalidCharForNumber {
iter.head = i
iter.assertInteger()
return value*1000000 + uint64(ind2)*100000 + uint64(ind3)*10000 + uint64(ind4)*1000 + uint64(ind5)*100 + uint64(ind6)*10 + uint64(ind7)
}
i++
ind9 := intDigits[iter.buf[i]]
value = value*10000000 + uint64(ind2)*1000000 + uint64(ind3)*100000 + uint64(ind4)*10000 + uint64(ind5)*1000 + uint64(ind6)*100 + uint64(ind7)*10 + uint64(ind8)
iter.head = i
if ind9 == invalidCharForNumber {
iter.assertInteger()
return value
}
}
for { for {
for i := iter.head; i < iter.tail; i++ { for i := iter.head; i < iter.tail; i++ {
ind = intDigits[iter.buf[i]] ind = intDigits[iter.buf[i]]
if ind == invalidCharForNumber { if ind == invalidCharForNumber {
iter.head = i iter.head = i
iter.assertInteger()
return value return value
} }
if value > uint64SafeToMultiple10 { if value > uint64SafeToMultiple10 {
@ -252,7 +326,14 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) {
value = (value << 3) + (value << 1) + uint64(ind) value = (value << 3) + (value << 1) + uint64(ind)
} }
if !iter.loadMore() { if !iter.loadMore() {
iter.assertInteger()
return value return value
} }
} }
} }
func (iter *Iterator) assertInteger() {
if iter.head < len(iter.buf) && iter.buf[iter.head] == '.' {
iter.ReportError("assertInteger", "can not decode float as int")
}
}

View File

@ -19,15 +19,33 @@ func (iter *Iterator) ReadObject() (ret string) {
c = iter.nextToken() c = iter.nextToken()
if c == '"' { if c == '"' {
iter.unreadByte() iter.unreadByte()
if iter.cfg.objectFieldMustBeSimpleString {
return string(iter.readObjectFieldAsBytes()) return string(iter.readObjectFieldAsBytes())
} else {
field := iter.ReadString()
c = iter.nextToken()
if c != ':' {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
return field
}
} }
if c == '}' { if c == '}' {
return "" // end of object return "" // end of object
} }
iter.ReportError("ReadObject", `expect " after {`) iter.ReportError("ReadObject", `expect " after {, but found `+string([]byte{c}))
return return
case ',': case ',':
if iter.cfg.objectFieldMustBeSimpleString {
return string(iter.readObjectFieldAsBytes()) return string(iter.readObjectFieldAsBytes())
} else {
field := iter.ReadString()
c = iter.nextToken()
if c != ':' {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
return field
}
case '}': case '}':
return "" // end of object return "" // end of object
default: default:
@ -44,17 +62,34 @@ func (iter *Iterator) readFieldHash() int32 {
for i := iter.head; i < iter.tail; i++ { for i := iter.head; i < iter.tail; i++ {
// require ascii string and no escape // require ascii string and no escape
b := iter.buf[i] b := iter.buf[i]
if !iter.cfg.objectFieldMustBeSimpleString && b == '\\' {
iter.head = i
for _, b := range iter.readStringSlowPath() {
if 'A' <= b && b <= 'Z' { if 'A' <= b && b <= 'Z' {
b += 'a' - 'A' b += 'a' - 'A'
} }
hash ^= int64(b)
hash *= 0x1000193
}
c = iter.nextToken()
if c != ':' {
iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c}))
return 0
}
return int32(hash)
}
if b == '"' { if b == '"' {
iter.head = i + 1 iter.head = i + 1
c = iter.nextToken() c = iter.nextToken()
if c != ':' { if c != ':' {
iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c})) iter.ReportError("readFieldHash", `expect :, but found `+string([]byte{c}))
return 0
} }
return int32(hash) return int32(hash)
} }
if 'A' <= b && b <= 'Z' {
b += 'a' - 'A'
}
hash ^= int64(b) hash ^= int64(b)
hash *= 0x1000193 hash *= 0x1000193
} }
@ -80,18 +115,38 @@ func calcHash(str string) int32 {
// ReadObjectCB read object with callback, the key is ascii only and field name not copied // ReadObjectCB read object with callback, the key is ascii only and field name not copied
func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool { func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
c := iter.nextToken() c := iter.nextToken()
var fieldBytes []byte
var field string
if c == '{' { if c == '{' {
c = iter.nextToken() c = iter.nextToken()
if c == '"' { if c == '"' {
iter.unreadByte() iter.unreadByte()
field := iter.readObjectFieldAsBytes() if iter.cfg.objectFieldMustBeSimpleString {
if !callback(iter, *(*string)(unsafe.Pointer(&field))) { fieldBytes = iter.readObjectFieldAsBytes()
field = *(*string)(unsafe.Pointer(&fieldBytes))
} else {
field = iter.ReadString()
c = iter.nextToken()
if c != ':' {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
}
if !callback(iter, field) {
return false return false
} }
c = iter.nextToken() c = iter.nextToken()
for c == ',' { for c == ',' {
field = iter.readObjectFieldAsBytes() if iter.cfg.objectFieldMustBeSimpleString {
if !callback(iter, *(*string)(unsafe.Pointer(&field))) { fieldBytes = iter.readObjectFieldAsBytes()
field = *(*string)(unsafe.Pointer(&fieldBytes))
} else {
field = iter.ReadString()
c = iter.nextToken()
if c != ':' {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
}
if !callback(iter, field) {
return false return false
} }
c = iter.nextToken() c = iter.nextToken()
@ -105,14 +160,14 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
if c == '}' { if c == '}' {
return true return true
} }
iter.ReportError("ReadObjectCB", `expect " after }`) iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
return false return false
} }
if c == 'n' { if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') iter.skipThreeBytes('u', 'l', 'l')
return true // null return true // null
} }
iter.ReportError("ReadObjectCB", `expect { or n`) iter.ReportError("ReadObjectCB", `expect { or n, but found `+string([]byte{c}))
return false return false
} }
@ -125,7 +180,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
iter.unreadByte() iter.unreadByte()
field := iter.ReadString() field := iter.ReadString()
if iter.nextToken() != ':' { if iter.nextToken() != ':' {
iter.ReportError("ReadMapCB", "expect : after object field") iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
return false return false
} }
if !callback(iter, field) { if !callback(iter, field) {
@ -135,7 +190,7 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
for c == ',' { for c == ',' {
field = iter.ReadString() field = iter.ReadString()
if iter.nextToken() != ':' { if iter.nextToken() != ':' {
iter.ReportError("ReadMapCB", "expect : after object field") iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
return false return false
} }
if !callback(iter, field) { if !callback(iter, field) {
@ -152,14 +207,14 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
if c == '}' { if c == '}' {
return true return true
} }
iter.ReportError("ReadMapCB", `expect " after }`) iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
return false return false
} }
if c == 'n' { if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') iter.skipThreeBytes('u', 'l', 'l')
return true // null return true // null
} }
iter.ReportError("ReadMapCB", `expect { or n`) iter.ReportError("ReadMapCB", `expect { or n, but found `+string([]byte{c}))
return false return false
} }
@ -176,7 +231,7 @@ func (iter *Iterator) readObjectStart() bool {
iter.skipThreeBytes('u', 'l', 'l') iter.skipThreeBytes('u', 'l', 'l')
return false return false
} }
iter.ReportError("readObjectStart", "expect { or n") iter.ReportError("readObjectStart", "expect { or n, but found "+string([]byte{c}))
return false return false
} }
@ -192,7 +247,7 @@ func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) {
} }
} }
if iter.buf[iter.head] != ':' { if iter.buf[iter.head] != ':' {
iter.ReportError("readObjectFieldAsBytes", "expect : after object field") iter.ReportError("readObjectFieldAsBytes", "expect : after object field, but found "+string([]byte{iter.buf[iter.head]}))
return return
} }
iter.head++ iter.head++

View File

@ -25,7 +25,7 @@ func (iter *Iterator) ReadBool() (ret bool) {
iter.skipFourBytes('a', 'l', 's', 'e') iter.skipFourBytes('a', 'l', 's', 'e')
return false return false
} }
iter.ReportError("ReadBool", "expect t or f") iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c}))
return return
} }
@ -59,7 +59,9 @@ func (iter *Iterator) stopCapture() []byte {
iter.captureStartedAt = -1 iter.captureStartedAt = -1
iter.captured = nil iter.captured = nil
if len(captured) == 0 { if len(captured) == 0 {
return remaining copied := make([]byte, len(remaining))
copy(copied, remaining)
return copied
} }
captured = append(captured, remaining...) captured = append(captured, remaining...)
return captured return captured

View File

@ -1,4 +1,4 @@
//+build jsoniter-sloppy //+build jsoniter_sloppy
package jsoniter package jsoniter

View File

@ -1,4 +1,4 @@
//+build !jsoniter-sloppy //+build !jsoniter_sloppy
package jsoniter package jsoniter
@ -64,7 +64,7 @@ func (iter *Iterator) trySkipString() bool {
} else if c == '\\' { } else if c == '\\' {
return false return false
} else if c < ' ' { } else if c < ' ' {
iter.ReportError("ReadString", iter.ReportError("trySkipString",
fmt.Sprintf(`invalid control character found: %d`, c)) fmt.Sprintf(`invalid control character found: %d`, c))
return true // already failed return true // already failed
} }

View File

@ -28,7 +28,7 @@ func (iter *Iterator) ReadString() (ret string) {
iter.skipThreeBytes('u', 'l', 'l') iter.skipThreeBytes('u', 'l', 'l')
return "" return ""
} }
iter.ReportError("ReadString", `expects " or n`) iter.ReportError("ReadString", `expects " or n, but found `+string([]byte{c}))
return return
} }
@ -47,7 +47,7 @@ func (iter *Iterator) readStringSlowPath() (ret string) {
str = append(str, c) str = append(str, c)
} }
} }
iter.ReportError("ReadString", "unexpected end of input") iter.ReportError("readStringSlowPath", "unexpected end of input")
return return
} }
@ -104,7 +104,7 @@ func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte {
case 't': case 't':
str = append(str, '\t') str = append(str, '\t')
default: default:
iter.ReportError("ReadString", iter.ReportError("readEscapedChar",
`invalid escape char after \`) `invalid escape char after \`)
return nil return nil
} }
@ -139,7 +139,7 @@ func (iter *Iterator) ReadStringAsSlice() (ret []byte) {
} }
return copied return copied
} }
iter.ReportError("ReadString", `expects " or n`) iter.ReportError("ReadStringAsSlice", `expects " or n, but found `+string([]byte{c}))
return return
} }
@ -156,7 +156,7 @@ func (iter *Iterator) readU4() (ret rune) {
} else if c >= 'A' && c <= 'F' { } else if c >= 'A' && c <= 'F' {
ret = ret*16 + rune(c-'A'+10) ret = ret*16 + rune(c-'A'+10)
} else { } else {
iter.ReportError("readU4", "expects 0~9 or a~f") iter.ReportError("readU4", "expects 0~9 or a~f, but found "+string([]byte{c}))
return return
} }
} }

View File

@ -1,9 +1,25 @@
package jsoniter package jsoniter
import "encoding/json" import (
"encoding/json"
"strconv"
)
type Number string type Number string
// String returns the literal text of the number.
func (n Number) String() string { return string(n) }
// Float64 returns the number as a float64.
func (n Number) Float64() (float64, error) {
return strconv.ParseFloat(string(n), 64)
}
// Int64 returns the number as an int64.
func (n Number) Int64() (int64, error) {
return strconv.ParseInt(string(n), 10, 64)
}
func CastJsonNumber(val interface{}) (string, bool) { func CastJsonNumber(val interface{}) (string, bool) {
switch typedVal := val.(type) { switch typedVal := val.(type) {
case json.Number: case json.Number:

View File

@ -28,6 +28,7 @@ func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream {
func (cfg *frozenConfig) ReturnStream(stream *Stream) { func (cfg *frozenConfig) ReturnStream(stream *Stream) {
stream.Error = nil stream.Error = nil
stream.Attachment = nil
select { select {
case cfg.streamPool <- stream: case cfg.streamPool <- stream:
return return
@ -48,6 +49,7 @@ func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator {
func (cfg *frozenConfig) ReturnIterator(iter *Iterator) { func (cfg *frozenConfig) ReturnIterator(iter *Iterator) {
iter.Error = nil iter.Error = nil
iter.Attachment = nil
select { select {
case cfg.iteratorPool <- iter: case cfg.iteratorPool <- iter:
return return

View File

@ -72,24 +72,24 @@ func init() {
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
} }
type optionalDecoder struct { type OptionalDecoder struct {
valueType reflect.Type ValueType reflect.Type
valueDecoder ValDecoder ValueDecoder ValDecoder
} }
func (decoder *optionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { if iter.ReadNil() {
*((*unsafe.Pointer)(ptr)) = nil *((*unsafe.Pointer)(ptr)) = nil
} else { } else {
if *((*unsafe.Pointer)(ptr)) == nil { if *((*unsafe.Pointer)(ptr)) == nil {
//pointer to null, we have to allocate memory to hold the value //pointer to null, we have to allocate memory to hold the value
value := reflect.New(decoder.valueType) value := reflect.New(decoder.ValueType)
newPtr := extractInterface(value.Interface()).word newPtr := extractInterface(value.Interface()).word
decoder.valueDecoder.Decode(newPtr, iter) decoder.ValueDecoder.Decode(newPtr, iter)
*((*uintptr)(ptr)) = uintptr(newPtr) *((*uintptr)(ptr)) = uintptr(newPtr)
} else { } else {
//reuse existing instance //reuse existing instance
decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter) decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter)
} }
} }
} }
@ -113,11 +113,31 @@ func (decoder *deferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
} }
} }
type optionalEncoder struct { type OptionalEncoder struct {
ValueEncoder ValEncoder
}
func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
if *((*unsafe.Pointer)(ptr)) == nil {
stream.WriteNil()
} else {
encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream)
}
}
func (encoder *OptionalEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*unsafe.Pointer)(ptr)) == nil
}
type optionalMapEncoder struct {
valueEncoder ValEncoder valueEncoder ValEncoder
} }
func (encoder *optionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *optionalMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
if *((*unsafe.Pointer)(ptr)) == nil { if *((*unsafe.Pointer)(ptr)) == nil {
stream.WriteNil() stream.WriteNil()
} else { } else {
@ -125,15 +145,13 @@ func (encoder *optionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
} }
} }
func (encoder *optionalEncoder) EncodeInterface(val interface{}, stream *Stream) { func (encoder *optionalMapEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder) WriteToStream(val, stream, encoder)
} }
func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *optionalMapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
if *((*unsafe.Pointer)(ptr)) == nil { p := *((*unsafe.Pointer)(ptr))
return true return p == nil || encoder.valueEncoder.IsEmpty(p)
}
return false
} }
type placeholderEncoder struct { type placeholderEncoder struct {
@ -146,7 +164,7 @@ func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
} }
func (encoder *placeholderEncoder) EncodeInterface(val interface{}, stream *Stream) { func (encoder *placeholderEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder) encoder.getRealEncoder().EncodeInterface(val, stream)
} }
func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool {
@ -154,11 +172,11 @@ func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool {
} }
func (encoder *placeholderEncoder) getRealEncoder() ValEncoder { func (encoder *placeholderEncoder) getRealEncoder() ValEncoder {
for i := 0; i < 30; i++ { for i := 0; i < 500; i++ {
realDecoder := encoder.cfg.getEncoderFromCache(encoder.cacheKey) realDecoder := encoder.cfg.getEncoderFromCache(encoder.cacheKey)
_, isPlaceholder := realDecoder.(*placeholderEncoder) _, isPlaceholder := realDecoder.(*placeholderEncoder)
if isPlaceholder { if isPlaceholder {
time.Sleep(time.Second) time.Sleep(10 * time.Millisecond)
} else { } else {
return realDecoder return realDecoder
} }
@ -172,11 +190,11 @@ type placeholderDecoder struct {
} }
func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
for i := 0; i < 30; i++ { for i := 0; i < 500; i++ {
realDecoder := decoder.cfg.getDecoderFromCache(decoder.cacheKey) realDecoder := decoder.cfg.getDecoderFromCache(decoder.cacheKey)
_, isPlaceholder := realDecoder.(*placeholderDecoder) _, isPlaceholder := realDecoder.(*placeholderDecoder)
if isPlaceholder { if isPlaceholder {
time.Sleep(time.Second) time.Sleep(10 * time.Millisecond)
} else { } else {
realDecoder.Decode(ptr, iter) realDecoder.Decode(ptr, iter)
return return
@ -256,7 +274,7 @@ func decoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) {
if decoder != nil { if decoder != nil {
return decoder, nil return decoder, nil
} }
decoder = getTypeDecoderFromExtension(typ) decoder = getTypeDecoderFromExtension(cfg, typ)
if decoder != nil { if decoder != nil {
cfg.addDecoderToCache(cacheKey, decoder) cfg.addDecoderToCache(cacheKey, decoder)
return decoder, nil return decoder, nil
@ -267,6 +285,9 @@ func decoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) {
for _, extension := range extensions { for _, extension := range extensions {
decoder = extension.DecorateDecoder(typ, decoder) decoder = extension.DecorateDecoder(typ, decoder)
} }
for _, extension := range cfg.extensions {
decoder = extension.DecorateDecoder(typ, decoder)
}
cfg.addDecoderToCache(cacheKey, decoder) cfg.addDecoderToCache(cacheKey, decoder)
return decoder, err return decoder, err
} }
@ -289,7 +310,7 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
templateInterface := reflect.New(typ).Elem().Interface() templateInterface := reflect.New(typ).Elem().Interface()
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)} var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
decoder = &optionalDecoder{typ.Elem(), decoder} decoder = &OptionalDecoder{typ.Elem(), decoder}
} }
return decoder, nil return decoder, nil
} }
@ -302,7 +323,7 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error
templateInterface := reflect.New(typ).Elem().Interface() templateInterface := reflect.New(typ).Elem().Interface()
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)} var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
decoder = &optionalDecoder{typ.Elem(), decoder} decoder = &OptionalDecoder{typ.Elem(), decoder}
} }
return decoder, nil return decoder, nil
} }
@ -423,7 +444,7 @@ func encoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
if encoder != nil { if encoder != nil {
return encoder, nil return encoder, nil
} }
encoder = getTypeEncoderFromExtension(typ) encoder = getTypeEncoderFromExtension(cfg, typ)
if encoder != nil { if encoder != nil {
cfg.addEncoderToCache(cacheKey, encoder) cfg.addEncoderToCache(cacheKey, encoder)
return encoder, nil return encoder, nil
@ -434,6 +455,9 @@ func encoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
for _, extension := range extensions { for _, extension := range extensions {
encoder = extension.DecorateEncoder(typ, encoder) encoder = extension.DecorateEncoder(typ, encoder)
} }
for _, extension := range cfg.extensions {
encoder = extension.DecorateEncoder(typ, encoder)
}
cfg.addEncoderToCache(cacheKey, encoder) cfg.addEncoderToCache(cacheKey, encoder)
return encoder, err return encoder, err
} }
@ -452,7 +476,7 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
return &jsoniterNumberCodec{}, nil return &jsoniterNumberCodec{}, nil
} }
if typ.Implements(marshalerType) { if typ.Implements(marshalerType) {
checkIsEmpty, err := createCheckIsEmpty(typ) checkIsEmpty, err := createCheckIsEmpty(cfg, typ)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -462,12 +486,24 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
checkIsEmpty: checkIsEmpty, checkIsEmpty: checkIsEmpty,
} }
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
encoder = &optionalEncoder{encoder} encoder = &OptionalEncoder{encoder}
}
return encoder, nil
}
if reflect.PtrTo(typ).Implements(marshalerType) {
checkIsEmpty, err := createCheckIsEmpty(cfg, reflect.PtrTo(typ))
if err != nil {
return nil, err
}
templateInterface := reflect.New(typ).Interface()
var encoder ValEncoder = &marshalerEncoder{
templateInterface: extractInterface(templateInterface),
checkIsEmpty: checkIsEmpty,
} }
return encoder, nil return encoder, nil
} }
if typ.Implements(textMarshalerType) { if typ.Implements(textMarshalerType) {
checkIsEmpty, err := createCheckIsEmpty(typ) checkIsEmpty, err := createCheckIsEmpty(cfg, typ)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -477,7 +513,7 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
checkIsEmpty: checkIsEmpty, checkIsEmpty: checkIsEmpty,
} }
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
encoder = &optionalEncoder{encoder} encoder = &OptionalEncoder{encoder}
} }
return encoder, nil return encoder, nil
} }
@ -490,7 +526,7 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
return createEncoderOfSimpleType(cfg, typ) return createEncoderOfSimpleType(cfg, typ)
} }
func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) { func createCheckIsEmpty(cfg *frozenConfig, typ reflect.Type) (checkIsEmpty, error) {
kind := typ.Kind() kind := typ.Kind()
switch kind { switch kind {
case reflect.String: case reflect.String:
@ -535,9 +571,9 @@ func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) {
case reflect.Slice: case reflect.Slice:
return &sliceEncoder{}, nil return &sliceEncoder{}, nil
case reflect.Map: case reflect.Map:
return &mapEncoder{}, nil return encoderOfMap(cfg, typ)
case reflect.Ptr: case reflect.Ptr:
return &optionalEncoder{}, nil return &OptionalEncoder{}, nil
default: default:
return nil, fmt.Errorf("unsupported type: %v", typ) return nil, fmt.Errorf("unsupported type: %v", typ)
} }
@ -648,7 +684,7 @@ func decoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &optionalDecoder{elemType, decoder}, nil return &OptionalDecoder{elemType, decoder}, nil
} }
func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
@ -657,9 +693,9 @@ func encoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
encoder := &optionalEncoder{elemEncoder} encoder := &OptionalEncoder{elemEncoder}
if elemType.Kind() == reflect.Map { if elemType.Kind() == reflect.Map {
encoder = &optionalEncoder{encoder} encoder = &OptionalEncoder{encoder}
} }
return encoder, nil return encoder, nil
} }

View File

@ -21,7 +21,7 @@ func encoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
return nil, err return nil, err
} }
if typ.Elem().Kind() == reflect.Map { if typ.Elem().Kind() == reflect.Map {
encoder = &optionalEncoder{encoder} encoder = &OptionalEncoder{encoder}
} }
return &arrayEncoder{typ, typ.Elem(), encoder}, nil return &arrayEncoder{typ, typ.Elem(), encoder}, nil
} }

View File

@ -161,22 +161,31 @@ func RegisterExtension(extension Extension) {
extensions = append(extensions, extension) extensions = append(extensions, extension)
} }
func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder { func getTypeDecoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValDecoder {
decoder := _getTypeDecoderFromExtension(typ) decoder := _getTypeDecoderFromExtension(cfg, typ)
if decoder != nil { if decoder != nil {
for _, extension := range extensions { for _, extension := range extensions {
decoder = extension.DecorateDecoder(typ, decoder) decoder = extension.DecorateDecoder(typ, decoder)
} }
for _, extension := range cfg.extensions {
decoder = extension.DecorateDecoder(typ, decoder)
}
} }
return decoder return decoder
} }
func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder { func _getTypeDecoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValDecoder {
for _, extension := range extensions { for _, extension := range extensions {
decoder := extension.CreateDecoder(typ) decoder := extension.CreateDecoder(typ)
if decoder != nil { if decoder != nil {
return decoder return decoder
} }
} }
for _, extension := range cfg.extensions {
decoder := extension.CreateDecoder(typ)
if decoder != nil {
return decoder
}
}
typeName := typ.String() typeName := typ.String()
decoder := typeDecoders[typeName] decoder := typeDecoders[typeName]
if decoder != nil { if decoder != nil {
@ -185,29 +194,38 @@ func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
decoder := typeDecoders[typ.Elem().String()] decoder := typeDecoders[typ.Elem().String()]
if decoder != nil { if decoder != nil {
return &optionalDecoder{typ.Elem(), decoder} return &OptionalDecoder{typ.Elem(), decoder}
} }
} }
return nil return nil
} }
func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder { func getTypeEncoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValEncoder {
encoder := _getTypeEncoderFromExtension(typ) encoder := _getTypeEncoderFromExtension(cfg, typ)
if encoder != nil { if encoder != nil {
for _, extension := range extensions { for _, extension := range extensions {
encoder = extension.DecorateEncoder(typ, encoder) encoder = extension.DecorateEncoder(typ, encoder)
} }
for _, extension := range cfg.extensions {
encoder = extension.DecorateEncoder(typ, encoder)
}
} }
return encoder return encoder
} }
func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder { func _getTypeEncoderFromExtension(cfg *frozenConfig, typ reflect.Type) ValEncoder {
for _, extension := range extensions { for _, extension := range extensions {
encoder := extension.CreateEncoder(typ) encoder := extension.CreateEncoder(typ)
if encoder != nil { if encoder != nil {
return encoder return encoder
} }
} }
for _, extension := range cfg.extensions {
encoder := extension.CreateEncoder(typ)
if encoder != nil {
return encoder
}
}
typeName := typ.String() typeName := typ.String()
encoder := typeEncoders[typeName] encoder := typeEncoders[typeName]
if encoder != nil { if encoder != nil {
@ -216,7 +234,7 @@ func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
if typ.Kind() == reflect.Ptr { if typ.Kind() == reflect.Ptr {
encoder := typeEncoders[typ.Elem().String()] encoder := typeEncoders[typ.Elem().String()]
if encoder != nil { if encoder != nil {
return &optionalEncoder{encoder} return &OptionalEncoder{encoder}
} }
} }
return nil return nil
@ -254,7 +272,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
for _, binding := range structDescriptor.Fields { for _, binding := range structDescriptor.Fields {
binding.levels = append([]int{i}, binding.levels...) binding.levels = append([]int{i}, binding.levels...)
omitempty := binding.Encoder.(*structFieldEncoder).omitempty omitempty := binding.Encoder.(*structFieldEncoder).omitempty
binding.Encoder = &optionalEncoder{binding.Encoder} binding.Encoder = &OptionalEncoder{binding.Encoder}
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty} binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty}
binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder} binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
binding.Decoder = &structFieldDecoder{&field, binding.Decoder} binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
@ -269,7 +287,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
if decoder == nil { if decoder == nil {
var err error var err error
decoder, err = decoderOfType(cfg, field.Type) decoder, err = decoderOfType(cfg, field.Type)
if err != nil { if len(fieldNames) > 0 && err != nil {
return nil, err return nil, err
} }
} }
@ -277,12 +295,13 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
if encoder == nil { if encoder == nil {
var err error var err error
encoder, err = encoderOfType(cfg, field.Type) encoder, err = encoderOfType(cfg, field.Type)
if err != nil { if len(fieldNames) > 0 && err != nil {
return nil, err return nil, err
} }
// map is stored as pointer in the struct // map is stored as pointer in the struct,
if field.Type.Kind() == reflect.Map { // and treat nil or empty map as empty field
encoder = &optionalEncoder{encoder} if encoder != nil && field.Type.Kind() == reflect.Map {
encoder = &optionalMapEncoder{encoder}
} }
} }
binding := &Binding{ binding := &Binding{
@ -323,6 +342,9 @@ func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Bin
for _, extension := range extensions { for _, extension := range extensions {
extension.UpdateStructDescriptor(structDescriptor) extension.UpdateStructDescriptor(structDescriptor)
} }
for _, extension := range cfg.extensions {
extension.UpdateStructDescriptor(structDescriptor)
}
processTags(structDescriptor, cfg) processTags(structDescriptor, cfg)
// merge normal & embedded bindings & sort with original order // merge normal & embedded bindings & sort with original order
allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...)) allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...))

View File

@ -4,6 +4,7 @@ import (
"encoding" "encoding"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"reflect"
"unsafe" "unsafe"
) )
@ -31,7 +32,9 @@ type intCodec struct {
} }
func (codec *intCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *intCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*int)(ptr)) = iter.ReadInt() *((*int)(ptr)) = iter.ReadInt()
}
} }
func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *intCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -50,7 +53,9 @@ type uintptrCodec struct {
} }
func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64()) *((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
}
} }
func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -69,7 +74,9 @@ type int8Codec struct {
} }
func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*int8)(ptr)) = iter.ReadInt8() *((*int8)(ptr)) = iter.ReadInt8()
}
} }
func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -88,7 +95,9 @@ type int16Codec struct {
} }
func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*int16)(ptr)) = iter.ReadInt16() *((*int16)(ptr)) = iter.ReadInt16()
}
} }
func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -107,7 +116,9 @@ type int32Codec struct {
} }
func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*int32)(ptr)) = iter.ReadInt32() *((*int32)(ptr)) = iter.ReadInt32()
}
} }
func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -126,7 +137,9 @@ type int64Codec struct {
} }
func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *int64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*int64)(ptr)) = iter.ReadInt64() *((*int64)(ptr)) = iter.ReadInt64()
}
} }
func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *int64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -145,7 +158,10 @@ type uintCodec struct {
} }
func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uint)(ptr)) = iter.ReadUint() *((*uint)(ptr)) = iter.ReadUint()
return
}
} }
func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -164,7 +180,9 @@ type uint8Codec struct {
} }
func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint8Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uint8)(ptr)) = iter.ReadUint8() *((*uint8)(ptr)) = iter.ReadUint8()
}
} }
func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint8Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -183,7 +201,9 @@ type uint16Codec struct {
} }
func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uint16)(ptr)) = iter.ReadUint16() *((*uint16)(ptr)) = iter.ReadUint16()
}
} }
func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -202,7 +222,9 @@ type uint32Codec struct {
} }
func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uint32)(ptr)) = iter.ReadUint32() *((*uint32)(ptr)) = iter.ReadUint32()
}
} }
func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -221,7 +243,9 @@ type uint64Codec struct {
} }
func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *uint64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uint64)(ptr)) = iter.ReadUint64() *((*uint64)(ptr)) = iter.ReadUint64()
}
} }
func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *uint64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -240,7 +264,9 @@ type float32Codec struct {
} }
func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *float32Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*float32)(ptr)) = iter.ReadFloat32() *((*float32)(ptr)) = iter.ReadFloat32()
}
} }
func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *float32Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -259,7 +285,9 @@ type float64Codec struct {
} }
func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *float64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*float64)(ptr)) = iter.ReadFloat64() *((*float64)(ptr)) = iter.ReadFloat64()
}
} }
func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *float64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -278,7 +306,9 @@ type boolCodec struct {
} }
func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*bool)(ptr)) = iter.ReadBool() *((*bool)(ptr)) = iter.ReadBool()
}
} }
func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -297,7 +327,42 @@ type emptyInterfaceCodec struct {
} }
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
existing := *((*interface{})(ptr))
// Checking for both typed and untyped nil pointers.
if existing != nil &&
reflect.TypeOf(existing).Kind() == reflect.Ptr &&
!reflect.ValueOf(existing).IsNil() {
var ptrToExisting interface{}
for {
elem := reflect.ValueOf(existing).Elem()
if elem.Kind() != reflect.Ptr || elem.IsNil() {
break
}
ptrToExisting = existing
existing = elem.Interface()
}
if iter.ReadNil() {
if ptrToExisting != nil {
nilPtr := reflect.Zero(reflect.TypeOf(ptrToExisting).Elem())
reflect.ValueOf(ptrToExisting).Elem().Set(nilPtr)
} else {
*((*interface{})(ptr)) = nil
}
} else {
iter.ReadVal(existing)
}
return
}
if iter.ReadNil() {
*((*interface{})(ptr)) = nil
} else {
*((*interface{})(ptr)) = iter.Read() *((*interface{})(ptr)) = iter.Read()
}
} }
func (codec *emptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *emptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -309,7 +374,8 @@ func (codec *emptyInterfaceCodec) EncodeInterface(val interface{}, stream *Strea
} }
func (codec *emptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *emptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool {
return ptr == nil emptyInterface := (*emptyInterface)(ptr)
return emptyInterface.typ == nil
} }
type nonEmptyInterfaceCodec struct { type nonEmptyInterfaceCodec struct {
@ -326,15 +392,20 @@ func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator)
e.typ = nonEmptyInterface.itab.typ e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word e.word = nonEmptyInterface.word
iter.ReadVal(&i) iter.ReadVal(&i)
if e.word == nil {
nonEmptyInterface.itab = nil
}
nonEmptyInterface.word = e.word nonEmptyInterface.word = e.word
} }
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
nonEmptyInterface := (*nonEmptyInterface)(ptr) nonEmptyInterface := (*nonEmptyInterface)(ptr)
var i interface{} var i interface{}
if nonEmptyInterface.itab != nil {
e := (*emptyInterface)(unsafe.Pointer(&i)) e := (*emptyInterface)(unsafe.Pointer(&i))
e.typ = nonEmptyInterface.itab.typ e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word e.word = nonEmptyInterface.word
}
stream.WriteVal(i) stream.WriteVal(i)
} }
@ -370,7 +441,15 @@ type jsonNumberCodec struct {
} }
func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
switch iter.WhatIsNext() {
case StringValue:
*((*json.Number)(ptr)) = json.Number(iter.ReadString())
case NilValue:
iter.skipFourBytes('n', 'u', 'l', 'l')
*((*json.Number)(ptr)) = ""
default:
*((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString())) *((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString()))
}
} }
func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -389,7 +468,15 @@ type jsoniterNumberCodec struct {
} }
func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
switch iter.WhatIsNext() {
case StringValue:
*((*Number)(ptr)) = Number(iter.ReadString())
case NilValue:
iter.skipFourBytes('n', 'u', 'l', 'l')
*((*Number)(ptr)) = ""
default:
*((*Number)(ptr)) = Number([]byte(iter.readNumberAsString())) *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString()))
}
} }
func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -521,7 +608,7 @@ type stringModeNumberDecoder struct {
func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
c := iter.nextToken() c := iter.nextToken()
if c != '"' { if c != '"' {
iter.ReportError("stringModeNumberDecoder", `expect "`) iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))
return return
} }
decoder.elemDecoder.Decode(ptr, iter) decoder.elemDecoder.Decode(ptr, iter)
@ -530,7 +617,7 @@ func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
} }
c = iter.readByte() c = iter.readByte()
if c != '"' { if c != '"' {
iter.ReportError("stringModeNumberDecoder", `expect "`) iter.ReportError("stringModeNumberDecoder", `expect ", but found `+string([]byte{c}))
return return
} }
} }
@ -595,7 +682,12 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
templateInterface := encoder.templateInterface templateInterface := encoder.templateInterface
templateInterface.word = ptr templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(json.Marshaler) marshaler, ok := (*realInterface).(json.Marshaler)
if !ok {
stream.WriteVal(nil)
return
}
bytes, err := marshaler.MarshalJSON() bytes, err := marshaler.MarshalJSON()
if err != nil { if err != nil {
stream.Error = err stream.Error = err

View File

@ -21,7 +21,7 @@ func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
return nil, err return nil, err
} }
if typ.Elem().Kind() == reflect.Map { if typ.Elem().Kind() == reflect.Map {
encoder = &optionalEncoder{encoder} encoder = &OptionalEncoder{encoder}
} }
return &sliceEncoder{typ, typ.Elem(), encoder}, nil return &sliceEncoder{typ, typ.Elem(), encoder}, nil
} }
@ -127,12 +127,10 @@ func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Typ
newVal := reflect.MakeSlice(sliceType, newLen, newCap) newVal := reflect.MakeSlice(sliceType, newLen, newCap)
dst := unsafe.Pointer(newVal.Pointer()) dst := unsafe.Pointer(newVal.Pointer())
// copy old array into new array // copy old array into new array
originalBytesCount := uintptr(slice.Len) * elementType.Size() originalBytesCount := slice.Len * int(elementType.Size())
srcPtr := (*[1 << 30]byte)(slice.Data) srcSliceHeader := (unsafe.Pointer)(&sliceHeader{slice.Data, originalBytesCount, originalBytesCount})
dstPtr := (*[1 << 30]byte)(dst) dstSliceHeader := (unsafe.Pointer)(&sliceHeader{dst, originalBytesCount, originalBytesCount})
for i := uintptr(0); i < originalBytesCount; i++ { copy(*(*[]byte)(dstSliceHeader), *(*[]byte)(srcSliceHeader))
dstPtr[i] = srcPtr[i]
}
slice.Data = dst slice.Data = dst
slice.Len = newLen slice.Len = newLen
slice.Cap = newCap slice.Cap = newCap

View File

@ -427,8 +427,18 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
if !iter.readObjectStart() { if !iter.readObjectStart() {
return return
} }
fieldBytes := iter.readObjectFieldAsBytes() var fieldBytes []byte
field := *(*string)(unsafe.Pointer(&fieldBytes)) var field string
if iter.cfg.objectFieldMustBeSimpleString {
fieldBytes = iter.readObjectFieldAsBytes()
field = *(*string)(unsafe.Pointer(&fieldBytes))
} else {
field = iter.ReadString()
c := iter.nextToken()
if c != ':' {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
}
fieldDecoder := decoder.fields[strings.ToLower(field)] fieldDecoder := decoder.fields[strings.ToLower(field)]
if fieldDecoder == nil { if fieldDecoder == nil {
iter.Skip() iter.Skip()
@ -436,8 +446,16 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
fieldDecoder.Decode(ptr, iter) fieldDecoder.Decode(ptr, iter)
} }
for iter.nextToken() == ',' { for iter.nextToken() == ',' {
fieldBytes = iter.readObjectFieldAsBytes() if iter.cfg.objectFieldMustBeSimpleString {
fieldBytes := iter.readObjectFieldAsBytes()
field = *(*string)(unsafe.Pointer(&fieldBytes)) field = *(*string)(unsafe.Pointer(&fieldBytes))
} else {
field = iter.ReadString()
c := iter.nextToken()
if c != ':' {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
}
fieldDecoder = decoder.fields[strings.ToLower(field)] fieldDecoder = decoder.fields[strings.ToLower(field)]
if fieldDecoder == nil { if fieldDecoder == nil {
iter.Skip() iter.Skip()

View File

@ -4,7 +4,7 @@ import (
"io" "io"
) )
// Stream is a io.Writer like object, with JSON specific write functions. // stream is a io.Writer like object, with JSON specific write functions.
// Error is not returned as return value, but stored as Error member on this stream instance. // Error is not returned as return value, but stored as Error member on this stream instance.
type Stream struct { type Stream struct {
cfg *frozenConfig cfg *frozenConfig
@ -13,6 +13,7 @@ type Stream struct {
n int n int
Error error Error error
indention int indention int
Attachment interface{} // open for customized encoder
} }
// NewStream create new stream instance. // NewStream create new stream instance.
@ -191,6 +192,9 @@ func (stream *Stream) ensure(minimal int) {
func (stream *Stream) growAtLeast(minimal int) { func (stream *Stream) growAtLeast(minimal int) {
if stream.out != nil { if stream.out != nil {
stream.Flush() stream.Flush()
if stream.Available() >= minimal {
return
}
} }
toGrow := len(stream.buf) toGrow := len(stream.buf)
if toGrow < minimal { if toGrow < minimal {
@ -280,8 +284,7 @@ func (stream *Stream) WriteArrayStart() {
// WriteEmptyArray write [] // WriteEmptyArray write []
func (stream *Stream) WriteEmptyArray() { func (stream *Stream) WriteEmptyArray() {
stream.writeByte('[') stream.writeTwoBytes('[', ']')
stream.writeByte(']')
} }
// WriteArrayEnd write ] with possible indention // WriteArrayEnd write ] with possible indention